relay-compiler 9.0.0 → 10.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/bin/RelayCompilerBin.js.flow +169 -0
- package/bin/RelayCompilerMain.js.flow +515 -0
- package/bin/__fixtures__/plugin-module.js.flow +17 -0
- package/bin/relay-compiler +3862 -2505
- package/codegen/CodegenDirectory.js.flow +375 -0
- package/codegen/CodegenRunner.js.flow +432 -0
- package/codegen/CodegenTypes.js.flow +28 -0
- package/codegen/CodegenWatcher.js.flow +254 -0
- package/codegen/NormalizationCodeGenerator.js.flow +571 -0
- package/codegen/ReaderCodeGenerator.js.flow +512 -0
- package/codegen/RelayCodeGenerator.js.flow +85 -0
- package/codegen/RelayFileWriter.js.flow +367 -0
- package/codegen/SourceControl.js.flow +58 -0
- package/codegen/compileRelayArtifacts.js.flow +182 -0
- package/codegen/createPrintRequireModuleDependency.js.flow +21 -0
- package/codegen/sortObjectByKey.js.flow +25 -0
- package/codegen/writeRelayGeneratedFile.js.flow +223 -0
- package/core/ASTCache.js.flow +74 -0
- package/core/ASTConvert.js.flow +233 -0
- package/core/CompilerContext.js.flow +191 -0
- package/core/CompilerError.js.flow +250 -0
- package/core/DotGraphQLParser.js.flow +39 -0
- package/core/GraphQLCompilerProfiler.js.flow +341 -0
- package/core/GraphQLDerivedFromMetadata.js.flow +36 -0
- package/core/GraphQLWatchmanClient.js.flow +111 -0
- package/core/IR.js.flow +326 -0
- package/core/IRPrinter.js.flow +477 -0
- package/core/IRTransformer.js.flow +377 -0
- package/core/IRValidator.js.flow +260 -0
- package/core/IRVisitor.js.flow +150 -0
- package/core/JSModuleParser.js.flow +24 -0
- package/core/RelayCompilerScope.js.flow +199 -0
- package/core/RelayFindGraphQLTags.js.flow +119 -0
- package/core/RelayGraphQLEnumsGenerator.js.flow +55 -0
- package/core/RelayIRTransforms.js.flow +138 -0
- package/core/RelayParser.js.flow +1731 -0
- package/core/RelaySourceModuleParser.js.flow +135 -0
- package/core/Schema.js.flow +2037 -0
- package/core/SchemaUtils.js.flow +120 -0
- package/core/filterContextForNode.js.flow +50 -0
- package/core/getFieldDefinition.js.flow +156 -0
- package/core/getIdentifierForArgumentValue.js.flow +49 -0
- package/core/getIdentifierForSelection.js.flow +69 -0
- package/core/getLiteralArgumentValues.js.flow +32 -0
- package/core/getNormalizationOperationName.js.flow +19 -0
- package/core/inferRootArgumentDefinitions.js.flow +323 -0
- package/index.js +1 -1
- package/index.js.flow +200 -0
- package/language/RelayLanguagePluginInterface.js.flow +283 -0
- package/language/javascript/FindGraphQLTags.js.flow +137 -0
- package/language/javascript/RelayFlowBabelFactories.js.flow +176 -0
- package/language/javascript/RelayFlowGenerator.js.flow +1099 -0
- package/language/javascript/RelayFlowTypeTransformers.js.flow +184 -0
- package/language/javascript/RelayLanguagePluginJavaScript.js.flow +34 -0
- package/language/javascript/formatGeneratedModule.js.flow +65 -0
- package/lib/bin/RelayCompilerBin.js +10 -0
- package/lib/bin/RelayCompilerMain.js +127 -130
- package/lib/codegen/CodegenDirectory.js +2 -6
- package/lib/codegen/CodegenRunner.js +37 -76
- package/lib/codegen/CodegenWatcher.js +13 -21
- package/lib/codegen/NormalizationCodeGenerator.js +131 -50
- package/lib/codegen/ReaderCodeGenerator.js +116 -49
- package/lib/codegen/RelayCodeGenerator.js +17 -6
- package/lib/codegen/RelayFileWriter.js +15 -37
- package/lib/codegen/compileRelayArtifacts.js +16 -30
- package/lib/codegen/sortObjectByKey.js +43 -0
- package/lib/codegen/writeRelayGeneratedFile.js +86 -96
- package/lib/core/ASTCache.js +3 -4
- package/lib/core/CompilerContext.js +3 -4
- package/lib/core/CompilerError.js +27 -54
- package/lib/core/GraphQLCompilerProfiler.js +8 -12
- package/lib/core/GraphQLDerivedFromMetadata.js +1 -10
- package/lib/core/GraphQLWatchmanClient.js +4 -12
- package/lib/core/IRPrinter.js +16 -21
- package/lib/core/IRTransformer.js +8 -6
- package/lib/core/IRValidator.js +1 -3
- package/lib/core/RelayCompilerScope.js +4 -4
- package/lib/core/RelayGraphQLEnumsGenerator.js +12 -15
- package/lib/core/RelayIRTransforms.js +23 -13
- package/lib/core/RelayParser.js +53 -89
- package/lib/core/RelaySourceModuleParser.js +1 -3
- package/lib/core/Schema.js +106 -77
- package/lib/core/SchemaUtils.js +15 -1
- package/lib/core/getFieldDefinition.js +12 -15
- package/lib/core/getIdentifierForSelection.js +1 -1
- package/lib/core/inferRootArgumentDefinitions.js +27 -36
- package/lib/index.js +1 -3
- package/lib/language/javascript/FindGraphQLTags.js +7 -72
- package/lib/language/javascript/RelayFlowBabelFactories.js +5 -5
- package/lib/language/javascript/RelayFlowGenerator.js +131 -108
- package/lib/language/javascript/RelayFlowTypeTransformers.js +1 -3
- package/lib/reporters/ConsoleReporter.js +1 -3
- package/lib/reporters/MultiReporter.js +1 -3
- package/lib/runner/Artifacts.js +69 -170
- package/lib/runner/BufferedFilesystem.js +32 -66
- package/lib/runner/GraphQLASTNodeGroup.js +54 -120
- package/lib/runner/GraphQLNodeMap.js +14 -19
- package/lib/runner/Sources.js +70 -85
- package/lib/runner/StrictMap.js +21 -37
- package/lib/runner/getChangedNodeNames.js +30 -62
- package/lib/transforms/ApplyFragmentArgumentTransform.js +71 -31
- package/lib/transforms/ClientExtensionsTransform.js +15 -15
- package/lib/transforms/ConnectionTransform.js +26 -38
- package/lib/transforms/DeclarativeConnectionMutationTransform.js +225 -0
- package/lib/transforms/DeferStreamTransform.js +27 -17
- package/lib/transforms/DisallowTypenameOnRoot.js +55 -0
- package/lib/transforms/FieldHandleTransform.js +7 -3
- package/lib/transforms/FilterCompilerDirectivesTransform.js +29 -0
- package/lib/transforms/FlattenTransform.js +23 -19
- package/lib/transforms/GenerateIDFieldTransform.js +56 -35
- package/lib/transforms/GenerateTypeNameTransform.js +84 -10
- package/lib/transforms/InlineDataFragmentTransform.js +9 -4
- package/lib/transforms/MaskTransform.js +17 -17
- package/lib/transforms/MatchTransform.js +114 -32
- package/lib/transforms/ReactFlightComponentTransform.js +162 -0
- package/lib/transforms/RefetchableFragmentTransform.js +21 -17
- package/lib/transforms/RelayDirectiveTransform.js +8 -3
- package/lib/transforms/RequiredFieldTransform.js +380 -0
- package/lib/transforms/SkipClientExtensionsTransform.js +8 -0
- package/lib/transforms/SkipHandleFieldTransform.js +6 -2
- package/lib/transforms/SkipRedundantNodesTransform.js +9 -2
- package/lib/transforms/SkipSplitOperationTransform.js +32 -0
- package/lib/transforms/SkipUnreachableNodeTransform.js +9 -2
- package/lib/transforms/SkipUnusedVariablesTransform.js +18 -17
- package/lib/transforms/SplitModuleImportTransform.js +2 -2
- package/lib/transforms/TestOperationTransform.js +26 -20
- package/lib/transforms/ValidateGlobalVariablesTransform.js +18 -30
- package/lib/transforms/ValidateRequiredArgumentsTransform.js +12 -15
- package/lib/transforms/ValidateServerOnlyDirectivesTransform.js +16 -30
- package/lib/transforms/ValidateUnusedVariablesTransform.js +18 -30
- package/lib/transforms/query-generators/FetchableQueryGenerator.js +161 -0
- package/lib/transforms/query-generators/NodeQueryGenerator.js +22 -3
- package/lib/transforms/query-generators/QueryQueryGenerator.js +2 -1
- package/lib/transforms/query-generators/ViewerQueryGenerator.js +1 -0
- package/lib/transforms/query-generators/index.js +23 -6
- package/lib/transforms/query-generators/utils.js +17 -16
- package/lib/util/RelayCompilerCache.js +2 -4
- package/lib/util/argumentContainsVariables.js +37 -0
- package/lib/util/dedupeJSONStringify.js +15 -12
- package/lib/util/generateAbstractTypeRefinementKey.js +24 -0
- package/lib/util/getModuleName.js +1 -1
- package/lib/util/joinArgumentDefinitions.js +3 -1
- package/package.json +7 -7
- package/relay-compiler.js +4 -4
- package/relay-compiler.min.js +4 -4
- package/reporters/ConsoleReporter.js.flow +81 -0
- package/reporters/MultiReporter.js.flow +43 -0
- package/reporters/Reporter.js.flow +19 -0
- package/runner/Artifacts.js.flow +219 -0
- package/runner/BufferedFilesystem.js.flow +194 -0
- package/runner/GraphQLASTNodeGroup.js.flow +176 -0
- package/runner/GraphQLASTUtils.js.flow +26 -0
- package/runner/GraphQLNodeMap.js.flow +55 -0
- package/runner/Sources.js.flow +228 -0
- package/runner/StrictMap.js.flow +96 -0
- package/runner/compileArtifacts.js.flow +76 -0
- package/runner/extractAST.js.flow +100 -0
- package/runner/getChangedNodeNames.js.flow +48 -0
- package/runner/getSchemaInstance.js.flow +36 -0
- package/runner/types.js.flow +37 -0
- package/transforms/ApplyFragmentArgumentTransform.js.flow +526 -0
- package/transforms/ClientExtensionsTransform.js.flow +224 -0
- package/transforms/ConnectionTransform.js.flow +855 -0
- package/transforms/DeclarativeConnectionMutationTransform.js.flow +246 -0
- package/transforms/DeferStreamTransform.js.flow +265 -0
- package/transforms/DisallowIdAsAlias.js.flow +47 -0
- package/transforms/DisallowTypenameOnRoot.js.flow +45 -0
- package/transforms/FieldHandleTransform.js.flow +79 -0
- package/transforms/FilterCompilerDirectivesTransform.js.flow +33 -0
- package/transforms/FilterDirectivesTransform.js.flow +45 -0
- package/transforms/FlattenTransform.js.flow +454 -0
- package/transforms/GenerateIDFieldTransform.js.flow +152 -0
- package/transforms/GenerateTypeNameTransform.js.flow +161 -0
- package/transforms/InlineDataFragmentTransform.js.flow +125 -0
- package/transforms/InlineFragmentsTransform.js.flow +71 -0
- package/transforms/MaskTransform.js.flow +126 -0
- package/transforms/MatchTransform.js.flow +589 -0
- package/transforms/ReactFlightComponentTransform.js.flow +195 -0
- package/transforms/RefetchableFragmentTransform.js.flow +272 -0
- package/transforms/RelayDirectiveTransform.js.flow +97 -0
- package/transforms/RequiredFieldTransform.js.flow +415 -0
- package/transforms/SkipClientExtensionsTransform.js.flow +54 -0
- package/transforms/SkipHandleFieldTransform.js.flow +44 -0
- package/transforms/SkipRedundantNodesTransform.js.flow +257 -0
- package/transforms/SkipSplitOperationTransform.js.flow +37 -0
- package/transforms/SkipUnreachableNodeTransform.js.flow +149 -0
- package/transforms/SkipUnusedVariablesTransform.js.flow +59 -0
- package/transforms/SplitModuleImportTransform.js.flow +98 -0
- package/transforms/TestOperationTransform.js.flow +142 -0
- package/transforms/TransformUtils.js.flow +26 -0
- package/transforms/ValidateGlobalVariablesTransform.js.flow +81 -0
- package/transforms/ValidateRequiredArgumentsTransform.js.flow +127 -0
- package/transforms/ValidateServerOnlyDirectivesTransform.js.flow +112 -0
- package/transforms/ValidateUnusedVariablesTransform.js.flow +89 -0
- package/transforms/query-generators/FetchableQueryGenerator.js.flow +189 -0
- package/transforms/query-generators/NodeQueryGenerator.js.flow +219 -0
- package/transforms/query-generators/QueryQueryGenerator.js.flow +57 -0
- package/transforms/query-generators/ViewerQueryGenerator.js.flow +97 -0
- package/transforms/query-generators/index.js.flow +90 -0
- package/transforms/query-generators/utils.js.flow +76 -0
- package/util/CodeMarker.js.flow +79 -0
- package/util/DefaultHandleKey.js.flow +17 -0
- package/util/RelayCompilerCache.js.flow +88 -0
- package/util/Rollout.js.flow +39 -0
- package/util/TimeReporter.js.flow +79 -0
- package/util/areEqualOSS.js.flow +123 -0
- package/util/argumentContainsVariables.js.flow +38 -0
- package/util/dedupeJSONStringify.js.flow +152 -0
- package/util/generateAbstractTypeRefinementKey.js.flow +29 -0
- package/util/getDefinitionNodeHash.js.flow +25 -0
- package/util/getModuleName.js.flow +39 -0
- package/util/joinArgumentDefinitions.js.flow +105 -0
- package/util/md5.js.flow +22 -0
- package/util/murmurHash.js.flow +94 -0
- package/util/nullthrowsOSS.js.flow +25 -0
- package/util/orList.js.flow +37 -0
- package/util/partitionArray.js.flow +37 -0
@@ -0,0 +1,176 @@
|
|
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
|
+
* @format
|
8
|
+
* @flow strict-local
|
9
|
+
*/
|
10
|
+
|
11
|
+
// flowlint ambiguous-object-type:error
|
12
|
+
|
13
|
+
'use strict';
|
14
|
+
|
15
|
+
const GraphQLNodeMap = require('./GraphQLNodeMap');
|
16
|
+
|
17
|
+
const {getName} = require('./GraphQLASTUtils');
|
18
|
+
const {visit} = require('graphql');
|
19
|
+
|
20
|
+
import type {ExecutableDefinitionNode} from 'graphql';
|
21
|
+
|
22
|
+
type DependencyMap = Map<string, Array<string>>;
|
23
|
+
|
24
|
+
export type NodeGroup = {|
|
25
|
+
+nodes: GraphQLNodeMap,
|
26
|
+
+baseNames: Set<string>,
|
27
|
+
|};
|
28
|
+
|
29
|
+
function buildDependencyMap(nodes: GraphQLNodeMap): DependencyMap {
|
30
|
+
const dependencyMap: DependencyMap = new Map();
|
31
|
+
for (const node of nodes.values()) {
|
32
|
+
const name = getName(node);
|
33
|
+
if (dependencyMap.has(name)) {
|
34
|
+
throw new Error(`Duplicated definition for ${name}`);
|
35
|
+
}
|
36
|
+
dependencyMap.set(name, findIncludedFragments(node));
|
37
|
+
}
|
38
|
+
return dependencyMap;
|
39
|
+
}
|
40
|
+
|
41
|
+
function mergeMaps<T>(maps: $ReadOnlyArray<Map<string, T>>): Map<string, T> {
|
42
|
+
const result = new Map();
|
43
|
+
for (const source of maps) {
|
44
|
+
for (const [key, value] of source.entries()) {
|
45
|
+
if (result.has(key)) {
|
46
|
+
throw new Error(`Duplicate entry for '${key}'.`);
|
47
|
+
}
|
48
|
+
result.set(key, value);
|
49
|
+
}
|
50
|
+
}
|
51
|
+
return result;
|
52
|
+
}
|
53
|
+
|
54
|
+
function forFullBuild(
|
55
|
+
nodes: GraphQLNodeMap,
|
56
|
+
baseNodes: $ReadOnlyArray<GraphQLNodeMap>,
|
57
|
+
): NodeGroup {
|
58
|
+
const dependencyMap = mergeMaps(
|
59
|
+
[nodes, ...baseNodes].map(buildDependencyMap),
|
60
|
+
);
|
61
|
+
const includedNames = includeReachable(new Set(nodes.keys()), dependencyMap);
|
62
|
+
return buildResult(includedNames, nodes, mergeMaps(baseNodes));
|
63
|
+
}
|
64
|
+
|
65
|
+
function forChanges(
|
66
|
+
nodes: GraphQLNodeMap,
|
67
|
+
changedNames: Set<string>,
|
68
|
+
baseNodes: $ReadOnlyArray<GraphQLNodeMap> = [],
|
69
|
+
): NodeGroup {
|
70
|
+
const projectDependencyMap = buildDependencyMap(nodes);
|
71
|
+
const baseDependencyMap = mergeMaps(baseNodes.map(buildDependencyMap));
|
72
|
+
const dependencyMap = mergeMaps([projectDependencyMap, baseDependencyMap]);
|
73
|
+
const invertedDependencyMap = inverseDependencyMap(dependencyMap);
|
74
|
+
const baseNameToNode: Map<string, ExecutableDefinitionNode> = mergeMaps(
|
75
|
+
baseNodes,
|
76
|
+
);
|
77
|
+
|
78
|
+
// The first step of the process is to find all ancestors of changed nodes.
|
79
|
+
// And we perform this search on complete dependency map (project + base)
|
80
|
+
const directlyChangedAndAncestors = includeReachable(
|
81
|
+
changedNames,
|
82
|
+
invertedDependencyMap,
|
83
|
+
);
|
84
|
+
// Now, we need to intersect obtained set with the project nodes
|
85
|
+
const directlyChangedRelatedToProject = new Set();
|
86
|
+
for (const node of directlyChangedAndAncestors) {
|
87
|
+
if (nodes.has(node)) {
|
88
|
+
directlyChangedRelatedToProject.add(node);
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
// Finally, we need to find all descendants of project-related changed nodes
|
93
|
+
// in the complete dependency map (project + base)
|
94
|
+
const allRelated = includeReachable(
|
95
|
+
directlyChangedRelatedToProject,
|
96
|
+
dependencyMap,
|
97
|
+
);
|
98
|
+
|
99
|
+
return buildResult(allRelated, nodes, baseNameToNode);
|
100
|
+
}
|
101
|
+
|
102
|
+
function buildResult(
|
103
|
+
includedNames: Set<string>,
|
104
|
+
nameToNode: Map<string, ExecutableDefinitionNode>,
|
105
|
+
baseNameToNode: Map<string, ExecutableDefinitionNode>,
|
106
|
+
): NodeGroup {
|
107
|
+
const baseNames = new Set();
|
108
|
+
const nodes = [];
|
109
|
+
for (const name of includedNames) {
|
110
|
+
const baseNode = baseNameToNode.get(name);
|
111
|
+
if (baseNode != null) {
|
112
|
+
nodes.push(baseNode);
|
113
|
+
baseNames.add(name);
|
114
|
+
}
|
115
|
+
|
116
|
+
const node = nameToNode.get(name);
|
117
|
+
if (node != null) {
|
118
|
+
nodes.push(node);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
return {
|
122
|
+
baseNames,
|
123
|
+
nodes: GraphQLNodeMap.from(nodes),
|
124
|
+
};
|
125
|
+
}
|
126
|
+
|
127
|
+
function includeReachable(
|
128
|
+
changed: Set<string>,
|
129
|
+
deps: DependencyMap,
|
130
|
+
): Set<string> {
|
131
|
+
const toVisit = Array.from(changed);
|
132
|
+
const visited = new Set();
|
133
|
+
while (toVisit.length > 0) {
|
134
|
+
const current = toVisit.pop();
|
135
|
+
visited.add(current);
|
136
|
+
for (const dep of deps.get(current) || []) {
|
137
|
+
if (!visited.has(dep)) {
|
138
|
+
toVisit.push(dep);
|
139
|
+
}
|
140
|
+
}
|
141
|
+
}
|
142
|
+
return visited;
|
143
|
+
}
|
144
|
+
|
145
|
+
function findIncludedFragments(node: ExecutableDefinitionNode): Array<string> {
|
146
|
+
const result = [];
|
147
|
+
visit(node, {
|
148
|
+
FragmentSpread(spread) {
|
149
|
+
result.push(spread.name.value);
|
150
|
+
},
|
151
|
+
});
|
152
|
+
return result;
|
153
|
+
}
|
154
|
+
|
155
|
+
function inverseDependencyMap(map: DependencyMap): DependencyMap {
|
156
|
+
const invertedMap = new Map();
|
157
|
+
for (const [source, dests] of map.entries()) {
|
158
|
+
const inverseDest = source;
|
159
|
+
for (const dest of dests) {
|
160
|
+
const inverseSource = dest;
|
161
|
+
|
162
|
+
let inverseDests = invertedMap.get(inverseSource);
|
163
|
+
if (inverseDests == null) {
|
164
|
+
inverseDests = [];
|
165
|
+
invertedMap.set(inverseSource, inverseDests);
|
166
|
+
}
|
167
|
+
inverseDests.push(inverseDest);
|
168
|
+
}
|
169
|
+
}
|
170
|
+
return invertedMap;
|
171
|
+
}
|
172
|
+
|
173
|
+
module.exports = {
|
174
|
+
forChanges,
|
175
|
+
forFullBuild,
|
176
|
+
};
|
@@ -0,0 +1,26 @@
|
|
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
|
+
* @format
|
8
|
+
* @flow strict
|
9
|
+
*/
|
10
|
+
|
11
|
+
// flowlint ambiguous-object-type:error
|
12
|
+
|
13
|
+
'use strict';
|
14
|
+
|
15
|
+
import type {ExecutableDefinitionNode} from 'graphql';
|
16
|
+
|
17
|
+
function getName(node: ExecutableDefinitionNode): string {
|
18
|
+
if (node.name == null) {
|
19
|
+
throw new Error('All fragments and operations have to have names in Relay');
|
20
|
+
}
|
21
|
+
return node.name.value;
|
22
|
+
}
|
23
|
+
|
24
|
+
module.exports = {
|
25
|
+
getName,
|
26
|
+
};
|
@@ -0,0 +1,55 @@
|
|
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
|
+
* @format
|
8
|
+
* @flow strict-local
|
9
|
+
*/
|
10
|
+
|
11
|
+
// flowlint ambiguous-object-type:error
|
12
|
+
|
13
|
+
'use strict';
|
14
|
+
|
15
|
+
const {createUserError, createCompilerError} = require('../core/CompilerError');
|
16
|
+
const {getName} = require('./GraphQLASTUtils');
|
17
|
+
|
18
|
+
import type {ExecutableDefinitionNode} from 'graphql';
|
19
|
+
import type {Sources} from 'relay-compiler';
|
20
|
+
|
21
|
+
class GraphQLNodeMap extends Map<string, ExecutableDefinitionNode> {
|
22
|
+
static from(nodes: Iterable<ExecutableDefinitionNode>): GraphQLNodeMap {
|
23
|
+
const result = new GraphQLNodeMap();
|
24
|
+
for (const node of nodes) {
|
25
|
+
const name = getName(node);
|
26
|
+
const prevNode = result.get(name);
|
27
|
+
if (prevNode) {
|
28
|
+
throw createUserError(`Duplicate node named '${name}'`, null, [
|
29
|
+
node,
|
30
|
+
prevNode,
|
31
|
+
]);
|
32
|
+
}
|
33
|
+
result.set(name, node);
|
34
|
+
}
|
35
|
+
return result;
|
36
|
+
}
|
37
|
+
|
38
|
+
static fromSources(
|
39
|
+
sources: Sources<ExecutableDefinitionNode>,
|
40
|
+
): GraphQLNodeMap {
|
41
|
+
return GraphQLNodeMap.from(sources.nodes());
|
42
|
+
}
|
43
|
+
|
44
|
+
enforceGet(name: string): ExecutableDefinitionNode {
|
45
|
+
const node = this.get(name);
|
46
|
+
if (!node) {
|
47
|
+
throw createCompilerError(
|
48
|
+
`GraphQLNodeMap: expected to have a node named ${name}.`,
|
49
|
+
);
|
50
|
+
}
|
51
|
+
return node;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
module.exports = GraphQLNodeMap;
|
@@ -0,0 +1,228 @@
|
|
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
|
+
* @format
|
8
|
+
* @flow strict-local
|
9
|
+
* @emails oncall+relay
|
10
|
+
*/
|
11
|
+
|
12
|
+
// flowlint ambiguous-object-type:error
|
13
|
+
|
14
|
+
'use strict';
|
15
|
+
|
16
|
+
const invariant = require('invariant');
|
17
|
+
const md5 = require('../util/md5');
|
18
|
+
|
19
|
+
const {toASTRecord} = require('./extractAST');
|
20
|
+
const {Source, parse} = require('graphql');
|
21
|
+
|
22
|
+
import type {ASTRecord} from './extractAST';
|
23
|
+
import type {SavedStateCollection, WatchmanFile} from './types';
|
24
|
+
import type {ASTNode} from 'graphql';
|
25
|
+
|
26
|
+
export type GraphQLExtractor<T: ASTNode> = (
|
27
|
+
baseDir: string,
|
28
|
+
file: WatchmanFile,
|
29
|
+
) => ?{|
|
30
|
+
+nodes: $ReadOnlyArray<ASTRecord<T>>,
|
31
|
+
+sources: $ReadOnlyArray<string>,
|
32
|
+
|};
|
33
|
+
|
34
|
+
type ASTNodeWithFile<T: ASTNode> = {|
|
35
|
+
+file: string,
|
36
|
+
+ast: T,
|
37
|
+
|};
|
38
|
+
|
39
|
+
export type SourceChanges<T: ASTNode> = {|
|
40
|
+
+added: $ReadOnlyArray<ASTNodeWithFile<T>>,
|
41
|
+
+removed: $ReadOnlyArray<ASTNodeWithFile<T>>,
|
42
|
+
|};
|
43
|
+
|
44
|
+
type SourcesState = {
|
45
|
+
[filename: string]: {
|
46
|
+
nodes: {[hash: string]: ASTNode, ...},
|
47
|
+
sources: [string],
|
48
|
+
...
|
49
|
+
},
|
50
|
+
...,
|
51
|
+
};
|
52
|
+
|
53
|
+
class Sources<T: ASTNode> {
|
54
|
+
_extractFromFile: GraphQLExtractor<T>;
|
55
|
+
_state: SourcesState;
|
56
|
+
|
57
|
+
static fromSavedState({
|
58
|
+
extractFromFile,
|
59
|
+
savedState,
|
60
|
+
}: {|
|
61
|
+
+extractFromFile: GraphQLExtractor<T>,
|
62
|
+
+savedState: SavedStateCollection,
|
63
|
+
|}): Sources<T> {
|
64
|
+
const state = {};
|
65
|
+
for (const {file, sources: savedStateSources} of savedState) {
|
66
|
+
const nodes = {};
|
67
|
+
const sources = [];
|
68
|
+
for (const text of savedStateSources) {
|
69
|
+
const doc = parse(new Source(text, file));
|
70
|
+
invariant(
|
71
|
+
doc.definitions.length,
|
72
|
+
'expected not empty list of definitions',
|
73
|
+
);
|
74
|
+
const entities = doc.definitions.map(node => {
|
75
|
+
return toASTRecord(node);
|
76
|
+
});
|
77
|
+
entities.forEach(astRecord => {
|
78
|
+
nodes[md5(astRecord.text)] = astRecord.ast;
|
79
|
+
});
|
80
|
+
sources.push(text);
|
81
|
+
}
|
82
|
+
state[file] = {
|
83
|
+
nodes,
|
84
|
+
sources,
|
85
|
+
};
|
86
|
+
}
|
87
|
+
return new Sources({
|
88
|
+
extractFromFile,
|
89
|
+
state,
|
90
|
+
});
|
91
|
+
}
|
92
|
+
|
93
|
+
constructor({
|
94
|
+
extractFromFile,
|
95
|
+
state,
|
96
|
+
}: {|
|
97
|
+
extractFromFile: GraphQLExtractor<T>,
|
98
|
+
state: SourcesState,
|
99
|
+
|}) {
|
100
|
+
this._extractFromFile = extractFromFile;
|
101
|
+
this._state = {...state};
|
102
|
+
}
|
103
|
+
|
104
|
+
processChanges(
|
105
|
+
baseDir: string,
|
106
|
+
files: $ReadOnlyArray<WatchmanFile>,
|
107
|
+
): {|
|
108
|
+
+changes: SourceChanges<T>,
|
109
|
+
+sources: Sources<T>,
|
110
|
+
|} {
|
111
|
+
const added = [];
|
112
|
+
const removed = [];
|
113
|
+
const state = {...this._state};
|
114
|
+
|
115
|
+
for (const file of files) {
|
116
|
+
let newDefs;
|
117
|
+
let newSources;
|
118
|
+
try {
|
119
|
+
const extracted = this._extractFromFile(baseDir, file);
|
120
|
+
if (extracted != null) {
|
121
|
+
newDefs = extracted.nodes;
|
122
|
+
newSources = extracted.sources;
|
123
|
+
}
|
124
|
+
} catch (error) {
|
125
|
+
throw new Error(
|
126
|
+
`RelayCompiler: Sources module failed to parse ${file.name}:\n${error.message}`,
|
127
|
+
);
|
128
|
+
}
|
129
|
+
const hasEntry = state.hasOwnProperty(file.name);
|
130
|
+
const oldEntry = state[file.name]?.nodes ?? {};
|
131
|
+
|
132
|
+
// First case, we have new changes in the file
|
133
|
+
// for example changed Query or Fragment
|
134
|
+
if (newDefs != null && newDefs.length > 0) {
|
135
|
+
// We need to add all entities from the changed file to added arrays
|
136
|
+
const newEntry = {};
|
137
|
+
const newTexts = new Set();
|
138
|
+
for (const {ast, text} of newDefs) {
|
139
|
+
const hashedText = md5(text);
|
140
|
+
if (newTexts.has(hashedText)) {
|
141
|
+
let name = 'unknown';
|
142
|
+
switch (ast.kind) {
|
143
|
+
case 'FragmentDefinition':
|
144
|
+
name = ast.name.value;
|
145
|
+
break;
|
146
|
+
case 'OperationDefinition':
|
147
|
+
name = ast.name?.value ?? 'unnamed operation';
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
throw new Error(
|
151
|
+
`Duplicate definition of \`${name}\` in \`${file.name}\``,
|
152
|
+
);
|
153
|
+
}
|
154
|
+
newTexts.add(hashedText);
|
155
|
+
if (hasEntry && oldEntry[hashedText] != null) {
|
156
|
+
// Entity text did not change, so we
|
157
|
+
// don't need to change it in the state
|
158
|
+
newEntry[hashedText] = oldEntry[hashedText];
|
159
|
+
} else {
|
160
|
+
// Here we have completely new text.
|
161
|
+
// We need add it to the `added` changes
|
162
|
+
newEntry[hashedText] = ast;
|
163
|
+
added.push({file: file.name, ast});
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
// Also, we need to delete all old entities
|
168
|
+
// that are not included in the new changes
|
169
|
+
if (hasEntry) {
|
170
|
+
for (const oldHashedText of Object.keys(oldEntry)) {
|
171
|
+
const ast = oldEntry[oldHashedText];
|
172
|
+
if (!newTexts.has(oldHashedText)) {
|
173
|
+
removed.push({file: file.name, ast});
|
174
|
+
}
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
// Finally, update the state with the changes
|
179
|
+
state[file.name] = {
|
180
|
+
nodes: newEntry,
|
181
|
+
// $FlowFixMe[incompatible-type]
|
182
|
+
sources: newSources,
|
183
|
+
};
|
184
|
+
} else {
|
185
|
+
// Otherwise, file has been removed or there are no entities in the file
|
186
|
+
if (hasEntry) {
|
187
|
+
// We will put all ASTNodes from current state to removed collection
|
188
|
+
for (const oldHashedText of Object.keys(oldEntry)) {
|
189
|
+
const ast = oldEntry[oldHashedText];
|
190
|
+
removed.push({file: file.name, ast});
|
191
|
+
}
|
192
|
+
delete state[file.name];
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
return {
|
198
|
+
// $FlowFixMe[incompatible-return]
|
199
|
+
changes: {added, removed},
|
200
|
+
sources: new Sources({
|
201
|
+
extractFromFile: this._extractFromFile,
|
202
|
+
state,
|
203
|
+
}),
|
204
|
+
};
|
205
|
+
}
|
206
|
+
|
207
|
+
*nodes(): Iterable<T> {
|
208
|
+
for (const file in this._state) {
|
209
|
+
const entry = this._state[file];
|
210
|
+
for (const node of Object.values(entry.nodes)) {
|
211
|
+
yield ((node: $FlowFixMe): T);
|
212
|
+
}
|
213
|
+
}
|
214
|
+
}
|
215
|
+
|
216
|
+
serializeState(): SavedStateCollection {
|
217
|
+
const serializedState = [];
|
218
|
+
for (const file in this._state) {
|
219
|
+
serializedState.push({
|
220
|
+
file,
|
221
|
+
sources: this._state[file].sources,
|
222
|
+
});
|
223
|
+
}
|
224
|
+
return serializedState;
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
module.exports = Sources;
|
@@ -0,0 +1,96 @@
|
|
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
|
+
* @emails oncall+relay
|
10
|
+
*/
|
11
|
+
|
12
|
+
// flowlint ambiguous-object-type:error
|
13
|
+
|
14
|
+
'use strict';
|
15
|
+
|
16
|
+
const invariant = require('invariant');
|
17
|
+
|
18
|
+
export type {StrictMap};
|
19
|
+
|
20
|
+
class StrictMap<K, V> {
|
21
|
+
_map: Map<K, V>;
|
22
|
+
|
23
|
+
constructor(iterable: ?Iterable<[K, V]>): StrictMap<K, V> {
|
24
|
+
this._map = new Map<K, V>(iterable);
|
25
|
+
return this;
|
26
|
+
}
|
27
|
+
|
28
|
+
clear(): void {
|
29
|
+
this._map.clear();
|
30
|
+
}
|
31
|
+
|
32
|
+
delete(key: K): boolean {
|
33
|
+
return this._map.delete(key);
|
34
|
+
}
|
35
|
+
|
36
|
+
entries(): Iterator<[K, V]> {
|
37
|
+
return this._map.entries();
|
38
|
+
}
|
39
|
+
|
40
|
+
forEach(
|
41
|
+
callbackfn: (value: V, index: K, map: Map<K, V>) => mixed,
|
42
|
+
thisArg?: mixed,
|
43
|
+
): void {
|
44
|
+
this._map.forEach(callbackfn, thisArg);
|
45
|
+
}
|
46
|
+
|
47
|
+
map<V2>(
|
48
|
+
f: (value: V, index: K, map: StrictMap<K, V>) => V2,
|
49
|
+
): StrictMap<K, V2> {
|
50
|
+
const result = new StrictMap();
|
51
|
+
for (const [key, val] of this._map) {
|
52
|
+
result.set(key, f(val, key, this));
|
53
|
+
}
|
54
|
+
return result;
|
55
|
+
}
|
56
|
+
|
57
|
+
async asyncMap<V2>(
|
58
|
+
f: (value: V, index: K, map: StrictMap<K, V>) => Promise<V2>,
|
59
|
+
): Promise<StrictMap<K, V2>> {
|
60
|
+
const entryPromises: Array<Promise<[K, V2]>> = [];
|
61
|
+
for (const [key, val] of this._map) {
|
62
|
+
entryPromises.push(f(val, key, this).then(resultVal => [key, resultVal]));
|
63
|
+
}
|
64
|
+
const entries = await Promise.all(entryPromises);
|
65
|
+
return new StrictMap(entries);
|
66
|
+
}
|
67
|
+
|
68
|
+
get(key: K): V {
|
69
|
+
invariant(
|
70
|
+
this.has(key),
|
71
|
+
'StrictMap: trying to read non-existent key `%s`.',
|
72
|
+
String(key),
|
73
|
+
);
|
74
|
+
// $FlowFixMe[incompatible-return] - we checked the key exists
|
75
|
+
return this._map.get(key);
|
76
|
+
}
|
77
|
+
|
78
|
+
has(key: K): boolean {
|
79
|
+
return this._map.has(key);
|
80
|
+
}
|
81
|
+
|
82
|
+
keys(): Iterator<K> {
|
83
|
+
return this._map.keys();
|
84
|
+
}
|
85
|
+
|
86
|
+
set(key: K, value: V): StrictMap<K, V> {
|
87
|
+
this._map.set(key, value);
|
88
|
+
return this;
|
89
|
+
}
|
90
|
+
|
91
|
+
values(): Iterator<V> {
|
92
|
+
return this._map.values();
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
module.exports = StrictMap;
|
@@ -0,0 +1,76 @@
|
|
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-local
|
8
|
+
* @format
|
9
|
+
*/
|
10
|
+
|
11
|
+
// flowlint ambiguous-object-type:error
|
12
|
+
|
13
|
+
'use strict';
|
14
|
+
|
15
|
+
const ASTConvert = require('../core/ASTConvert');
|
16
|
+
const CompilerContext = require('../core/CompilerContext');
|
17
|
+
const RelayParser = require('../core/RelayParser');
|
18
|
+
|
19
|
+
const compileRelayArtifacts = require('../codegen/compileRelayArtifacts');
|
20
|
+
|
21
|
+
import type {ExecutableDefinitionNode, ValidationContext} from 'graphql';
|
22
|
+
import type {
|
23
|
+
GeneratedDefinition,
|
24
|
+
RelayCompilerTransforms,
|
25
|
+
Reporter,
|
26
|
+
Schema,
|
27
|
+
TypeGenerator,
|
28
|
+
} from 'relay-compiler';
|
29
|
+
import type {GeneratedNode} from 'relay-runtime';
|
30
|
+
|
31
|
+
export type ValidationRule = (context: ValidationContext) => $FlowFixMe;
|
32
|
+
|
33
|
+
function compileArtifacts({
|
34
|
+
schema,
|
35
|
+
compilerTransforms,
|
36
|
+
definitions: inputDefinitions,
|
37
|
+
reporter,
|
38
|
+
typeGenerator,
|
39
|
+
}: {|
|
40
|
+
schema: Schema,
|
41
|
+
compilerTransforms: RelayCompilerTransforms,
|
42
|
+
definitions: $ReadOnlyArray<ExecutableDefinitionNode>,
|
43
|
+
reporter: Reporter,
|
44
|
+
typeGenerator: TypeGenerator,
|
45
|
+
|}): {|
|
46
|
+
artifacts: $ReadOnlyArray<[GeneratedDefinition, GeneratedNode]>,
|
47
|
+
transformedTypeContext: CompilerContext,
|
48
|
+
|} {
|
49
|
+
const definitions = ASTConvert.convertASTDocuments(
|
50
|
+
schema,
|
51
|
+
[
|
52
|
+
{
|
53
|
+
kind: 'Document',
|
54
|
+
definitions: inputDefinitions,
|
55
|
+
},
|
56
|
+
],
|
57
|
+
RelayParser.transform,
|
58
|
+
);
|
59
|
+
|
60
|
+
const compilerContext = new CompilerContext(schema).addAll(definitions);
|
61
|
+
const transformedTypeContext = compilerContext.applyTransforms(
|
62
|
+
typeGenerator.transforms,
|
63
|
+
reporter,
|
64
|
+
);
|
65
|
+
|
66
|
+
return {
|
67
|
+
transformedTypeContext,
|
68
|
+
artifacts: compileRelayArtifacts(
|
69
|
+
compilerContext,
|
70
|
+
compilerTransforms,
|
71
|
+
reporter,
|
72
|
+
),
|
73
|
+
};
|
74
|
+
}
|
75
|
+
|
76
|
+
module.exports = compileArtifacts;
|