157 lines
4.7 KiB
JavaScript
157 lines
4.7 KiB
JavaScript
/**
|
|
* 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.
|
|
*
|
|
* strict-local
|
|
* @format
|
|
*/
|
|
'use strict';
|
|
|
|
var _require = require("./RelayCompilerError"),
|
|
createCombinedError = _require.createCombinedError,
|
|
createUserError = _require.createUserError,
|
|
eachWithErrors = _require.eachWithErrors;
|
|
|
|
var _require2 = require("graphql"),
|
|
GraphQLNonNull = _require2.GraphQLNonNull;
|
|
|
|
/**
|
|
* Creates a scope for a `Root`, with each argument mapped to a variable of the
|
|
* same name. Example:
|
|
*
|
|
* Query:
|
|
* query Foo($id: ID, $size: Int = 42) { ... }
|
|
*
|
|
* Scope:
|
|
* {
|
|
* id: $id,
|
|
* size: $size,
|
|
* }
|
|
*
|
|
* Note that even though a default value is defined for $size, the scope must
|
|
* assume that this could be overridden at runtime. The value cannot be decided
|
|
* statically and therefore is set to a variable.
|
|
*/
|
|
function getRootScope(definitions) {
|
|
var scope = {};
|
|
definitions.forEach(function (definition) {
|
|
scope[definition.name] = {
|
|
kind: 'Variable',
|
|
metadata: null,
|
|
variableName: definition.name,
|
|
type: definition.type
|
|
};
|
|
});
|
|
return scope;
|
|
}
|
|
/**
|
|
* Creates a scope for a `Fragment` by translating fragment spread arguments in
|
|
* the context of a parent scope into a new scope and validating them against
|
|
* the argument definitions.
|
|
*
|
|
*
|
|
* Parent Scope:
|
|
* {
|
|
* active: $parentActive
|
|
* }
|
|
*
|
|
* Fragment Spread:
|
|
* ...Bar(size: 42, enabled: $active)
|
|
*
|
|
* Fragment:
|
|
* fragment Bar on Foo @argumentDefinitions(
|
|
* id: {type: "ID"}
|
|
* size: {type: "Int"}
|
|
* enabled: {type: "Boolean}
|
|
* scale: {type: "Int", imports: "pixelRatio"}
|
|
* )
|
|
*
|
|
* Scope:
|
|
* {
|
|
* // No argument is provided for $id, it gets the default value which in this
|
|
* // case is `null`:
|
|
* id: null,
|
|
*
|
|
* // The parent passes 42 as a literal value for $size:
|
|
* size: 42,
|
|
*
|
|
* // The parent passes a variable as the value of $enabled. This variable is
|
|
* // resolved in the parent scope to the value $parentActive, which becomes
|
|
* // the value of $enabled:
|
|
* $enabled: $parentActive,
|
|
*
|
|
* // $scale imports pixelRatio from the root scope. Since any argument in a
|
|
* // root scope maps to a variable of the same name, that means the value of
|
|
* // pixelRatio in the root is $pixelRatio:
|
|
* $scale: $pixelRatio,
|
|
* }
|
|
*/
|
|
|
|
|
|
function getFragmentScope(definitions, args, parentScope, spread) {
|
|
var argMap = new Map();
|
|
args.forEach(function (arg) {
|
|
if (arg.value.kind === 'Literal') {
|
|
argMap.set(arg.name, arg.value);
|
|
} else if (arg.value.kind === 'Variable') {
|
|
argMap.set(arg.name, parentScope[arg.value.variableName]);
|
|
}
|
|
});
|
|
var fragmentScope = {};
|
|
var errors = eachWithErrors(definitions, function (definition) {
|
|
if (definition.kind === 'RootArgumentDefinition') {
|
|
if (argMap.has(definition.name)) {
|
|
var _ref;
|
|
|
|
var argNode = args.find(function (a) {
|
|
return a.name === definition.name;
|
|
});
|
|
throw createUserError("Unexpected argument '".concat(definition.name, "' supplied to fragment '").concat(spread.name, "'. @arguments may only be provided for variables defined in the fragment's @argumentDefinitions."), [(_ref = argNode === null || argNode === void 0 ? void 0 : argNode.loc) !== null && _ref !== void 0 ? _ref : spread.loc]);
|
|
}
|
|
|
|
fragmentScope[definition.name] = {
|
|
kind: 'Variable',
|
|
metadata: null,
|
|
variableName: definition.name,
|
|
type: definition.type
|
|
};
|
|
} else {
|
|
var arg = argMap.get(definition.name);
|
|
|
|
if (arg == null || arg.kind === 'Literal' && arg.value == null) {
|
|
// No variable or literal null was passed, fall back to default
|
|
// value.
|
|
if (definition.defaultValue == null && definition.type instanceof GraphQLNonNull) {
|
|
var _ref2;
|
|
|
|
var _argNode = args.find(function (a) {
|
|
return a.name === definition.name;
|
|
});
|
|
|
|
throw createUserError("No value found for required argument '".concat(definition.name, ": ").concat(String(definition.type), "' on fragment '").concat(spread.name, "'."), [(_ref2 = _argNode === null || _argNode === void 0 ? void 0 : _argNode.loc) !== null && _ref2 !== void 0 ? _ref2 : spread.loc]);
|
|
}
|
|
|
|
fragmentScope[definition.name] = {
|
|
kind: 'Literal',
|
|
value: definition.defaultValue
|
|
};
|
|
} else {
|
|
// Variable or non-null literal.
|
|
fragmentScope[definition.name] = arg;
|
|
}
|
|
}
|
|
});
|
|
|
|
if (errors != null && errors.length) {
|
|
throw createCombinedError(errors);
|
|
}
|
|
|
|
return fragmentScope;
|
|
}
|
|
|
|
module.exports = {
|
|
getFragmentScope: getFragmentScope,
|
|
getRootScope: getRootScope
|
|
}; |