relay-compiler 0.0.0-main-4d287de9 → 0.0.0-main-9a79039d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +23 -0
- package/index.js +19 -3
- package/linux-x64/relay +0 -0
- package/macos-x64/relay +0 -0
- package/package.json +2 -26
- package/win-x64/relay.exe +0 -0
- package/bin/RelayCompilerBin.js.flow +0 -168
- package/bin/RelayCompilerMain.js.flow +0 -513
- package/bin/__fixtures__/plugin-module.js.flow +0 -17
- package/bin/relay-compiler +0 -19066
- package/codegen/CodegenDirectory.js.flow +0 -372
- package/codegen/CodegenRunner.js.flow +0 -424
- package/codegen/CodegenTypes.js.flow +0 -28
- package/codegen/CodegenWatcher.js.flow +0 -250
- package/codegen/NormalizationCodeGenerator.js.flow +0 -565
- package/codegen/ReaderCodeGenerator.js.flow +0 -510
- package/codegen/RelayCodeGenerator.js.flow +0 -85
- package/codegen/RelayFileWriter.js.flow +0 -365
- package/codegen/SourceControl.js.flow +0 -58
- package/codegen/compileRelayArtifacts.js.flow +0 -181
- package/codegen/createPrintRequireModuleDependency.js.flow +0 -19
- package/codegen/sortObjectByKey.js.flow +0 -25
- package/codegen/writeRelayGeneratedFile.js.flow +0 -235
- package/core/ASTCache.js.flow +0 -73
- package/core/ASTConvert.js.flow +0 -230
- package/core/CompilerContext.js.flow +0 -189
- package/core/CompilerError.js.flow +0 -255
- package/core/DotGraphQLParser.js.flow +0 -37
- package/core/GraphQLCompilerProfiler.js.flow +0 -341
- package/core/GraphQLDerivedFromMetadata.js.flow +0 -36
- package/core/GraphQLWatchmanClient.js.flow +0 -109
- package/core/IR.js.flow +0 -326
- package/core/IRPrinter.js.flow +0 -472
- package/core/IRTransformer.js.flow +0 -376
- package/core/IRValidator.js.flow +0 -259
- package/core/IRVisitor.js.flow +0 -150
- package/core/JSModuleParser.js.flow +0 -24
- package/core/RelayCompilerScope.js.flow +0 -199
- package/core/RelayFindGraphQLTags.js.flow +0 -118
- package/core/RelayGraphQLEnumsGenerator.js.flow +0 -55
- package/core/RelayIRTransforms.js.flow +0 -138
- package/core/RelayParser.js.flow +0 -1731
- package/core/RelaySourceModuleParser.js.flow +0 -133
- package/core/Schema.js.flow +0 -2035
- package/core/SchemaUtils.js.flow +0 -120
- package/core/filterContextForNode.js.flow +0 -49
- package/core/getFieldDefinition.js.flow +0 -156
- package/core/getIdentifierForArgumentValue.js.flow +0 -49
- package/core/getIdentifierForSelection.js.flow +0 -68
- package/core/getLiteralArgumentValues.js.flow +0 -32
- package/core/getNormalizationOperationName.js.flow +0 -19
- package/core/inferRootArgumentDefinitions.js.flow +0 -322
- package/index.js.flow +0 -198
- package/language/RelayLanguagePluginInterface.js.flow +0 -283
- package/language/javascript/FindGraphQLTags.js.flow +0 -136
- package/language/javascript/RelayFlowBabelFactories.js.flow +0 -176
- package/language/javascript/RelayFlowGenerator.js.flow +0 -1096
- package/language/javascript/RelayFlowTypeTransformers.js.flow +0 -181
- package/language/javascript/RelayLanguagePluginJavaScript.js.flow +0 -33
- package/language/javascript/formatGeneratedModule.js.flow +0 -65
- package/lib/bin/RelayCompilerBin.js +0 -143
- package/lib/bin/RelayCompilerMain.js +0 -486
- package/lib/bin/__fixtures__/plugin-module.js +0 -16
- package/lib/codegen/CodegenDirectory.js +0 -335
- package/lib/codegen/CodegenRunner.js +0 -433
- package/lib/codegen/CodegenTypes.js +0 -11
- package/lib/codegen/CodegenWatcher.js +0 -271
- package/lib/codegen/NormalizationCodeGenerator.js +0 -487
- package/lib/codegen/ReaderCodeGenerator.js +0 -473
- package/lib/codegen/RelayCodeGenerator.js +0 -75
- package/lib/codegen/RelayFileWriter.js +0 -270
- package/lib/codegen/SourceControl.js +0 -60
- package/lib/codegen/compileRelayArtifacts.js +0 -157
- package/lib/codegen/createPrintRequireModuleDependency.js +0 -19
- package/lib/codegen/sortObjectByKey.js +0 -41
- package/lib/codegen/writeRelayGeneratedFile.js +0 -206
- package/lib/core/ASTCache.js +0 -70
- package/lib/core/ASTConvert.js +0 -198
- package/lib/core/CompilerContext.js +0 -165
- package/lib/core/CompilerError.js +0 -252
- package/lib/core/DotGraphQLParser.js +0 -40
- package/lib/core/GraphQLCompilerProfiler.js +0 -299
- package/lib/core/GraphQLDerivedFromMetadata.js +0 -31
- package/lib/core/GraphQLWatchmanClient.js +0 -150
- package/lib/core/IR.js +0 -11
- package/lib/core/IRPrinter.js +0 -388
- package/lib/core/IRTransformer.js +0 -345
- package/lib/core/IRValidator.js +0 -226
- package/lib/core/IRVisitor.js +0 -45
- package/lib/core/JSModuleParser.js +0 -18
- package/lib/core/RelayCompilerScope.js +0 -183
- package/lib/core/RelayFindGraphQLTags.js +0 -79
- package/lib/core/RelayGraphQLEnumsGenerator.js +0 -50
- package/lib/core/RelayIRTransforms.js +0 -109
- package/lib/core/RelayParser.js +0 -1381
- package/lib/core/RelaySourceModuleParser.js +0 -104
- package/lib/core/Schema.js +0 -1877
- package/lib/core/SchemaUtils.js +0 -98
- package/lib/core/filterContextForNode.js +0 -50
- package/lib/core/getFieldDefinition.js +0 -145
- package/lib/core/getIdentifierForArgumentValue.js +0 -54
- package/lib/core/getIdentifierForSelection.js +0 -49
- package/lib/core/getLiteralArgumentValues.js +0 -26
- package/lib/core/getNormalizationOperationName.js +0 -17
- package/lib/core/inferRootArgumentDefinitions.js +0 -351
- package/lib/index.js +0 -178
- package/lib/language/RelayLanguagePluginInterface.js +0 -26
- package/lib/language/javascript/FindGraphQLTags.js +0 -126
- package/lib/language/javascript/RelayFlowBabelFactories.js +0 -160
- package/lib/language/javascript/RelayFlowGenerator.js +0 -856
- package/lib/language/javascript/RelayFlowTypeTransformers.js +0 -119
- package/lib/language/javascript/RelayLanguagePluginJavaScript.js +0 -30
- package/lib/language/javascript/formatGeneratedModule.js +0 -36
- package/lib/reporters/ConsoleReporter.js +0 -61
- package/lib/reporters/MultiReporter.js +0 -45
- package/lib/reporters/Reporter.js +0 -11
- package/lib/runner/Artifacts.js +0 -323
- package/lib/runner/BufferedFilesystem.js +0 -262
- package/lib/runner/GraphQLASTNodeGroup.js +0 -256
- package/lib/runner/GraphQLASTUtils.js +0 -23
- package/lib/runner/GraphQLNodeMap.js +0 -81
- package/lib/runner/Sources.js +0 -271
- package/lib/runner/StrictMap.js +0 -134
- package/lib/runner/compileArtifacts.js +0 -39
- package/lib/runner/extractAST.js +0 -77
- package/lib/runner/getChangedNodeNames.js +0 -82
- package/lib/runner/getSchemaInstance.js +0 -30
- package/lib/runner/types.js +0 -12
- package/lib/transforms/ApplyFragmentArgumentTransform.js +0 -393
- package/lib/transforms/ClientExtensionsTransform.js +0 -221
- package/lib/transforms/ConnectionTransform.js +0 -639
- package/lib/transforms/DeclarativeConnectionMutationTransform.js +0 -218
- package/lib/transforms/DeferStreamTransform.js +0 -246
- package/lib/transforms/DisallowIdAsAlias.js +0 -40
- package/lib/transforms/DisallowTypenameOnRoot.js +0 -53
- package/lib/transforms/FieldHandleTransform.js +0 -79
- package/lib/transforms/FilterCompilerDirectivesTransform.js +0 -29
- package/lib/transforms/FilterDirectivesTransform.js +0 -42
- package/lib/transforms/FlattenTransform.js +0 -306
- package/lib/transforms/GenerateIDFieldTransform.js +0 -135
- package/lib/transforms/GenerateTypeNameTransform.js +0 -149
- package/lib/transforms/InlineDataFragmentTransform.js +0 -100
- package/lib/transforms/InlineFragmentsTransform.js +0 -61
- package/lib/transforms/MaskTransform.js +0 -117
- package/lib/transforms/MatchTransform.js +0 -434
- package/lib/transforms/ReactFlightComponentTransform.js +0 -158
- package/lib/transforms/RefetchableFragmentTransform.js +0 -249
- package/lib/transforms/RelayDirectiveTransform.js +0 -83
- package/lib/transforms/RequiredFieldTransform.js +0 -369
- package/lib/transforms/SkipClientExtensionsTransform.js +0 -46
- package/lib/transforms/SkipHandleFieldTransform.js +0 -45
- package/lib/transforms/SkipRedundantNodesTransform.js +0 -261
- package/lib/transforms/SkipSplitOperationTransform.js +0 -32
- package/lib/transforms/SkipUnreachableNodeTransform.js +0 -158
- package/lib/transforms/SkipUnusedVariablesTransform.js +0 -75
- package/lib/transforms/SplitModuleImportTransform.js +0 -82
- package/lib/transforms/TestOperationTransform.js +0 -144
- package/lib/transforms/TransformUtils.js +0 -21
- package/lib/transforms/ValidateGlobalVariablesTransform.js +0 -92
- package/lib/transforms/ValidateRequiredArgumentsTransform.js +0 -114
- package/lib/transforms/ValidateServerOnlyDirectivesTransform.js +0 -108
- package/lib/transforms/ValidateUnusedVariablesTransform.js +0 -96
- package/lib/transforms/query-generators/FetchableQueryGenerator.js +0 -157
- package/lib/transforms/query-generators/NodeQueryGenerator.js +0 -166
- package/lib/transforms/query-generators/QueryQueryGenerator.js +0 -48
- package/lib/transforms/query-generators/ViewerQueryGenerator.js +0 -77
- package/lib/transforms/query-generators/index.js +0 -60
- package/lib/transforms/query-generators/utils.js +0 -92
- package/lib/util/CodeMarker.js +0 -80
- package/lib/util/DefaultHandleKey.js +0 -15
- package/lib/util/RelayCompilerCache.js +0 -97
- package/lib/util/Rollout.js +0 -40
- package/lib/util/TimeReporter.js +0 -83
- package/lib/util/areEqualArgValues.js +0 -135
- package/lib/util/argumentContainsVariables.js +0 -37
- package/lib/util/dedupeJSONStringify.js +0 -160
- package/lib/util/generateAbstractTypeRefinementKey.js +0 -24
- package/lib/util/getDefinitionNodeHash.js +0 -22
- package/lib/util/getModuleName.js +0 -32
- package/lib/util/joinArgumentDefinitions.js +0 -67
- package/lib/util/md5.js +0 -17
- package/lib/util/murmurHash.js +0 -86
- package/lib/util/nullthrowsOSS.js +0 -23
- package/lib/util/orList.js +0 -36
- package/lib/util/partitionArray.js +0 -35
- package/relay-compiler.js +0 -17
- package/relay-compiler.min.js +0 -22
- package/reporters/ConsoleReporter.js.flow +0 -81
- package/reporters/MultiReporter.js.flow +0 -43
- package/reporters/Reporter.js.flow +0 -19
- package/runner/Artifacts.js.flow +0 -215
- package/runner/BufferedFilesystem.js.flow +0 -194
- package/runner/GraphQLASTNodeGroup.js.flow +0 -174
- package/runner/GraphQLASTUtils.js.flow +0 -26
- package/runner/GraphQLNodeMap.js.flow +0 -55
- package/runner/Sources.js.flow +0 -227
- package/runner/StrictMap.js.flow +0 -96
- package/runner/compileArtifacts.js.flow +0 -75
- package/runner/extractAST.js.flow +0 -98
- package/runner/getChangedNodeNames.js.flow +0 -48
- package/runner/getSchemaInstance.js.flow +0 -36
- package/runner/types.js.flow +0 -37
- package/transforms/ApplyFragmentArgumentTransform.js.flow +0 -524
- package/transforms/ClientExtensionsTransform.js.flow +0 -224
- package/transforms/ConnectionTransform.js.flow +0 -850
- package/transforms/DeclarativeConnectionMutationTransform.js.flow +0 -245
- package/transforms/DeferStreamTransform.js.flow +0 -263
- package/transforms/DisallowIdAsAlias.js.flow +0 -46
- package/transforms/DisallowTypenameOnRoot.js.flow +0 -44
- package/transforms/FieldHandleTransform.js.flow +0 -77
- package/transforms/FilterCompilerDirectivesTransform.js.flow +0 -33
- package/transforms/FilterDirectivesTransform.js.flow +0 -45
- package/transforms/FlattenTransform.js.flow +0 -458
- package/transforms/GenerateIDFieldTransform.js.flow +0 -151
- package/transforms/GenerateTypeNameTransform.js.flow +0 -159
- package/transforms/InlineDataFragmentTransform.js.flow +0 -123
- package/transforms/InlineFragmentsTransform.js.flow +0 -70
- package/transforms/MaskTransform.js.flow +0 -124
- package/transforms/MatchTransform.js.flow +0 -587
- package/transforms/ReactFlightComponentTransform.js.flow +0 -194
- package/transforms/RefetchableFragmentTransform.js.flow +0 -266
- package/transforms/RelayDirectiveTransform.js.flow +0 -96
- package/transforms/RequiredFieldTransform.js.flow +0 -413
- package/transforms/SkipClientExtensionsTransform.js.flow +0 -54
- package/transforms/SkipHandleFieldTransform.js.flow +0 -44
- package/transforms/SkipRedundantNodesTransform.js.flow +0 -255
- package/transforms/SkipSplitOperationTransform.js.flow +0 -37
- package/transforms/SkipUnreachableNodeTransform.js.flow +0 -148
- package/transforms/SkipUnusedVariablesTransform.js.flow +0 -59
- package/transforms/SplitModuleImportTransform.js.flow +0 -97
- package/transforms/TestOperationTransform.js.flow +0 -142
- package/transforms/TransformUtils.js.flow +0 -26
- package/transforms/ValidateGlobalVariablesTransform.js.flow +0 -80
- package/transforms/ValidateRequiredArgumentsTransform.js.flow +0 -126
- package/transforms/ValidateServerOnlyDirectivesTransform.js.flow +0 -111
- package/transforms/ValidateUnusedVariablesTransform.js.flow +0 -88
- package/transforms/query-generators/FetchableQueryGenerator.js.flow +0 -188
- package/transforms/query-generators/NodeQueryGenerator.js.flow +0 -217
- package/transforms/query-generators/QueryQueryGenerator.js.flow +0 -57
- package/transforms/query-generators/ViewerQueryGenerator.js.flow +0 -97
- package/transforms/query-generators/index.js.flow +0 -89
- package/transforms/query-generators/utils.js.flow +0 -76
- package/util/CodeMarker.js.flow +0 -79
- package/util/DefaultHandleKey.js.flow +0 -17
- package/util/RelayCompilerCache.js.flow +0 -86
- package/util/Rollout.js.flow +0 -39
- package/util/TimeReporter.js.flow +0 -79
- package/util/areEqualArgValues.js.flow +0 -126
- package/util/argumentContainsVariables.js.flow +0 -38
- package/util/dedupeJSONStringify.js.flow +0 -152
- package/util/generateAbstractTypeRefinementKey.js.flow +0 -29
- package/util/getDefinitionNodeHash.js.flow +0 -24
- package/util/getModuleName.js.flow +0 -39
- package/util/joinArgumentDefinitions.js.flow +0 -105
- package/util/md5.js.flow +0 -19
- package/util/murmurHash.js.flow +0 -94
- package/util/nullthrowsOSS.js.flow +0 -25
- package/util/orList.js.flow +0 -37
- package/util/partitionArray.js.flow +0 -37
package/core/RelayParser.js.flow
DELETED
@@ -1,1731 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Copyright (c) Facebook, Inc. and its affiliates.
|
3
|
-
*
|
4
|
-
* This source code is licensed under the MIT license found in the
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
6
|
-
*
|
7
|
-
* @flow strict
|
8
|
-
* @format
|
9
|
-
*/
|
10
|
-
|
11
|
-
// flowlint ambiguous-object-type:error
|
12
|
-
|
13
|
-
'use strict';
|
14
|
-
|
15
|
-
import type {GetFieldDefinitionFn} from './getFieldDefinition';
|
16
|
-
import type {
|
17
|
-
Argument,
|
18
|
-
ArgumentValue,
|
19
|
-
Condition,
|
20
|
-
Directive,
|
21
|
-
Field,
|
22
|
-
Fragment,
|
23
|
-
FragmentSpread,
|
24
|
-
Handle,
|
25
|
-
InlineFragment,
|
26
|
-
LocalArgumentDefinition,
|
27
|
-
Location,
|
28
|
-
Root,
|
29
|
-
Selection,
|
30
|
-
Variable,
|
31
|
-
} from './IR';
|
32
|
-
import type {
|
33
|
-
Argument as FieldArgument,
|
34
|
-
CompositeTypeID,
|
35
|
-
FieldID,
|
36
|
-
InputTypeID,
|
37
|
-
Schema,
|
38
|
-
TypeID,
|
39
|
-
} from './Schema';
|
40
|
-
import type {
|
41
|
-
ArgumentNode,
|
42
|
-
ASTNode,
|
43
|
-
BooleanValueNode,
|
44
|
-
DefinitionNode,
|
45
|
-
DirectiveLocationEnum,
|
46
|
-
DirectiveNode,
|
47
|
-
EnumValueNode,
|
48
|
-
FieldNode,
|
49
|
-
FloatValueNode,
|
50
|
-
FragmentDefinitionNode,
|
51
|
-
FragmentSpreadNode,
|
52
|
-
InlineFragmentNode,
|
53
|
-
IntValueNode,
|
54
|
-
ListValueNode,
|
55
|
-
Location as ASTLocation,
|
56
|
-
ObjectValueNode,
|
57
|
-
OperationDefinitionNode,
|
58
|
-
SelectionSetNode,
|
59
|
-
StringValueNode,
|
60
|
-
TypeNode,
|
61
|
-
ValueNode,
|
62
|
-
VariableNode,
|
63
|
-
} from 'graphql';
|
64
|
-
|
65
|
-
const {DEFAULT_HANDLE_KEY} = require('../util/DefaultHandleKey');
|
66
|
-
const orList = require('../util/orList');
|
67
|
-
const partitionArray = require('../util/partitionArray');
|
68
|
-
const {
|
69
|
-
createCompilerError,
|
70
|
-
createUserError,
|
71
|
-
eachWithCombinedError,
|
72
|
-
} = require('./CompilerError');
|
73
|
-
const {getFieldDefinitionLegacy} = require('./getFieldDefinition');
|
74
|
-
const Profiler = require('./GraphQLCompilerProfiler');
|
75
|
-
const {isExecutableDefinitionAST} = require('./SchemaUtils');
|
76
|
-
const {Source, parse: parseGraphQL, parseType, print} = require('graphql');
|
77
|
-
|
78
|
-
type ASTDefinitionNode = FragmentDefinitionNode | OperationDefinitionNode;
|
79
|
-
type NonNullLiteralValueNode =
|
80
|
-
| IntValueNode
|
81
|
-
| FloatValueNode
|
82
|
-
| StringValueNode
|
83
|
-
| BooleanValueNode
|
84
|
-
| EnumValueNode
|
85
|
-
| ListValueNode
|
86
|
-
| ObjectValueNode;
|
87
|
-
|
88
|
-
type VariableDefinitions = Map<string, VariableDefinition>;
|
89
|
-
type VariableDefinition = {|
|
90
|
-
ast: ASTNode,
|
91
|
-
name: string,
|
92
|
-
defaultValue: mixed,
|
93
|
-
type: InputTypeID,
|
94
|
-
defined: boolean,
|
95
|
-
|};
|
96
|
-
|
97
|
-
type UnknownVariable = {|
|
98
|
-
ast: VariableNode,
|
99
|
-
type: ?TypeID,
|
100
|
-
|};
|
101
|
-
|
102
|
-
const ARGUMENT_DEFINITIONS = 'argumentDefinitions';
|
103
|
-
const ARGUMENTS = 'arguments';
|
104
|
-
const DEPRECATED_UNCHECKED_ARGUMENTS = 'uncheckedArguments_DEPRECATED';
|
105
|
-
const DIRECTIVE_WHITELIST: $ReadOnlySet<string> = new Set([
|
106
|
-
ARGUMENT_DEFINITIONS,
|
107
|
-
DEPRECATED_UNCHECKED_ARGUMENTS,
|
108
|
-
ARGUMENTS,
|
109
|
-
]);
|
110
|
-
|
111
|
-
/**
|
112
|
-
* @internal
|
113
|
-
*
|
114
|
-
* This directive is not intended for use by developers directly. To set a field
|
115
|
-
* handle in product code use a compiler plugin.
|
116
|
-
*/
|
117
|
-
const CLIENT_FIELD = '__clientField';
|
118
|
-
const CLIENT_FIELD_HANDLE = 'handle';
|
119
|
-
const CLIENT_FIELD_KEY = 'key';
|
120
|
-
const CLIENT_FIELD_FILTERS = 'filters';
|
121
|
-
|
122
|
-
const INCLUDE = 'include';
|
123
|
-
const SKIP = 'skip';
|
124
|
-
const IF = 'if';
|
125
|
-
|
126
|
-
/**
|
127
|
-
* Transforms GraphQL text into Relay Compiler's internal, strongly-typed
|
128
|
-
* intermediate representation (IR).
|
129
|
-
*/
|
130
|
-
function parse(
|
131
|
-
schema: Schema,
|
132
|
-
text: string,
|
133
|
-
filename?: string,
|
134
|
-
): $ReadOnlyArray<Root | Fragment> {
|
135
|
-
const ast = parseGraphQL(new Source(text, filename));
|
136
|
-
const parser = new RelayParser(schema.extend(ast), ast.definitions);
|
137
|
-
return parser.transform();
|
138
|
-
}
|
139
|
-
|
140
|
-
/**
|
141
|
-
* Transforms untyped GraphQL parse trees (ASTs) into Relay Compiler's
|
142
|
-
* internal, strongly-typed intermediate representation (IR).
|
143
|
-
*/
|
144
|
-
function transform(
|
145
|
-
schema: Schema,
|
146
|
-
definitions: $ReadOnlyArray<DefinitionNode>,
|
147
|
-
): $ReadOnlyArray<Root | Fragment> {
|
148
|
-
return Profiler.run('RelayParser.transform', () => {
|
149
|
-
const parser = new RelayParser(schema, definitions);
|
150
|
-
return parser.transform();
|
151
|
-
});
|
152
|
-
}
|
153
|
-
|
154
|
-
/**
|
155
|
-
* @private
|
156
|
-
*/
|
157
|
-
class RelayParser {
|
158
|
-
_definitions: Map<string, ASTDefinitionNode>;
|
159
|
-
_getFieldDefinition: GetFieldDefinitionFn;
|
160
|
-
+_schema: Schema;
|
161
|
-
|
162
|
-
constructor(schema: Schema, definitions: $ReadOnlyArray<DefinitionNode>) {
|
163
|
-
this._definitions = new Map();
|
164
|
-
// leaving this configurable to make it easy to experiment w changing later
|
165
|
-
this._getFieldDefinition = getFieldDefinitionLegacy;
|
166
|
-
this._schema = schema;
|
167
|
-
|
168
|
-
const duplicated = new Set();
|
169
|
-
definitions.forEach(def => {
|
170
|
-
if (isExecutableDefinitionAST(def)) {
|
171
|
-
const name = getName(def);
|
172
|
-
if (this._definitions.has(name)) {
|
173
|
-
duplicated.add(name);
|
174
|
-
return;
|
175
|
-
}
|
176
|
-
this._definitions.set(name, def);
|
177
|
-
}
|
178
|
-
});
|
179
|
-
if (duplicated.size) {
|
180
|
-
throw createUserError(
|
181
|
-
'RelayParser: Encountered duplicate definitions for one or more ' +
|
182
|
-
'documents: each document must have a unique name. Duplicated documents:\n' +
|
183
|
-
Array.from(duplicated, name => `- ${name}`).join('\n'),
|
184
|
-
);
|
185
|
-
}
|
186
|
-
}
|
187
|
-
|
188
|
-
transform(): $ReadOnlyArray<Root | Fragment> {
|
189
|
-
const nodes = [];
|
190
|
-
const entries = new Map();
|
191
|
-
// Construct a mapping of name to definition ast + variable definitions.
|
192
|
-
// This allows the subsequent AST -> IR tranformation to reference the
|
193
|
-
// defined arguments of referenced fragments.
|
194
|
-
eachWithCombinedError(this._definitions, ([name, definition]) => {
|
195
|
-
const variableDefinitions = this._buildArgumentDefinitions(definition);
|
196
|
-
entries.set(name, {definition, variableDefinitions});
|
197
|
-
});
|
198
|
-
// Convert the ASTs to IR.
|
199
|
-
eachWithCombinedError(
|
200
|
-
entries.values(),
|
201
|
-
({definition, variableDefinitions}) => {
|
202
|
-
const node = parseDefinition(
|
203
|
-
this._schema,
|
204
|
-
this._getFieldDefinition,
|
205
|
-
entries,
|
206
|
-
definition,
|
207
|
-
variableDefinitions,
|
208
|
-
);
|
209
|
-
nodes.push(node);
|
210
|
-
},
|
211
|
-
);
|
212
|
-
return nodes;
|
213
|
-
}
|
214
|
-
|
215
|
-
/**
|
216
|
-
* Constructs a mapping of variable names to definitions for the given
|
217
|
-
* operation/fragment definition.
|
218
|
-
*/
|
219
|
-
_buildArgumentDefinitions(
|
220
|
-
definition: ASTDefinitionNode,
|
221
|
-
): VariableDefinitions {
|
222
|
-
switch (definition.kind) {
|
223
|
-
case 'OperationDefinition':
|
224
|
-
return this._buildOperationArgumentDefinitions(definition);
|
225
|
-
case 'FragmentDefinition':
|
226
|
-
return this._buildFragmentArgumentDefinitions(definition);
|
227
|
-
default:
|
228
|
-
(definition: empty);
|
229
|
-
throw createCompilerError(`Unexpected ast kind '${definition.kind}'.`, [
|
230
|
-
definition,
|
231
|
-
]);
|
232
|
-
}
|
233
|
-
}
|
234
|
-
|
235
|
-
/**
|
236
|
-
* Constructs a mapping of variable names to definitions using the
|
237
|
-
* variables defined in `@argumentDefinitions`.
|
238
|
-
*/
|
239
|
-
_buildFragmentArgumentDefinitions(
|
240
|
-
fragment: FragmentDefinitionNode,
|
241
|
-
): VariableDefinitions {
|
242
|
-
const variableDirectives = (fragment.directives || []).filter(
|
243
|
-
directive => getName(directive) === ARGUMENT_DEFINITIONS,
|
244
|
-
);
|
245
|
-
if (!variableDirectives.length) {
|
246
|
-
return new Map();
|
247
|
-
}
|
248
|
-
if (variableDirectives.length !== 1) {
|
249
|
-
throw createUserError(
|
250
|
-
`Directive @${ARGUMENT_DEFINITIONS} may be defined at most once per ` +
|
251
|
-
'fragment.',
|
252
|
-
null,
|
253
|
-
variableDirectives,
|
254
|
-
);
|
255
|
-
}
|
256
|
-
const variableDirective = variableDirectives[0];
|
257
|
-
// work, below accesses all report arguments could still be null/undefined.
|
258
|
-
const args = variableDirective.arguments;
|
259
|
-
if (variableDirective == null || !Array.isArray(args)) {
|
260
|
-
return new Map();
|
261
|
-
}
|
262
|
-
if (!args.length) {
|
263
|
-
throw createUserError(
|
264
|
-
`Directive @${ARGUMENT_DEFINITIONS} requires arguments: remove the ` +
|
265
|
-
'directive to skip defining local variables for this fragment.',
|
266
|
-
null,
|
267
|
-
[variableDirective],
|
268
|
-
);
|
269
|
-
}
|
270
|
-
const variables = new Map();
|
271
|
-
args.forEach(arg => {
|
272
|
-
const argName = getName(arg);
|
273
|
-
const previousVariable = variables.get(argName);
|
274
|
-
if (previousVariable != null) {
|
275
|
-
throw createUserError(
|
276
|
-
`Duplicate definition for variable '\$${argName}'.`,
|
277
|
-
null,
|
278
|
-
[previousVariable.ast, arg],
|
279
|
-
);
|
280
|
-
}
|
281
|
-
if (arg.value.kind !== 'ObjectValue') {
|
282
|
-
throw createUserError(
|
283
|
-
`Expected definition for variable '\$${argName}' to be an object ` +
|
284
|
-
"with the shape: '{type: string, defaultValue?: mixed}.",
|
285
|
-
null,
|
286
|
-
[arg.value],
|
287
|
-
);
|
288
|
-
}
|
289
|
-
let defaultValueNode;
|
290
|
-
let typeString;
|
291
|
-
arg.value.fields.forEach(field => {
|
292
|
-
const name = getName(field);
|
293
|
-
if (name === 'type') {
|
294
|
-
typeString = transformLiteralValue(field.value, field);
|
295
|
-
} else if (name === 'defaultValue') {
|
296
|
-
defaultValueNode = field.value;
|
297
|
-
} else {
|
298
|
-
throw createUserError(
|
299
|
-
`Expected definition for variable '\$${argName}' to be an object ` +
|
300
|
-
"with the shape: '{type: string, defaultValue?: mixed}.",
|
301
|
-
null,
|
302
|
-
[arg.value],
|
303
|
-
);
|
304
|
-
}
|
305
|
-
});
|
306
|
-
if (typeof typeString !== 'string') {
|
307
|
-
throw createUserError(
|
308
|
-
`Expected definition for variable '\$${argName}' to be an object ` +
|
309
|
-
"with the shape: '{type: string, defaultValue?: mixed}.",
|
310
|
-
null,
|
311
|
-
[arg.value],
|
312
|
-
);
|
313
|
-
}
|
314
|
-
const typeFromAST = this._schema.getTypeFromAST(parseType(typeString));
|
315
|
-
if (typeFromAST == null) {
|
316
|
-
throw createUserError(
|
317
|
-
// $FlowFixMe[incompatible-type]
|
318
|
-
`Unknown type "${typeString}" referenced in the argument definitions.`,
|
319
|
-
null,
|
320
|
-
[arg],
|
321
|
-
);
|
322
|
-
}
|
323
|
-
const type = this._schema.asInputType(typeFromAST);
|
324
|
-
if (type == null) {
|
325
|
-
throw createUserError(
|
326
|
-
// $FlowFixMe[incompatible-type]
|
327
|
-
`Expected type "${typeString}" to be an input type in the "${arg.name.value}" argument definitions.`,
|
328
|
-
null,
|
329
|
-
[arg.value],
|
330
|
-
);
|
331
|
-
}
|
332
|
-
const defaultValue =
|
333
|
-
defaultValueNode != null
|
334
|
-
? transformValue(
|
335
|
-
this._schema,
|
336
|
-
defaultValueNode,
|
337
|
-
type,
|
338
|
-
variableAst => {
|
339
|
-
throw createUserError(
|
340
|
-
"Expected 'defaultValue' to be a literal, got a variable.",
|
341
|
-
null,
|
342
|
-
[variableAst],
|
343
|
-
);
|
344
|
-
},
|
345
|
-
)
|
346
|
-
: null;
|
347
|
-
if (defaultValue != null && defaultValue.kind !== 'Literal') {
|
348
|
-
throw createUserError(
|
349
|
-
"Expected 'defaultValue' to be a literal, got a variable.",
|
350
|
-
[defaultValue.loc],
|
351
|
-
);
|
352
|
-
}
|
353
|
-
variables.set(argName, {
|
354
|
-
ast: arg,
|
355
|
-
defaultValue: defaultValue?.value ?? null,
|
356
|
-
defined: true,
|
357
|
-
name: argName,
|
358
|
-
type,
|
359
|
-
});
|
360
|
-
});
|
361
|
-
return variables;
|
362
|
-
}
|
363
|
-
|
364
|
-
/**
|
365
|
-
* Constructs a mapping of variable names to definitions using the
|
366
|
-
* standard GraphQL syntax for variable definitions.
|
367
|
-
*/
|
368
|
-
_buildOperationArgumentDefinitions(
|
369
|
-
operation: OperationDefinitionNode,
|
370
|
-
): VariableDefinitions {
|
371
|
-
const schema = this._schema;
|
372
|
-
const variableDefinitions = new Map();
|
373
|
-
(operation.variableDefinitions || []).forEach(def => {
|
374
|
-
const name = getName(def.variable);
|
375
|
-
const typeFromAST = schema.getTypeFromAST(def.type);
|
376
|
-
if (typeFromAST == null) {
|
377
|
-
throw createUserError(
|
378
|
-
`Unknown type: '${getTypeName(def.type)}'.`,
|
379
|
-
null,
|
380
|
-
[def.type],
|
381
|
-
);
|
382
|
-
}
|
383
|
-
|
384
|
-
const type = schema.asInputType(typeFromAST);
|
385
|
-
if (type == null) {
|
386
|
-
throw createUserError(
|
387
|
-
`Expected type "${getTypeName(def.type)}" to be an input type.`,
|
388
|
-
null,
|
389
|
-
[def.type],
|
390
|
-
);
|
391
|
-
}
|
392
|
-
|
393
|
-
const defaultValue = def.defaultValue
|
394
|
-
? transformLiteralValue(def.defaultValue, def)
|
395
|
-
: null;
|
396
|
-
const previousDefinition = variableDefinitions.get(name);
|
397
|
-
if (previousDefinition != null) {
|
398
|
-
throw createUserError(
|
399
|
-
`Duplicate definition for variable '\$${name}'.`,
|
400
|
-
null,
|
401
|
-
[previousDefinition.ast, def],
|
402
|
-
);
|
403
|
-
}
|
404
|
-
variableDefinitions.set(name, {
|
405
|
-
ast: def,
|
406
|
-
defaultValue,
|
407
|
-
defined: true,
|
408
|
-
name,
|
409
|
-
type,
|
410
|
-
});
|
411
|
-
});
|
412
|
-
return variableDefinitions;
|
413
|
-
}
|
414
|
-
}
|
415
|
-
|
416
|
-
/**
|
417
|
-
* @private
|
418
|
-
*/
|
419
|
-
function parseDefinition(
|
420
|
-
schema: Schema,
|
421
|
-
getFieldDefinition: GetFieldDefinitionFn,
|
422
|
-
entries: Map<
|
423
|
-
string,
|
424
|
-
{|definition: ASTDefinitionNode, variableDefinitions: VariableDefinitions|},
|
425
|
-
>,
|
426
|
-
definition: ASTDefinitionNode,
|
427
|
-
variableDefinitions: VariableDefinitions,
|
428
|
-
): Fragment | Root {
|
429
|
-
const parser = new GraphQLDefinitionParser(
|
430
|
-
schema,
|
431
|
-
getFieldDefinition,
|
432
|
-
entries,
|
433
|
-
definition,
|
434
|
-
variableDefinitions,
|
435
|
-
);
|
436
|
-
return parser.transform();
|
437
|
-
}
|
438
|
-
|
439
|
-
/**
|
440
|
-
* @private
|
441
|
-
*/
|
442
|
-
class GraphQLDefinitionParser {
|
443
|
-
_definition: ASTDefinitionNode;
|
444
|
-
_entries: Map<
|
445
|
-
string,
|
446
|
-
{|
|
447
|
-
definition: ASTDefinitionNode,
|
448
|
-
variableDefinitions: VariableDefinitions,
|
449
|
-
|},
|
450
|
-
>;
|
451
|
-
_getFieldDefinition: GetFieldDefinitionFn;
|
452
|
-
_schema: Schema;
|
453
|
-
_variableDefinitions: VariableDefinitions;
|
454
|
-
_unknownVariables: Map<string, UnknownVariable>;
|
455
|
-
_directiveLocations: ?Map<string, $ReadOnlyArray<DirectiveLocationEnum>>;
|
456
|
-
|
457
|
-
constructor(
|
458
|
-
schema: Schema,
|
459
|
-
getFieldDefinition: GetFieldDefinitionFn,
|
460
|
-
entries: Map<
|
461
|
-
string,
|
462
|
-
{|
|
463
|
-
definition: ASTDefinitionNode,
|
464
|
-
variableDefinitions: VariableDefinitions,
|
465
|
-
|},
|
466
|
-
>,
|
467
|
-
definition: ASTDefinitionNode,
|
468
|
-
variableDefinitions: VariableDefinitions,
|
469
|
-
): void {
|
470
|
-
this._definition = definition;
|
471
|
-
this._entries = entries;
|
472
|
-
this._getFieldDefinition = getFieldDefinition;
|
473
|
-
this._schema = schema;
|
474
|
-
this._variableDefinitions = variableDefinitions;
|
475
|
-
this._unknownVariables = new Map();
|
476
|
-
}
|
477
|
-
|
478
|
-
transform(): Root | Fragment {
|
479
|
-
const definition = this._definition;
|
480
|
-
switch (definition.kind) {
|
481
|
-
case 'OperationDefinition':
|
482
|
-
return this._transformOperation(definition);
|
483
|
-
case 'FragmentDefinition':
|
484
|
-
return this._transformFragment(definition);
|
485
|
-
default:
|
486
|
-
(definition: empty);
|
487
|
-
throw createCompilerError(
|
488
|
-
`Unsupported definition type ${definition.kind}`,
|
489
|
-
[definition],
|
490
|
-
);
|
491
|
-
}
|
492
|
-
}
|
493
|
-
|
494
|
-
_recordAndVerifyVariableReference(
|
495
|
-
variable: VariableNode,
|
496
|
-
name: string,
|
497
|
-
usedAsType: ?TypeID,
|
498
|
-
): void {
|
499
|
-
// Special case for variables used in @arguments where we currently
|
500
|
-
// aren't guaranteed to be able to resolve the type.
|
501
|
-
if (usedAsType == null) {
|
502
|
-
if (
|
503
|
-
!this._variableDefinitions.has(name) &&
|
504
|
-
!this._unknownVariables.has(name)
|
505
|
-
) {
|
506
|
-
this._unknownVariables.set(name, {
|
507
|
-
ast: variable,
|
508
|
-
type: null,
|
509
|
-
});
|
510
|
-
}
|
511
|
-
return;
|
512
|
-
}
|
513
|
-
const variableDefinition = this._variableDefinitions.get(name);
|
514
|
-
if (variableDefinition != null) {
|
515
|
-
// If the variable is defined, all usages must be compatible
|
516
|
-
let effectiveType = variableDefinition.type;
|
517
|
-
if (variableDefinition.defaultValue != null) {
|
518
|
-
// If a default value is defined then it is guaranteed to be used
|
519
|
-
// at runtime such that the effective type of the variable is non-null
|
520
|
-
effectiveType = this._schema.getNonNullType(
|
521
|
-
this._schema.getNullableType(effectiveType),
|
522
|
-
);
|
523
|
-
}
|
524
|
-
|
525
|
-
if (!this._schema.isTypeSubTypeOf(effectiveType, usedAsType)) {
|
526
|
-
throw createUserError(
|
527
|
-
`Variable '\$${name}' was defined as type '${String(
|
528
|
-
variableDefinition.type,
|
529
|
-
)}' but used in a location expecting the type '${String(
|
530
|
-
usedAsType,
|
531
|
-
)}'`,
|
532
|
-
null,
|
533
|
-
[variableDefinition.ast, variable],
|
534
|
-
);
|
535
|
-
}
|
536
|
-
} else {
|
537
|
-
const previous = this._unknownVariables.get(name);
|
538
|
-
|
539
|
-
if (!previous || !previous.type) {
|
540
|
-
// No previous usage, current type is strongest
|
541
|
-
this._unknownVariables.set(name, {
|
542
|
-
ast: variable,
|
543
|
-
type: usedAsType,
|
544
|
-
});
|
545
|
-
} else {
|
546
|
-
const {ast: previousVariable, type: previousType} = previous;
|
547
|
-
if (
|
548
|
-
!(
|
549
|
-
this._schema.isTypeSubTypeOf(usedAsType, previousType) ||
|
550
|
-
this._schema.isTypeSubTypeOf(previousType, usedAsType)
|
551
|
-
)
|
552
|
-
) {
|
553
|
-
throw createUserError(
|
554
|
-
`Variable '\$${name}' was used in locations expecting the conflicting types '${String(
|
555
|
-
previousType,
|
556
|
-
)}' and '${String(usedAsType)}'.`,
|
557
|
-
null,
|
558
|
-
[previousVariable, variable],
|
559
|
-
);
|
560
|
-
}
|
561
|
-
|
562
|
-
// If the new used type has stronger requirements, use that type as reference,
|
563
|
-
// otherwise keep referencing the previous type
|
564
|
-
if (this._schema.isTypeSubTypeOf(usedAsType, previousType)) {
|
565
|
-
this._unknownVariables.set(name, {
|
566
|
-
ast: variable,
|
567
|
-
type: usedAsType,
|
568
|
-
});
|
569
|
-
}
|
570
|
-
}
|
571
|
-
}
|
572
|
-
}
|
573
|
-
|
574
|
-
_getDirectiveLocations(): Map<string, $ReadOnlyArray<DirectiveLocationEnum>> {
|
575
|
-
if (!this._directiveLocations) {
|
576
|
-
const directiveDefs = this._schema.getDirectives();
|
577
|
-
this._directiveLocations = new Map();
|
578
|
-
for (const def of directiveDefs) {
|
579
|
-
this._directiveLocations.set(def.name, def.locations);
|
580
|
-
}
|
581
|
-
}
|
582
|
-
return this._directiveLocations;
|
583
|
-
}
|
584
|
-
|
585
|
-
_validateDirectivesLocation(
|
586
|
-
directives: ?$ReadOnlyArray<DirectiveNode>,
|
587
|
-
allowedLocaction: DirectiveLocationEnum,
|
588
|
-
): void {
|
589
|
-
if (!directives || !directives.length) {
|
590
|
-
return;
|
591
|
-
}
|
592
|
-
const directiveLocs = this._getDirectiveLocations();
|
593
|
-
const mismatches = directives.filter(directive => {
|
594
|
-
const name = getName(directive);
|
595
|
-
if (DIRECTIVE_WHITELIST.has(name)) {
|
596
|
-
return false;
|
597
|
-
}
|
598
|
-
const locs = directiveLocs.get(name);
|
599
|
-
if (locs == null) {
|
600
|
-
throw createUserError(`Unknown directive '${name}'.`, null, [
|
601
|
-
directive,
|
602
|
-
]);
|
603
|
-
}
|
604
|
-
return !locs.some(loc => loc === allowedLocaction);
|
605
|
-
});
|
606
|
-
if (mismatches.length) {
|
607
|
-
const invalidDirectives = mismatches
|
608
|
-
.map(directive => '@' + getName(directive))
|
609
|
-
.join(', ');
|
610
|
-
throw createUserError(
|
611
|
-
`Invalid directives ${invalidDirectives} found on ${allowedLocaction}.`,
|
612
|
-
null,
|
613
|
-
mismatches,
|
614
|
-
);
|
615
|
-
}
|
616
|
-
}
|
617
|
-
|
618
|
-
_transformFragment(fragment: FragmentDefinitionNode): Fragment {
|
619
|
-
const directives = this._transformDirectives(
|
620
|
-
(fragment.directives || []).filter(
|
621
|
-
directive => getName(directive) !== ARGUMENT_DEFINITIONS,
|
622
|
-
),
|
623
|
-
'FRAGMENT_DEFINITION',
|
624
|
-
);
|
625
|
-
|
626
|
-
const typeFromAST = this._schema.getTypeFromAST(fragment.typeCondition);
|
627
|
-
if (typeFromAST == null) {
|
628
|
-
throw createUserError(
|
629
|
-
`Fragment "${fragment.name.value}" cannot condition on unknown ` +
|
630
|
-
`type "${String(fragment.typeCondition.name.value)}".`,
|
631
|
-
null,
|
632
|
-
[fragment.typeCondition],
|
633
|
-
);
|
634
|
-
}
|
635
|
-
|
636
|
-
const type = this._schema.asCompositeType(typeFromAST);
|
637
|
-
if (type == null) {
|
638
|
-
throw createUserError(
|
639
|
-
`Fragment "${fragment.name.value}" cannot condition on non composite ` +
|
640
|
-
`type "${String(type)}".`,
|
641
|
-
null,
|
642
|
-
[fragment.typeCondition],
|
643
|
-
);
|
644
|
-
}
|
645
|
-
|
646
|
-
const selections = this._transformSelections(
|
647
|
-
fragment.selectionSet,
|
648
|
-
type,
|
649
|
-
fragment.typeCondition,
|
650
|
-
);
|
651
|
-
const argumentDefinitions = [
|
652
|
-
...buildArgumentDefinitions(this._variableDefinitions),
|
653
|
-
];
|
654
|
-
for (const [name, variableReference] of this._unknownVariables) {
|
655
|
-
argumentDefinitions.push({
|
656
|
-
kind: 'RootArgumentDefinition',
|
657
|
-
loc: buildLocation(variableReference.ast.loc),
|
658
|
-
name,
|
659
|
-
type: variableReference.type,
|
660
|
-
});
|
661
|
-
}
|
662
|
-
return {
|
663
|
-
kind: 'Fragment',
|
664
|
-
directives,
|
665
|
-
loc: buildLocation(fragment.loc),
|
666
|
-
metadata: null,
|
667
|
-
name: getName(fragment),
|
668
|
-
selections,
|
669
|
-
type,
|
670
|
-
// $FlowFixMe[incompatible-return] - could be null
|
671
|
-
argumentDefinitions,
|
672
|
-
};
|
673
|
-
}
|
674
|
-
|
675
|
-
_getLocationFromOperation(
|
676
|
-
definition: OperationDefinitionNode,
|
677
|
-
): DirectiveLocationEnum {
|
678
|
-
switch (definition.operation) {
|
679
|
-
case 'query':
|
680
|
-
return 'QUERY';
|
681
|
-
case 'mutation':
|
682
|
-
return 'MUTATION';
|
683
|
-
case 'subscription':
|
684
|
-
return 'SUBSCRIPTION';
|
685
|
-
default:
|
686
|
-
(definition.operation: empty);
|
687
|
-
throw createCompilerError(
|
688
|
-
`Unknown operation type '${definition.operation}'.`,
|
689
|
-
null,
|
690
|
-
[definition],
|
691
|
-
);
|
692
|
-
}
|
693
|
-
}
|
694
|
-
|
695
|
-
_transformOperation(definition: OperationDefinitionNode): Root {
|
696
|
-
const name = getName(definition);
|
697
|
-
const directives = this._transformDirectives(
|
698
|
-
definition.directives || [],
|
699
|
-
this._getLocationFromOperation(definition),
|
700
|
-
);
|
701
|
-
let type: TypeID;
|
702
|
-
let operation;
|
703
|
-
const schema = this._schema;
|
704
|
-
switch (definition.operation) {
|
705
|
-
case 'query':
|
706
|
-
operation = 'query';
|
707
|
-
type = schema.expectQueryType();
|
708
|
-
break;
|
709
|
-
case 'mutation':
|
710
|
-
operation = 'mutation';
|
711
|
-
type = schema.expectMutationType();
|
712
|
-
break;
|
713
|
-
case 'subscription':
|
714
|
-
operation = 'subscription';
|
715
|
-
type = schema.expectSubscriptionType();
|
716
|
-
break;
|
717
|
-
default:
|
718
|
-
(definition.operation: empty);
|
719
|
-
throw createCompilerError(
|
720
|
-
`Unknown operation type '${definition.operation}'.`,
|
721
|
-
null,
|
722
|
-
[definition],
|
723
|
-
);
|
724
|
-
}
|
725
|
-
if (!definition.selectionSet) {
|
726
|
-
throw createUserError('Expected operation to have selections.', null, [
|
727
|
-
definition,
|
728
|
-
]);
|
729
|
-
}
|
730
|
-
const selections = this._transformSelections(definition.selectionSet, type);
|
731
|
-
const argumentDefinitions = buildArgumentDefinitions(
|
732
|
-
this._variableDefinitions,
|
733
|
-
);
|
734
|
-
if (this._unknownVariables.size !== 0) {
|
735
|
-
throw createUserError(
|
736
|
-
`Query '${name}' references undefined variables.`,
|
737
|
-
null,
|
738
|
-
Array.from(
|
739
|
-
this._unknownVariables.values(),
|
740
|
-
variableReference => variableReference.ast,
|
741
|
-
),
|
742
|
-
);
|
743
|
-
}
|
744
|
-
return {
|
745
|
-
kind: 'Root',
|
746
|
-
operation,
|
747
|
-
loc: buildLocation(definition.loc),
|
748
|
-
metadata: null,
|
749
|
-
name,
|
750
|
-
argumentDefinitions,
|
751
|
-
directives,
|
752
|
-
selections,
|
753
|
-
type,
|
754
|
-
};
|
755
|
-
}
|
756
|
-
|
757
|
-
_transformSelections(
|
758
|
-
selectionSet: SelectionSetNode,
|
759
|
-
parentType: TypeID,
|
760
|
-
parentTypeAST?: TypeNode,
|
761
|
-
): $ReadOnlyArray<Selection> {
|
762
|
-
return selectionSet.selections.map(selection => {
|
763
|
-
let node;
|
764
|
-
if (selection.kind === 'Field') {
|
765
|
-
node = this._transformField(selection, parentType);
|
766
|
-
} else if (selection.kind === 'FragmentSpread') {
|
767
|
-
node = this._transformFragmentSpread(
|
768
|
-
selection,
|
769
|
-
parentType,
|
770
|
-
parentTypeAST,
|
771
|
-
);
|
772
|
-
} else if (selection.kind === 'InlineFragment') {
|
773
|
-
node = this._transformInlineFragment(
|
774
|
-
selection,
|
775
|
-
parentType,
|
776
|
-
parentTypeAST,
|
777
|
-
);
|
778
|
-
} else {
|
779
|
-
(selection.kind: empty);
|
780
|
-
throw createCompilerError(`Unknown ast kind '${selection.kind}'.`, [
|
781
|
-
selection,
|
782
|
-
]);
|
783
|
-
}
|
784
|
-
const [conditions, directives] = this._splitConditions(node.directives);
|
785
|
-
const conditionalNodes = applyConditions(
|
786
|
-
conditions,
|
787
|
-
// $FlowFixMe[incompatible-call]
|
788
|
-
[{...node, directives}],
|
789
|
-
);
|
790
|
-
if (conditionalNodes.length !== 1) {
|
791
|
-
throw createCompilerError(
|
792
|
-
'Expected exactly one condition node.',
|
793
|
-
null,
|
794
|
-
selection.directives,
|
795
|
-
);
|
796
|
-
}
|
797
|
-
return conditionalNodes[0];
|
798
|
-
});
|
799
|
-
}
|
800
|
-
|
801
|
-
_transformInlineFragment(
|
802
|
-
fragment: InlineFragmentNode,
|
803
|
-
parentType: TypeID,
|
804
|
-
parentTypeAST: ?TypeNode,
|
805
|
-
): InlineFragment {
|
806
|
-
const schema = this._schema;
|
807
|
-
let typeCondition =
|
808
|
-
fragment.typeCondition != null
|
809
|
-
? schema.getTypeFromAST(fragment.typeCondition)
|
810
|
-
: parentType;
|
811
|
-
|
812
|
-
if (typeCondition == null) {
|
813
|
-
throw createUserError(
|
814
|
-
'Inline fragments can only be on object, interface or union types' +
|
815
|
-
`, got unknown type '${getTypeName(fragment.typeCondition)}'.`,
|
816
|
-
null,
|
817
|
-
[fragment.typeCondition ?? fragment],
|
818
|
-
);
|
819
|
-
}
|
820
|
-
const typeConditionName = schema.getTypeString(typeCondition);
|
821
|
-
typeCondition = schema.asCompositeType(typeCondition);
|
822
|
-
if (typeCondition == null) {
|
823
|
-
throw createUserError(
|
824
|
-
'Inline fragments can only be on object, interface or union types' +
|
825
|
-
`, got '${typeConditionName}'.`,
|
826
|
-
null,
|
827
|
-
[fragment.typeCondition ?? fragment],
|
828
|
-
);
|
829
|
-
}
|
830
|
-
const rawParentType = this._schema.assertCompositeType(
|
831
|
-
this._schema.getRawType(parentType),
|
832
|
-
);
|
833
|
-
|
834
|
-
checkFragmentSpreadTypeCompatibility(
|
835
|
-
this._schema,
|
836
|
-
typeCondition,
|
837
|
-
rawParentType,
|
838
|
-
null,
|
839
|
-
fragment.typeCondition,
|
840
|
-
parentTypeAST,
|
841
|
-
);
|
842
|
-
|
843
|
-
const directives = this._transformDirectives(
|
844
|
-
fragment.directives || [],
|
845
|
-
'INLINE_FRAGMENT',
|
846
|
-
);
|
847
|
-
const selections = this._transformSelections(
|
848
|
-
fragment.selectionSet,
|
849
|
-
typeCondition,
|
850
|
-
fragment.typeCondition,
|
851
|
-
);
|
852
|
-
return {
|
853
|
-
kind: 'InlineFragment',
|
854
|
-
directives,
|
855
|
-
loc: buildLocation(fragment.loc),
|
856
|
-
metadata: null,
|
857
|
-
selections,
|
858
|
-
typeCondition,
|
859
|
-
};
|
860
|
-
}
|
861
|
-
|
862
|
-
_transformFragmentSpread(
|
863
|
-
fragmentSpread: FragmentSpreadNode,
|
864
|
-
parentType: TypeID,
|
865
|
-
parentTypeAST: ?TypeNode,
|
866
|
-
): FragmentSpread {
|
867
|
-
const fragmentName = getName(fragmentSpread);
|
868
|
-
const [argumentDirectives, otherDirectives] = partitionArray(
|
869
|
-
fragmentSpread.directives || [],
|
870
|
-
directive => {
|
871
|
-
const name = getName(directive);
|
872
|
-
return name === ARGUMENTS || name === DEPRECATED_UNCHECKED_ARGUMENTS;
|
873
|
-
},
|
874
|
-
);
|
875
|
-
if (argumentDirectives.length > 1) {
|
876
|
-
throw createUserError(
|
877
|
-
`Directive @${ARGUMENTS} may be used at most once per a fragment spread.`,
|
878
|
-
null,
|
879
|
-
argumentDirectives,
|
880
|
-
);
|
881
|
-
}
|
882
|
-
const fragmentDefinition = this._entries.get(fragmentName);
|
883
|
-
if (fragmentDefinition == null) {
|
884
|
-
throw createUserError(`Unknown fragment '${fragmentName}'.`, null, [
|
885
|
-
fragmentSpread.name,
|
886
|
-
]);
|
887
|
-
}
|
888
|
-
|
889
|
-
const fragmentTypeNode = getFragmentType(fragmentDefinition.definition);
|
890
|
-
const fragmentType = this._schema.assertCompositeType(
|
891
|
-
this._schema.expectTypeFromAST(fragmentTypeNode),
|
892
|
-
);
|
893
|
-
const rawParentType = this._schema.assertCompositeType(
|
894
|
-
this._schema.getRawType(parentType),
|
895
|
-
);
|
896
|
-
|
897
|
-
checkFragmentSpreadTypeCompatibility(
|
898
|
-
this._schema,
|
899
|
-
fragmentType,
|
900
|
-
rawParentType,
|
901
|
-
fragmentSpread.name.value,
|
902
|
-
fragmentSpread,
|
903
|
-
parentTypeAST,
|
904
|
-
);
|
905
|
-
|
906
|
-
const fragmentArgumentDefinitions = fragmentDefinition.variableDefinitions;
|
907
|
-
const argumentsDirective = argumentDirectives[0];
|
908
|
-
let args;
|
909
|
-
if (argumentsDirective != null) {
|
910
|
-
const isDeprecatedUncheckedArguments =
|
911
|
-
getName(argumentsDirective) === DEPRECATED_UNCHECKED_ARGUMENTS;
|
912
|
-
let hasInvalidArgument = false;
|
913
|
-
args = (argumentsDirective.arguments || []).map(arg => {
|
914
|
-
const argName = getName(arg);
|
915
|
-
const argValue = arg.value;
|
916
|
-
const argumentDefinition = fragmentArgumentDefinitions.get(argName);
|
917
|
-
const argumentType = argumentDefinition?.type ?? null;
|
918
|
-
|
919
|
-
if (argValue.kind === 'Variable') {
|
920
|
-
if (argumentDefinition == null && !isDeprecatedUncheckedArguments) {
|
921
|
-
throw createUserError(
|
922
|
-
`Variable @${ARGUMENTS} values are only supported when the ` +
|
923
|
-
`argument is defined with @${ARGUMENT_DEFINITIONS}. Check ` +
|
924
|
-
`the definition of fragment '${fragmentName}'.`,
|
925
|
-
null,
|
926
|
-
[arg.value, fragmentDefinition.definition],
|
927
|
-
);
|
928
|
-
}
|
929
|
-
hasInvalidArgument = hasInvalidArgument || argumentDefinition == null;
|
930
|
-
// TODO: check the type of the variable and use the type
|
931
|
-
return {
|
932
|
-
kind: 'Argument',
|
933
|
-
loc: buildLocation(arg.loc),
|
934
|
-
name: argName,
|
935
|
-
value: this._transformVariable(argValue, null),
|
936
|
-
type: null,
|
937
|
-
};
|
938
|
-
} else {
|
939
|
-
if (argumentType == null) {
|
940
|
-
throw createUserError(
|
941
|
-
`Literal @${ARGUMENTS} values are only supported when the ` +
|
942
|
-
`argument is defined with @${ARGUMENT_DEFINITIONS}. Check ` +
|
943
|
-
`the definition of fragment '${fragmentName}'.`,
|
944
|
-
null,
|
945
|
-
[arg.value, fragmentDefinition.definition],
|
946
|
-
);
|
947
|
-
}
|
948
|
-
const value = this._transformValue(argValue, argumentType);
|
949
|
-
return {
|
950
|
-
kind: 'Argument',
|
951
|
-
loc: buildLocation(arg.loc),
|
952
|
-
name: argName,
|
953
|
-
value,
|
954
|
-
type: argumentType,
|
955
|
-
};
|
956
|
-
}
|
957
|
-
});
|
958
|
-
if (isDeprecatedUncheckedArguments && !hasInvalidArgument) {
|
959
|
-
throw createUserError(
|
960
|
-
`Invalid use of @${DEPRECATED_UNCHECKED_ARGUMENTS}: all arguments ` +
|
961
|
-
`are defined, use @${ARGUMENTS} instead.`,
|
962
|
-
null,
|
963
|
-
[argumentsDirective],
|
964
|
-
);
|
965
|
-
}
|
966
|
-
}
|
967
|
-
const directives = this._transformDirectives(
|
968
|
-
otherDirectives,
|
969
|
-
'FRAGMENT_SPREAD',
|
970
|
-
);
|
971
|
-
return {
|
972
|
-
kind: 'FragmentSpread',
|
973
|
-
args: args || [],
|
974
|
-
metadata: null,
|
975
|
-
loc: buildLocation(fragmentSpread.loc),
|
976
|
-
name: fragmentName,
|
977
|
-
directives,
|
978
|
-
};
|
979
|
-
}
|
980
|
-
|
981
|
-
_transformField(field: FieldNode, parentType: TypeID): Field {
|
982
|
-
const schema = this._schema;
|
983
|
-
const name = getName(field);
|
984
|
-
const fieldDef = this._getFieldDefinition(schema, parentType, name, field);
|
985
|
-
if (fieldDef == null) {
|
986
|
-
throw createUserError(
|
987
|
-
`Unknown field '${name}' on type '${schema.getTypeString(
|
988
|
-
parentType,
|
989
|
-
)}'.`,
|
990
|
-
null,
|
991
|
-
[field],
|
992
|
-
);
|
993
|
-
}
|
994
|
-
const alias = field.alias?.value ?? name;
|
995
|
-
const args = this._transformArguments(
|
996
|
-
field.arguments || [],
|
997
|
-
schema.getFieldArgs(fieldDef),
|
998
|
-
fieldDef,
|
999
|
-
);
|
1000
|
-
const [otherDirectives, clientFieldDirectives] = partitionArray(
|
1001
|
-
field.directives || [],
|
1002
|
-
directive => getName(directive) !== CLIENT_FIELD,
|
1003
|
-
);
|
1004
|
-
const directives = this._transformDirectives(otherDirectives, 'FIELD');
|
1005
|
-
const type = schema.getFieldType(fieldDef);
|
1006
|
-
|
1007
|
-
const handles = this._transformHandle(name, args, clientFieldDirectives);
|
1008
|
-
if (schema.isLeafType(schema.getRawType(type))) {
|
1009
|
-
if (
|
1010
|
-
field.selectionSet &&
|
1011
|
-
field.selectionSet.selections &&
|
1012
|
-
field.selectionSet.selections.length
|
1013
|
-
) {
|
1014
|
-
throw createUserError(
|
1015
|
-
`Expected no selections for scalar field '${name}'.`,
|
1016
|
-
null,
|
1017
|
-
[field],
|
1018
|
-
);
|
1019
|
-
}
|
1020
|
-
return {
|
1021
|
-
kind: 'ScalarField',
|
1022
|
-
alias,
|
1023
|
-
args,
|
1024
|
-
directives,
|
1025
|
-
handles,
|
1026
|
-
loc: buildLocation(field.loc),
|
1027
|
-
metadata: null,
|
1028
|
-
name,
|
1029
|
-
type: schema.assertScalarFieldType(type),
|
1030
|
-
};
|
1031
|
-
} else {
|
1032
|
-
const selections = field.selectionSet
|
1033
|
-
? this._transformSelections(field.selectionSet, type)
|
1034
|
-
: null;
|
1035
|
-
if (selections == null || selections.length === 0) {
|
1036
|
-
throw createUserError(
|
1037
|
-
`Expected at least one selection for non-scalar field '${name}' on type '${schema.getTypeString(
|
1038
|
-
type,
|
1039
|
-
)}'.`,
|
1040
|
-
null,
|
1041
|
-
[field],
|
1042
|
-
);
|
1043
|
-
}
|
1044
|
-
return {
|
1045
|
-
kind: 'LinkedField',
|
1046
|
-
alias,
|
1047
|
-
args,
|
1048
|
-
connection: false,
|
1049
|
-
directives,
|
1050
|
-
handles,
|
1051
|
-
loc: buildLocation(field.loc),
|
1052
|
-
metadata: null,
|
1053
|
-
name,
|
1054
|
-
selections,
|
1055
|
-
type: schema.assertLinkedFieldType(type),
|
1056
|
-
};
|
1057
|
-
}
|
1058
|
-
}
|
1059
|
-
|
1060
|
-
_transformHandle(
|
1061
|
-
fieldName: string,
|
1062
|
-
fieldArgs: $ReadOnlyArray<Argument>,
|
1063
|
-
clientFieldDirectives: $ReadOnlyArray<DirectiveNode>,
|
1064
|
-
): ?$ReadOnlyArray<Handle> {
|
1065
|
-
let handles: ?Array<Handle> = null;
|
1066
|
-
clientFieldDirectives.forEach(clientFieldDirective => {
|
1067
|
-
const handleArgument = (clientFieldDirective.arguments || []).find(
|
1068
|
-
arg => getName(arg) === CLIENT_FIELD_HANDLE,
|
1069
|
-
);
|
1070
|
-
if (handleArgument) {
|
1071
|
-
let name = null;
|
1072
|
-
let key = DEFAULT_HANDLE_KEY;
|
1073
|
-
let filters = null;
|
1074
|
-
const maybeHandle = transformLiteralValue(
|
1075
|
-
handleArgument.value,
|
1076
|
-
handleArgument,
|
1077
|
-
);
|
1078
|
-
if (typeof maybeHandle !== 'string') {
|
1079
|
-
throw createUserError(
|
1080
|
-
`Expected a string literal argument for the @${CLIENT_FIELD} directive.`,
|
1081
|
-
null,
|
1082
|
-
[handleArgument.value],
|
1083
|
-
);
|
1084
|
-
}
|
1085
|
-
name = maybeHandle;
|
1086
|
-
|
1087
|
-
const keyArgument = (clientFieldDirective.arguments || []).find(
|
1088
|
-
arg => getName(arg) === CLIENT_FIELD_KEY,
|
1089
|
-
);
|
1090
|
-
if (keyArgument) {
|
1091
|
-
const maybeKey = transformLiteralValue(
|
1092
|
-
keyArgument.value,
|
1093
|
-
keyArgument,
|
1094
|
-
);
|
1095
|
-
if (typeof maybeKey !== 'string') {
|
1096
|
-
throw createUserError(
|
1097
|
-
`Expected a string literal argument for the @${CLIENT_FIELD} directive.`,
|
1098
|
-
null,
|
1099
|
-
[keyArgument.value],
|
1100
|
-
);
|
1101
|
-
}
|
1102
|
-
key = maybeKey;
|
1103
|
-
}
|
1104
|
-
const filtersArgument = (clientFieldDirective.arguments || []).find(
|
1105
|
-
arg => getName(arg) === CLIENT_FIELD_FILTERS,
|
1106
|
-
);
|
1107
|
-
if (filtersArgument) {
|
1108
|
-
const maybeFilters = transformLiteralValue(
|
1109
|
-
filtersArgument.value,
|
1110
|
-
filtersArgument,
|
1111
|
-
);
|
1112
|
-
if (
|
1113
|
-
!(
|
1114
|
-
Array.isArray(maybeFilters) &&
|
1115
|
-
maybeFilters.every(
|
1116
|
-
filter =>
|
1117
|
-
typeof filter === 'string' &&
|
1118
|
-
fieldArgs.some(fieldArg => fieldArg.name === filter),
|
1119
|
-
)
|
1120
|
-
)
|
1121
|
-
) {
|
1122
|
-
throw createUserError(
|
1123
|
-
`Expected an array of argument names on field '${fieldName}'.`,
|
1124
|
-
null,
|
1125
|
-
[filtersArgument.value],
|
1126
|
-
);
|
1127
|
-
}
|
1128
|
-
// $FlowFixMe[incompatible-cast]
|
1129
|
-
filters = (maybeFilters: Array<string>);
|
1130
|
-
}
|
1131
|
-
const dynamicKeyArgument = (clientFieldDirective.arguments || []).find(
|
1132
|
-
arg => getName(arg) === 'dynamicKey_UNSTABLE',
|
1133
|
-
);
|
1134
|
-
if (dynamicKeyArgument != null) {
|
1135
|
-
throw createUserError(
|
1136
|
-
'Dynamic keys are only supported with @connection.',
|
1137
|
-
null,
|
1138
|
-
[dynamicKeyArgument.value],
|
1139
|
-
);
|
1140
|
-
}
|
1141
|
-
handles = handles || [];
|
1142
|
-
handles.push({name, key, filters, dynamicKey: null});
|
1143
|
-
}
|
1144
|
-
});
|
1145
|
-
return handles;
|
1146
|
-
}
|
1147
|
-
|
1148
|
-
_transformDirectives(
|
1149
|
-
directives: $ReadOnlyArray<DirectiveNode>,
|
1150
|
-
location: DirectiveLocationEnum,
|
1151
|
-
): $ReadOnlyArray<Directive> {
|
1152
|
-
this._validateDirectivesLocation(directives, location);
|
1153
|
-
return directives.map(directive => {
|
1154
|
-
const name = getName(directive);
|
1155
|
-
const directiveDef = this._schema.getDirective(name);
|
1156
|
-
if (directiveDef == null) {
|
1157
|
-
throw createUserError(`Unknown directive '${name}'.`, null, [
|
1158
|
-
directive,
|
1159
|
-
]);
|
1160
|
-
}
|
1161
|
-
const args = this._transformArguments(
|
1162
|
-
directive.arguments || [],
|
1163
|
-
directiveDef.args.map(item => {
|
1164
|
-
return {
|
1165
|
-
name: item.name,
|
1166
|
-
type: item.type,
|
1167
|
-
defaultValue: item.defaultValue,
|
1168
|
-
};
|
1169
|
-
}),
|
1170
|
-
null,
|
1171
|
-
name,
|
1172
|
-
);
|
1173
|
-
return {
|
1174
|
-
kind: 'Directive',
|
1175
|
-
loc: buildLocation(directive.loc),
|
1176
|
-
name,
|
1177
|
-
args,
|
1178
|
-
};
|
1179
|
-
});
|
1180
|
-
}
|
1181
|
-
|
1182
|
-
_transformArguments(
|
1183
|
-
args: $ReadOnlyArray<ArgumentNode>,
|
1184
|
-
argumentDefinitions: $ReadOnlyArray<FieldArgument>,
|
1185
|
-
field?: ?FieldID,
|
1186
|
-
directiveName?: ?string,
|
1187
|
-
): $ReadOnlyArray<Argument> {
|
1188
|
-
return args.map(arg => {
|
1189
|
-
const argName = getName(arg);
|
1190
|
-
const argDef = argumentDefinitions.find(def => def.name === argName);
|
1191
|
-
if (argDef == null) {
|
1192
|
-
const message =
|
1193
|
-
`Unknown argument '${argName}'` +
|
1194
|
-
(field
|
1195
|
-
? ` on field '${this._schema.getFieldName(field)}'` +
|
1196
|
-
` of type '${this._schema.getTypeString(
|
1197
|
-
this._schema.getFieldParentType(field),
|
1198
|
-
)}'.`
|
1199
|
-
: directiveName != null
|
1200
|
-
? ` on directive '@${directiveName}'.`
|
1201
|
-
: '.');
|
1202
|
-
|
1203
|
-
throw createUserError(message, null, [arg]);
|
1204
|
-
}
|
1205
|
-
|
1206
|
-
const value = this._transformValue(arg.value, argDef.type);
|
1207
|
-
return {
|
1208
|
-
kind: 'Argument',
|
1209
|
-
loc: buildLocation(arg.loc),
|
1210
|
-
name: argName,
|
1211
|
-
value,
|
1212
|
-
type: argDef.type,
|
1213
|
-
};
|
1214
|
-
});
|
1215
|
-
}
|
1216
|
-
|
1217
|
-
_splitConditions(
|
1218
|
-
mixedDirectives: $ReadOnlyArray<Directive>,
|
1219
|
-
): [$ReadOnlyArray<Condition>, $ReadOnlyArray<Directive>] {
|
1220
|
-
const [conditionDirectives, otherDirectives] = partitionArray(
|
1221
|
-
mixedDirectives,
|
1222
|
-
directive => directive.name === INCLUDE || directive.name === SKIP,
|
1223
|
-
);
|
1224
|
-
const conditions = conditionDirectives.map(directive => {
|
1225
|
-
const passingValue = directive.name === INCLUDE;
|
1226
|
-
const arg = directive.args[0];
|
1227
|
-
if (arg == null || arg.name !== IF) {
|
1228
|
-
throw createUserError(
|
1229
|
-
`Expected an 'if' argument to @${directive.name}.`,
|
1230
|
-
[directive.loc],
|
1231
|
-
);
|
1232
|
-
}
|
1233
|
-
if (!(arg.value.kind === 'Variable' || arg.value.kind === 'Literal')) {
|
1234
|
-
throw createUserError(
|
1235
|
-
`Expected the 'if' argument to @${directive.name} to be a variable or literal.`,
|
1236
|
-
[directive.loc],
|
1237
|
-
);
|
1238
|
-
}
|
1239
|
-
return {
|
1240
|
-
kind: 'Condition',
|
1241
|
-
condition: arg.value,
|
1242
|
-
loc: directive.loc,
|
1243
|
-
passingValue,
|
1244
|
-
selections: [],
|
1245
|
-
};
|
1246
|
-
});
|
1247
|
-
const sortedConditions = conditions.sort((a, b) => {
|
1248
|
-
if (a.condition.kind === 'Variable' && b.condition.kind === 'Variable') {
|
1249
|
-
return a.condition.variableName < b.condition.variableName
|
1250
|
-
? -1
|
1251
|
-
: a.condition.variableName > b.condition.variableName
|
1252
|
-
? 1
|
1253
|
-
: 0;
|
1254
|
-
} else {
|
1255
|
-
// sort literals earlier, variables later
|
1256
|
-
return a.condition.kind === 'Variable'
|
1257
|
-
? 1
|
1258
|
-
: b.condition.kind === 'Variable'
|
1259
|
-
? -1
|
1260
|
-
: 0;
|
1261
|
-
}
|
1262
|
-
});
|
1263
|
-
return [sortedConditions, otherDirectives];
|
1264
|
-
}
|
1265
|
-
|
1266
|
-
_transformVariable(ast: VariableNode, usedAsType: ?InputTypeID): Variable {
|
1267
|
-
const variableName = getName(ast);
|
1268
|
-
this._recordAndVerifyVariableReference(ast, variableName, usedAsType);
|
1269
|
-
return {
|
1270
|
-
kind: 'Variable',
|
1271
|
-
loc: buildLocation(ast.loc),
|
1272
|
-
variableName,
|
1273
|
-
type: usedAsType,
|
1274
|
-
};
|
1275
|
-
}
|
1276
|
-
|
1277
|
-
_transformValue(ast: ValueNode, type: InputTypeID): ArgumentValue {
|
1278
|
-
return transformValue(
|
1279
|
-
this._schema,
|
1280
|
-
ast,
|
1281
|
-
type,
|
1282
|
-
(variableAst, variableType) =>
|
1283
|
-
this._transformVariable(variableAst, variableType),
|
1284
|
-
);
|
1285
|
-
}
|
1286
|
-
}
|
1287
|
-
|
1288
|
-
/**
|
1289
|
-
* Transforms and validates argument values according to the expected
|
1290
|
-
* type.
|
1291
|
-
*/
|
1292
|
-
function transformValue(
|
1293
|
-
schema: Schema,
|
1294
|
-
ast: ValueNode,
|
1295
|
-
type: InputTypeID,
|
1296
|
-
transformVariable: (
|
1297
|
-
variableAst: VariableNode,
|
1298
|
-
variableType: InputTypeID,
|
1299
|
-
) => ArgumentValue,
|
1300
|
-
): ArgumentValue {
|
1301
|
-
if (ast.kind === 'Variable') {
|
1302
|
-
// Special case variables since there is no value to parse
|
1303
|
-
return transformVariable(ast, type);
|
1304
|
-
} else if (ast.kind === 'NullValue') {
|
1305
|
-
// Special case null literals since there is no value to parse
|
1306
|
-
if (schema.isNonNull(type)) {
|
1307
|
-
throw createUserError(
|
1308
|
-
`Expected a value matching type '${String(type)}'.`,
|
1309
|
-
null,
|
1310
|
-
[ast],
|
1311
|
-
);
|
1312
|
-
}
|
1313
|
-
return {
|
1314
|
-
kind: 'Literal',
|
1315
|
-
loc: buildLocation(ast.loc),
|
1316
|
-
value: null,
|
1317
|
-
};
|
1318
|
-
} else {
|
1319
|
-
return transformNonNullLiteral(schema, ast, type, transformVariable);
|
1320
|
-
}
|
1321
|
-
}
|
1322
|
-
|
1323
|
-
/**
|
1324
|
-
* Transforms and validates non-null literal (non-variable) values
|
1325
|
-
* according to the expected type.
|
1326
|
-
*/
|
1327
|
-
function transformNonNullLiteral(
|
1328
|
-
schema: Schema,
|
1329
|
-
ast: NonNullLiteralValueNode,
|
1330
|
-
type: InputTypeID,
|
1331
|
-
transformVariable: (
|
1332
|
-
variableAst: VariableNode,
|
1333
|
-
variableType: InputTypeID,
|
1334
|
-
) => ArgumentValue,
|
1335
|
-
): ArgumentValue {
|
1336
|
-
// Transform the value based on the type without a non-null wrapper.
|
1337
|
-
// Note that error messages should still use the original `type`
|
1338
|
-
// since that accurately describes to the user what the expected
|
1339
|
-
// type is (using nullableType would suggest that `null` is legal
|
1340
|
-
// even when it may not be, for example).
|
1341
|
-
const nullableType = schema.getNullableType(type);
|
1342
|
-
if (schema.isList(nullableType)) {
|
1343
|
-
if (ast.kind !== 'ListValue') {
|
1344
|
-
// Parse singular (non-list) values flowing into a list type
|
1345
|
-
// as scalars, ie without wrapping them in an array.
|
1346
|
-
if (!schema.isInputType(schema.getListItemType(nullableType))) {
|
1347
|
-
throw createUserError(
|
1348
|
-
`Expected type ${schema.getTypeString(
|
1349
|
-
nullableType,
|
1350
|
-
)} to be an input type.`,
|
1351
|
-
null,
|
1352
|
-
[ast],
|
1353
|
-
);
|
1354
|
-
}
|
1355
|
-
return transformValue(
|
1356
|
-
schema,
|
1357
|
-
ast,
|
1358
|
-
schema.assertInputType(schema.getListItemType(nullableType)),
|
1359
|
-
transformVariable,
|
1360
|
-
);
|
1361
|
-
}
|
1362
|
-
const itemType = schema.assertInputType(
|
1363
|
-
schema.getListItemType(nullableType),
|
1364
|
-
);
|
1365
|
-
const literalList = [];
|
1366
|
-
const items = [];
|
1367
|
-
let areAllItemsScalar = true;
|
1368
|
-
ast.values.forEach(item => {
|
1369
|
-
const itemValue = transformValue(
|
1370
|
-
schema,
|
1371
|
-
item,
|
1372
|
-
itemType,
|
1373
|
-
transformVariable,
|
1374
|
-
);
|
1375
|
-
if (itemValue.kind === 'Literal') {
|
1376
|
-
literalList.push(itemValue.value);
|
1377
|
-
}
|
1378
|
-
items.push(itemValue);
|
1379
|
-
areAllItemsScalar = areAllItemsScalar && itemValue.kind === 'Literal';
|
1380
|
-
});
|
1381
|
-
if (areAllItemsScalar) {
|
1382
|
-
return {
|
1383
|
-
kind: 'Literal',
|
1384
|
-
loc: buildLocation(ast.loc),
|
1385
|
-
value: literalList,
|
1386
|
-
};
|
1387
|
-
} else {
|
1388
|
-
return {
|
1389
|
-
kind: 'ListValue',
|
1390
|
-
loc: buildLocation(ast.loc),
|
1391
|
-
items,
|
1392
|
-
};
|
1393
|
-
}
|
1394
|
-
} else if (schema.isInputObject(nullableType)) {
|
1395
|
-
if (ast.kind !== 'ObjectValue') {
|
1396
|
-
throw createUserError(
|
1397
|
-
`Expected a value matching type '${schema.getTypeString(type)}'.`,
|
1398
|
-
null,
|
1399
|
-
[ast],
|
1400
|
-
);
|
1401
|
-
}
|
1402
|
-
const literalObject = {};
|
1403
|
-
const fields = [];
|
1404
|
-
let areAllFieldsScalar = true;
|
1405
|
-
const inputType = schema.assertInputObjectType(nullableType);
|
1406
|
-
const requiredFieldNames = new Set(
|
1407
|
-
schema
|
1408
|
-
.getFields(inputType)
|
1409
|
-
.filter(field => {
|
1410
|
-
return schema.isNonNull(schema.getFieldType(field));
|
1411
|
-
})
|
1412
|
-
.map(field => schema.getFieldName(field)),
|
1413
|
-
);
|
1414
|
-
|
1415
|
-
const seenFields = new Map();
|
1416
|
-
ast.fields.forEach(field => {
|
1417
|
-
const fieldName = getName(field);
|
1418
|
-
const seenField = seenFields.get(fieldName);
|
1419
|
-
if (seenField) {
|
1420
|
-
throw createUserError(
|
1421
|
-
`Duplicated field name '${fieldName}' in the input object.`,
|
1422
|
-
null,
|
1423
|
-
[field, seenField],
|
1424
|
-
);
|
1425
|
-
}
|
1426
|
-
const fieldID = schema.getFieldByName(inputType, fieldName);
|
1427
|
-
if (!fieldID) {
|
1428
|
-
throw createUserError(
|
1429
|
-
`Unknown field '${fieldName}' on type '${schema.getTypeString(
|
1430
|
-
inputType,
|
1431
|
-
)}'.`,
|
1432
|
-
null,
|
1433
|
-
[field],
|
1434
|
-
);
|
1435
|
-
}
|
1436
|
-
const fieldConfig = schema.getFieldConfig(fieldID);
|
1437
|
-
const fieldType = schema.assertInputType(fieldConfig.type);
|
1438
|
-
const fieldValue = transformValue(
|
1439
|
-
schema,
|
1440
|
-
field.value,
|
1441
|
-
fieldType,
|
1442
|
-
transformVariable,
|
1443
|
-
);
|
1444
|
-
if (fieldValue.kind === 'Literal') {
|
1445
|
-
literalObject[field.name.value] = fieldValue.value;
|
1446
|
-
}
|
1447
|
-
fields.push({
|
1448
|
-
kind: 'ObjectFieldValue',
|
1449
|
-
loc: buildLocation(field.loc),
|
1450
|
-
name: fieldName,
|
1451
|
-
value: fieldValue,
|
1452
|
-
});
|
1453
|
-
seenFields.set(fieldName, field);
|
1454
|
-
requiredFieldNames.delete(fieldName);
|
1455
|
-
areAllFieldsScalar = areAllFieldsScalar && fieldValue.kind === 'Literal';
|
1456
|
-
});
|
1457
|
-
if (requiredFieldNames.size > 0) {
|
1458
|
-
const requiredFieldStr = Array.from(requiredFieldNames)
|
1459
|
-
.map(item => `'${item}'`)
|
1460
|
-
.join(', ');
|
1461
|
-
throw createUserError(
|
1462
|
-
`Missing non-optional field${
|
1463
|
-
requiredFieldNames.size > 1 ? 's:' : ''
|
1464
|
-
} ${requiredFieldStr} for input type '${schema.getTypeString(
|
1465
|
-
inputType,
|
1466
|
-
)}'.`,
|
1467
|
-
null,
|
1468
|
-
[ast],
|
1469
|
-
);
|
1470
|
-
}
|
1471
|
-
if (areAllFieldsScalar) {
|
1472
|
-
return {
|
1473
|
-
kind: 'Literal',
|
1474
|
-
loc: buildLocation(ast.loc),
|
1475
|
-
value: literalObject,
|
1476
|
-
};
|
1477
|
-
} else {
|
1478
|
-
return {
|
1479
|
-
kind: 'ObjectValue',
|
1480
|
-
loc: buildLocation(ast.loc),
|
1481
|
-
fields,
|
1482
|
-
};
|
1483
|
-
}
|
1484
|
-
} else if (schema.isId(nullableType)) {
|
1485
|
-
// GraphQLID's parseLiteral() always returns the string value. However
|
1486
|
-
// the int/string distinction may be important at runtime, so this
|
1487
|
-
// transform parses int/string literals into the corresponding JS types.
|
1488
|
-
if (ast.kind === 'IntValue') {
|
1489
|
-
return {
|
1490
|
-
kind: 'Literal',
|
1491
|
-
loc: buildLocation(ast.loc),
|
1492
|
-
value: parseInt(ast.value, 10),
|
1493
|
-
};
|
1494
|
-
} else if (ast.kind === 'StringValue') {
|
1495
|
-
return {
|
1496
|
-
kind: 'Literal',
|
1497
|
-
loc: buildLocation(ast.loc),
|
1498
|
-
value: ast.value,
|
1499
|
-
};
|
1500
|
-
} else {
|
1501
|
-
throw createUserError(
|
1502
|
-
`Invalid value, expected a value matching type '${schema.getTypeString(
|
1503
|
-
type,
|
1504
|
-
)}'.`,
|
1505
|
-
null,
|
1506
|
-
[ast],
|
1507
|
-
);
|
1508
|
-
}
|
1509
|
-
} else if (schema.isEnum(nullableType)) {
|
1510
|
-
const enumType = schema.assertEnumType(nullableType);
|
1511
|
-
const value = schema.parseLiteral(enumType, ast);
|
1512
|
-
if (value == null) {
|
1513
|
-
const suggestions = schema.getEnumValues(enumType);
|
1514
|
-
|
1515
|
-
// parseLiteral() should return a non-null JavaScript value
|
1516
|
-
// if the ast value is valid for the type.
|
1517
|
-
throw createUserError(
|
1518
|
-
`Expected a value matching type '${schema.getTypeString(
|
1519
|
-
type,
|
1520
|
-
)}'. Possible values: ${orList(suggestions)}?'`,
|
1521
|
-
null,
|
1522
|
-
[ast],
|
1523
|
-
);
|
1524
|
-
}
|
1525
|
-
return {
|
1526
|
-
kind: 'Literal',
|
1527
|
-
loc: buildLocation(ast.loc),
|
1528
|
-
value,
|
1529
|
-
};
|
1530
|
-
} else if (schema.isScalar(nullableType)) {
|
1531
|
-
const value = schema.parseLiteral(
|
1532
|
-
schema.assertScalarType(nullableType),
|
1533
|
-
ast,
|
1534
|
-
);
|
1535
|
-
if (value == null) {
|
1536
|
-
// parseLiteral() should return a non-null JavaScript value
|
1537
|
-
// if the ast value is valid for the type.
|
1538
|
-
throw createUserError(
|
1539
|
-
`Expected a value matching type '${schema.getTypeString(type)}'.`,
|
1540
|
-
null,
|
1541
|
-
[ast],
|
1542
|
-
);
|
1543
|
-
}
|
1544
|
-
return {
|
1545
|
-
kind: 'Literal',
|
1546
|
-
loc: buildLocation(ast.loc),
|
1547
|
-
value,
|
1548
|
-
};
|
1549
|
-
} else {
|
1550
|
-
throw createCompilerError(
|
1551
|
-
`Unsupported type '${schema.getTypeString(
|
1552
|
-
type,
|
1553
|
-
)}' for input value, expected a GraphQLList, ` +
|
1554
|
-
'GraphQLInputObjectType, GraphQLEnumType, or GraphQLScalarType.',
|
1555
|
-
null,
|
1556
|
-
[ast],
|
1557
|
-
);
|
1558
|
-
}
|
1559
|
-
}
|
1560
|
-
|
1561
|
-
/**
|
1562
|
-
* @private
|
1563
|
-
*/
|
1564
|
-
function transformLiteralValue(ast: ValueNode, context: ASTNode): mixed {
|
1565
|
-
switch (ast.kind) {
|
1566
|
-
case 'IntValue':
|
1567
|
-
return parseInt(ast.value, 10);
|
1568
|
-
case 'FloatValue':
|
1569
|
-
return parseFloat(ast.value);
|
1570
|
-
case 'StringValue':
|
1571
|
-
return ast.value;
|
1572
|
-
case 'BooleanValue':
|
1573
|
-
// Note: duplicated because Flow does not understand fall-through cases
|
1574
|
-
return ast.value;
|
1575
|
-
case 'EnumValue':
|
1576
|
-
// Note: duplicated because Flow does not understand fall-through cases
|
1577
|
-
return ast.value;
|
1578
|
-
case 'ListValue':
|
1579
|
-
return ast.values.map(item => transformLiteralValue(item, context));
|
1580
|
-
case 'NullValue':
|
1581
|
-
return null;
|
1582
|
-
case 'ObjectValue': {
|
1583
|
-
const objectValue = {};
|
1584
|
-
ast.fields.forEach(field => {
|
1585
|
-
const fieldName = getName(field);
|
1586
|
-
const value = transformLiteralValue(field.value, context);
|
1587
|
-
objectValue[fieldName] = value;
|
1588
|
-
});
|
1589
|
-
return objectValue;
|
1590
|
-
}
|
1591
|
-
case 'Variable':
|
1592
|
-
throw createUserError(
|
1593
|
-
'Unexpected variable where a literal (static) value is required.',
|
1594
|
-
null,
|
1595
|
-
[ast, context],
|
1596
|
-
);
|
1597
|
-
default:
|
1598
|
-
(ast.kind: empty);
|
1599
|
-
throw createCompilerError(`Unknown ast kind '${ast.kind}'.`, [ast]);
|
1600
|
-
}
|
1601
|
-
}
|
1602
|
-
|
1603
|
-
/**
|
1604
|
-
* @private
|
1605
|
-
*/
|
1606
|
-
function buildArgumentDefinitions(
|
1607
|
-
variables: VariableDefinitions,
|
1608
|
-
): $ReadOnlyArray<LocalArgumentDefinition> {
|
1609
|
-
return Array.from(variables.values(), ({ast, name, defaultValue, type}) => {
|
1610
|
-
return {
|
1611
|
-
kind: 'LocalArgumentDefinition',
|
1612
|
-
loc: buildLocation(ast.loc),
|
1613
|
-
name,
|
1614
|
-
type,
|
1615
|
-
defaultValue,
|
1616
|
-
};
|
1617
|
-
});
|
1618
|
-
}
|
1619
|
-
|
1620
|
-
/**
|
1621
|
-
* @private
|
1622
|
-
*/
|
1623
|
-
function buildLocation(loc: ?ASTLocation): Location {
|
1624
|
-
if (loc == null) {
|
1625
|
-
return {kind: 'Unknown'};
|
1626
|
-
}
|
1627
|
-
return {
|
1628
|
-
kind: 'Source',
|
1629
|
-
start: loc.start,
|
1630
|
-
end: loc.end,
|
1631
|
-
source: loc.source,
|
1632
|
-
};
|
1633
|
-
}
|
1634
|
-
|
1635
|
-
/**
|
1636
|
-
* @private
|
1637
|
-
*/
|
1638
|
-
function applyConditions(
|
1639
|
-
conditions: $ReadOnlyArray<Condition>,
|
1640
|
-
selections: $ReadOnlyArray<Selection>,
|
1641
|
-
): $ReadOnlyArray<Condition | Selection> {
|
1642
|
-
let nextSelections = selections;
|
1643
|
-
conditions.forEach(condition => {
|
1644
|
-
nextSelections = [
|
1645
|
-
{
|
1646
|
-
...condition,
|
1647
|
-
selections: nextSelections,
|
1648
|
-
},
|
1649
|
-
];
|
1650
|
-
});
|
1651
|
-
return nextSelections;
|
1652
|
-
}
|
1653
|
-
|
1654
|
-
/**
|
1655
|
-
* @private
|
1656
|
-
*/
|
1657
|
-
function getName(ast): string {
|
1658
|
-
const name = ast.name?.value;
|
1659
|
-
if (typeof name !== 'string') {
|
1660
|
-
throw createCompilerError("Expected ast node to have a 'name'.", null, [
|
1661
|
-
ast,
|
1662
|
-
]);
|
1663
|
-
}
|
1664
|
-
return name;
|
1665
|
-
}
|
1666
|
-
|
1667
|
-
function getTypeName(ast: ?TypeNode): string {
|
1668
|
-
return ast ? print(ast) : 'Undefined Type Name';
|
1669
|
-
}
|
1670
|
-
|
1671
|
-
/**
|
1672
|
-
* @private
|
1673
|
-
*/
|
1674
|
-
function getFragmentType(ast: ASTDefinitionNode): TypeNode {
|
1675
|
-
if (ast.kind === 'FragmentDefinition') {
|
1676
|
-
return ast.typeCondition;
|
1677
|
-
}
|
1678
|
-
throw createCompilerError(
|
1679
|
-
'Expected ast node to be a FragmentDefinition node.',
|
1680
|
-
null,
|
1681
|
-
[ast],
|
1682
|
-
);
|
1683
|
-
}
|
1684
|
-
|
1685
|
-
function checkFragmentSpreadTypeCompatibility(
|
1686
|
-
schema: Schema,
|
1687
|
-
fragmentType: CompositeTypeID,
|
1688
|
-
parentType: TypeID,
|
1689
|
-
fragmentName: ?string,
|
1690
|
-
fragmentTypeAST: ?TypeNode | ?FragmentSpreadNode,
|
1691
|
-
parentTypeAST: ?TypeNode,
|
1692
|
-
) {
|
1693
|
-
if (
|
1694
|
-
!schema.doTypesOverlap(fragmentType, schema.assertCompositeType(parentType))
|
1695
|
-
) {
|
1696
|
-
const nodes = [];
|
1697
|
-
if (parentTypeAST) {
|
1698
|
-
nodes.push(parentTypeAST);
|
1699
|
-
}
|
1700
|
-
if (fragmentTypeAST) {
|
1701
|
-
nodes.push(fragmentTypeAST);
|
1702
|
-
}
|
1703
|
-
|
1704
|
-
const possibleConcreteTypes = schema.isAbstractType(parentType)
|
1705
|
-
? Array.from(
|
1706
|
-
schema.getPossibleTypes(schema.assertAbstractType(parentType)),
|
1707
|
-
)
|
1708
|
-
: [];
|
1709
|
-
let suggestedTypesMessage = '';
|
1710
|
-
if (possibleConcreteTypes.length !== 0) {
|
1711
|
-
suggestedTypesMessage = ` Possible concrete types include ${possibleConcreteTypes
|
1712
|
-
.sort()
|
1713
|
-
.slice(0, 3)
|
1714
|
-
.map(type => `'${schema.getTypeString(type)}'`)
|
1715
|
-
.join(', ')}, etc.`;
|
1716
|
-
}
|
1717
|
-
|
1718
|
-
throw createUserError(
|
1719
|
-
(fragmentName != null
|
1720
|
-
? `Fragment '${fragmentName}' cannot be spread here as objects of `
|
1721
|
-
: 'Fragment cannot be spread here as objects of ') +
|
1722
|
-
`type '${schema.getTypeString(parentType)}' ` +
|
1723
|
-
`can never be of type '${schema.getTypeString(fragmentType)}'.` +
|
1724
|
-
suggestedTypesMessage,
|
1725
|
-
null,
|
1726
|
-
nodes,
|
1727
|
-
);
|
1728
|
-
}
|
1729
|
-
}
|
1730
|
-
|
1731
|
-
module.exports = {parse, transform};
|