text: /**
   * 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
   */
  
  // flowlint ambiguous-object-type:error
  
  'use strict';
  
  const invariant = require('invariant');
  
  import type {NormalizationOperation} from '../util/NormalizationNode';
  import type {ReaderFragment} from '../util/ReaderNode';
  import type {Variables} from '../util/RelayRuntimeTypes';
  
  /**
   * Determines the variables that are in scope for a fragment given the variables
   * in scope at the root query as well as any arguments applied at the fragment
   * spread via `@arguments`.
   *
   * Note that this is analagous to determining function arguments given a function call.
   */
  function getFragmentVariables(
    fragment: ReaderFragment,
    rootVariables: Variables,
    argumentVariables: Variables,
  ): Variables {
    let variables;
    fragment.argumentDefinitions.forEach(definition => {
      if (argumentVariables.hasOwnProperty(definition.name)) {
        return;
      }
      variables = variables || {...argumentVariables};
      switch (definition.kind) {
        case 'LocalArgument':
          variables[definition.name] = definition.defaultValue;
          break;
        case 'RootArgument':
          if (!rootVariables.hasOwnProperty(definition.name)) {
            /*
             * Global variables passed as values of @arguments are not required to
             * be declared unless they are used by the callee fragment or a
             * descendant. In this case, the root variable may not be defined when
             * resolving the callee's variables. The value is explicitly set to
             * undefined to conform to the check in
             * RelayStoreUtils.getStableVariableValue() that variable keys are all
             * present.
             */
            // $FlowFixMe[incompatible-use]
            variables[definition.name] = undefined;
            break;
          }
          // $FlowFixMe[incompatible-use]
          variables[definition.name] = rootVariables[definition.name];
          break;
        default:
          (definition: empty);
          invariant(
            false,
            'RelayConcreteVariables: Unexpected node kind `%s` in fragment `%s`.',
            definition.kind,
            fragment.name,
          );
      }
    });
    return variables || argumentVariables;
  }
  
  /**
   * Determines the variables that are in scope for a given operation given values
   * for some/all of its arguments. Extraneous input variables are filtered from
   * the output, and missing variables are set to default values (if given in the
   * operation's definition).
   */
  function getOperationVariables(
    operation: NormalizationOperation,
    variables: Variables,
  ): Variables {
    const operationVariables = {};
    operation.argumentDefinitions.forEach(def => {
      let value = def.defaultValue;
      if (variables[def.name] != null) {
        value = variables[def.name];
      }
      operationVariables[def.name] = value;
    });
    return operationVariables;
  }
  
  module.exports = {
    getFragmentVariables,
    getOperationVariables,
  };
  