relay-compiler 8.0.0 → 10.0.1

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