UNPKG

@ardatan/relay-compiler

Version:

Fork of `relay-compiler`

1,726 lines (1,480 loc) 51.9 kB
/** * 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 */ // flowlint ambiguous-object-type:error 'use strict'; var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault'); var _objectSpread2 = _interopRequireDefault(require('@babel/runtime/helpers/objectSpread2')); var _createForOfIteratorHelper2 = _interopRequireDefault( require('@babel/runtime/helpers/createForOfIteratorHelper'), ); var _toConsumableArray2 = _interopRequireDefault( require('@babel/runtime/helpers/toConsumableArray'), ); var Profiler = require('./GraphQLCompilerProfiler'); var orList = require('../util/orList'); var partitionArray = require('../util/partitionArray'); var _require = require('../util/DefaultHandleKey'), DEFAULT_HANDLE_KEY = _require.DEFAULT_HANDLE_KEY; var _require2 = require('./CompilerError'), createCompilerError = _require2.createCompilerError, createUserError = _require2.createUserError, eachWithCombinedError = _require2.eachWithCombinedError; var _require3 = require('./SchemaUtils'), isExecutableDefinitionAST = _require3.isExecutableDefinitionAST; var _require4 = require('./getFieldDefinition'), getFieldDefinitionLegacy = _require4.getFieldDefinitionLegacy; var _require5 = require('graphql'), parseGraphQL = _require5.parse, parseType = _require5.parseType, print = _require5.print, Source = _require5.Source; var ARGUMENT_DEFINITIONS = 'argumentDefinitions'; var ARGUMENTS = 'arguments'; var DEPRECATED_UNCHECKED_ARGUMENTS = 'uncheckedArguments_DEPRECATED'; var DIRECTIVE_WHITELIST = new Set([ ARGUMENT_DEFINITIONS, DEPRECATED_UNCHECKED_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)); var parser = new RelayParser(schema.extend(ast), 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 createUserError( 'RelayParser: Encountered duplicate definitions 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 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. eachWithCombinedError(this._definitions, function (_ref) { var name = _ref[0], definition = _ref[1]; var variableDefinitions = _this2._buildArgumentDefinitions(definition); entries.set(name, { definition: definition, variableDefinitions: variableDefinitions, }); }); // Convert the ASTs to IR. eachWithCombinedError(entries.values(), function (_ref2) { var definition = _ref2.definition, variableDefinitions = _ref2.variableDefinitions; var node = parseDefinition( _this2._schema, _this2._getFieldDefinition, entries, definition, variableDefinitions, ); nodes.push(node); }); 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]; // 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 _defaultValue$value; var argName = getName(arg); var previousVariable = variables.get(argName); if (previousVariable != null) { throw createUserError("Duplicate definition for variable '$".concat(argName, "'."), null, [ previousVariable.ast, arg, ]); } if (arg.value.kind !== 'ObjectValue') { throw createUserError( "Expected definition for variable '$".concat(argName, "' to be an object ") + "with the shape: '{type: string, defaultValue?: mixed}.", null, [arg.value], ); } var defaultValueNode; var typeString; arg.value.fields.forEach(function (field) { var name = getName(field); if (name === 'type') { typeString = transformLiteralValue(field.value, field); } else if (name === 'defaultValue') { defaultValueNode = field.value; } else { throw createUserError( "Expected definition for variable '$".concat(argName, "' to be an object ") + "with the shape: '{type: string, defaultValue?: mixed}.", null, [arg.value], ); } }); if (typeof typeString !== 'string') { throw createUserError( "Expected definition for variable '$".concat(argName, "' to be an object ") + "with the shape: '{type: string, defaultValue?: mixed}.", null, [arg.value], ); } var typeFromAST = _this3._schema.getTypeFromAST(parseType(typeString)); if (typeFromAST == null) { throw createUserError( // $FlowFixMe[incompatible-type] 'Unknown type "'.concat(typeString, '" referenced in the argument definitions.'), null, [arg], ); } var type = _this3._schema.asInputType(typeFromAST); if (type == null) { throw createUserError( // $FlowFixMe[incompatible-type] 'Expected type "' .concat(typeString, '" to be an input type in the "') .concat(arg.name.value, '" argument definitions.'), null, [arg.value], ); } var defaultValue = defaultValueNode != null ? transformValue(_this3._schema, defaultValueNode, type, function (variableAst) { throw createUserError( "Expected 'defaultValue' to be a literal, got a variable.", null, [variableAst], ); }) : null; if (defaultValue != null && defaultValue.kind !== 'Literal') { throw createUserError("Expected 'defaultValue' to be a literal, got a variable.", [ defaultValue.loc, ]); } variables.set(argName, { ast: arg, defaultValue: (_defaultValue$value = defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.value) !== null && _defaultValue$value !== void 0 ? _defaultValue$value : 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 schema = this._schema; var variableDefinitions = new Map(); (operation.variableDefinitions || []).forEach(function (def) { var name = getName(def.variable); var typeFromAST = schema.getTypeFromAST(def.type); if (typeFromAST == null) { throw createUserError("Unknown type: '".concat(getTypeName(def.type), "'."), null, [ def.type, ]); } var type = schema.asInputType(typeFromAST); if (type == null) { throw createUserError( 'Expected type "'.concat(getTypeName(def.type), '" to be an input type.'), null, [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._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 = this._schema.getNonNullType(this._schema.getNullableType(effectiveType)); } if (!this._schema.isTypeSubTypeOf(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 previousVariable = previous.ast, previousType = previous.type; if ( !( this._schema.isTypeSubTypeOf(usedAsType, previousType) || this._schema.isTypeSubTypeOf(previousType, usedAsType) ) ) { throw createUserError( "Variable '$" .concat(name, "' was used in locations expecting the conflicting types '") .concat(String(previousType), "' and '") .concat(String(usedAsType), "'."), null, [previousVariable, variable], ); } // If the new used type has stronger requirements, use that type as reference, // otherwise keep referencing the previous type if (this._schema.isTypeSubTypeOf(usedAsType, previousType)) { this._unknownVariables.set(name, { ast: variable, type: usedAsType, }); } } } }; _proto2._getDirectiveLocations = function _getDirectiveLocations() { if (!this._directiveLocations) { var directiveDefs = this._schema.getDirectives(); this._directiveLocations = new Map(); var _iterator = (0, _createForOfIteratorHelper2['default'])(directiveDefs), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done; ) { var def = _step.value; this._directiveLocations.set(def.name, def.locations); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } return this._directiveLocations; }; _proto2._validateDirectivesLocation = function _validateDirectivesLocation( directives, allowedLocaction, ) { if (!directives || !directives.length) { return; } var directiveLocs = this._getDirectiveLocations(); var mismatches = directives.filter(function (directive) { var name = getName(directive); if (DIRECTIVE_WHITELIST.has(name)) { return false; } var locs = directiveLocs.get(name); if (locs == null) { throw createUserError("Unknown directive '".concat(name, "'."), null, [directive]); } return !locs.some(function (loc) { return loc === allowedLocaction; }); }); if (mismatches.length) { var invalidDirectives = mismatches .map(function (directive) { return '@' + getName(directive); }) .join(', '); throw createUserError( 'Invalid directives '.concat(invalidDirectives, ' found on ').concat(allowedLocaction, '.'), null, mismatches, ); } }; _proto2._transformFragment = function _transformFragment(fragment) { var directives = this._transformDirectives( (fragment.directives || []).filter(function (directive) { return getName(directive) !== ARGUMENT_DEFINITIONS; }), 'FRAGMENT_DEFINITION', ); var typeFromAST = this._schema.getTypeFromAST(fragment.typeCondition); if (typeFromAST == null) { throw createUserError( 'Fragment "'.concat(fragment.name.value, '" cannot condition on unknown ') + 'type "'.concat(String(fragment.typeCondition.name.value), '".'), null, [fragment.typeCondition], ); } var type = this._schema.asCompositeType(typeFromAST); if (type == null) { throw createUserError( 'Fragment "'.concat(fragment.name.value, '" cannot condition on non composite ') + 'type "'.concat(String(type), '".'), null, [fragment.typeCondition], ); } var selections = this._transformSelections(fragment.selectionSet, type, fragment.typeCondition); var argumentDefinitions = (0, _toConsumableArray2['default'])( buildArgumentDefinitions(this._variableDefinitions), ); var _iterator2 = (0, _createForOfIteratorHelper2['default'])(this._unknownVariables), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done; ) { var _step2$value = _step2.value, name = _step2$value[0], variableReference = _step2$value[1]; argumentDefinitions.push({ kind: 'RootArgumentDefinition', loc: buildLocation(variableReference.ast.loc), name: name, type: variableReference.type, }); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } return { kind: 'Fragment', directives: directives, loc: buildLocation(fragment.loc), metadata: null, name: getName(fragment), selections: selections, type: type, // $FlowFixMe[incompatible-return] - could be null argumentDefinitions: argumentDefinitions, }; }; _proto2._getLocationFromOperation = function _getLocationFromOperation(definition) { switch (definition.operation) { case 'query': return 'QUERY'; case 'mutation': return 'MUTATION'; case 'subscription': return 'SUBSCRIPTION'; default: definition.operation; throw createCompilerError( "Unknown operation type '".concat(definition.operation, "'."), null, [definition], ); } }; _proto2._transformOperation = function _transformOperation(definition) { var name = getName(definition); var directives = this._transformDirectives( definition.directives || [], this._getLocationFromOperation(definition), ); var type; var operation; var schema = this._schema; switch (definition.operation) { case 'query': operation = 'query'; type = schema.expectQueryType(); break; case 'mutation': operation = 'mutation'; type = schema.expectMutationType(); break; case 'subscription': operation = 'subscription'; type = schema.expectSubscriptionType(); break; default: definition.operation; throw createCompilerError( "Unknown operation type '".concat(definition.operation, "'."), null, [definition], ); } if (!definition.selectionSet) { throw createUserError('Expected operation to have selections.', 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, // $FlowFixMe[incompatible-return] type: type, }; }; _proto2._transformSelections = function _transformSelections( selectionSet, parentType, parentTypeAST, ) { var _this4 = this; return selectionSet.selections.map(function (selection) { var node; if (selection.kind === 'Field') { node = _this4._transformField(selection, parentType); } else if (selection.kind === 'FragmentSpread') { node = _this4._transformFragmentSpread(selection, parentType, parentTypeAST); } else if (selection.kind === 'InlineFragment') { node = _this4._transformInlineFragment(selection, parentType, parentTypeAST); } else { selection.kind; throw createCompilerError("Unknown ast kind '".concat(selection.kind, "'."), [selection]); } var _this4$_splitConditio = _this4._splitConditions(node.directives), conditions = _this4$_splitConditio[0], directives = _this4$_splitConditio[1]; var conditionalNodes = applyConditions( conditions, // $FlowFixMe[incompatible-call] [ (0, _objectSpread2['default'])( (0, _objectSpread2['default'])({}, node), {}, { directives: directives, }, ), ], ); if (conditionalNodes.length !== 1) { throw createCompilerError( 'Expected exactly one condition node.', null, selection.directives, ); } return conditionalNodes[0]; }); }; _proto2._transformInlineFragment = function _transformInlineFragment( fragment, parentType, parentTypeAST, ) { var schema = this._schema; var typeCondition = fragment.typeCondition != null ? schema.getTypeFromAST(fragment.typeCondition) : parentType; if (typeCondition == null) { var _fragment$typeConditi; throw createUserError( 'Inline fragments can only be on object, interface or union types' + ", got unknown type '".concat(getTypeName(fragment.typeCondition), "'."), null, [ (_fragment$typeConditi = fragment.typeCondition) !== null && _fragment$typeConditi !== void 0 ? _fragment$typeConditi : fragment, ], ); } var typeConditionName = schema.getTypeString(typeCondition); typeCondition = schema.asCompositeType(typeCondition); if (typeCondition == null) { var _fragment$typeConditi2; throw createUserError( 'Inline fragments can only be on object, interface or union types' + ", got '".concat(typeConditionName, "'."), null, [ (_fragment$typeConditi2 = fragment.typeCondition) !== null && _fragment$typeConditi2 !== void 0 ? _fragment$typeConditi2 : fragment, ], ); } var rawParentType = this._schema.assertCompositeType(this._schema.getRawType(parentType)); checkFragmentSpreadTypeCompatibility( this._schema, typeCondition, rawParentType, null, fragment.typeCondition, parentTypeAST, ); var directives = this._transformDirectives(fragment.directives || [], 'INLINE_FRAGMENT'); var selections = this._transformSelections( fragment.selectionSet, typeCondition, fragment.typeCondition, ); return { kind: 'InlineFragment', directives: directives, loc: buildLocation(fragment.loc), metadata: null, selections: selections, typeCondition: typeCondition, }; }; _proto2._transformFragmentSpread = function _transformFragmentSpread( fragmentSpread, parentType, parentTypeAST, ) { var _this5 = this; var fragmentName = getName(fragmentSpread); var _partitionArray = partitionArray(fragmentSpread.directives || [], function (directive) { var name = getName(directive); return name === ARGUMENTS || name === DEPRECATED_UNCHECKED_ARGUMENTS; }), argumentDirectives = _partitionArray[0], otherDirectives = _partitionArray[1]; if (argumentDirectives.length > 1) { throw createUserError( 'Directive @'.concat(ARGUMENTS, ' may be used at most once per a fragment spread.'), null, argumentDirectives, ); } var fragmentDefinition = this._entries.get(fragmentName); if (fragmentDefinition == null) { throw createUserError("Unknown fragment '".concat(fragmentName, "'."), null, [ fragmentSpread.name, ]); } var fragmentTypeNode = getFragmentType(fragmentDefinition.definition); var fragmentType = this._schema.assertCompositeType( this._schema.expectTypeFromAST(fragmentTypeNode), ); var rawParentType = this._schema.assertCompositeType(this._schema.getRawType(parentType)); checkFragmentSpreadTypeCompatibility( this._schema, fragmentType, rawParentType, fragmentSpread.name.value, fragmentSpread, parentTypeAST, ); var fragmentArgumentDefinitions = fragmentDefinition.variableDefinitions; var argumentsDirective = argumentDirectives[0]; var args; if (argumentsDirective != null) { var isDeprecatedUncheckedArguments = getName(argumentsDirective) === DEPRECATED_UNCHECKED_ARGUMENTS; var hasInvalidArgument = false; args = (argumentsDirective.arguments || []).map(function (arg) { var _argumentDefinition$t; var argName = getName(arg); var argValue = arg.value; var argumentDefinition = fragmentArgumentDefinitions.get(argName); var argumentType = (_argumentDefinition$t = argumentDefinition === null || argumentDefinition === void 0 ? void 0 : argumentDefinition.type) !== null && _argumentDefinition$t !== void 0 ? _argumentDefinition$t : null; if (argValue.kind === 'Variable') { if (argumentDefinition == null && !isDeprecatedUncheckedArguments) { throw createUserError( 'Variable @'.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, fragmentDefinition.definition], ); } hasInvalidArgument = hasInvalidArgument || argumentDefinition == null; // TODO: check the type of the variable and use the type return { kind: 'Argument', loc: buildLocation(arg.loc), name: argName, value: _this5._transformVariable(argValue, null), type: null, }; } else { if (argumentType == null) { 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, fragmentDefinition.definition], ); } var value = _this5._transformValue(argValue, argumentType); return { kind: 'Argument', loc: buildLocation(arg.loc), name: argName, value: value, type: argumentType, }; } }); if (isDeprecatedUncheckedArguments && !hasInvalidArgument) { throw createUserError( 'Invalid use of @'.concat(DEPRECATED_UNCHECKED_ARGUMENTS, ': all arguments ') + 'are defined, use @'.concat(ARGUMENTS, ' instead.'), null, [argumentsDirective], ); } } var directives = this._transformDirectives(otherDirectives, 'FRAGMENT_SPREAD'); return { kind: 'FragmentSpread', args: args || [], metadata: null, loc: buildLocation(fragmentSpread.loc), name: fragmentName, directives: directives, }; }; _proto2._transformField = function _transformField(field, parentType) { var _field$alias$value, _field$alias; var schema = this._schema; var name = getName(field); var fieldDef = this._getFieldDefinition(schema, parentType, name, field); if (fieldDef == null) { throw createUserError( "Unknown field '" .concat(name, "' on type '") .concat(schema.getTypeString(parentType), "'."), null, [field], ); } var alias = (_field$alias$value = (_field$alias = field.alias) === null || _field$alias === void 0 ? void 0 : _field$alias.value) !== null && _field$alias$value !== void 0 ? _field$alias$value : name; var args = this._transformArguments( field.arguments || [], schema.getFieldArgs(fieldDef), fieldDef, ); var _partitionArray2 = partitionArray(field.directives || [], function (directive) { return getName(directive) !== CLIENT_FIELD; }), otherDirectives = _partitionArray2[0], clientFieldDirectives = _partitionArray2[1]; var directives = this._transformDirectives(otherDirectives, 'FIELD'); var type = schema.getFieldType(fieldDef); var handles = this._transformHandle(name, args, clientFieldDirectives); if (schema.isLeafType(schema.getRawType(type))) { if ( field.selectionSet && field.selectionSet.selections && field.selectionSet.selections.length ) { throw createUserError( "Expected no selections for scalar field '".concat(name, "'."), null, [field], ); } return { kind: 'ScalarField', alias: alias, args: args, directives: directives, handles: handles, loc: buildLocation(field.loc), metadata: null, name: name, type: schema.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(schema.getTypeString(type), "'."), null, [field], ); } return { kind: 'LinkedField', alias: alias, args: args, connection: false, directives: directives, handles: handles, loc: buildLocation(field.loc), metadata: null, name: name, selections: selections, type: schema.assertLinkedFieldType(type), }; } }; _proto2._transformHandle = function _transformHandle( fieldName, fieldArgs, clientFieldDirectives, ) { var handles = null; 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.'), 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.'), 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, "'."), null, [filtersArgument.value], ); } // $FlowFixMe[incompatible-cast] filters = maybeFilters; } var dynamicKeyArgument = (clientFieldDirective.arguments || []).find(function (arg) { return getName(arg) === 'dynamicKey_UNSTABLE'; }); if (dynamicKeyArgument != null) { throw createUserError('Dynamic keys are only supported with @connection.', null, [ dynamicKeyArgument.value, ]); } handles = handles || []; handles.push({ name: name, key: key, filters: filters, dynamicKey: null, }); } }); return handles; }; _proto2._transformDirectives = function _transformDirectives(directives, location) { var _this6 = this; this._validateDirectivesLocation(directives, location); return directives.map(function (directive) { var name = getName(directive); var directiveDef = _this6._schema.getDirective(name); if (directiveDef == null) { throw createUserError("Unknown directive '".concat(name, "'."), null, [directive]); } var args = _this6._transformArguments( directive.arguments || [], directiveDef.args.map(function (item) { return { name: item.name, type: item.type, defaultValue: item.defaultValue, }; }), null, name, ); return { kind: 'Directive', loc: buildLocation(directive.loc), name: name, args: args, }; }); }; _proto2._transformArguments = function _transformArguments( args, argumentDefinitions, field, directiveName, ) { var _this7 = this; return args.map(function (arg) { var argName = getName(arg); var argDef = argumentDefinitions.find(function (def) { return def.name === argName; }); if (argDef == null) { var message = "Unknown argument '".concat(argName, "'") + (field ? " on field '".concat(_this7._schema.getFieldName(field), "'") + " of type '".concat( _this7._schema.getTypeString(_this7._schema.getFieldParentType(field)), "'.", ) : directiveName != null ? " on directive '@".concat(directiveName, "'.") : '.'); throw createUserError(message, null, [arg]); } var value = _this7._transformValue(arg.value, argDef.type); return { kind: 'Argument', loc: buildLocation(arg.loc), name: argName, value: value, type: argDef.type, }; }); }; _proto2._splitConditions = function _splitConditions(mixedDirectives) { 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, '.'), [ 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.'), [directive.loc], ); } return { kind: 'Condition', condition: arg.value, loc: directive.loc, 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), variableName: variableName, type: usedAsType, }; }; _proto2._transformValue = function _transformValue(ast, type) { var _this8 = this; return transformValue(this._schema, ast, type, function (variableAst, variableType) { return _this8._transformVariable(variableAst, variableType); }); }; return GraphQLDefinitionParser; })(); /** * Transforms and validates argument values according to the expected * type. */ function transformValue(schema, ast, type, transformVariable) { if (ast.kind === 'Variable') { // Special case variables since there is no value to parse return transformVariable(ast, type); } else if (ast.kind === 'NullValue') { // Special case null literals since there is no value to parse if (schema.isNonNull(type)) { throw createUserError("Expected a value matching type '".concat(String(type), "'."), null, [ ast, ]); } return { kind: 'Literal', loc: buildLocation(ast.loc), value: null, }; } else { return transformNonNullLiteral(schema, ast, type, transformVariable); } } /** * Transforms and validates non-null literal (non-variable) values * according to the expected type. */ function transformNonNullLiteral(schema, ast, type, transformVariable) { // 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 = schema.getNullableType(type); if (schema.isList(nullableType)) { if (ast.kind !== 'ListValue') { // Parse singular (non-list) values flowing into a list type // as scalars, ie without wrapping them in an array. if (!schema.isInputType(schema.getListItemType(nullableType))) { throw createUserError( 'Expected type '.concat(schema.getTypeString(nullableType), ' to be an input type.'), null, [ast], ); } return transformValue( schema, ast, schema.assertInputType(schema.getListItemType(nullableType)), transformVariable, ); } var itemType = schema.assertInputType(schema.getListItemType(nullableType)); var literalList = []; var items = []; var areAllItemsScalar = true; ast.values.forEach(function (item) { var itemValue = transformValue(schema, item, itemType, transformVariable); 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), value: literalList, }; } else { return { kind: 'ListValue', loc: buildLocation(ast.loc), items: items, }; } } else if (schema.isInputObject(nullableType)) { if (ast.kind !== 'ObjectValue') { throw createUserError( "Expected a value matching type '".concat(schema.getTypeString(type), "'."), null, [ast], ); } var literalObject = {}; var fields = []; var areAllFieldsScalar = true; var inputType = schema.assertInputObjectType(nullableType); var requiredFieldNames = new Set( schema .getFields(inputType) .filter(function (field) { return schema.isNonNull(schema.getFieldType(field)); }) .map(function (field) { return schema.getFieldName(field); }), ); var seenFields = new Map(); ast.fields.forEach(function (field) { var fieldName = getName(field); var seenField = seenFields.get(fieldName); if (seenField) { throw createUserError( "Duplicated field name '".concat(fieldName, "' in the input object."), null, [field, seenField], ); } var fieldID = schema.getFieldByName(inputType, fieldName); if (!fieldID) { throw createUserError( "Unknown field '" .concat(fieldName, "' on type '") .concat(schema.getTypeString(inputType), "'."), null, [field], ); } var fieldConfig = schema.getFieldConfig(fieldID); var fieldType = schema.assertInputType(fieldConfig.type); var fieldValue = transformValue(schema, field.value, fieldType, transformVariable); if (fieldValue.kind === 'Literal') { literalObject[field.name.value] = fieldValue.value; } fields.push({ kind: 'ObjectFieldValue', loc: buildLocation(field.loc), name: fieldName, value: fieldValue, }); seenFields.set(fieldName, field); requiredFieldNames['delete'](fieldName); areAllFieldsScalar = areAllFieldsScalar && fieldValue.kind === 'Literal'; }); if (requiredFieldNames.size > 0) { var requiredFieldStr = Array.from(requiredFieldNames) .map(function (item) { return "'".concat(item, "'"); }) .join(', '); throw createUserError( 'Missing non-optional field' .concat(requiredFieldNames.size > 1 ? 's:' : '', ' ') .concat(requiredFieldStr, " for input type '") .concat(schema.getTypeString(inputType), "'."), null, [ast], ); } if (areAllFieldsScalar) { return { kind: 'Literal', loc: buildLocation(ast.loc), value: literalObject, }; } else { return { kind: 'ObjectValue', loc: buildLocation(ast.loc), fields: fields, }; } } else if (schema.isId(nullableType)) { // 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), value: parseInt(ast.value, 10), }; } else if (ast.kind === 'StringValue') { return { kind: 'Literal', loc: buildLocation(ast.loc), value: ast.value, }; } else { throw createUserError( "Invalid value, expected a value matching type '".concat(schema.getTypeString(type), "'."), null, [ast], ); } } else if (schema.isEnum(nullableType)) { var enumType = schema.assertEnumType(nullableType); var value = schema.parseLiteral(enumType, ast); if (value == null) { var suggestions = schema.getEnumValues(enumType); // 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(schema.getTypeString(type), "'. Possible values: ") .concat(orList(suggestions), "?'"), null, [ast], ); } return { kind: 'Literal', loc: buildLocation(ast.loc), value: value, }; } else if (schema.isScalar(nullableType)) { var _value = schema.parseLiteral(schema.assertScalarType(nullableType), ast); if (_value == 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(schema.getTypeString(type), "'."), null, [ast], ); } return { kind: 'Literal', loc: buildLocation(ast.loc), value: _value, }; } else { throw createCompilerError( "Unsupported type '".concat( schema.getTypeString(type), "' for input value, expected a GraphQLList, ", ) + 'GraphQLInputObjectType, GraphQLEnumType, or GraphQLScalarType.', null, [ast], ); } } /** * @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 (_ref3) { var ast = _ref3.ast, name = _ref3.name, defaultValue = _ref3.defaultValue, type = _ref3.type; return { kind: 'LocalArgumentDefinition', loc: buildLocation(ast.loc), 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 applyConditions(conditions, selections) { var nextSelections = selections; conditions.forEach(function (condition) { nextSelections = [ (0, _objectSpread2['default'])( (0, _objectSpread2['default'])({}, condition), {}, { selections: nextSelections, }, ), ]; }); return nextSelections; } /** * @private */ function getName(ast) { var _ast$name; var name = (_ast$name = ast.name) === null || _ast$n