relay-compiler 7.0.0 → 9.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (242) hide show
  1. package/bin/RelayCompilerBin.js.flow +169 -0
  2. package/bin/RelayCompilerMain.js.flow +508 -0
  3. package/bin/__fixtures__/plugin-module.js.flow +17 -0
  4. package/bin/relay-compiler +8554 -8142
  5. package/codegen/CodegenDirectory.js.flow +375 -0
  6. package/codegen/CodegenRunner.js.flow +431 -0
  7. package/codegen/CodegenTypes.js.flow +28 -0
  8. package/codegen/CodegenWatcher.js.flow +254 -0
  9. package/codegen/NormalizationCodeGenerator.js.flow +499 -0
  10. package/codegen/ReaderCodeGenerator.js.flow +453 -0
  11. package/codegen/RelayCodeGenerator.js.flow +76 -0
  12. package/codegen/RelayFileWriter.js.flow +366 -0
  13. package/codegen/SourceControl.js.flow +58 -0
  14. package/codegen/compileRelayArtifacts.js.flow +182 -0
  15. package/codegen/createPrintRequireModuleDependency.js.flow +21 -0
  16. package/codegen/writeRelayGeneratedFile.js.flow +194 -0
  17. package/core/ASTCache.js.flow +73 -0
  18. package/core/ASTConvert.js.flow +233 -0
  19. package/core/CompilerContext.js.flow +190 -0
  20. package/core/CompilerError.js.flow +250 -0
  21. package/core/DotGraphQLParser.js.flow +39 -0
  22. package/core/GraphQLCompilerProfiler.js.flow +341 -0
  23. package/core/GraphQLDerivedFromMetadata.js.flow +48 -0
  24. package/core/GraphQLWatchmanClient.js.flow +111 -0
  25. package/core/IR.js.flow +329 -0
  26. package/core/IRPrinter.js.flow +488 -0
  27. package/core/IRTransformer.js.flow +377 -0
  28. package/core/IRValidator.js.flow +260 -0
  29. package/core/IRVisitor.js.flow +150 -0
  30. package/core/JSModuleParser.js.flow +24 -0
  31. package/core/RelayCompilerScope.js.flow +199 -0
  32. package/core/RelayFindGraphQLTags.js.flow +119 -0
  33. package/core/RelayGraphQLEnumsGenerator.js.flow +55 -0
  34. package/core/RelayIRTransforms.js.flow +130 -0
  35. package/core/RelayParser.js.flow +1759 -0
  36. package/core/RelaySourceModuleParser.js.flow +135 -0
  37. package/core/Schema.js.flow +1985 -0
  38. package/core/SchemaUtils.js.flow +109 -0
  39. package/core/filterContextForNode.js.flow +50 -0
  40. package/core/getFieldDefinition.js.flow +156 -0
  41. package/core/getIdentifierForArgumentValue.js.flow +49 -0
  42. package/core/getIdentifierForSelection.js.flow +69 -0
  43. package/core/getLiteralArgumentValues.js.flow +32 -0
  44. package/core/getNormalizationOperationName.js.flow +19 -0
  45. package/core/inferRootArgumentDefinitions.js.flow +323 -0
  46. package/index.js +1 -1
  47. package/index.js.flow +202 -0
  48. package/language/RelayLanguagePluginInterface.js.flow +283 -0
  49. package/language/javascript/FindGraphQLTags.js.flow +233 -0
  50. package/language/javascript/RelayFlowBabelFactories.js.flow +180 -0
  51. package/language/javascript/RelayFlowGenerator.js.flow +1040 -0
  52. package/language/javascript/RelayFlowTypeTransformers.js.flow +184 -0
  53. package/language/javascript/RelayLanguagePluginJavaScript.js.flow +34 -0
  54. package/language/javascript/formatGeneratedModule.js.flow +65 -0
  55. package/lib/bin/RelayCompilerBin.js +25 -7
  56. package/lib/bin/RelayCompilerMain.js +134 -125
  57. package/lib/bin/__fixtures__/plugin-module.js +1 -0
  58. package/lib/codegen/CodegenDirectory.js +14 -8
  59. package/lib/codegen/CodegenRunner.js +35 -75
  60. package/lib/codegen/CodegenTypes.js +1 -0
  61. package/lib/codegen/CodegenWatcher.js +14 -21
  62. package/lib/codegen/NormalizationCodeGenerator.js +80 -127
  63. package/lib/codegen/ReaderCodeGenerator.js +85 -111
  64. package/lib/codegen/RelayCodeGenerator.js +9 -6
  65. package/lib/codegen/RelayFileWriter.js +22 -41
  66. package/lib/codegen/SourceControl.js +1 -0
  67. package/lib/codegen/compileRelayArtifacts.js +18 -31
  68. package/lib/codegen/createPrintRequireModuleDependency.js +1 -0
  69. package/lib/codegen/writeRelayGeneratedFile.js +62 -90
  70. package/lib/core/ASTCache.js +4 -4
  71. package/lib/core/ASTConvert.js +1 -0
  72. package/lib/core/{GraphQLCompilerContext.js → CompilerContext.js} +10 -11
  73. package/lib/core/{RelayCompilerError.js → CompilerError.js} +29 -55
  74. package/lib/core/DotGraphQLParser.js +1 -0
  75. package/lib/core/GraphQLCompilerProfiler.js +9 -12
  76. package/lib/core/GraphQLDerivedFromMetadata.js +1 -0
  77. package/lib/core/GraphQLWatchmanClient.js +5 -12
  78. package/lib/core/{GraphQLIR.js → IR.js} +1 -0
  79. package/lib/core/{GraphQLIRPrinter.js → IRPrinter.js} +39 -17
  80. package/lib/core/{GraphQLIRTransformer.js → IRTransformer.js} +21 -16
  81. package/lib/core/{GraphQLIRValidator.js → IRValidator.js} +18 -10
  82. package/lib/core/{GraphQLIRVisitor.js → IRVisitor.js} +1 -2
  83. package/lib/core/JSModuleParser.js +18 -0
  84. package/lib/core/RelayCompilerScope.js +6 -5
  85. package/lib/core/RelayFindGraphQLTags.js +1 -0
  86. package/lib/core/RelayGraphQLEnumsGenerator.js +26 -12
  87. package/lib/core/RelayIRTransforms.js +12 -9
  88. package/lib/core/RelayParser.js +113 -75
  89. package/lib/core/RelaySourceModuleParser.js +4 -3
  90. package/lib/core/Schema.js +808 -317
  91. package/lib/core/SchemaUtils.js +1 -0
  92. package/lib/core/filterContextForNode.js +5 -4
  93. package/lib/core/getFieldDefinition.js +14 -16
  94. package/lib/core/getIdentifierForArgumentValue.js +18 -0
  95. package/lib/core/getIdentifierForSelection.js +4 -5
  96. package/lib/core/getLiteralArgumentValues.js +1 -0
  97. package/lib/core/getNormalizationOperationName.js +1 -0
  98. package/lib/core/inferRootArgumentDefinitions.js +79 -99
  99. package/lib/index.js +69 -19
  100. package/lib/language/RelayLanguagePluginInterface.js +1 -0
  101. package/lib/language/javascript/FindGraphQLTags.js +1 -0
  102. package/lib/language/javascript/RelayFlowBabelFactories.js +15 -0
  103. package/lib/language/javascript/RelayFlowGenerator.js +94 -173
  104. package/lib/language/javascript/RelayFlowTypeTransformers.js +2 -3
  105. package/lib/language/javascript/RelayLanguagePluginJavaScript.js +7 -4
  106. package/lib/language/javascript/formatGeneratedModule.js +14 -4
  107. package/lib/reporters/ConsoleReporter.js +2 -3
  108. package/lib/reporters/MultiReporter.js +2 -3
  109. package/lib/reporters/Reporter.js +1 -0
  110. package/lib/runner/Artifacts.js +327 -0
  111. package/lib/runner/BufferedFilesystem.js +265 -0
  112. package/lib/runner/GraphQLASTNodeGroup.js +260 -0
  113. package/lib/runner/GraphQLASTUtils.js +23 -0
  114. package/lib/runner/GraphQLNodeMap.js +85 -0
  115. package/lib/runner/Sources.js +266 -0
  116. package/lib/runner/StrictMap.js +136 -0
  117. package/lib/runner/compileArtifacts.js +39 -0
  118. package/lib/runner/extractAST.js +77 -0
  119. package/lib/runner/getChangedNodeNames.js +84 -0
  120. package/lib/runner/getSchemaInstance.js +30 -0
  121. package/lib/runner/types.js +12 -0
  122. package/lib/transforms/ApplyFragmentArgumentTransform.js +49 -55
  123. package/lib/transforms/ClientExtensionsTransform.js +11 -17
  124. package/lib/transforms/ConnectionTransform.js +35 -28
  125. package/lib/transforms/DeferStreamTransform.js +26 -74
  126. package/lib/transforms/DisallowIdAsAlias.js +5 -4
  127. package/lib/transforms/DisallowTypenameOnRoot.js +55 -0
  128. package/lib/transforms/FieldHandleTransform.js +8 -3
  129. package/lib/transforms/FilterDirectivesTransform.js +4 -3
  130. package/lib/transforms/FlattenTransform.js +23 -47
  131. package/lib/transforms/GenerateIDFieldTransform.js +9 -4
  132. package/lib/transforms/GenerateTypeNameTransform.js +8 -3
  133. package/lib/transforms/InlineDataFragmentTransform.js +11 -6
  134. package/lib/transforms/InlineFragmentsTransform.js +3 -2
  135. package/lib/transforms/MaskTransform.js +20 -19
  136. package/lib/transforms/MatchTransform.js +113 -34
  137. package/lib/transforms/RefetchableFragmentTransform.js +25 -41
  138. package/lib/transforms/RelayDirectiveTransform.js +13 -4
  139. package/lib/transforms/SkipClientExtensionsTransform.js +11 -2
  140. package/lib/transforms/SkipHandleFieldTransform.js +8 -3
  141. package/lib/transforms/SkipRedundantNodesTransform.js +9 -6
  142. package/lib/transforms/SkipSplitOperationTransform.js +32 -0
  143. package/lib/transforms/SkipUnreachableNodeTransform.js +12 -12
  144. package/lib/transforms/SkipUnusedVariablesTransform.js +19 -17
  145. package/lib/transforms/SplitModuleImportTransform.js +4 -3
  146. package/lib/transforms/TestOperationTransform.js +9 -6
  147. package/lib/transforms/TransformUtils.js +1 -0
  148. package/lib/transforms/ValidateGlobalVariablesTransform.js +20 -31
  149. package/lib/transforms/ValidateRequiredArgumentsTransform.js +17 -20
  150. package/lib/transforms/ValidateServerOnlyDirectivesTransform.js +20 -33
  151. package/lib/transforms/ValidateUnusedVariablesTransform.js +20 -31
  152. package/lib/transforms/query-generators/FetchableQueryGenerator.js +161 -0
  153. package/lib/transforms/query-generators/NodeQueryGenerator.js +9 -3
  154. package/lib/transforms/query-generators/QueryQueryGenerator.js +2 -0
  155. package/lib/transforms/query-generators/ViewerQueryGenerator.js +6 -3
  156. package/lib/transforms/query-generators/index.js +25 -7
  157. package/lib/transforms/query-generators/utils.js +13 -15
  158. package/lib/util/CodeMarker.js +1 -0
  159. package/lib/util/DefaultHandleKey.js +1 -0
  160. package/lib/util/RelayCompilerCache.js +2 -3
  161. package/lib/util/Rollout.js +1 -0
  162. package/lib/util/TimeReporter.js +83 -0
  163. package/lib/util/areEqualOSS.js +1 -0
  164. package/lib/util/dedupeJSONStringify.js +16 -12
  165. package/lib/util/getDefinitionNodeHash.js +22 -0
  166. package/lib/util/getModuleName.js +4 -5
  167. package/lib/util/joinArgumentDefinitions.js +2 -1
  168. package/lib/util/md5.js +17 -0
  169. package/lib/util/murmurHash.js +1 -0
  170. package/lib/util/nullthrowsOSS.js +1 -0
  171. package/lib/util/orList.js +2 -1
  172. package/lib/util/partitionArray.js +1 -0
  173. package/package.json +4 -4
  174. package/relay-compiler.js +4 -4
  175. package/relay-compiler.min.js +4 -4
  176. package/reporters/ConsoleReporter.js.flow +81 -0
  177. package/reporters/MultiReporter.js.flow +43 -0
  178. package/reporters/Reporter.js.flow +19 -0
  179. package/runner/Artifacts.js.flow +219 -0
  180. package/runner/BufferedFilesystem.js.flow +194 -0
  181. package/runner/GraphQLASTNodeGroup.js.flow +176 -0
  182. package/runner/GraphQLASTUtils.js.flow +26 -0
  183. package/runner/GraphQLNodeMap.js.flow +55 -0
  184. package/runner/Sources.js.flow +218 -0
  185. package/runner/StrictMap.js.flow +96 -0
  186. package/runner/compileArtifacts.js.flow +76 -0
  187. package/runner/extractAST.js.flow +100 -0
  188. package/runner/getChangedNodeNames.js.flow +48 -0
  189. package/runner/getSchemaInstance.js.flow +36 -0
  190. package/runner/types.js.flow +37 -0
  191. package/transforms/ApplyFragmentArgumentTransform.js.flow +474 -0
  192. package/transforms/ClientExtensionsTransform.js.flow +220 -0
  193. package/transforms/ConnectionTransform.js.flow +869 -0
  194. package/transforms/DeferStreamTransform.js.flow +258 -0
  195. package/transforms/DisallowIdAsAlias.js.flow +47 -0
  196. package/transforms/DisallowTypenameOnRoot.js.flow +45 -0
  197. package/transforms/FieldHandleTransform.js.flow +80 -0
  198. package/transforms/FilterDirectivesTransform.js.flow +45 -0
  199. package/transforms/FlattenTransform.js.flow +456 -0
  200. package/transforms/GenerateIDFieldTransform.js.flow +134 -0
  201. package/transforms/GenerateTypeNameTransform.js.flow +81 -0
  202. package/transforms/InlineDataFragmentTransform.js.flow +124 -0
  203. package/transforms/InlineFragmentsTransform.js.flow +71 -0
  204. package/transforms/MaskTransform.js.flow +126 -0
  205. package/transforms/MatchTransform.js.flow +583 -0
  206. package/transforms/RefetchableFragmentTransform.js.flow +272 -0
  207. package/transforms/RelayDirectiveTransform.js.flow +99 -0
  208. package/transforms/SkipClientExtensionsTransform.js.flow +54 -0
  209. package/transforms/SkipHandleFieldTransform.js.flow +44 -0
  210. package/transforms/SkipRedundantNodesTransform.js.flow +253 -0
  211. package/transforms/SkipSplitOperationTransform.js.flow +37 -0
  212. package/transforms/SkipUnreachableNodeTransform.js.flow +149 -0
  213. package/transforms/SkipUnusedVariablesTransform.js.flow +59 -0
  214. package/transforms/SplitModuleImportTransform.js.flow +98 -0
  215. package/transforms/TestOperationTransform.js.flow +138 -0
  216. package/transforms/TransformUtils.js.flow +26 -0
  217. package/transforms/ValidateGlobalVariablesTransform.js.flow +81 -0
  218. package/transforms/ValidateRequiredArgumentsTransform.js.flow +127 -0
  219. package/transforms/ValidateServerOnlyDirectivesTransform.js.flow +112 -0
  220. package/transforms/ValidateUnusedVariablesTransform.js.flow +89 -0
  221. package/transforms/query-generators/FetchableQueryGenerator.js.flow +190 -0
  222. package/transforms/query-generators/NodeQueryGenerator.js.flow +206 -0
  223. package/transforms/query-generators/QueryQueryGenerator.js.flow +57 -0
  224. package/transforms/query-generators/ViewerQueryGenerator.js.flow +97 -0
  225. package/transforms/query-generators/index.js.flow +90 -0
  226. package/transforms/query-generators/utils.js.flow +72 -0
  227. package/util/CodeMarker.js.flow +79 -0
  228. package/util/DefaultHandleKey.js.flow +17 -0
  229. package/util/RelayCompilerCache.js.flow +88 -0
  230. package/util/Rollout.js.flow +39 -0
  231. package/util/TimeReporter.js.flow +79 -0
  232. package/util/areEqualOSS.js.flow +123 -0
  233. package/util/dedupeJSONStringify.js.flow +152 -0
  234. package/util/getDefinitionNodeHash.js.flow +25 -0
  235. package/util/getModuleName.js.flow +39 -0
  236. package/util/joinArgumentDefinitions.js.flow +99 -0
  237. package/util/md5.js.flow +22 -0
  238. package/util/murmurHash.js.flow +94 -0
  239. package/util/nullthrowsOSS.js.flow +25 -0
  240. package/util/orList.js.flow +37 -0
  241. package/util/partitionArray.js.flow +37 -0
  242. package/lib/transforms/ConnectionFieldTransform.js +0 -275
@@ -0,0 +1,190 @@
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 SchemaUtils = require('../../core/SchemaUtils');
16
+
17
+ const {createUserError} = require('../../core/CompilerError');
18
+ const {
19
+ buildFragmentSpread,
20
+ buildOperationArgumentDefinitions,
21
+ } = require('./utils');
22
+
23
+ import type {Fragment} from '../../core/IR';
24
+ import type {Schema} from '../../core/Schema';
25
+ import type {QueryGenerator, RefetchRoot} from '.';
26
+
27
+ function buildRefetchOperation(
28
+ schema: Schema,
29
+ fragment: Fragment,
30
+ queryName: string,
31
+ ): ?RefetchRoot {
32
+ let fetchableIdentifierField = null;
33
+ if (schema.isObject(fragment.type)) {
34
+ const objectType = schema.assertObjectType(fragment.type);
35
+ fetchableIdentifierField = schema.getFetchableFieldName(objectType);
36
+ }
37
+ if (fetchableIdentifierField == null) {
38
+ return null;
39
+ }
40
+ const identifierField = schema.getFieldConfig(
41
+ schema.expectField(fragment.type, fetchableIdentifierField),
42
+ );
43
+ if (!schema.isId(schema.getRawType(identifierField.type))) {
44
+ const typeName = schema.getTypeString(fragment.type);
45
+ throw createUserError(
46
+ `Invalid use of @refetchable on fragment '${fragment.name}', the type ` +
47
+ `'${typeName}' is @fetchable but the identifying field '${fetchableIdentifierField}' ` +
48
+ "does not have type 'ID'.",
49
+ [fragment.loc],
50
+ );
51
+ }
52
+
53
+ const queryType = schema.expectQueryType();
54
+ const fetchFieldName = `fetch__${schema.getTypeString(fragment.type)}`;
55
+ const fetchField = schema.getFieldConfig(
56
+ schema.expectField(queryType, fetchFieldName),
57
+ );
58
+ if (
59
+ !(
60
+ fetchField != null &&
61
+ schema.isObject(fetchField.type) &&
62
+ schema.areEqualTypes(fetchField.type, fragment.type) &&
63
+ fetchField.args.length === 1 &&
64
+ schema.areEqualTypes(
65
+ schema.getNullableType(fetchField.args[0].type),
66
+ schema.expectIdType(),
67
+ )
68
+ )
69
+ ) {
70
+ const typeName = schema.getTypeString(fragment.type);
71
+ throw createUserError(
72
+ `Invalid use of @refetchable on fragment '${fragment.name}', the type ` +
73
+ `'${typeName}' is @fetchable but there is no corresponding '${fetchFieldName}'` +
74
+ `field or it is invalid (expected '${fetchFieldName}(id: ID!): ${typeName}').`,
75
+ [fragment.loc],
76
+ );
77
+ }
78
+
79
+ // name and type of the node(_: ID) field parameter
80
+ const idArgName = fetchField.args[0].name;
81
+ const idArgType = fetchField.args[0].type;
82
+ // name and type of the query variable
83
+ const idVariableType = SchemaUtils.getNonNullIdInput(schema);
84
+ const idVariableName = 'id';
85
+
86
+ const argumentDefinitions = buildOperationArgumentDefinitions(
87
+ fragment.argumentDefinitions,
88
+ );
89
+ const idArgument = argumentDefinitions.find(
90
+ argDef => argDef.name === idVariableName,
91
+ );
92
+ if (idArgument != null) {
93
+ throw createUserError(
94
+ `Invalid use of @refetchable on fragment \`${fragment.name}\`, this ` +
95
+ 'fragment already has an `$id` variable in scope.',
96
+ [idArgument.loc],
97
+ );
98
+ }
99
+ const argumentDefinitionsWithId = [
100
+ ...argumentDefinitions,
101
+ {
102
+ defaultValue: null,
103
+ kind: 'LocalArgumentDefinition',
104
+ loc: {kind: 'Derived', source: fragment.loc},
105
+ name: idVariableName,
106
+ type: idVariableType,
107
+ },
108
+ ];
109
+ return {
110
+ identifierField: fetchableIdentifierField,
111
+ path: [fetchFieldName],
112
+ node: {
113
+ argumentDefinitions: argumentDefinitionsWithId,
114
+ directives: [],
115
+ kind: 'Root',
116
+ loc: {kind: 'Derived', source: fragment.loc},
117
+ metadata: null,
118
+ name: queryName,
119
+ operation: 'query',
120
+ selections: [
121
+ {
122
+ alias: fetchFieldName,
123
+ args: [
124
+ {
125
+ kind: 'Argument',
126
+ loc: {kind: 'Derived', source: fragment.loc},
127
+ name: idArgName,
128
+ type: schema.assertInputType(idArgType),
129
+ value: {
130
+ kind: 'Variable',
131
+ loc: {kind: 'Derived', source: fragment.loc},
132
+ variableName: idVariableName,
133
+ type: idVariableType,
134
+ },
135
+ },
136
+ ],
137
+ connection: false,
138
+ directives: [],
139
+ handles: null,
140
+ kind: 'LinkedField',
141
+ loc: {kind: 'Derived', source: fragment.loc},
142
+ metadata: null,
143
+ name: fetchFieldName,
144
+ selections: [buildFragmentSpread(fragment)],
145
+ type: fragment.type,
146
+ },
147
+ ],
148
+ type: queryType,
149
+ },
150
+ transformedFragment: enforceIDField(
151
+ schema,
152
+ fragment,
153
+ fetchableIdentifierField,
154
+ ),
155
+ };
156
+ }
157
+
158
+ function enforceIDField(
159
+ schema: Schema,
160
+ fragment: Fragment,
161
+ fetchableIdentifierField: string,
162
+ ): Fragment {
163
+ const idSelection = fragment.selections.find(
164
+ selection =>
165
+ selection.kind === 'ScalarField' &&
166
+ selection.name === fetchableIdentifierField &&
167
+ selection.alias === fetchableIdentifierField &&
168
+ schema.areEqualTypes(
169
+ schema.getNullableType(selection.type),
170
+ schema.expectIdType(),
171
+ ),
172
+ );
173
+ if (idSelection) {
174
+ return fragment;
175
+ }
176
+ const idField = SchemaUtils.generateIDField(schema.expectIdType());
177
+ // idField is uniquely owned here, safe to mutate
178
+ (idField: $FlowFixMe).alias = fetchableIdentifierField;
179
+ // idField is uniquely owned here, safe to mutate
180
+ (idField: $FlowFixMe).name = fetchableIdentifierField;
181
+ return {
182
+ ...fragment,
183
+ selections: [...fragment.selections, idField],
184
+ };
185
+ }
186
+
187
+ module.exports = ({
188
+ description: '@fetchable types',
189
+ buildRefetchOperation,
190
+ }: QueryGenerator);
@@ -0,0 +1,206 @@
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 SchemaUtils = require('../../core/SchemaUtils');
16
+
17
+ const {createUserError} = require('../../core/CompilerError');
18
+ const {
19
+ buildFragmentSpread,
20
+ buildOperationArgumentDefinitions,
21
+ } = require('./utils');
22
+
23
+ import type {Fragment} from '../../core/IR';
24
+ import type {Schema} from '../../core/Schema';
25
+ import type {QueryGenerator, RefetchRoot} from '.';
26
+
27
+ const NODE_TYPE_NAME = 'Node';
28
+ const NODE_FIELD_NAME = 'node';
29
+
30
+ function buildRefetchOperation(
31
+ schema: Schema,
32
+ fragment: Fragment,
33
+ queryName: string,
34
+ ): ?RefetchRoot {
35
+ const eligible =
36
+ schema.getTypeString(fragment.type) === NODE_TYPE_NAME ||
37
+ (schema.isObject(fragment.type) &&
38
+ schema
39
+ .getInterfaces(schema.assertCompositeType(fragment.type))
40
+ .some(interfaceType =>
41
+ schema.areEqualTypes(
42
+ interfaceType,
43
+ schema.expectTypeFromString(NODE_TYPE_NAME),
44
+ ),
45
+ )) ||
46
+ (schema.isAbstractType(fragment.type) &&
47
+ Array.from(
48
+ schema.getPossibleTypes(schema.assertAbstractType(fragment.type)),
49
+ ).every(possibleType =>
50
+ schema.implementsInterface(
51
+ schema.assertCompositeType(possibleType),
52
+ schema.assertInterfaceType(
53
+ schema.expectTypeFromString(NODE_TYPE_NAME),
54
+ ),
55
+ ),
56
+ ));
57
+ if (!eligible) {
58
+ return null;
59
+ }
60
+
61
+ const queryType = schema.expectQueryType();
62
+ const nodeType = schema.getTypeFromString(NODE_TYPE_NAME);
63
+ const nodeField = schema.getFieldConfig(
64
+ schema.expectField(queryType, NODE_FIELD_NAME),
65
+ );
66
+ if (
67
+ !(
68
+ nodeType &&
69
+ schema.isInterface(nodeType) &&
70
+ schema.isInterface(nodeField.type) &&
71
+ schema.areEqualTypes(nodeField.type, nodeType) &&
72
+ nodeField.args.length === 1 &&
73
+ schema.areEqualTypes(
74
+ schema.getNullableType(nodeField.args[0].type),
75
+ schema.expectIdType(),
76
+ ) &&
77
+ // the fragment must be on Node or on a type that implements Node
78
+ ((schema.isObject(fragment.type) &&
79
+ schema
80
+ .getInterfaces(schema.assertCompositeType(fragment.type))
81
+ .some(interfaceType =>
82
+ schema.areEqualTypes(interfaceType, nodeType),
83
+ )) ||
84
+ (schema.isAbstractType(fragment.type) &&
85
+ Array.from(
86
+ schema.getPossibleTypes(schema.assertAbstractType(fragment.type)),
87
+ ).every(possibleType =>
88
+ schema
89
+ .getInterfaces(schema.assertCompositeType(possibleType))
90
+ .some(interfaceType =>
91
+ schema.areEqualTypes(interfaceType, nodeType),
92
+ ),
93
+ )))
94
+ )
95
+ ) {
96
+ throw createUserError(
97
+ `Invalid use of @refetchable on fragment '${fragment.name}', check ` +
98
+ 'that your schema defines a `Node { id: ID }` interface and has a ' +
99
+ '`node(id: ID): Node` field on the query type (the id argument may ' +
100
+ 'also be non-null).',
101
+ [fragment.loc],
102
+ );
103
+ }
104
+
105
+ // name and type of the node(_: ID) field parameter
106
+ const idArgName = nodeField.args[0].name;
107
+ const idArgType = nodeField.args[0].type;
108
+ // name and type of the query variable
109
+ const idVariableType = SchemaUtils.getNonNullIdInput(schema);
110
+ const idVariableName = 'id';
111
+
112
+ const argumentDefinitions = buildOperationArgumentDefinitions(
113
+ fragment.argumentDefinitions,
114
+ );
115
+ const idArgument = argumentDefinitions.find(
116
+ argDef => argDef.name === idVariableName,
117
+ );
118
+ if (idArgument != null) {
119
+ throw createUserError(
120
+ `Invalid use of @refetchable on fragment \`${fragment.name}\`, this ` +
121
+ 'fragment already has an `$id` variable in scope.',
122
+ [idArgument.loc],
123
+ );
124
+ }
125
+ const argumentDefinitionsWithId = [
126
+ ...argumentDefinitions,
127
+ {
128
+ defaultValue: null,
129
+ kind: 'LocalArgumentDefinition',
130
+ loc: {kind: 'Derived', source: fragment.loc},
131
+ name: idVariableName,
132
+ type: idVariableType,
133
+ },
134
+ ];
135
+ return {
136
+ identifierField: 'id',
137
+ path: [NODE_FIELD_NAME],
138
+ node: {
139
+ argumentDefinitions: argumentDefinitionsWithId,
140
+ directives: [],
141
+ kind: 'Root',
142
+ loc: {kind: 'Derived', source: fragment.loc},
143
+ metadata: null,
144
+ name: queryName,
145
+ operation: 'query',
146
+ selections: [
147
+ {
148
+ alias: NODE_FIELD_NAME,
149
+ args: [
150
+ {
151
+ kind: 'Argument',
152
+ loc: {kind: 'Derived', source: fragment.loc},
153
+ name: idArgName,
154
+ type: schema.assertInputType(idArgType),
155
+ value: {
156
+ kind: 'Variable',
157
+ loc: {kind: 'Derived', source: fragment.loc},
158
+ variableName: idVariableName,
159
+ type: idVariableType,
160
+ },
161
+ },
162
+ ],
163
+ connection: false,
164
+ directives: [],
165
+ handles: null,
166
+ kind: 'LinkedField',
167
+ loc: {kind: 'Derived', source: fragment.loc},
168
+ metadata: null,
169
+ name: NODE_FIELD_NAME,
170
+ selections: [buildFragmentSpread(fragment)],
171
+ type: schema.assertLinkedFieldType(nodeType),
172
+ },
173
+ ],
174
+ type: queryType,
175
+ },
176
+ transformedFragment: enforceIDField(schema, fragment),
177
+ };
178
+ }
179
+
180
+ function enforceIDField(schema: Schema, fragment: Fragment): Fragment {
181
+ const idSelection = fragment.selections.find(
182
+ selection =>
183
+ selection.kind === 'ScalarField' &&
184
+ selection.name === 'id' &&
185
+ selection.alias === 'id' &&
186
+ schema.areEqualTypes(
187
+ schema.getNullableType(selection.type),
188
+ schema.expectIdType(),
189
+ ),
190
+ );
191
+ if (idSelection) {
192
+ return fragment;
193
+ }
194
+ return {
195
+ ...fragment,
196
+ selections: [
197
+ ...fragment.selections,
198
+ SchemaUtils.generateIDField(schema.expectIdType()),
199
+ ],
200
+ };
201
+ }
202
+
203
+ module.exports = ({
204
+ description: 'the Node interface or types implementing the Node interface',
205
+ buildRefetchOperation,
206
+ }: QueryGenerator);
@@ -0,0 +1,57 @@
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 {
16
+ buildFragmentSpread,
17
+ buildOperationArgumentDefinitions,
18
+ } = require('./utils');
19
+
20
+ import type {Fragment} from '../../core/IR';
21
+ import type {Schema} from '../../core/Schema';
22
+ import type {QueryGenerator, RefetchRoot} from '.';
23
+
24
+ function buildRefetchOperation(
25
+ schema: Schema,
26
+ fragment: Fragment,
27
+ queryName: string,
28
+ ): ?RefetchRoot {
29
+ const queryType = schema.expectQueryType();
30
+ if (!schema.areEqualTypes(fragment.type, queryType)) {
31
+ return null;
32
+ }
33
+
34
+ return {
35
+ identifierField: null,
36
+ path: [],
37
+ node: {
38
+ argumentDefinitions: buildOperationArgumentDefinitions(
39
+ fragment.argumentDefinitions,
40
+ ),
41
+ directives: [],
42
+ kind: 'Root',
43
+ loc: {kind: 'Derived', source: fragment.loc},
44
+ metadata: null,
45
+ name: queryName,
46
+ operation: 'query',
47
+ selections: [buildFragmentSpread(fragment)],
48
+ type: queryType,
49
+ },
50
+ transformedFragment: fragment,
51
+ };
52
+ }
53
+
54
+ module.exports = ({
55
+ description: 'the query type',
56
+ buildRefetchOperation,
57
+ }: QueryGenerator);
@@ -0,0 +1,97 @@
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 {createUserError} = require('../../core/CompilerError');
16
+ const {
17
+ buildFragmentSpread,
18
+ buildOperationArgumentDefinitions,
19
+ } = require('./utils');
20
+
21
+ import type {Fragment} from '../../core/IR';
22
+ import type {Schema} from '../../core/Schema';
23
+ import type {QueryGenerator, RefetchRoot} from '.';
24
+
25
+ const VIEWER_TYPE_NAME = 'Viewer';
26
+ const VIEWER_FIELD_NAME = 'viewer';
27
+
28
+ function buildRefetchOperation(
29
+ schema: Schema,
30
+ fragment: Fragment,
31
+ queryName: string,
32
+ ): ?RefetchRoot {
33
+ if (schema.getTypeString(fragment.type) !== VIEWER_TYPE_NAME) {
34
+ return null;
35
+ }
36
+ // Handle fragments on viewer
37
+ const queryType = schema.expectQueryType();
38
+ const viewerType = schema.getTypeFromString(VIEWER_TYPE_NAME);
39
+ const viewerField = schema.getFieldConfig(
40
+ schema.expectField(queryType, VIEWER_FIELD_NAME),
41
+ );
42
+ const viewerFieldType = schema.getNullableType(viewerField.type);
43
+ if (
44
+ !(
45
+ viewerType &&
46
+ schema.isObject(viewerType) &&
47
+ schema.isObject(viewerFieldType) &&
48
+ schema.areEqualTypes(viewerFieldType, viewerType) &&
49
+ viewerField.args.length === 0 &&
50
+ schema.areEqualTypes(fragment.type, viewerType)
51
+ )
52
+ ) {
53
+ throw createUserError(
54
+ `Invalid use of @refetchable on fragment '${fragment.name}', check ` +
55
+ "that your schema defines a 'Viewer' object type and has a " +
56
+ "'viewer: Viewer' field on the query type.",
57
+ [fragment.loc],
58
+ );
59
+ }
60
+ return {
61
+ identifierField: null,
62
+ path: [VIEWER_FIELD_NAME],
63
+ node: {
64
+ argumentDefinitions: buildOperationArgumentDefinitions(
65
+ fragment.argumentDefinitions,
66
+ ),
67
+ directives: [],
68
+ kind: 'Root',
69
+ loc: {kind: 'Derived', source: fragment.loc},
70
+ metadata: null,
71
+ name: queryName,
72
+ operation: 'query',
73
+ selections: [
74
+ {
75
+ alias: VIEWER_FIELD_NAME,
76
+ args: [],
77
+ connection: false,
78
+ directives: [],
79
+ handles: null,
80
+ kind: 'LinkedField',
81
+ loc: {kind: 'Derived', source: fragment.loc},
82
+ metadata: null,
83
+ name: VIEWER_FIELD_NAME,
84
+ selections: [buildFragmentSpread(fragment)],
85
+ type: schema.assertLinkedFieldType(viewerField.type),
86
+ },
87
+ ],
88
+ type: queryType,
89
+ },
90
+ transformedFragment: fragment,
91
+ };
92
+ }
93
+
94
+ module.exports = ({
95
+ description: 'the Viewer type',
96
+ buildRefetchOperation,
97
+ }: QueryGenerator);
@@ -0,0 +1,90 @@
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 FetchableQueryGenerator = require('./FetchableQueryGenerator');
16
+ const NodeQueryGenerator = require('./NodeQueryGenerator');
17
+ const QueryQueryGenerator = require('./QueryQueryGenerator');
18
+ const ViewerQueryGenerator = require('./ViewerQueryGenerator');
19
+
20
+ const {createUserError} = require('../../core/CompilerError');
21
+
22
+ import type {Fragment, Root} from '../../core/IR';
23
+ import type {Schema} from '../../core/Schema';
24
+
25
+ export type RefetchRoot = {|
26
+ identifierField: ?string,
27
+ path: $ReadOnlyArray<string>,
28
+ node: Root,
29
+ transformedFragment: Fragment,
30
+ |};
31
+
32
+ /**
33
+ * A strategy to generate queries for a given fragment. Multiple stategies
34
+ * can be tried, such as generating a `node(id: ID)` query or a query directly
35
+ * on the root query type.
36
+ */
37
+ export type QueryGenerator = {|
38
+ /**
39
+ * Used to describe what fragments this QueryGenerator applies to, used in
40
+ * error messages.
41
+ */
42
+ +description: string,
43
+ /**
44
+ * Returns RefetchRoot or null if not applicable. Might throw a user error
45
+ * for an invalid schema or other problems.
46
+ */
47
+ +buildRefetchOperation: (
48
+ schema: Schema,
49
+ fragment: Fragment,
50
+ queryName: string,
51
+ ) => ?RefetchRoot,
52
+ |};
53
+
54
+ const GENERATORS = [
55
+ ViewerQueryGenerator,
56
+ QueryQueryGenerator,
57
+ NodeQueryGenerator,
58
+ FetchableQueryGenerator,
59
+ ];
60
+
61
+ /**
62
+ * Builds a query to refetch the given fragment or throws if we have not way to
63
+ * generate one.
64
+ */
65
+ function buildRefetchOperation(
66
+ schema: Schema,
67
+ fragment: Fragment,
68
+ queryName: string,
69
+ ): RefetchRoot {
70
+ for (const generator of GENERATORS) {
71
+ const refetchRoot = generator.buildRefetchOperation(
72
+ schema,
73
+ fragment,
74
+ queryName,
75
+ );
76
+ if (refetchRoot != null) {
77
+ return refetchRoot;
78
+ }
79
+ }
80
+ throw createUserError(
81
+ `Invalid use of @refetchable on fragment '${fragment.name}', only ` +
82
+ 'supported are fragments on:\n' +
83
+ GENERATORS.map(generator => ` - ${generator.description}`).join('\n'),
84
+ [fragment.loc],
85
+ );
86
+ }
87
+
88
+ module.exports = {
89
+ buildRefetchOperation,
90
+ };
@@ -0,0 +1,72 @@
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
+ import type {
16
+ ArgumentDefinition,
17
+ Fragment,
18
+ FragmentSpread,
19
+ LocalArgumentDefinition,
20
+ } from '../../core/IR';
21
+
22
+ function buildFragmentSpread(fragment: Fragment): FragmentSpread {
23
+ const args = [];
24
+ for (const argDef of fragment.argumentDefinitions) {
25
+ if (argDef.kind !== 'LocalArgumentDefinition') {
26
+ continue;
27
+ }
28
+ args.push({
29
+ kind: 'Argument',
30
+ loc: {kind: 'Derived', source: argDef.loc},
31
+ name: argDef.name,
32
+ type: argDef.type,
33
+ value: {
34
+ kind: 'Variable',
35
+ loc: {kind: 'Derived', source: argDef.loc},
36
+ variableName: argDef.name,
37
+ type: argDef.type,
38
+ },
39
+ });
40
+ }
41
+ return {
42
+ args,
43
+ directives: [],
44
+ kind: 'FragmentSpread',
45
+ loc: {kind: 'Derived', source: fragment.loc},
46
+ metadata: null,
47
+ name: fragment.name,
48
+ };
49
+ }
50
+
51
+ function buildOperationArgumentDefinitions(
52
+ argumentDefinitions: $ReadOnlyArray<ArgumentDefinition>,
53
+ ): $ReadOnlyArray<LocalArgumentDefinition> {
54
+ return argumentDefinitions.map(argDef => {
55
+ if (argDef.kind === 'LocalArgumentDefinition') {
56
+ return argDef;
57
+ } else {
58
+ return {
59
+ kind: 'LocalArgumentDefinition',
60
+ name: argDef.name,
61
+ type: argDef.type,
62
+ defaultValue: null,
63
+ loc: argDef.loc,
64
+ };
65
+ }
66
+ });
67
+ }
68
+
69
+ module.exports = {
70
+ buildFragmentSpread,
71
+ buildOperationArgumentDefinitions,
72
+ };