graphql-jit 0.8.9 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.md +25 -0
  2. package/dist/cjs/ast.d.ts +89 -0
  3. package/dist/cjs/ast.js +766 -0
  4. package/dist/cjs/ast.js.map +1 -0
  5. package/dist/cjs/compat.d.ts +70 -0
  6. package/dist/cjs/compat.js +144 -0
  7. package/dist/cjs/compat.js.map +1 -0
  8. package/dist/cjs/debug.d.ts +29 -0
  9. package/dist/cjs/debug.js +46 -0
  10. package/dist/cjs/debug.js.map +1 -0
  11. package/dist/cjs/error.d.ts +7 -0
  12. package/dist/cjs/error.js +58 -0
  13. package/dist/cjs/error.js.map +1 -0
  14. package/dist/cjs/execution.d.ts +154 -0
  15. package/dist/cjs/execution.js +1240 -0
  16. package/dist/cjs/execution.js.map +1 -0
  17. package/dist/cjs/generate.d.ts +4 -0
  18. package/dist/cjs/generate.js +13 -0
  19. package/dist/cjs/generate.js.map +1 -0
  20. package/dist/cjs/index.d.ts +3 -0
  21. package/dist/cjs/index.js +10 -0
  22. package/dist/cjs/index.js.map +1 -0
  23. package/dist/cjs/inspect.d.ts +5 -0
  24. package/dist/cjs/inspect.js +110 -0
  25. package/dist/cjs/inspect.js.map +1 -0
  26. package/dist/cjs/json.d.ts +9 -0
  27. package/dist/cjs/json.js +144 -0
  28. package/dist/cjs/json.js.map +1 -0
  29. package/dist/cjs/memoize.d.ts +5 -0
  30. package/dist/cjs/memoize.js +28 -0
  31. package/dist/cjs/memoize.js.map +1 -0
  32. package/dist/cjs/non-null.d.ts +9 -0
  33. package/dist/cjs/non-null.js +205 -0
  34. package/dist/cjs/non-null.js.map +1 -0
  35. package/dist/cjs/package.json +3 -0
  36. package/dist/{resolve-info.d.ts → cjs/resolve-info.d.ts} +10 -12
  37. package/dist/cjs/resolve-info.js +232 -0
  38. package/dist/cjs/resolve-info.js.map +1 -0
  39. package/dist/cjs/runtime.d.ts +14 -0
  40. package/dist/cjs/runtime.js +92 -0
  41. package/dist/cjs/runtime.js.map +1 -0
  42. package/dist/cjs/types.d.ts +1 -0
  43. package/dist/cjs/types.js +3 -0
  44. package/dist/cjs/types.js.map +1 -0
  45. package/dist/cjs/variables.d.ts +20 -0
  46. package/dist/cjs/variables.js +357 -0
  47. package/dist/cjs/variables.js.map +1 -0
  48. package/dist/esm/ast.d.ts +89 -0
  49. package/dist/esm/ast.js +751 -0
  50. package/dist/esm/ast.js.map +1 -0
  51. package/dist/esm/compat.d.ts +70 -0
  52. package/dist/esm/compat.js +102 -0
  53. package/dist/esm/compat.js.map +1 -0
  54. package/dist/esm/debug.d.ts +29 -0
  55. package/dist/esm/debug.js +40 -0
  56. package/dist/esm/debug.js.map +1 -0
  57. package/dist/esm/error.d.ts +7 -0
  58. package/dist/esm/error.js +55 -0
  59. package/dist/esm/error.js.map +1 -0
  60. package/dist/esm/execution.d.ts +154 -0
  61. package/dist/esm/execution.js +1227 -0
  62. package/dist/esm/execution.js.map +1 -0
  63. package/dist/esm/generate.d.ts +4 -0
  64. package/dist/esm/generate.js +10 -0
  65. package/dist/esm/generate.js.map +1 -0
  66. package/dist/esm/index.d.ts +3 -0
  67. package/dist/esm/index.js +3 -0
  68. package/dist/esm/index.js.map +1 -0
  69. package/dist/esm/inspect.d.ts +5 -0
  70. package/dist/esm/inspect.js +106 -0
  71. package/dist/esm/inspect.js.map +1 -0
  72. package/dist/esm/json.d.ts +9 -0
  73. package/dist/esm/json.js +141 -0
  74. package/dist/esm/json.js.map +1 -0
  75. package/dist/esm/memoize.d.ts +5 -0
  76. package/dist/esm/memoize.js +20 -0
  77. package/dist/esm/memoize.js.map +1 -0
  78. package/dist/esm/non-null.d.ts +9 -0
  79. package/dist/esm/non-null.js +199 -0
  80. package/dist/esm/non-null.js.map +1 -0
  81. package/dist/esm/package.json +3 -0
  82. package/dist/{resolve-info.d.mts → esm/resolve-info.d.ts} +10 -12
  83. package/dist/esm/resolve-info.js +224 -0
  84. package/dist/esm/resolve-info.js.map +1 -0
  85. package/dist/esm/runtime.d.ts +14 -0
  86. package/dist/esm/runtime.js +89 -0
  87. package/dist/esm/runtime.js.map +1 -0
  88. package/dist/esm/types.d.ts +1 -0
  89. package/dist/esm/types.js +2 -0
  90. package/dist/esm/types.js.map +1 -0
  91. package/dist/esm/variables.d.ts +20 -0
  92. package/dist/esm/variables.js +350 -0
  93. package/dist/esm/variables.js.map +1 -0
  94. package/package.json +39 -35
  95. package/dist/ast.d.mts +0 -7
  96. package/dist/ast.d.ts +0 -7
  97. package/dist/ast.js +0 -635
  98. package/dist/ast.js.map +0 -1
  99. package/dist/ast.mjs +0 -612
  100. package/dist/ast.mjs.map +0 -1
  101. package/dist/compat.d.mts +0 -7
  102. package/dist/compat.d.ts +0 -7
  103. package/dist/compat.js +0 -113
  104. package/dist/compat.js.map +0 -1
  105. package/dist/compat.mjs +0 -75
  106. package/dist/compat.mjs.map +0 -1
  107. package/dist/error.d.mts +0 -11
  108. package/dist/error.d.ts +0 -11
  109. package/dist/error.js +0 -79
  110. package/dist/error.js.map +0 -1
  111. package/dist/error.mjs +0 -57
  112. package/dist/error.mjs.map +0 -1
  113. package/dist/execution.d.mts +0 -7
  114. package/dist/execution.d.ts +0 -7
  115. package/dist/execution.js +0 -1262
  116. package/dist/execution.js.map +0 -1
  117. package/dist/execution.mjs +0 -1248
  118. package/dist/execution.mjs.map +0 -1
  119. package/dist/generate.d.mts +0 -6
  120. package/dist/generate.d.ts +0 -6
  121. package/dist/generate.js +0 -37
  122. package/dist/generate.js.map +0 -1
  123. package/dist/generate.mjs +0 -13
  124. package/dist/generate.mjs.map +0 -1
  125. package/dist/index-CeluTkd4.d.mts +0 -329
  126. package/dist/index-mKv2zpdA.d.ts +0 -329
  127. package/dist/index.d.mts +0 -7
  128. package/dist/index.d.ts +0 -7
  129. package/dist/index.js +0 -36
  130. package/dist/index.js.map +0 -1
  131. package/dist/index.mjs +0 -15
  132. package/dist/index.mjs.map +0 -1
  133. package/dist/inspect.d.mts +0 -7
  134. package/dist/inspect.d.ts +0 -7
  135. package/dist/inspect.js +0 -121
  136. package/dist/inspect.js.map +0 -1
  137. package/dist/inspect.mjs +0 -97
  138. package/dist/inspect.mjs.map +0 -1
  139. package/dist/json.d.mts +0 -18
  140. package/dist/json.d.ts +0 -18
  141. package/dist/json.js +0 -181
  142. package/dist/json.js.map +0 -1
  143. package/dist/json.mjs +0 -164
  144. package/dist/json.mjs.map +0 -1
  145. package/dist/memoize.d.mts +0 -6
  146. package/dist/memoize.d.ts +0 -6
  147. package/dist/memoize.js +0 -67
  148. package/dist/memoize.js.map +0 -1
  149. package/dist/memoize.mjs +0 -31
  150. package/dist/memoize.mjs.map +0 -1
  151. package/dist/non-null.d.mts +0 -7
  152. package/dist/non-null.d.ts +0 -7
  153. package/dist/non-null.js +0 -196
  154. package/dist/non-null.js.map +0 -1
  155. package/dist/non-null.mjs +0 -167
  156. package/dist/non-null.mjs.map +0 -1
  157. package/dist/resolve-info.js +0 -245
  158. package/dist/resolve-info.js.map +0 -1
  159. package/dist/resolve-info.mjs +0 -219
  160. package/dist/resolve-info.mjs.map +0 -1
  161. package/dist/runtime.d.mts +0 -7
  162. package/dist/runtime.d.ts +0 -7
  163. package/dist/runtime.js +0 -115
  164. package/dist/runtime.js.map +0 -1
  165. package/dist/runtime.mjs +0 -91
  166. package/dist/runtime.mjs.map +0 -1
  167. package/dist/types.d.mts +0 -3
  168. package/dist/types.d.ts +0 -3
  169. package/dist/types.js +0 -17
  170. package/dist/types.js.map +0 -1
  171. package/dist/types.mjs +0 -1
  172. package/dist/types.mjs.map +0 -1
  173. package/dist/variables.d.mts +0 -17
  174. package/dist/variables.d.ts +0 -17
  175. package/dist/variables.js +0 -412
  176. package/dist/variables.js.map +0 -1
  177. package/dist/variables.mjs +0 -391
  178. package/dist/variables.mjs.map +0 -1
@@ -0,0 +1,751 @@
1
+ import { GraphQLError, GraphQLIncludeDirective, GraphQLSkipDirective, isEnumType, isInputObjectType, isListType, isNonNullType, isScalarType, print, typeFromAST, valueFromASTUntyped, Kind, isAbstractType } from "graphql";
2
+ import { GLOBAL_VARIABLES_NAME } from "./execution.js";
3
+ import createInspect from "./inspect.js";
4
+ import { coerceInputLiteral, getDefaultValue, getGraphQLErrorOptions, hasDefaultValue, resolveFieldDef } from "./compat.js";
5
+ const inspect = createInspect();
6
+ /**
7
+ * Given a selectionSet, adds all of the fields in that selection to
8
+ * the passed in map of fields, and returns it at the end.
9
+ *
10
+ * CollectFields requires the "runtime type" of an object. For a field which
11
+ * returns an Interface or Union type, the "runtime type" will be the actual
12
+ * Object type returned by that field.
13
+ */
14
+ export function collectFields(compilationContext, runtimeType, selectionSet, fields, visitedFragmentNames, parentResponsePath) {
15
+ return collectFieldsImpl(compilationContext, runtimeType, selectionSet, fields, visitedFragmentNames, undefined, serializeObjectPathForSkipInclude(parentResponsePath));
16
+ }
17
+ /**
18
+ * Implementation of collectFields defined above with extra parameters
19
+ * used for recursion and need not be exposed publically
20
+ */
21
+ function collectFieldsImpl(compilationContext, runtimeType, selectionSet, fields, visitedFragmentNames, previousShouldInclude = [], parentResponsePath = "") {
22
+ const stack = [];
23
+ // Push in reverse so that stack.pop() will process in document order
24
+ for (let i = selectionSet.selections.length - 1; i >= 0; i--) {
25
+ stack.push({
26
+ selection: selectionSet.selections[i],
27
+ parentResponsePath,
28
+ previousShouldInclude
29
+ });
30
+ }
31
+ while (stack.length > 0) {
32
+ const { selection, parentResponsePath, previousShouldInclude } = stack.pop();
33
+ switch (selection.kind) {
34
+ case Kind.FIELD: {
35
+ collectFieldsForField({
36
+ compilationContext,
37
+ fields,
38
+ parentResponsePath,
39
+ previousShouldInclude,
40
+ selection
41
+ });
42
+ break;
43
+ }
44
+ case Kind.INLINE_FRAGMENT: {
45
+ if (!doesFragmentConditionMatch(compilationContext, selection, runtimeType)) {
46
+ break;
47
+ }
48
+ // current fragment's shouldInclude
49
+ const compiledSkipInclude = compileSkipInclude(compilationContext, selection);
50
+ const mergedShouldInclude = joinShouldIncludeCompilations(previousShouldInclude, [compiledSkipInclude]);
51
+ // Push in reverse so that stack.pop() will process in document order
52
+ const selectionsLength = selection.selectionSet.selections.length;
53
+ for (let i = selectionsLength - 1; i >= 0; i--) {
54
+ stack.push({
55
+ selection: selection.selectionSet.selections[i],
56
+ parentResponsePath,
57
+ previousShouldInclude: mergedShouldInclude
58
+ });
59
+ }
60
+ break;
61
+ }
62
+ case Kind.FRAGMENT_SPREAD: {
63
+ const fragName = selection.name.value;
64
+ if (visitedFragmentNames[fragName]) {
65
+ break;
66
+ }
67
+ visitedFragmentNames[fragName] = true;
68
+ const fragment = compilationContext.fragments[fragName];
69
+ if (!fragment ||
70
+ !doesFragmentConditionMatch(compilationContext, fragment, runtimeType)) {
71
+ break;
72
+ }
73
+ // current fragment's shouldInclude
74
+ const compiledSkipInclude = compileSkipInclude(compilationContext, selection);
75
+ const mergedShouldInclude = joinShouldIncludeCompilations(previousShouldInclude, [compiledSkipInclude]);
76
+ // Push in reverse so that stack.pop() will process in document order
77
+ const selectionsLength = fragment.selectionSet.selections.length;
78
+ for (let i = selectionsLength - 1; i >= 0; i--) {
79
+ stack.push({
80
+ selection: fragment.selectionSet.selections[i],
81
+ parentResponsePath,
82
+ previousShouldInclude: mergedShouldInclude
83
+ });
84
+ }
85
+ break;
86
+ }
87
+ }
88
+ }
89
+ return fields;
90
+ }
91
+ function collectFieldsForField({ compilationContext, fields, parentResponsePath, previousShouldInclude, selection }) {
92
+ const name = getFieldEntryKey(selection);
93
+ if (!fields[name]) {
94
+ fields[name] = [];
95
+ }
96
+ const fieldNode = selection;
97
+ // the current path of the field
98
+ // This is used to generate per path skip/include code
99
+ // because the same field can be reached from different paths (e.g. fragment reuse)
100
+ const currentPath = joinSkipIncludePath(parentResponsePath,
101
+ // use alias(instead of selection.name.value) if available as the responsePath used for lookup uses alias
102
+ name);
103
+ // `should include`s generated for the current fieldNode
104
+ const compiledSkipInclude = compileSkipInclude(compilationContext, selection);
105
+ /**
106
+ * Carry over fragment's skip and include code
107
+ *
108
+ * fieldNode.__internalShouldInclude
109
+ * ---------------------------------
110
+ * When the parent field has a skip or include, the current one
111
+ * should be skipped if the parent is skipped in the path.
112
+ *
113
+ * previousShouldInclude
114
+ * ---------------------
115
+ * `should include`s from fragment spread and inline fragments
116
+ *
117
+ * compileSkipInclude(selection)
118
+ * -----------------------------
119
+ * `should include`s generated for the current fieldNode
120
+ */
121
+ if (compilationContext.options.useExperimentalPathBasedSkipInclude) {
122
+ if (!fieldNode.__internalShouldIncludePath)
123
+ fieldNode.__internalShouldIncludePath = {};
124
+ fieldNode.__internalShouldIncludePath[currentPath] =
125
+ joinShouldIncludeCompilations(fieldNode.__internalShouldIncludePath?.[currentPath] ?? [], previousShouldInclude, [compiledSkipInclude]);
126
+ }
127
+ else {
128
+ // @deprecated
129
+ fieldNode.__internalShouldInclude = joinShouldIncludeCompilations(fieldNode.__internalShouldInclude ?? [], previousShouldInclude, [compiledSkipInclude]);
130
+ }
131
+ /**
132
+ * We augment the entire subtree as the parent object's skip/include
133
+ * directives influence the child even if the child doesn't have
134
+ * skip/include on it's own.
135
+ *
136
+ * Refer the function definition for example.
137
+ */
138
+ augmentFieldNodeTree(compilationContext, fieldNode, currentPath);
139
+ fields[name].push(fieldNode);
140
+ }
141
+ /**
142
+ * Augment __internalShouldInclude code for all sub-fields in the
143
+ * tree with @param rootfieldNode as the root.
144
+ *
145
+ * This is required to handle cases where there are multiple paths to
146
+ * the same node. And each of those paths contain different skip/include
147
+ * values.
148
+ *
149
+ * For example,
150
+ *
151
+ * ```
152
+ * {
153
+ * foo @skip(if: $c1) {
154
+ * bar @skip(if: $c2)
155
+ * }
156
+ * ... {
157
+ * foo @skip(if: $c3) {
158
+ * bar
159
+ * }
160
+ * }
161
+ * }
162
+ * ```
163
+ *
164
+ * We decide shouldInclude at runtime per fieldNode. When we handle the
165
+ * field `foo`, the logic is straight forward - it requires one of $c1 or $c3
166
+ * to be false.
167
+ *
168
+ * But, when we handle the field `bar`, and we are in the context of the fieldNode,
169
+ * not enough information is available. This is because, if we only included $c2
170
+ * to decide if bar is included, consider the case -
171
+ *
172
+ * $c1: true, $c2: true, $c3: false
173
+ *
174
+ * If we considered only $c2, we would have skipped bar. But the correct implementation
175
+ * is to include bar, because foo($c3) { bar } is not skipped. The entire sub-tree's
176
+ * logic is required to handle bar.
177
+ *
178
+ * So, to handle this case, we augment the tree at each point to consider the
179
+ * skip/include logic from the parent as well.
180
+ *
181
+ * @param compilationContext {CompilationContext} Required for getFragment by
182
+ * name to handle fragment spread operation.
183
+ *
184
+ * @param rootFieldNode {JitFieldNode} The root field to traverse from for
185
+ * adding __internalShouldInclude to all sub field nodes.
186
+ *
187
+ * @param parentResponsePath {string} The response path of the parent field.
188
+ */
189
+ function augmentFieldNodeTree(compilationContext, rootFieldNode, parentResponsePath) {
190
+ for (const selection of rootFieldNode.selectionSet?.selections ?? []) {
191
+ const stack = [];
192
+ stack.push({
193
+ parentFieldNode: rootFieldNode,
194
+ selection,
195
+ comesFromFragmentSpread: false,
196
+ parentResponsePath
197
+ });
198
+ while (stack.length > 0) {
199
+ const { parentFieldNode, selection, comesFromFragmentSpread, parentResponsePath } = stack.pop();
200
+ switch (selection.kind) {
201
+ case Kind.FIELD: {
202
+ const jitFieldNode = selection;
203
+ const currentPath = joinSkipIncludePath(parentResponsePath,
204
+ // use alias(instead of selection.name.value) if available as the responsePath used for lookup uses alias
205
+ getFieldEntryKey(jitFieldNode));
206
+ if (!comesFromFragmentSpread) {
207
+ if (compilationContext.options.useExperimentalPathBasedSkipInclude) {
208
+ if (!jitFieldNode.__internalShouldIncludePath)
209
+ jitFieldNode.__internalShouldIncludePath = {};
210
+ jitFieldNode.__internalShouldIncludePath[currentPath] =
211
+ joinShouldIncludeCompilations(parentFieldNode.__internalShouldIncludePath?.[parentResponsePath] ?? [], jitFieldNode.__internalShouldIncludePath?.[currentPath] ?? []);
212
+ }
213
+ else {
214
+ // @deprecated
215
+ jitFieldNode.__internalShouldInclude =
216
+ joinShouldIncludeCompilations(parentFieldNode.__internalShouldInclude ?? [], jitFieldNode.__internalShouldInclude ?? []);
217
+ }
218
+ }
219
+ // go further down the query tree
220
+ for (const selection of jitFieldNode.selectionSet?.selections ?? []) {
221
+ stack.push({
222
+ parentFieldNode: jitFieldNode,
223
+ selection,
224
+ comesFromFragmentSpread: false,
225
+ parentResponsePath: currentPath
226
+ });
227
+ }
228
+ break;
229
+ }
230
+ case Kind.INLINE_FRAGMENT: {
231
+ for (const subSelection of selection.selectionSet.selections) {
232
+ stack.push({
233
+ parentFieldNode,
234
+ selection: subSelection,
235
+ comesFromFragmentSpread: true,
236
+ parentResponsePath
237
+ });
238
+ }
239
+ break;
240
+ }
241
+ case Kind.FRAGMENT_SPREAD: {
242
+ const fragment = compilationContext.fragments[selection.name.value];
243
+ for (const subSelection of fragment.selectionSet.selections) {
244
+ stack.push({
245
+ parentFieldNode,
246
+ selection: subSelection,
247
+ comesFromFragmentSpread: true,
248
+ parentResponsePath
249
+ });
250
+ }
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ /**
257
+ * Joins a list of shouldInclude compiled code into a single logical
258
+ * statement.
259
+ *
260
+ * The operation is `&&` because, it is used to join parent->child
261
+ * relations in the query tree. Note: parent can be either parent field
262
+ * or fragment.
263
+ *
264
+ * For example,
265
+ * {
266
+ * foo @skip(if: $c1) {
267
+ * ... @skip(if: $c2) {
268
+ * bar @skip(if: $c3)
269
+ * }
270
+ * }
271
+ * }
272
+ *
273
+ * Only when a parent is included, the child is included. So, we use `&&`.
274
+ *
275
+ * compilationFor($c1) && compilationFor($c2) && compilationFor($c3)
276
+ *
277
+ * @param compilations
278
+ */
279
+ function joinShouldIncludeCompilations(...compilations) {
280
+ // remove "true" since we are joining with '&&' as `true && X` = `X`
281
+ // This prevents an explosion of `&& true` which could break
282
+ // V8's internal size limit for string.
283
+ //
284
+ // Note: the `true` appears if a field does not have a skip/include directive
285
+ // So, the more nested the query is, the more of unnecessary `&& true`
286
+ // we get.
287
+ //
288
+ // Failing to do this results in [RangeError: invalid array length]
289
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_array_length
290
+ const conditionsSet = new Set();
291
+ for (const conditions of compilations) {
292
+ for (const condition of conditions) {
293
+ if (condition !== "true") {
294
+ conditionsSet.add(condition);
295
+ }
296
+ }
297
+ }
298
+ return Array.from(conditionsSet);
299
+ }
300
+ /**
301
+ * Compiles directives `skip` and `include` and generates the compilation
302
+ * code based on GraphQL specification.
303
+ *
304
+ * @param node {SelectionNode} The selection node (field/fragment/inline-fragment)
305
+ * for which we generate the compiled skipInclude.
306
+ */
307
+ function compileSkipInclude(compilationContext, node) {
308
+ // minor optimization to avoid compilation if there are no directives
309
+ if (node.directives == null || node.directives.length < 1) {
310
+ return "true";
311
+ }
312
+ const { skipValue, includeValue } = compileSkipIncludeDirectiveValues(compilationContext, node);
313
+ /**
314
+ * Spec: https://spec.graphql.org/June2018/#sec--include
315
+ *
316
+ * Neither @skip nor @include has precedence over the other.
317
+ * In the case that both the @skip and @include directives
318
+ * are provided in on the same the field or fragment, it must
319
+ * be queried only if the @skip condition is false and the
320
+ * @include condition is true. Stated conversely, the field
321
+ * or fragment must not be queried if either the @skip
322
+ * condition is true or the @include condition is false.
323
+ */
324
+ if (skipValue != null && includeValue != null) {
325
+ return `${skipValue} === false && ${includeValue} === true`;
326
+ }
327
+ else if (skipValue != null) {
328
+ return `(${skipValue} === false)`;
329
+ }
330
+ else if (includeValue != null) {
331
+ return `(${includeValue} === true)`;
332
+ }
333
+ else {
334
+ return `true`;
335
+ }
336
+ }
337
+ /**
338
+ * Compile skip or include directive values into JIT compatible
339
+ * runtime code.
340
+ *
341
+ * @param node {SelectionNode}
342
+ */
343
+ function compileSkipIncludeDirectiveValues(compilationContext, node) {
344
+ const skipDirective = node.directives?.find((it) => it.name.value === GraphQLSkipDirective.name);
345
+ const includeDirective = node.directives?.find((it) => it.name.value === GraphQLIncludeDirective.name);
346
+ const skipValue = skipDirective
347
+ ? compileSkipIncludeDirective(compilationContext, skipDirective)
348
+ : // The null here indicates the absense of the directive
349
+ // which is later used to determine if both skip and include
350
+ // are present
351
+ null;
352
+ const includeValue = includeDirective
353
+ ? compileSkipIncludeDirective(compilationContext, includeDirective)
354
+ : // The null here indicates the absense of the directive
355
+ // which is later used to determine if both skip and include
356
+ // are present
357
+ null;
358
+ return { skipValue, includeValue };
359
+ }
360
+ /**
361
+ * Compile the skip/include directive node. Resolve variables to it's
362
+ * path from context, resolve scalars to their respective values.
363
+ *
364
+ * @param directive {DirectiveNode}
365
+ */
366
+ function compileSkipIncludeDirective(compilationContext, directive) {
367
+ const ifNode = directive.arguments?.find((it) => it.name.value === "if");
368
+ if (ifNode == null) {
369
+ throw new GraphQLError(`Directive '${directive.name.value}' is missing required arguments: 'if'`, getGraphQLErrorOptions([directive]));
370
+ }
371
+ switch (ifNode.value.kind) {
372
+ case Kind.VARIABLE:
373
+ validateSkipIncludeVariableType(compilationContext, ifNode.value);
374
+ return `${GLOBAL_VARIABLES_NAME}["${ifNode.value.name.value}"]`;
375
+ case Kind.BOOLEAN:
376
+ return `${ifNode.value.value.toString()}`;
377
+ default:
378
+ throw new GraphQLError(`Argument 'if' on Directive '${directive.name.value}' has an invalid value (${valueFromASTUntyped(ifNode.value)}). Expected type 'Boolean!'`, getGraphQLErrorOptions([ifNode]));
379
+ }
380
+ }
381
+ /**
382
+ * Validate the skip and include directive's argument values at compile time.
383
+ *
384
+ * This validation step is required as these directives are part of an
385
+ * implicit schema in GraphQL.
386
+ *
387
+ * @param compilationContext {CompilationContext}
388
+ * @param variable {VariableNode} the variable used in 'if' argument of the skip/include directive
389
+ */
390
+ function validateSkipIncludeVariableType(compilationContext, variable) {
391
+ const variableDefinition = compilationContext.operation.variableDefinitions?.find((it) => it.variable.name.value === variable.name.value);
392
+ if (variableDefinition == null) {
393
+ throw new GraphQLError(`Variable '${variable.name.value}' is not defined`, getGraphQLErrorOptions([variable]));
394
+ }
395
+ // Part of Spec text: https://spec.graphql.org/June2018/#sec-All-Variable-Usages-are-Allowed
396
+ if (!(
397
+ // The variable defintion is a Non-nullable Boolean type
398
+ ((variableDefinition.type.kind === Kind.NON_NULL_TYPE &&
399
+ variableDefinition.type.type.kind === Kind.NAMED_TYPE &&
400
+ variableDefinition.type.type.name.value === "Boolean") ||
401
+ // or the variable definition is a nullable Boolean type with a default value
402
+ (variableDefinition.type.kind === Kind.NAMED_TYPE &&
403
+ variableDefinition.type.name.value === "Boolean" &&
404
+ variableDefinition.defaultValue != null)))) {
405
+ throw new GraphQLError(`Variable '${variable.name.value}' of type '${typeNodeToString(variableDefinition.type)}' used in position expecting type 'Boolean!'`, getGraphQLErrorOptions([variableDefinition]));
406
+ }
407
+ }
408
+ /**
409
+ * Print the string representation of the TypeNode for error messages
410
+ *
411
+ * @param type {TypeNode} type node to be converted to string representation
412
+ */
413
+ function typeNodeToString(type) {
414
+ switch (type.kind) {
415
+ case Kind.NAMED_TYPE:
416
+ return type.name.value;
417
+ case Kind.NON_NULL_TYPE:
418
+ return `${typeNodeToString(type.type)}!`;
419
+ case Kind.LIST_TYPE:
420
+ return `[${typeNodeToString(type.type)}]`;
421
+ }
422
+ }
423
+ /**
424
+ * Determines if a fragment is applicable to the given type.
425
+ */
426
+ function doesFragmentConditionMatch(compilationContext, fragment, type) {
427
+ const typeConditionNode = fragment.typeCondition;
428
+ if (!typeConditionNode) {
429
+ return true;
430
+ }
431
+ const conditionalType = typeFromAST(compilationContext.schema, typeConditionNode);
432
+ if (conditionalType === type) {
433
+ return true;
434
+ }
435
+ if (!conditionalType) {
436
+ return false;
437
+ }
438
+ if (isAbstractType(conditionalType)) {
439
+ return compilationContext.schema.isSubType(conditionalType, type);
440
+ }
441
+ return false;
442
+ }
443
+ /**
444
+ * Implements the logic to compute the key of a given field's entry
445
+ */
446
+ function getFieldEntryKey(node) {
447
+ return node.alias ? node.alias.value : node.name.value;
448
+ }
449
+ export { resolveFieldDef };
450
+ export function collectSubfields(compilationContext, returnType, fieldNodes, parentResponsePath) {
451
+ let subFieldNodes = Object.create(null);
452
+ const visitedFragmentNames = Object.create(null);
453
+ for (const fieldNode of fieldNodes) {
454
+ const selectionSet = fieldNode.selectionSet;
455
+ if (selectionSet) {
456
+ subFieldNodes = collectFields(compilationContext, returnType, selectionSet, subFieldNodes, visitedFragmentNames, parentResponsePath);
457
+ }
458
+ }
459
+ return subFieldNodes;
460
+ }
461
+ /**
462
+ * Prepares an object map of argument values given a list of argument
463
+ * definitions and list of argument AST nodes.
464
+ *
465
+ * Note: The returned value is a plain Object with a prototype, since it is
466
+ * exposed to user code. Care should be taken to not pull values from the
467
+ * Object prototype.
468
+ */
469
+ export function getArgumentDefs(def, node) {
470
+ const values = {};
471
+ const missing = [];
472
+ const argDefs = def.args;
473
+ const argNodes = node.arguments || [];
474
+ const argNodeMap = keyMap(argNodes, (arg) => arg.name.value);
475
+ for (const argDef of argDefs) {
476
+ const name = argDef.name;
477
+ if (hasDefaultValue(argDef)) {
478
+ // handle both v16 defaultValue and v17 default.value
479
+ values[name] = getDefaultValue(argDef);
480
+ }
481
+ const argType = argDef.type;
482
+ const argumentNode = argNodeMap[name];
483
+ let hasVariables = false;
484
+ if (argumentNode && argumentNode.value.kind === Kind.VARIABLE) {
485
+ hasVariables = true;
486
+ missing.push({
487
+ valueNode: argumentNode.value,
488
+ path: addPath(undefined, name, "literal"),
489
+ argument: { definition: argDef, node: argumentNode }
490
+ });
491
+ }
492
+ else if (argumentNode) {
493
+ const coercedValue = valueFromAST(argumentNode.value, argType);
494
+ if (coercedValue === undefined) {
495
+ // Note: ValuesOfCorrectType validation should catch this before
496
+ // execution. This is a runtime check to ensure execution does not
497
+ // continue with an invalid argument value.
498
+ throw new GraphQLError(`Argument "${name}" of type "${argType}" has invalid value ${print(argumentNode.value)}.`, getGraphQLErrorOptions(argumentNode.value));
499
+ }
500
+ if (isASTValueWithVariables(coercedValue)) {
501
+ missing.push(...coercedValue.variables.map(({ valueNode, path }) => ({
502
+ valueNode,
503
+ path: addPath(path, name, "literal")
504
+ })));
505
+ }
506
+ values[name] = coercedValue.value;
507
+ }
508
+ if (isNonNullType(argType) && values[name] === undefined && !hasVariables) {
509
+ // If no value or a nullish value was provided to a variable with a
510
+ // non-null type (required), produce an error.
511
+ throw new GraphQLError(argumentNode
512
+ ? `Argument "${name}" of non-null type ` +
513
+ `"${argType}" must not be null.`
514
+ : `Argument "${name}" of required type ` +
515
+ `"${argType}" was not provided.`, getGraphQLErrorOptions(node));
516
+ }
517
+ }
518
+ return { values, missing };
519
+ }
520
+ function isASTValueWithVariables(x) {
521
+ return !!x.variables;
522
+ }
523
+ export function valueFromAST(valueNode, type) {
524
+ if (isNonNullType(type)) {
525
+ if (valueNode.kind === Kind.NULL) {
526
+ return; // Invalid: intentionally return no value.
527
+ }
528
+ return valueFromAST(valueNode, type.ofType);
529
+ }
530
+ if (valueNode.kind === Kind.NULL) {
531
+ // This is explicitly returning the value null.
532
+ return {
533
+ value: null
534
+ };
535
+ }
536
+ if (valueNode.kind === Kind.VARIABLE) {
537
+ return { value: null, variables: [{ valueNode, path: undefined }] };
538
+ }
539
+ if (isListType(type)) {
540
+ const itemType = type.ofType;
541
+ if (valueNode.kind === Kind.LIST) {
542
+ const coercedValues = [];
543
+ const variables = [];
544
+ const itemNodes = valueNode.values;
545
+ for (let i = 0; i < itemNodes.length; i++) {
546
+ const itemNode = itemNodes[i];
547
+ if (itemNode.kind === Kind.VARIABLE) {
548
+ coercedValues.push(null);
549
+ variables.push({
550
+ valueNode: itemNode,
551
+ path: addPath(undefined, i.toString(), "literal")
552
+ });
553
+ }
554
+ else {
555
+ const itemValue = valueFromAST(itemNode, itemType);
556
+ if (!itemValue) {
557
+ return; // Invalid: intentionally return no value.
558
+ }
559
+ coercedValues.push(itemValue.value);
560
+ if (isASTValueWithVariables(itemValue)) {
561
+ variables.push(...itemValue.variables.map(({ valueNode, path }) => ({
562
+ valueNode,
563
+ path: addPath(path, i.toString(), "literal")
564
+ })));
565
+ }
566
+ }
567
+ }
568
+ return { value: coercedValues, variables };
569
+ }
570
+ // Single item which will be coerced to a list
571
+ const coercedValue = valueFromAST(valueNode, itemType);
572
+ if (coercedValue === undefined) {
573
+ return; // Invalid: intentionally return no value.
574
+ }
575
+ if (isASTValueWithVariables(coercedValue)) {
576
+ return {
577
+ value: [coercedValue.value],
578
+ variables: coercedValue.variables.map(({ valueNode, path }) => ({
579
+ valueNode,
580
+ path: addPath(path, "0", "literal")
581
+ }))
582
+ };
583
+ }
584
+ return { value: [coercedValue.value] };
585
+ }
586
+ if (isInputObjectType(type)) {
587
+ if (valueNode.kind !== Kind.OBJECT) {
588
+ return; // Invalid: intentionally return no value.
589
+ }
590
+ const coercedObj = Object.create(null);
591
+ const variables = [];
592
+ const fieldNodes = keyMap(valueNode.fields, (field) => field.name.value);
593
+ const fields = Object.values(type.getFields());
594
+ for (const field of fields) {
595
+ if (hasDefaultValue(field)) {
596
+ coercedObj[field.name] = getDefaultValue(field);
597
+ }
598
+ const fieldNode = fieldNodes[field.name];
599
+ if (!fieldNode) {
600
+ continue;
601
+ }
602
+ const fieldValue = valueFromAST(fieldNode.value, field.type);
603
+ if (!fieldValue) {
604
+ return; // Invalid: intentionally return no value.
605
+ }
606
+ if (isASTValueWithVariables(fieldValue)) {
607
+ variables.push(...fieldValue.variables.map(({ valueNode, path }) => ({
608
+ valueNode,
609
+ path: addPath(path, field.name, "literal")
610
+ })));
611
+ }
612
+ coercedObj[field.name] = fieldValue.value;
613
+ }
614
+ return { value: coercedObj, variables };
615
+ }
616
+ if (isEnumType(type)) {
617
+ if (valueNode.kind !== Kind.ENUM) {
618
+ return; // Invalid: intentionally return no value.
619
+ }
620
+ const enumValue = type.getValue(valueNode.value);
621
+ if (!enumValue) {
622
+ return; // Invalid: intentionally return no value.
623
+ }
624
+ return { value: enumValue.value };
625
+ }
626
+ if (isScalarType(type)) {
627
+ // Scalars fulfill parsing a literal value via coerceInputLiteral().
628
+ // Invalid values represent a failure to parse correctly, in which case
629
+ // no value is returned.
630
+ let result;
631
+ try {
632
+ // By this point, we've filtered out VARIABLE nodes, so valueNode is a ConstValueNode
633
+ result = coerceInputLiteral(type, valueNode);
634
+ }
635
+ catch (error) {
636
+ return; // Invalid: intentionally return no value.
637
+ }
638
+ if (isInvalid(result)) {
639
+ return; // Invalid: intentionally return no value.
640
+ }
641
+ return { value: result };
642
+ }
643
+ // Not reachable. All possible input types have been considered.
644
+ /* istanbul ignore next */
645
+ throw new Error(`Unexpected input type: "${inspect(type)}".`);
646
+ }
647
+ /**
648
+ * Creates a keyed JS object from an array, given a function to produce the keys
649
+ * for each value in the array.
650
+ *
651
+ * This provides a convenient lookup for the array items if the key function
652
+ * produces unique results.
653
+ *
654
+ * const phoneBook = [
655
+ * { name: 'Jon', num: '555-1234' },
656
+ * { name: 'Jenny', num: '867-5309' }
657
+ * ]
658
+ *
659
+ * // { Jon: { name: 'Jon', num: '555-1234' },
660
+ * // Jenny: { name: 'Jenny', num: '867-5309' } }
661
+ * const entriesByName = keyMap(
662
+ * phoneBook,
663
+ * entry => entry.name
664
+ * )
665
+ *
666
+ * // { name: 'Jenny', num: '857-6309' }
667
+ * const jennyEntry = entriesByName['Jenny']
668
+ *
669
+ */
670
+ function keyMap(list, keyFn) {
671
+ return list.reduce(
672
+ // eslint-disable-next-line no-sequences
673
+ (map, item) => ((map[keyFn(item)] = item), map), Object.create(null));
674
+ }
675
+ export function computeLocations(nodes) {
676
+ return nodes.reduce((list, node) => {
677
+ if (node.loc) {
678
+ list.push(getLocation(node.loc));
679
+ }
680
+ return list;
681
+ }, []);
682
+ }
683
+ /**
684
+ * This is an alternate faster implementation of getLocation in graphql-js
685
+ *
686
+ * Optimization:
687
+ * In graphql-js, getLocation is implemented as finding line and column
688
+ * from a given position in the source. Since the use-case in GraphQL-JIT
689
+ * is to find the location of a node, we can directly use the line and
690
+ * column from the startToken of the node's location.
691
+ *
692
+ * @param loc the Node's location
693
+ * @returns the SourceLocation for the position
694
+ */
695
+ function getLocation(loc) {
696
+ // If the location already contains line and column, return it directly
697
+ return {
698
+ line: loc.startToken.line,
699
+ column: loc.startToken.column
700
+ };
701
+ }
702
+ export function addPath(responsePath, key, type = "literal") {
703
+ return { prev: responsePath, key, type };
704
+ }
705
+ export function flattenPath(path) {
706
+ const flattened = [];
707
+ let curr = path;
708
+ while (curr) {
709
+ flattened.push({ key: curr.key, type: curr.type });
710
+ curr = curr.prev;
711
+ }
712
+ return flattened;
713
+ }
714
+ /**
715
+ * Serialize a path for use in the skip/include directives.
716
+ *
717
+ * @param path The path to serialize
718
+ * @returns The path serialized as a string, with the root path first.
719
+ */
720
+ export function serializeObjectPathForSkipInclude(path) {
721
+ let serialized = "";
722
+ let curr = path;
723
+ while (curr) {
724
+ if (curr.type === "literal") {
725
+ serialized = joinSkipIncludePath(curr.key, serialized);
726
+ }
727
+ curr = curr.prev;
728
+ }
729
+ return serialized;
730
+ }
731
+ /**
732
+ * join two path segments to a dot notation, handling empty strings
733
+ *
734
+ * @param a path segment
735
+ * @param b path segment
736
+ * @returns combined path in dot notation
737
+ */
738
+ export function joinSkipIncludePath(a, b) {
739
+ if (a) {
740
+ if (b) {
741
+ return `${a}.${b}`;
742
+ }
743
+ return a;
744
+ }
745
+ return b;
746
+ }
747
+ function isInvalid(value) {
748
+ // eslint-disable-next-line no-self-compare
749
+ return value === undefined || value !== value;
750
+ }
751
+ //# sourceMappingURL=ast.js.map