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,157 @@
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 IRTransformer = require('../core/IRTransformer');
16
+
17
+ const {createUserError} = require('../core/CompilerError');
18
+ const {ConnectionInterface} = require('relay-runtime');
19
+
20
+ const DELETE_RECORD = 'deleteRecord';
21
+ const APPEND_EDGE = 'appendEdge';
22
+ const PREPEND_EDGE = 'prependEdge';
23
+ const LINKED_FIELD_DIRECTIVES = [APPEND_EDGE, PREPEND_EDGE];
24
+
25
+ const SCHEMA_EXTENSION = `
26
+ directive @${DELETE_RECORD} on FIELD
27
+ directive @${APPEND_EDGE}(
28
+ connections: [String!]!
29
+ ) on FIELD
30
+ directive @${PREPEND_EDGE}(
31
+ connections: [String!]!
32
+ ) on FIELD
33
+ `;
34
+
35
+ import type CompilerContext from '../core/CompilerContext';
36
+ import type {ScalarField, LinkedField, Root, Handle} from '../core/IR';
37
+
38
+ function transform(context: CompilerContext): CompilerContext {
39
+ return IRTransformer.transform(context, {
40
+ ScalarField: visitScalarField,
41
+ LinkedField: visitLinkedField,
42
+ SplitOperation: skip,
43
+ Fragment: skip,
44
+ });
45
+ }
46
+
47
+ function skip<T>(node: T): T {
48
+ return node;
49
+ }
50
+
51
+ function visitScalarField(field: ScalarField): ScalarField {
52
+ const linkedFieldDirective = field.directives.find(
53
+ directive => LINKED_FIELD_DIRECTIVES.indexOf(directive.name) > -1,
54
+ );
55
+ if (linkedFieldDirective != null) {
56
+ throw createUserError(
57
+ `Invalid use of @${linkedFieldDirective.name} on scalar field '${field.name}'`,
58
+ [linkedFieldDirective.loc],
59
+ );
60
+ }
61
+ const deleteDirective = field.directives.find(
62
+ directive => directive.name === DELETE_RECORD,
63
+ );
64
+ if (deleteDirective == null) {
65
+ return field;
66
+ }
67
+ const schema = this.getContext().getSchema();
68
+ if (!schema.isId(field.type)) {
69
+ throw createUserError(
70
+ `Invalid use of @${DELETE_RECORD} on field '${
71
+ field.name
72
+ }'. Expected field type ID, got ${schema.getTypeString(field.type)}.`,
73
+ [deleteDirective.loc],
74
+ );
75
+ }
76
+ const handle: Handle = {
77
+ name: DELETE_RECORD,
78
+ key: '',
79
+ dynamicKey: null,
80
+ filters: null,
81
+ };
82
+ return {
83
+ ...field,
84
+ directives: field.directives.filter(
85
+ directive => directive !== deleteDirective,
86
+ ),
87
+ handles: field.handles ? [...field.handles, handle] : [handle],
88
+ };
89
+ }
90
+
91
+ function visitLinkedField(field: LinkedField): LinkedField {
92
+ const transformedField = this.traverse(field);
93
+ const deleteDirective = transformedField.directives.find(
94
+ directive => directive.name === DELETE_RECORD,
95
+ );
96
+ if (deleteDirective != null) {
97
+ throw createUserError(
98
+ `Invalid use of @${deleteDirective.name} on scalar field '${transformedField.name}'.`,
99
+ [deleteDirective.loc],
100
+ );
101
+ }
102
+ const edgeDirective = transformedField.directives.find(
103
+ directive => LINKED_FIELD_DIRECTIVES.indexOf(directive.name) > -1,
104
+ );
105
+ if (edgeDirective == null) {
106
+ return transformedField;
107
+ }
108
+ const connectionsArg = edgeDirective.args.find(
109
+ arg => arg.name === 'connections',
110
+ );
111
+ if (connectionsArg == null) {
112
+ throw createUserError(
113
+ `Expected the 'connections' argument to be defined on @${edgeDirective.name}.`,
114
+ [edgeDirective.loc],
115
+ );
116
+ }
117
+ const schema = this.getContext().getSchema();
118
+ const fields = schema.getFields(transformedField.type);
119
+ let cursorFieldID;
120
+ let nodeFieldID;
121
+ for (const fieldID of fields) {
122
+ const fieldName = schema.getFieldName(fieldID);
123
+ if (fieldName === ConnectionInterface.get().CURSOR) {
124
+ cursorFieldID = fieldID;
125
+ } else if (fieldName === ConnectionInterface.get().NODE) {
126
+ nodeFieldID = fieldID;
127
+ }
128
+ }
129
+ // Edge
130
+ if (cursorFieldID != null && nodeFieldID != null) {
131
+ const handle: Handle = {
132
+ name: edgeDirective.name,
133
+ key: '',
134
+ dynamicKey: null,
135
+ filters: null,
136
+ handleArgs: [connectionsArg],
137
+ };
138
+ return {
139
+ ...transformedField,
140
+ directives: transformedField.directives.filter(
141
+ directive => directive !== edgeDirective,
142
+ ),
143
+ handles: transformedField.handles
144
+ ? [...transformedField.handles, handle]
145
+ : [handle],
146
+ };
147
+ }
148
+ throw createUserError(
149
+ `Unsupported use of @${edgeDirective.name} on field '${transformedField.name}', expected an edge field (a field with 'cursor' and 'node' selection).`,
150
+ [edgeDirective.loc],
151
+ );
152
+ }
153
+
154
+ module.exports = {
155
+ SCHEMA_EXTENSION,
156
+ transform,
157
+ };
@@ -0,0 +1,265 @@
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 IRTransformer = require('../core/IRTransformer');
16
+
17
+ const getIdentifierForArgumentValue = require('../core/getIdentifierForArgumentValue');
18
+ const murmurHash = require('../util/murmurHash');
19
+
20
+ const {createUserError} = require('../core/CompilerError');
21
+
22
+ import type CompilerContext from '../core/CompilerContext';
23
+ import type {
24
+ Argument,
25
+ Defer,
26
+ Directive,
27
+ FragmentSpread,
28
+ InlineFragment,
29
+ LinkedField,
30
+ ScalarField,
31
+ Stream,
32
+ } from '../core/IR';
33
+
34
+ type State = {|
35
+ +documentName: string,
36
+ +recordLabel: (label: string, directive: Directive) => void,
37
+ |};
38
+
39
+ /**
40
+ * This transform finds usages of @defer and @stream, validates them, and
41
+ * converts the using node to specialized IR nodes (Defer/Stream).
42
+ */
43
+ function deferStreamTransform(context: CompilerContext): CompilerContext {
44
+ return IRTransformer.transform(
45
+ context,
46
+ {
47
+ // TODO: type IRTransformer to allow changing result type
48
+ FragmentSpread: (visitFragmentSpread: $FlowFixMe),
49
+ // TODO: type IRTransformer to allow changing result type
50
+ InlineFragment: (visitInlineFragment: $FlowFixMe),
51
+ // TODO: type IRTransformer to allow changing result type
52
+ LinkedField: (visitLinkedField: $FlowFixMe),
53
+ ScalarField: visitScalarField,
54
+ },
55
+ sourceNode => {
56
+ const labels = new Map();
57
+ return {
58
+ documentName: sourceNode.name,
59
+ recordLabel: (label, directive) => {
60
+ const prevDirective = labels.get(label);
61
+ if (prevDirective) {
62
+ const labelArg = directive.args.find(({name}) => name === 'label');
63
+ const prevLabelArg = prevDirective.args.find(
64
+ ({name}) => name === 'label',
65
+ );
66
+ const previousLocation = prevLabelArg?.loc ?? prevDirective.loc;
67
+ if (labelArg) {
68
+ throw createUserError(
69
+ `Invalid use of @${directive.name}, the provided label is ` +
70
+ "not unique. Specify a unique 'label' as a literal string.",
71
+ [labelArg?.loc, previousLocation],
72
+ );
73
+ } else {
74
+ throw createUserError(
75
+ `Invalid use of @${directive.name}, could not generate a ` +
76
+ "default label that is unique. Specify a unique 'label' " +
77
+ 'as a literal string.',
78
+ [directive.loc, previousLocation],
79
+ );
80
+ }
81
+ }
82
+ labels.set(label, directive);
83
+ },
84
+ };
85
+ },
86
+ );
87
+ }
88
+
89
+ function visitLinkedField(
90
+ field: LinkedField,
91
+ state: State,
92
+ ): LinkedField | Stream {
93
+ const context: CompilerContext = this.getContext();
94
+ const schema = context.getSchema();
95
+
96
+ let transformedField: LinkedField = this.traverse(field, state);
97
+ const streamDirective = transformedField.directives.find(
98
+ directive => directive.name === 'stream',
99
+ );
100
+ if (streamDirective == null) {
101
+ return transformedField;
102
+ }
103
+ const type = schema.getNullableType(field.type);
104
+ if (!schema.isList(type)) {
105
+ throw createUserError(
106
+ `Invalid use of @stream on non-plural field '${field.name}'`,
107
+ [streamDirective.loc],
108
+ );
109
+ }
110
+ transformedField = {
111
+ ...transformedField,
112
+ directives: transformedField.directives.filter(
113
+ directive => directive.name !== 'stream',
114
+ ),
115
+ };
116
+ const ifArg = streamDirective.args.find(arg => arg.name === 'if');
117
+ if (isLiteralFalse(ifArg)) {
118
+ return transformedField;
119
+ }
120
+ const initialCount = streamDirective.args.find(
121
+ arg => arg.name === 'initial_count',
122
+ );
123
+ if (initialCount == null) {
124
+ throw createUserError(
125
+ "Invalid use of @stream, the 'initial_count' argument is required.",
126
+ [streamDirective.loc],
127
+ );
128
+ }
129
+ const useCustomizedBatch = streamDirective.args.find(
130
+ arg => arg.name === 'use_customized_batch',
131
+ );
132
+
133
+ const label =
134
+ getLiteralStringArgument(streamDirective, 'label') ?? field.alias;
135
+ const transformedLabel = transformLabel(state.documentName, 'stream', label);
136
+ state.recordLabel(transformedLabel, streamDirective);
137
+ return {
138
+ if: ifArg?.value ?? null,
139
+ initialCount: initialCount.value,
140
+ useCustomizedBatch: useCustomizedBatch?.value ?? null,
141
+ kind: 'Stream',
142
+ label: transformedLabel,
143
+ loc: {kind: 'Derived', source: streamDirective.loc},
144
+ metadata: null,
145
+ selections: [transformedField],
146
+ };
147
+ }
148
+
149
+ function visitScalarField(field: ScalarField, state: State): ScalarField {
150
+ const streamDirective = field.directives.find(
151
+ directive => directive.name === 'stream',
152
+ );
153
+ if (streamDirective != null) {
154
+ throw createUserError(
155
+ `Invalid use of @stream on scalar field '${field.name}'`,
156
+ [streamDirective.loc],
157
+ );
158
+ }
159
+ return this.traverse(field, state);
160
+ }
161
+
162
+ function visitInlineFragment(
163
+ fragment: InlineFragment,
164
+ state: State,
165
+ ): InlineFragment | Defer {
166
+ const deferDirective = fragment.directives.find(
167
+ directive => directive.name === 'defer',
168
+ );
169
+ if (deferDirective != null) {
170
+ throw createUserError(
171
+ 'Invalid use of @defer on an inline fragment, @defer is only supported on fragment spreads.',
172
+ [fragment.loc],
173
+ );
174
+ }
175
+ return this.traverse(fragment, state);
176
+ }
177
+
178
+ function visitFragmentSpread(
179
+ spread: FragmentSpread,
180
+ state: State,
181
+ ): FragmentSpread | Defer {
182
+ let transformedSpread: FragmentSpread = this.traverse(spread, state);
183
+ const deferDirective = transformedSpread.directives.find(
184
+ directive => directive.name === 'defer',
185
+ );
186
+ if (deferDirective == null) {
187
+ return transformedSpread;
188
+ }
189
+ transformedSpread = {
190
+ ...transformedSpread,
191
+ directives: transformedSpread.directives.filter(
192
+ directive => directive.name !== 'defer',
193
+ ),
194
+ };
195
+ const ifArg = deferDirective.args.find(arg => arg.name === 'if');
196
+ if (isLiteralFalse(ifArg)) {
197
+ return transformedSpread;
198
+ }
199
+ const label =
200
+ getLiteralStringArgument(deferDirective, 'label') ??
201
+ getFragmentSpreadName(spread);
202
+ const transformedLabel = transformLabel(state.documentName, 'defer', label);
203
+ state.recordLabel(transformedLabel, deferDirective);
204
+ return {
205
+ if: ifArg?.value ?? null,
206
+ kind: 'Defer',
207
+ label: transformedLabel,
208
+ loc: {kind: 'Derived', source: deferDirective.loc},
209
+ selections: [transformedSpread],
210
+ };
211
+ }
212
+
213
+ function getLiteralStringArgument(
214
+ directive: Directive,
215
+ argName: string,
216
+ ): ?string {
217
+ const arg = directive.args.find(({name}) => name === argName);
218
+ if (arg == null) {
219
+ return null;
220
+ }
221
+ const value = arg.value.kind === 'Literal' ? arg.value.value : null;
222
+ if (value == null || typeof value !== 'string') {
223
+ throw createUserError(
224
+ `Expected the '${argName}' value to @${directive.name} to be a string literal if provided.`,
225
+ [arg.value.loc],
226
+ );
227
+ }
228
+ return value;
229
+ }
230
+
231
+ function transformLabel(
232
+ parentName: string,
233
+ directive: string,
234
+ label: string,
235
+ ): string {
236
+ return `${parentName}$${directive}$${label}`;
237
+ }
238
+
239
+ function isLiteralFalse(arg: ?Argument): boolean {
240
+ return (
241
+ arg != null && arg.value.kind === 'Literal' && arg.value.value === false
242
+ );
243
+ }
244
+
245
+ function getFragmentSpreadName(fragmentSpread: FragmentSpread): string {
246
+ if (fragmentSpread.args.length === 0) {
247
+ return fragmentSpread.name;
248
+ }
249
+ const sortedArgs = [...fragmentSpread.args]
250
+ .sort((a, b) => {
251
+ return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
252
+ })
253
+ .map(argument => {
254
+ return {
255
+ name: argument.name,
256
+ value: getIdentifierForArgumentValue(argument.value),
257
+ };
258
+ });
259
+ const hash = murmurHash(JSON.stringify(sortedArgs));
260
+ return `${fragmentSpread.name}_${hash}`;
261
+ }
262
+
263
+ module.exports = {
264
+ transform: deferStreamTransform,
265
+ };
@@ -0,0 +1,47 @@
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 IRTransformer = require('../core/IRTransformer');
16
+
17
+ const {createUserError} = require('../core/CompilerError');
18
+
19
+ import type CompilerContext from '../core/CompilerContext';
20
+ import type {ScalarField, LinkedField} from '../core/IR';
21
+
22
+ function visitField<T: ScalarField | LinkedField>(field: T): T {
23
+ if (field.alias === 'id' && field.name !== 'id') {
24
+ throw createUserError(
25
+ 'Relay does not allow aliasing fields to `id`. ' +
26
+ 'This name is reserved for the globally unique `id` field on ' +
27
+ '`Node`.',
28
+ [field.loc],
29
+ );
30
+ }
31
+ return this.traverse(field);
32
+ }
33
+
34
+ /**
35
+ * This is not an actual transform (but more a validation)
36
+ * Relay does not allow aliasing fields to `id`.
37
+ */
38
+ function disallowIdAsAlias(context: CompilerContext): CompilerContext {
39
+ return IRTransformer.transform(context, {
40
+ ScalarField: visitField,
41
+ LinkedField: visitField,
42
+ });
43
+ }
44
+
45
+ module.exports = {
46
+ transform: disallowIdAsAlias,
47
+ };
@@ -0,0 +1,45 @@
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 IRValidator = require('../core/IRValidator');
16
+
17
+ const {createUserError} = require('../core/CompilerError');
18
+
19
+ import type CompilerContext from '../core/CompilerContext';
20
+ import type {Root} from '../core/IR';
21
+
22
+ function visitRoot(node: Root) {
23
+ for (const selection of node.selections) {
24
+ if (selection.kind === 'ScalarField' && selection.name === '__typename') {
25
+ throw createUserError(
26
+ 'Relay does not allow `__typename` field on Query, Mutation or Subscription',
27
+ [selection.loc],
28
+ );
29
+ }
30
+ }
31
+ }
32
+
33
+ function stopVisit() {}
34
+
35
+ function disallowTypenameOnRoot(context: CompilerContext): CompilerContext {
36
+ IRValidator.validate(context, {
37
+ Root: visitRoot,
38
+ Fragment: stopVisit,
39
+ });
40
+ return context;
41
+ }
42
+
43
+ module.exports = {
44
+ transform: disallowTypenameOnRoot,
45
+ };
@@ -0,0 +1,80 @@
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 IRTransformer = require('../core/IRTransformer');
16
+ const SchemaUtils = require('../core/SchemaUtils');
17
+
18
+ const invariant = require('invariant');
19
+ const nullthrows = require('nullthrows');
20
+
21
+ const {getRelayHandleKey} = require('relay-runtime');
22
+
23
+ import type CompilerContext from '../core/CompilerContext';
24
+ import type {LinkedField, ScalarField} from '../core/IR';
25
+
26
+ function fieldHandleTransform(context: CompilerContext): CompilerContext {
27
+ return IRTransformer.transform(context, {
28
+ LinkedField: visitField,
29
+ ScalarField: visitField,
30
+ });
31
+ }
32
+
33
+ /**
34
+ * @internal
35
+ */
36
+ function visitField<F: LinkedField | ScalarField>(field: F): F {
37
+ const nextField = field.kind === 'LinkedField' ? this.traverse(field) : field;
38
+ const handles = nextField.handles;
39
+ if (!handles || !handles.length) {
40
+ return nextField;
41
+ }
42
+ // ensure exactly one handle
43
+ invariant(
44
+ handles.length === 1,
45
+ 'FieldHandleTransform: Expected fields to have at most one ' +
46
+ '"handle" property, got `%s`.',
47
+ handles.join(', '),
48
+ );
49
+ const context: CompilerContext = this.getContext();
50
+ const schema = context.getSchema();
51
+ const alias = nextField.alias;
52
+ const handle = handles[0];
53
+ const name = getRelayHandleKey(handle.name, handle.key, nextField.name);
54
+ const filters = handle.filters;
55
+ const args = filters
56
+ ? nextField.args.filter(arg => filters.indexOf(arg.name) !== -1)
57
+ : [];
58
+ // T45504512: new connection model
59
+ if (handle.dynamicKey != null) {
60
+ args.push({
61
+ kind: 'Argument',
62
+ loc: handle.dynamicKey.loc,
63
+ name: '__dynamicKey',
64
+ type: SchemaUtils.getNullableStringInput(schema),
65
+ value: nullthrows(handle.dynamicKey),
66
+ });
67
+ }
68
+
69
+ return ({
70
+ ...nextField,
71
+ args,
72
+ alias,
73
+ name,
74
+ handles: null,
75
+ }: $FlowIssue);
76
+ }
77
+
78
+ module.exports = {
79
+ transform: fieldHandleTransform,
80
+ };
@@ -0,0 +1,45 @@
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 IRTransformer = require('../core/IRTransformer');
16
+
17
+ import type CompilerContext from '../core/CompilerContext';
18
+ import type {Directive} from '../core/IR';
19
+
20
+ /**
21
+ * A transform that removes any directives that were not present in the
22
+ * server schema.
23
+ */
24
+ function filterDirectivesTransform(context: CompilerContext): CompilerContext {
25
+ const schemaDirectives = new Set(
26
+ context
27
+ .getSchema()
28
+ .getDirectives()
29
+ .filter(directive => !directive.isClient)
30
+ .map(schemaDirective => schemaDirective.name),
31
+ );
32
+ const visitDirective = (directive: Directive): ?Directive => {
33
+ if (schemaDirectives.has(directive.name)) {
34
+ return directive;
35
+ }
36
+ return null;
37
+ };
38
+ return IRTransformer.transform(context, {
39
+ Directive: visitDirective,
40
+ });
41
+ }
42
+
43
+ module.exports = {
44
+ transform: filterDirectivesTransform,
45
+ };