/** * 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. * * * @format */ 'use strict'; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var Profiler = require("./GraphQLCompilerProfiler"); var _require = require("./DefaultHandleKey"), DEFAULT_HANDLE_KEY = _require.DEFAULT_HANDLE_KEY; var _require2 = require("./GraphQLSchemaUtils"), getNullableType = _require2.getNullableType, getTypeFromAST = _require2.getTypeFromAST, isExecutableDefinitionAST = _require2.isExecutableDefinitionAST; var _require3 = require("./RelayCompilerError"), createCombinedError = _require3.createCombinedError, createCompilerError = _require3.createCompilerError, createUserError = _require3.createUserError, eachWithErrors = _require3.eachWithErrors; var _require4 = require("./getFieldDefinition"), getFieldDefinitionLegacy = _require4.getFieldDefinitionLegacy; var _require5 = require("graphql"), assertCompositeType = _require5.assertCompositeType, assertInputType = _require5.assertInputType, assertOutputType = _require5.assertOutputType, extendSchema = _require5.extendSchema, getNamedType = _require5.getNamedType, GraphQLEnumType = _require5.GraphQLEnumType, GraphQLID = _require5.GraphQLID, GraphQLInputObjectType = _require5.GraphQLInputObjectType, GraphQLList = _require5.GraphQLList, GraphQLNonNull = _require5.GraphQLNonNull, GraphQLScalarType = _require5.GraphQLScalarType, isLeafType = _require5.isLeafType, isTypeSubTypeOf = _require5.isTypeSubTypeOf, parseGraphQL = _require5.parse, parseType = _require5.parseType, Source = _require5.Source; var ARGUMENT_DEFINITIONS = 'argumentDefinitions'; var ARGUMENTS = 'arguments'; /** * @internal * * This directive is not intended for use by developers directly. To set a field * handle in product code use a compiler plugin. */ var CLIENT_FIELD = '__clientField'; var CLIENT_FIELD_HANDLE = 'handle'; var CLIENT_FIELD_KEY = 'key'; var CLIENT_FIELD_FILTERS = 'filters'; var INCLUDE = 'include'; var SKIP = 'skip'; var IF = 'if'; /** * Transforms GraphQL text into Relay Compiler's internal, strongly-typed * intermediate representation (IR). */ function parse(schema, text, filename) { var ast = parseGraphQL(new Source(text, filename)); // TODO T24511737 figure out if this is dangerous schema = extendSchema(schema, ast, { assumeValid: true }); var parser = new RelayParser(schema, ast.definitions); return parser.transform(); } /** * Transforms untyped GraphQL parse trees (ASTs) into Relay Compiler's * internal, strongly-typed intermediate representation (IR). */ function transform(schema, definitions) { return Profiler.run('RelayParser.transform', function () { var parser = new RelayParser(schema, definitions); return parser.transform(); }); } /** * @private */ var RelayParser = /*#__PURE__*/ function () { function RelayParser(schema, definitions) { var _this = this; this._definitions = new Map(); // leaving this configurable to make it easy to experiment w changing later this._getFieldDefinition = getFieldDefinitionLegacy; this._schema = schema; var duplicated = new Set(); definitions.forEach(function (def) { if (isExecutableDefinitionAST(def)) { var name = getName(def); if (_this._definitions.has(name)) { duplicated.add(name); return; } _this._definitions.set(name, def); } }); if (duplicated.size) { throw new Error('RelayParser: Encountered duplicate defintitions for one or more ' + 'documents: each document must have a unique name. Duplicated documents:\n' + Array.from(duplicated, function (name) { return "- ".concat(name); }).join('\n')); } } var _proto = RelayParser.prototype; _proto.transform = function transform() { var _this2 = this; var errors; var nodes = []; var entries = new Map(); // Construct a mapping of name to definition ast + variable definitions. // This allows the subsequent AST -> IR tranformation to reference the // defined arguments of referenced fragments. errors = eachWithErrors(this._definitions, function (_ref2) { var name = _ref2[0], definition = _ref2[1]; var variableDefinitions = _this2._buildArgumentDefinitions(definition); entries.set(name, { definition: definition, variableDefinitions: variableDefinitions }); }); // Convert the ASTs to IR. if (errors == null) { errors = eachWithErrors(entries.values(), function (_ref3) { var definition = _ref3.definition, variableDefinitions = _ref3.variableDefinitions; var node = parseDefinition(_this2._schema, _this2._getFieldDefinition, entries, definition, variableDefinitions); nodes.push(node); }); } if (errors != null && errors.length !== 0) { throw createCombinedError(errors, 'RelayParser'); } return nodes; }; /** * Constructs a mapping of variable names to definitions for the given * operation/fragment definition. */ _proto._buildArgumentDefinitions = function _buildArgumentDefinitions(definition) { switch (definition.kind) { case 'OperationDefinition': return this._buildOperationArgumentDefinitions(definition); case 'FragmentDefinition': return this._buildFragmentArgumentDefinitions(definition); default: definition; throw createCompilerError("Unexpected ast kind '".concat(definition.kind, "'."), [definition]); } }; /** * Constructs a mapping of variable names to definitions using the * variables defined in `@argumentDefinitions`. */ _proto._buildFragmentArgumentDefinitions = function _buildFragmentArgumentDefinitions(fragment) { var _this3 = this; var variableDirectives = (fragment.directives || []).filter(function (directive) { return getName(directive) === ARGUMENT_DEFINITIONS; }); if (!variableDirectives.length) { return new Map(); } if (variableDirectives.length !== 1) { throw createUserError("Directive @".concat(ARGUMENT_DEFINITIONS, " may be defined at most once per ") + 'fragment.', null, variableDirectives); } var variableDirective = variableDirectives[0]; // $FlowIssue: refining directly on `variableDirective.arguments` doesn't // work, below accesses all report arguments could still be null/undefined. var args = variableDirective.arguments; if (variableDirective == null || !Array.isArray(args)) { return new Map(); } if (!args.length) { throw createUserError("Directive @".concat(ARGUMENT_DEFINITIONS, " requires arguments: remove the ") + 'directive to skip defining local variables for this fragment.', null, [variableDirective]); } var variables = new Map(); args.forEach(function (arg) { var argName = getName(arg); var previousVariable = variables.get(argName); if (previousVariable != null) { throw createUserError("Duplicate definition for variable '$".concat(argName, "'."), null, [previousVariable.ast, arg]); } var value = transformLiteralValue(arg.value, arg); if (Array.isArray(value) || typeof value !== 'object' || value === null || typeof value.type !== 'string') { throw createUserError("Expected definition for variable '$".concat(argName, "' to be an object ") + "with the shape: '{type: string, defaultValue?: mixed, nonNull?: " + "boolean, list?: boolean}'.", null, [arg.value]); } var unknownKeys = Object.keys(value).filter(function (key) { return key !== 'type' && key !== 'defaultValue' && key !== 'nonNull' && key !== 'list'; }); if (unknownKeys.length !== 0) { var unknownKeysString = "'" + unknownKeys.join("', '") + "'"; throw createUserError("Expected definition for variable '$".concat(argName, "' to be an object ") + "with the following shape: '{type: string, defaultValue?: mixed, " + "nonNull?: boolean, list?: boolean}', got unknown key(s) " + "".concat(unknownKeysString, "."), null, [arg]); } var typeAST = parseType(String(value.type)); var type = assertInputType(getTypeFromAST(_this3._schema, typeAST)); variables.set(argName, { ast: arg, defaultValue: value.defaultValue != null ? value.defaultValue : null, defined: true, name: argName, type: type }); }); return variables; }; /** * Constructs a mapping of variable names to definitions using the * standard GraphQL syntax for variable definitions. */ _proto._buildOperationArgumentDefinitions = function _buildOperationArgumentDefinitions(operation) { var _this4 = this; var variableDefinitions = new Map(); (operation.variableDefinitions || []).forEach(function (def) { var name = getName(def.variable); var type = assertInputType(getTypeFromAST(_this4._schema, def.type)); var defaultValue = def.defaultValue ? transformLiteralValue(def.defaultValue, def) : null; var previousDefinition = variableDefinitions.get(name); if (previousDefinition != null) { throw createUserError("Duplicate definition for variable '$".concat(name, "'."), null, [previousDefinition.ast, def]); } variableDefinitions.set(name, { ast: def, defaultValue: defaultValue, defined: true, name: name, type: type }); }); return variableDefinitions; }; return RelayParser; }(); /** * @private */ function parseDefinition(schema, getFieldDefinition, entries, definition, variableDefinitions) { var parser = new GraphQLDefinitionParser(schema, getFieldDefinition, entries, definition, variableDefinitions); return parser.transform(); } /** * @private */ var GraphQLDefinitionParser = /*#__PURE__*/ function () { function GraphQLDefinitionParser(schema, getFieldDefinition, entries, definition, variableDefinitions) { this._definition = definition; this._entries = entries; this._getFieldDefinition = getFieldDefinition; this._schema = schema; this._variableDefinitions = variableDefinitions; this._unknownVariables = new Map(); } var _proto2 = GraphQLDefinitionParser.prototype; _proto2.transform = function transform() { var definition = this._definition; switch (definition.kind) { case 'OperationDefinition': return this._transformOperation(definition); case 'FragmentDefinition': return this._transformFragment(definition); default: definition; throw createCompilerError("Unsupported definition type ".concat(definition.kind), [definition]); } }; _proto2._getErrorContext = function _getErrorContext() { var message = "document `".concat(getName(this._definition), "`"); if (this._definition.loc && this._definition.loc.source) { message += " file: `".concat(this._definition.loc.source.name, "`"); } return message; }; _proto2._recordAndVerifyVariableReference = function _recordAndVerifyVariableReference(variable, name, usedAsType) { // Special case for variables used in @arguments where we currently // aren't guaranteed to be able to resolve the type. if (usedAsType == null) { if (!this._variableDefinitions.has(name) && !this._unknownVariables.has(name)) { this._unknownVariables.set(name, { ast: variable, type: null }); } return; } var variableDefinition = this._variableDefinitions.get(name); if (variableDefinition != null) { // If the variable is defined, all usages must be compatible var effectiveType = variableDefinition.type; if (variableDefinition.defaultValue != null) { // If a default value is defined then it is guaranteed to be used // at runtime such that the effective type of the variable is non-null effectiveType = new GraphQLNonNull(getNullableType(effectiveType)); } if (!isTypeSubTypeOf(this._schema, effectiveType, usedAsType)) { throw createUserError("Variable '$".concat(name, "' was defined as type '").concat(String(variableDefinition.type), "' but used in a location expecting the type '").concat(String(usedAsType), "'"), null, [variableDefinition.ast, variable]); } } else { var previous = this._unknownVariables.get(name); if (!previous || !previous.type) { // No previous usage, current type is strongest this._unknownVariables.set(name, { ast: variable, type: usedAsType }); } else { var previousType = previous.type, previousVariable = previous.ast; if (!(isTypeSubTypeOf(this._schema, usedAsType, previousType) || isTypeSubTypeOf(this._schema, previousType, usedAsType))) { throw createUserError("Variable '$".concat(name, "' was used in locations expecting the conflicting types '").concat(String(previousType), "' and '").concat(String(usedAsType), "'. Source: ").concat(this._getErrorContext()), null, [previousVariable, variable]); } // If the new used type has stronger requirements, use that type as reference, // otherwise keep referencing the previous type if (isTypeSubTypeOf(this._schema, usedAsType, previousType)) { this._unknownVariables.set(name, { ast: variable, type: usedAsType }); } } } }; _proto2._transformFragment = function _transformFragment(fragment) { var directives = this._transformDirectives((fragment.directives || []).filter(function (directive) { return getName(directive) !== ARGUMENT_DEFINITIONS; })); var type = assertCompositeType(getTypeFromAST(this._schema, fragment.typeCondition)); var selections = this._transformSelections(fragment.selectionSet, type); var argumentDefinitions = (0, _toConsumableArray2["default"])(buildArgumentDefinitions(this._variableDefinitions)); var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = this._unknownVariables[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var _step$value = _step.value, name = _step$value[0], variableReference = _step$value[1]; argumentDefinitions.push({ kind: 'RootArgumentDefinition', loc: buildLocation(variableReference.ast.loc), metadata: null, name: name, // $FlowFixMe - could be null type: variableReference.type }); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator["return"] != null) { _iterator["return"](); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return { kind: 'Fragment', directives: directives, loc: buildLocation(fragment.loc), metadata: null, name: getName(fragment), selections: selections, type: type, argumentDefinitions: argumentDefinitions }; }; _proto2._transformOperation = function _transformOperation(definition) { var name = getName(definition); var directives = this._transformDirectives(definition.directives || []); var type; var operation; switch (definition.operation) { case 'query': operation = 'query'; type = assertCompositeType(this._schema.getQueryType()); break; case 'mutation': operation = 'mutation'; type = assertCompositeType(this._schema.getMutationType()); break; case 'subscription': operation = 'subscription'; type = assertCompositeType(this._schema.getSubscriptionType()); break; default: definition.operation; throw createCompilerError("Unknown ast kind '".concat(definition.operation, "'. Source: ").concat(this._getErrorContext(), "."), null, [definition]); } if (!definition.selectionSet) { throw createUserError("Expected operation to have selections. Source: ".concat(this._getErrorContext()), null, [definition]); } var selections = this._transformSelections(definition.selectionSet, type); var argumentDefinitions = buildArgumentDefinitions(this._variableDefinitions); if (this._unknownVariables.size !== 0) { throw createUserError("Query '".concat(name, "' references undefined variables."), null, Array.from(this._unknownVariables.values(), function (variableReference) { return variableReference.ast; })); } return { kind: 'Root', operation: operation, loc: buildLocation(definition.loc), metadata: null, name: name, argumentDefinitions: argumentDefinitions, directives: directives, selections: selections, type: type }; }; _proto2._transformSelections = function _transformSelections(selectionSet, parentType) { var _this5 = this; return selectionSet.selections.map(function (selection) { var node; if (selection.kind === 'Field') { node = _this5._transformField(selection, parentType); } else if (selection.kind === 'FragmentSpread') { node = _this5._transformFragmentSpread(selection, parentType); } else if (selection.kind === 'InlineFragment') { node = _this5._transformInlineFragment(selection, parentType); } else { selection.kind; throw createCompilerError("Unknown ast kind '".concat(selection.kind, "'. Source: ").concat(_this5._getErrorContext(), "."), [selection]); } var _this5$_splitConditio = _this5._splitConditions(node.directives), conditions = _this5$_splitConditio[0], directives = _this5$_splitConditio[1]; var conditionalNodes = applyConditions(conditions, // $FlowFixMe(>=0.28.0) [(0, _objectSpread2["default"])({}, node, { directives: directives })]); if (conditionalNodes.length !== 1) { throw createCompilerError("Expected exactly one condition node. Source: ".concat(_this5._getErrorContext()), null, selection.directives); } return conditionalNodes[0]; }); }; _proto2._transformInlineFragment = function _transformInlineFragment(fragment, parentType) { var typeCondition = assertCompositeType(fragment.typeCondition ? getTypeFromAST(this._schema, fragment.typeCondition) : parentType); var directives = this._transformDirectives(fragment.directives || []); var selections = this._transformSelections(fragment.selectionSet, typeCondition); return { kind: 'InlineFragment', directives: directives, loc: buildLocation(fragment.loc), metadata: null, selections: selections, typeCondition: typeCondition }; }; _proto2._transformFragmentSpread = function _transformFragmentSpread(fragmentSpread, parentType) { var _this6 = this; var fragmentName = getName(fragmentSpread); var _partitionArray = partitionArray(fragmentSpread.directives || [], function (directive) { return getName(directive) !== ARGUMENTS; }), otherDirectives = _partitionArray[0], argumentDirectives = _partitionArray[1]; if (argumentDirectives.length > 1) { throw createUserError("Directive @".concat(ARGUMENTS, " may be used at most once per a fragment spread. ") + "Source: ".concat(this._getErrorContext()), null, argumentDirectives); } var fragmentDefinition = this._entries.get(fragmentName); var fragmentArgumentDefinitions = fragmentDefinition === null || fragmentDefinition === void 0 ? void 0 : fragmentDefinition.variableDefinitions; var args; if (argumentDirectives.length) { args = (argumentDirectives[0].arguments || []).map(function (arg) { var _ref; var argName = getName(arg); var argValue = arg.value; var argumentDefinition = fragmentArgumentDefinitions != null ? fragmentArgumentDefinitions.get(argName) : null; var argumentType = (_ref = argumentDefinition === null || argumentDefinition === void 0 ? void 0 : argumentDefinition.type) !== null && _ref !== void 0 ? _ref : null; if (argValue.kind === 'Variable') { // TODO: check the type of the variable and use the type return { kind: 'Argument', loc: buildLocation(arg.loc), metadata: null, name: argName, value: _this6._transformVariable(argValue, null), type: null }; } else { if (argumentType == null) { var _this$_entries$get; throw createUserError("Literal @".concat(ARGUMENTS, " values are only supported when the ") + "argument is defined with @".concat(ARGUMENT_DEFINITIONS, ". Check ") + "the definition of fragment '".concat(fragmentName, "'."), null, [arg.value, (_this$_entries$get = _this6._entries.get(fragmentName)) === null || _this$_entries$get === void 0 ? void 0 : _this$_entries$get.definition].filter(Boolean)); } var _value = _this6._transformValue(argValue, argumentType); return { kind: 'Argument', loc: buildLocation(arg.loc), metadata: null, name: argName, value: _value, type: argumentType }; } }); } var directives = this._transformDirectives(otherDirectives); return { kind: 'FragmentSpread', args: args || [], metadata: null, loc: buildLocation(fragmentSpread.loc), name: fragmentName, directives: directives }; }; _proto2._transformField = function _transformField(field, parentType) { var name = getName(field); var fieldDef = this._getFieldDefinition(this._schema, parentType, name, field); if (fieldDef == null) { throw createUserError("Unknown field '".concat(name, "' on type '").concat(String(parentType), "'. Source: ").concat(this._getErrorContext()), null, [field]); } var alias = field.alias ? field.alias.value : null; var args = this._transformArguments(field.arguments || [], fieldDef.args); var _partitionArray2 = partitionArray(field.directives || [], function (directive) { return getName(directive) !== CLIENT_FIELD; }), otherDirectives = _partitionArray2[0], clientFieldDirectives = _partitionArray2[1]; var directives = this._transformDirectives(otherDirectives); var type = assertOutputType(fieldDef.type); var handles = this._transformHandle(name, args, clientFieldDirectives); if (isLeafType(getNamedType(type))) { if (field.selectionSet && field.selectionSet.selections && field.selectionSet.selections.length) { throw createUserError("Expected no selections for scalar field '".concat(name, "'. Source: ").concat(this._getErrorContext()), null, [field]); } return { kind: 'ScalarField', alias: alias, args: args, directives: directives, handles: handles, loc: buildLocation(field.loc), metadata: null, name: name, type: assertScalarFieldType(type) }; } else { var selections = field.selectionSet ? this._transformSelections(field.selectionSet, type) : null; if (selections == null || selections.length === 0) { throw createUserError("Expected at least one selection for non-scalar field '".concat(name, "' on type '").concat(String(type), "'. Source: ").concat(this._getErrorContext(), "."), null, [field]); } return { kind: 'LinkedField', alias: alias, args: args, directives: directives, handles: handles, loc: buildLocation(field.loc), metadata: null, name: name, selections: selections, type: type }; } }; _proto2._transformHandle = function _transformHandle(fieldName, fieldArgs, clientFieldDirectives) { var _this7 = this; var handles; clientFieldDirectives.forEach(function (clientFieldDirective) { var handleArgument = (clientFieldDirective.arguments || []).find(function (arg) { return getName(arg) === CLIENT_FIELD_HANDLE; }); if (handleArgument) { var name = null; var key = DEFAULT_HANDLE_KEY; var filters = null; var maybeHandle = transformLiteralValue(handleArgument.value, handleArgument); if (typeof maybeHandle !== 'string') { throw createUserError("Expected a string literal argument for the @".concat(CLIENT_FIELD, " directive. ") + "Source: ".concat(_this7._getErrorContext()), null, [handleArgument.value]); } name = maybeHandle; var keyArgument = (clientFieldDirective.arguments || []).find(function (arg) { return getName(arg) === CLIENT_FIELD_KEY; }); if (keyArgument) { var maybeKey = transformLiteralValue(keyArgument.value, keyArgument); if (typeof maybeKey !== 'string') { throw createUserError("Expected a string literal argument for the @".concat(CLIENT_FIELD, " directive. ") + "Source: ".concat(_this7._getErrorContext()), null, [keyArgument.value]); } key = maybeKey; } var filtersArgument = (clientFieldDirective.arguments || []).find(function (arg) { return getName(arg) === CLIENT_FIELD_FILTERS; }); if (filtersArgument) { var maybeFilters = transformLiteralValue(filtersArgument.value, filtersArgument); if (!(Array.isArray(maybeFilters) && maybeFilters.every(function (filter) { return typeof filter === 'string' && fieldArgs.some(function (fieldArg) { return fieldArg.name === filter; }); }))) { throw createUserError("Expected an array of argument names on field '".concat(fieldName, "'. ") + "Source: ".concat(_this7._getErrorContext()), null, [filtersArgument.value]); } // $FlowFixMe filters = maybeFilters; } handles = handles || []; handles.push({ name: name, key: key, filters: filters }); } }); return handles; }; _proto2._transformDirectives = function _transformDirectives(directives) { var _this8 = this; return directives.map(function (directive) { var name = getName(directive); var directiveDef = _this8._schema.getDirective(name); if (directiveDef == null) { throw createUserError("Unknown directive '".concat(name, "'. Source: ").concat(_this8._getErrorContext()), null, [directive]); } var args = _this8._transformArguments(directive.arguments || [], directiveDef.args); return { kind: 'Directive', loc: buildLocation(directive.loc), metadata: null, name: name, args: args }; }); }; _proto2._transformArguments = function _transformArguments(args, argumentDefinitions) { var _this9 = this; return args.map(function (arg) { var argName = getName(arg); var argDef = argumentDefinitions.find(function (def) { return def.name === argName; }); if (argDef == null) { throw createUserError("Unknown argument '".concat(argName, "'. Source: ").concat(_this9._getErrorContext()), null, [arg]); } var value = _this9._transformValue(arg.value, argDef.type); return { kind: 'Argument', loc: buildLocation(arg.loc), metadata: null, name: argName, value: value, type: argDef.type }; }); }; _proto2._splitConditions = function _splitConditions(mixedDirectives) { var _this10 = this; var _partitionArray3 = partitionArray(mixedDirectives, function (directive) { return directive.name === INCLUDE || directive.name === SKIP; }), conditionDirectives = _partitionArray3[0], otherDirectives = _partitionArray3[1]; var conditions = conditionDirectives.map(function (directive) { var passingValue = directive.name === INCLUDE; var arg = directive.args[0]; if (arg == null || arg.name !== IF) { throw createUserError("Expected an 'if' argument to @".concat(directive.name, ". Source: ").concat(_this10._getErrorContext()), [directive.loc]); } if (!(arg.value.kind === 'Variable' || arg.value.kind === 'Literal')) { throw createUserError("Expected the 'if' argument to @".concat(directive.name, " to be a variable or literal. Source: ").concat(_this10._getErrorContext()), [directive.loc]); } return { kind: 'Condition', condition: arg.value, loc: directive.loc, metadata: null, passingValue: passingValue, selections: [] }; }); var sortedConditions = conditions.sort(function (a, b) { if (a.condition.kind === 'Variable' && b.condition.kind === 'Variable') { return a.condition.variableName < b.condition.variableName ? -1 : a.condition.variableName > b.condition.variableName ? 1 : 0; } else { // sort literals earlier, variables later return a.condition.kind === 'Variable' ? 1 : b.condition.kind === 'Variable' ? -1 : 0; } }); return [sortedConditions, otherDirectives]; }; _proto2._transformVariable = function _transformVariable(ast, usedAsType) { var variableName = getName(ast); this._recordAndVerifyVariableReference(ast, variableName, usedAsType); return { kind: 'Variable', loc: buildLocation(ast.loc), metadata: null, variableName: variableName, type: usedAsType }; }; /** * Transforms and validates argument values according to the expected * type. */ _proto2._transformValue = function _transformValue(ast, type) { if (ast.kind === 'Variable') { // Special case variables since there is no value to parse return this._transformVariable(ast, type); } else if (ast.kind === 'NullValue') { // Special case null literals since there is no value to parse if (type instanceof GraphQLNonNull) { throw createUserError("Expected a value matching type '".concat(String(type), "'."), null, [ast]); } return { kind: 'Literal', loc: buildLocation(ast.loc), metadata: null, value: null }; } else { return this._transformNonNullLiteral(ast, type); } }; /** * Transforms and validates non-null literal (non-variable) values * according to the expected type. */ _proto2._transformNonNullLiteral = function _transformNonNullLiteral(ast, type) { var _this11 = this; // Transform the value based on the type without a non-null wrapper. // Note that error messages should still use the original `type` // since that accurately describes to the user what the expected // type is (using nullableType would suggest that `null` is legal // even when it may not be, for example). var nullableType = getNullableType(type); if (nullableType instanceof GraphQLList) { if (ast.kind !== 'ListValue') { // Parse singular (non-list) values flowing into a list type // as scalars, ie without wrapping them in an array. return this._transformValue(ast, nullableType.ofType); } var itemType = assertInputType(nullableType.ofType); var literalList = []; var items = []; var areAllItemsScalar = true; ast.values.forEach(function (item) { var itemValue = _this11._transformValue(item, itemType); if (itemValue.kind === 'Literal') { literalList.push(itemValue.value); } items.push(itemValue); areAllItemsScalar = areAllItemsScalar && itemValue.kind === 'Literal'; }); if (areAllItemsScalar) { return { kind: 'Literal', loc: buildLocation(ast.loc), metadata: null, value: literalList }; } else { return { kind: 'ListValue', loc: buildLocation(ast.loc), metadata: null, items: items }; } } else if (nullableType instanceof GraphQLInputObjectType) { var objectType = nullableType; if (ast.kind !== 'ObjectValue') { throw createUserError("Expected a value matching type '".concat(String(type), "'."), null, [ast]); } var literalObject = {}; var fields = []; var areAllFieldsScalar = true; ast.fields.forEach(function (field) { var fieldName = getName(field); var fieldConfig = objectType.getFields()[fieldName]; if (fieldConfig == null) { throw createUserError("Uknown field '".concat(fieldName, "' on type '").concat(String(type), "'."), null, [field]); } var fieldType = assertInputType(fieldConfig.type); var fieldValue = _this11._transformValue(field.value, fieldType); if (fieldValue.kind === 'Literal') { literalObject[field.name.value] = fieldValue.value; } fields.push({ kind: 'ObjectFieldValue', loc: buildLocation(field.loc), metadata: null, name: fieldName, value: fieldValue }); areAllFieldsScalar = areAllFieldsScalar && fieldValue.kind === 'Literal'; }); if (areAllFieldsScalar) { return { kind: 'Literal', loc: buildLocation(ast.loc), metadata: null, value: literalObject }; } else { return { kind: 'ObjectValue', loc: buildLocation(ast.loc), metadata: null, fields: fields }; } } else if (nullableType === GraphQLID) { // GraphQLID's parseLiteral() always returns the string value. However // the int/string distinction may be important at runtime, so this // transform parses int/string literals into the corresponding JS types. if (ast.kind === 'IntValue') { return { kind: 'Literal', loc: buildLocation(ast.loc), metadata: null, value: parseInt(ast.value, 10) }; } else if (ast.kind === 'StringValue') { return { kind: 'Literal', loc: buildLocation(ast.loc), metadata: null, value: ast.value }; } else { throw createUserError("Invalid value, expected a value matching type '".concat(String(type), "'."), null, [ast]); } } else if (nullableType instanceof GraphQLScalarType || nullableType instanceof GraphQLEnumType) { var _value2 = nullableType.parseLiteral(ast); if (_value2 == null) { // parseLiteral() should return a non-null JavaScript value // if the ast value is valid for the type. throw createUserError("Expected a value matching type '".concat(String(type), "'."), null, [ast]); } return { kind: 'Literal', loc: buildLocation(ast.loc), metadata: null, value: _value2 }; } else { nullableType; throw createCompilerError("Unsupported type '".concat(String(type), "' for input value, expected a GraphQLList, ") + 'GraphQLInputObjectType, GraphQLEnumType, or GraphQLScalarType.', null, [ast]); } }; return GraphQLDefinitionParser; }(); /** * @private */ function transformLiteralValue(ast, context) { switch (ast.kind) { case 'IntValue': return parseInt(ast.value, 10); case 'FloatValue': return parseFloat(ast.value); case 'StringValue': return ast.value; case 'BooleanValue': // Note: duplicated because Flow does not understand fall-through cases return ast.value; case 'EnumValue': // Note: duplicated because Flow does not understand fall-through cases return ast.value; case 'ListValue': return ast.values.map(function (item) { return transformLiteralValue(item, context); }); case 'NullValue': return null; case 'ObjectValue': { var objectValue = {}; ast.fields.forEach(function (field) { var fieldName = getName(field); var value = transformLiteralValue(field.value, context); objectValue[fieldName] = value; }); return objectValue; } case 'Variable': throw createUserError('Unexpected variable where a literal (static) value is required.', null, [ast, context]); default: ast.kind; throw createCompilerError("Unknown ast kind '".concat(ast.kind, "'."), [ast]); } } /** * @private */ function buildArgumentDefinitions(variables) { return Array.from(variables.values(), function (_ref4) { var ast = _ref4.ast, name = _ref4.name, type = _ref4.type, defaultValue = _ref4.defaultValue; return { kind: 'LocalArgumentDefinition', loc: buildLocation(ast.loc), metadata: null, name: name, type: type, defaultValue: defaultValue }; }); } /** * @private */ function buildLocation(loc) { if (loc == null) { return { kind: 'Unknown' }; } return { kind: 'Source', start: loc.start, end: loc.end, source: loc.source }; } /** * @private */ function isScalarFieldType(type) { var namedType = getNamedType(type); return namedType instanceof GraphQLScalarType || namedType instanceof GraphQLEnumType; } /** * @private */ function assertScalarFieldType(type) { if (!isScalarFieldType(type)) { throw createUserError("Expected a scalar field type, got type '".concat(String(type), "'.")); } return type; } /** * @private */ function applyConditions(conditions, selections) { var nextSelections = selections; conditions.forEach(function (condition) { nextSelections = [(0, _objectSpread2["default"])({}, condition, { selections: nextSelections })]; }); return nextSelections; } /** * @private */ function getName(ast) { var _ast$name; var name = (_ast$name = ast.name) === null || _ast$name === void 0 ? void 0 : _ast$name.value; if (typeof name !== 'string') { throw createCompilerError("Expected ast node to have a 'name'.", null, [ast]); } return name; } /** * Partitions an array given a predicate. All elements satisfying the predicate * are part of the first returned array, and all elements that don't are in the * second. * * @private */ function partitionArray(array, predicate) { var first = []; var second = []; for (var i = 0; i < array.length; i++) { var item = array[i]; if (predicate(item)) { first.push(item); } else { second.push(item); } } return [first, second]; } module.exports = { parse: parse, transform: transform };