<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

'use strict';

const RelayConcreteNode = require('../util/RelayConcreteNode');
const RelayConnection = require('./RelayConnection');
const RelayModernRecord = require('./RelayModernRecord');
const RelayStoreUtils = require('./RelayStoreUtils');

const cloneRelayHandleSourceField = require('./cloneRelayHandleSourceField');
const invariant = require('invariant');

import type {
  NormalizationConnection,
  NormalizationLinkedField,
  NormalizationModuleImport,
  NormalizationNode,
  NormalizationSelection,
} from '../util/NormalizationNode';
import type {DataID, Variables} from '../util/RelayRuntimeTypes';
import type {GetConnectionEvents} from './RelayConnection';
import type {
  NormalizationSelector,
  OperationLoader,
  Record,
  RecordSource,
} from './RelayStoreTypes';

const {
  CONDITION,
  CLIENT_EXTENSION,
  DEFER,
  CONNECTION,
  FRAGMENT_SPREAD,
  INLINE_FRAGMENT,
  LINKED_FIELD,
  MODULE_IMPORT,
  LINKED_HANDLE,
  SCALAR_FIELD,
  SCALAR_HANDLE,
  STREAM,
} = RelayConcreteNode;
const {getStorageKey, getModuleOperationKey} = RelayStoreUtils;

function mark(
  recordSource: RecordSource,
  selector: NormalizationSelector,
  references: Set<DataID>,
  connectionReferences: Set<string>,
  getConnectionEvents: GetConnectionEvents,
  operationLoader: ?OperationLoader,
): void {
  const {dataID, node, variables} = selector;
  const marker = new RelayReferenceMarker(
    recordSource,
    variables,
    references,
    connectionReferences,
    getConnectionEvents,
    operationLoader,
  );
  marker.mark(node, dataID);
}

/**
 * @private
 */
class RelayReferenceMarker {
  _connectionReferences: Set<string>;
  _getConnectionEvents: GetConnectionEvents;
  _operationLoader: OperationLoader | null;
  _recordSource: RecordSource;
  _references: Set<DataID>;
  _variables: Variables;

  constructor(
    recordSource: RecordSource,
    variables: Variables,
    references: Set<DataID>,
    connectionReferences: Set<string>,
    getConnectionEvents: GetConnectionEvents,
    operationLoader: ?OperationLoader,
  ) {
    this._connectionReferences = connectionReferences;
    this._getConnectionEvents = getConnectionEvents;
    this._operationLoader = operationLoader ?? null;
    this._recordSource = recordSource;
    this._references = references;
    this._variables = variables;
  }

  mark(node: NormalizationNode, dataID: DataID): void {
    this._traverse(node, dataID);
  }

  _traverse(node: NormalizationNode, dataID: DataID): void {
    this._references.add(dataID);
    const record = this._recordSource.get(dataID);
    if (record == null) {
      return;
    }
    this._traverseSelections(node.selections, record);
  }

  _getVariableValue(name: string): mixed {
    invariant(
      this._variables.hasOwnProperty(name),
      'RelayReferenceMarker(): Undefined variable `%s`.',
      name,
    );
    return this._variables[name];
  }

  _traverseSelections(
    selections: $ReadOnlyArray<NormalizationSelection>,
    record: Record,
  ): void {
    selections.forEach(selection => {
      /* eslint-disable no-fallthrough */
      switch (selection.kind) {
        case LINKED_FIELD:
          if (selection.plural) {
            this._traversePluralLink(selection, record);
          } else {
            this._traverseLink(selection, record);
          }
          break;
        case CONDITION:
          const conditionValue = this._getVariableValue(selection.condition);
          if (conditionValue === selection.passingValue) {
            this._traverseSelections(selection.selections, record);
          }
          break;
        case INLINE_FRAGMENT:
          const typeName = RelayModernRecord.getType(record);
          if (typeName != null && typeName === selection.type) {
            this._traverseSelections(selection.selections, record);
          }
          break;
        case FRAGMENT_SPREAD:
          invariant(
            false,
            'RelayReferenceMarker(): Unexpected fragment spread `...%s`, ' +
              'expected all fragments to be inlined.',
            selection.name,
          );
        case LINKED_HANDLE:
          // The selections for a "handle" field are the same as those of the
          // original linked field where the handle was applied. Reference marking
          // therefore requires traversing the original field selections against
          // the synthesized client field.
          //
          // TODO: Instead of finding the source field in `selections`, change
          // the concrete structure to allow shared subtrees, and have the linked
          // handle directly refer to the same selections as the LinkedField that
          // it was split from.
          const handleField = cloneRelayHandleSourceField(
            selection,
            selections,
            this._variables,
          );
          if (handleField.plural) {
            this._traversePluralLink(handleField, record);
          } else {
            this._traverseLink(handleField, record);
          }
          break;
        case DEFER:
        case STREAM:
          this._traverseSelections(selection.selections, record);
          break;
        case SCALAR_FIELD:
        case SCALAR_HANDLE:
          break;
        case MODULE_IMPORT:
          this._traverseModuleImport(selection, record);
          break;
        case CLIENT_EXTENSION:
          this._traverseSelections(selection.selections, record);
          break;
        case CONNECTION:
          this._traverseConnection(selection, record);
          // $FlowExpectedError - we need the break; for OSS linter
          break;
        default:
          (selection: empty);
          invariant(
            false,
            'RelayReferenceMarker: Unknown AST node `%s`.',
            selection,
          );
      }
    });
  }

  _traverseConnection(
    connection: NormalizationConnection,
    record: Record,
  ): void {
    const parentID = RelayModernRecord.getDataID(record);
    const connectionID = RelayConnection.createConnectionID(<commit_msg>Remove unused suppression comments ahead of v0.108.0 deploy<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

'use strict';

const RelayConcreteNode = require('../util/RelayConcreteNode');
const RelayConnection = require('./RelayConnection');
const RelayModernRecord = require('./RelayModernRecord');
const RelayStoreUtils = require('./RelayStoreUtils');

const cloneRelayHandleSourceField = require('./cloneRelayHandleSourceField');
const invariant = require('invariant');

import type {
  NormalizationConnection,
  NormalizationLinkedField,
  NormalizationModuleImport,
  NormalizationNode,
  NormalizationSelection,
} from '../util/NormalizationNode';
import type {DataID, Variables} from '../util/RelayRuntimeTypes';
import type {GetConnectionEvents} from './RelayConnection';
import type {
  NormalizationSelector,
  OperationLoader,
  Record,
  RecordSource,
} from './RelayStoreTypes';

const {
  CONDITION,
  CLIENT_EXTENSION,
  DEFER,
  CONNECTION,
  FRAGMENT_SPREAD,
  INLINE_FRAGMENT,
  LINKED_FIELD,
  MODULE_IMPORT,
  LINKED_HANDLE,
  SCALAR_FIELD,
  SCALAR_HANDLE,
  STREAM,
} = RelayConcreteNode;
const {getStorageKey, getModuleOperationKey} = RelayStoreUtils;

function mark(
  recordSource: RecordSource,
  selector: NormalizationSelector,
  references: Set<DataID>,
  connectionReferences: Set<string>,
  getConnectionEvents: GetConnectionEvents,
  operationLoader: ?OperationLoader,
): void {
  const {dataID, node, variables} = selector;
  const marker = new RelayReferenceMarker(
    recordSource,
    variables,
    references,
    connectionReferences,
    getConnectionEvents,
    operationLoader,
  );
  marker.mark(node, dataID);
}

/**
 * @private
 */
class RelayReferenceMarker {
  _connectionReferences: Set<string>;
  _getConnectionEvents: GetConnectionEvents;
  _operationLoader: OperationLoader | null;
  _recordSource: RecordSource;
  _references: Set<DataID>;
  _variables: Variables;

  constructor(
    recordSource: RecordSource,
    variables: Variables,
    references: Set<DataID>,
    connectionReferences: Set<string>,
    getConnectionEvents: GetConnectionEvents,
    operationLoader: ?OperationLoader,
  ) {
    this._connectionReferences = connectionReferences;
    this._getConnectionEvents = getConnectionEvents;
    this._operationLoader = operationLoader ?? null;
    this._recordSource = recordSource;
    this._references = references;
    this._variables = variables;
  }

  mark(node: NormalizationNode, dataID: DataID): void {
    this._traverse(node, dataID);
  }

  _traverse(node: NormalizationNode, dataID: DataID): void {
    this._references.add(dataID);
    const record = this._recordSource.get(dataID);
    if (record == null) {
      return;
    }
    this._traverseSelections(node.selections, record);
  }

  _getVariableValue(name: string): mixed {
    invariant(
      this._variables.hasOwnProperty(name),
      'RelayReferenceMarker(): Undefined variable `%s`.',
      name,
    );
    return this._variables[name];
  }

  _traverseSelections(
    selections: $ReadOnlyArray<NormalizationSelection>,
    record: Record,
  ): void {
    selections.forEach(selection => {
      /* eslint-disable no-fallthrough */
      switch (selection.kind) {
        case LINKED_FIELD:
          if (selection.plural) {
            this._traversePluralLink(selection, record);
          } else {
            this._traverseLink(selection, record);
          }
          break;
        case CONDITION:
          const conditionValue = this._getVariableValue(selection.condition);
          if (conditionValue === selection.passingValue) {
            this._traverseSelections(selection.selections, record);
          }
          break;
        case INLINE_FRAGMENT:
          const typeName = RelayModernRecord.getType(record);
          if (typeName != null && typeName === selection.type) {
            this._traverseSelections(selection.selections, record);
          }
          break;
        case FRAGMENT_SPREAD:
          invariant(
            false,
            'RelayReferenceMarker(): Unexpected fragment spread `...%s`, ' +
              'expected all fragments to be inlined.',
            selection.name,
          );
        case LINKED_HANDLE:
          // The selections for a "handle" field are the same as those of the
          // original linked field where the handle was applied. Reference marking
          // therefore requires traversing the original field selections against
          // the synthesized client field.
          //
          // TODO: Instead of finding the source field in `selections`, change
          // the concrete structure to allow shared subtrees, and have the linked
          // handle directly refer to the same selections as the LinkedField that
          // it was split from.
          const handleField = cloneRelayHandleSourceField(
            selection,
            selections,
            this._variables,
          );
          if (handleField.plural) {
            this._traversePluralLink(handleField, record);
          } else {
            this._traverseLink(handleField, record);
          }
          break;
        case DEFER:
        case STREAM:
          this._traverseSelections(selection.selections, record);
          break;
        case SCALAR_FIELD:
        case SCALAR_HANDLE:
          break;
        case MODULE_IMPORT:
          this._traverseModuleImport(selection, record);
          break;
        case CLIENT_EXTENSION:
          this._traverseSelections(selection.selections, record);
          break;
        case CONNECTION:
          this._traverseConnection(selection, record);
          break;
        default:
          (selection: empty);
          invariant(
            false,
            'RelayReferenceMarker: Unknown AST node `%s`.',
            selection,
          );
      }
    });
  }

  _traverseConnection(
    connection: NormalizationConnection,
    record: Record,
  ): void {
    const parentID = RelayModernRecord.getDataID(record);
    const connectionID = RelayConnection.createConnectionID(
{'fraction_non_alphanumeric': 0.09084372003835091, 'fraction_numerical': 0.0003994886545222116, 'mean_word_length': 2.8080316397931244, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7315716', 'n_tokens_mistral': 3380, 'n_tokens_neox': 3311, 'n_words': 824}