houdini 0.17.9 → 0.17.11

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 (121) hide show
  1. package/README.md +33 -0
  2. package/build/cmd-cjs/index.js +2 -2
  3. package/build/cmd-esm/index.js +2 -2
  4. package/package.json +16 -1
  5. package/.turbo/turbo-compile.log +0 -5
  6. package/.turbo/turbo-typedefs.log +0 -5
  7. package/CHANGELOG.md +0 -377
  8. package/src/cmd/generate.ts +0 -54
  9. package/src/cmd/index.ts +0 -60
  10. package/src/cmd/init.ts +0 -637
  11. package/src/cmd/pullSchema.ts +0 -40
  12. package/src/codegen/generators/artifacts/artifacts.test.ts +0 -3246
  13. package/src/codegen/generators/artifacts/fieldKey.ts +0 -60
  14. package/src/codegen/generators/artifacts/index.ts +0 -330
  15. package/src/codegen/generators/artifacts/indexFile.ts +0 -24
  16. package/src/codegen/generators/artifacts/inputs.ts +0 -81
  17. package/src/codegen/generators/artifacts/operations.ts +0 -281
  18. package/src/codegen/generators/artifacts/pagination.test.ts +0 -664
  19. package/src/codegen/generators/artifacts/policy.test.ts +0 -298
  20. package/src/codegen/generators/artifacts/selection.ts +0 -208
  21. package/src/codegen/generators/artifacts/utils.test.ts +0 -118
  22. package/src/codegen/generators/artifacts/utils.ts +0 -108
  23. package/src/codegen/generators/definitions/enums.test.ts +0 -61
  24. package/src/codegen/generators/definitions/enums.ts +0 -68
  25. package/src/codegen/generators/definitions/index.ts +0 -11
  26. package/src/codegen/generators/definitions/schema.test.ts +0 -236
  27. package/src/codegen/generators/index.ts +0 -6
  28. package/src/codegen/generators/indexFile/index.ts +0 -63
  29. package/src/codegen/generators/indexFile/indexFile.test.ts +0 -72
  30. package/src/codegen/generators/persistedQueries/index.ts +0 -55
  31. package/src/codegen/generators/persistedQueries/persistedQuery.test.ts +0 -26
  32. package/src/codegen/generators/runtime/index.test.ts +0 -74
  33. package/src/codegen/generators/runtime/index.ts +0 -64
  34. package/src/codegen/generators/runtime/runtime.test.ts +0 -25
  35. package/src/codegen/generators/typescript/addReferencedInputTypes.ts +0 -77
  36. package/src/codegen/generators/typescript/index.ts +0 -412
  37. package/src/codegen/generators/typescript/inlineType.ts +0 -409
  38. package/src/codegen/generators/typescript/typeReference.ts +0 -44
  39. package/src/codegen/generators/typescript/types.ts +0 -81
  40. package/src/codegen/generators/typescript/typescript.test.ts +0 -1434
  41. package/src/codegen/index.ts +0 -406
  42. package/src/codegen/transforms/addID.test.ts +0 -93
  43. package/src/codegen/transforms/addID.ts +0 -86
  44. package/src/codegen/transforms/composeQueries.test.ts +0 -50
  45. package/src/codegen/transforms/composeQueries.ts +0 -154
  46. package/src/codegen/transforms/fragmentVariables.test.ts +0 -636
  47. package/src/codegen/transforms/fragmentVariables.ts +0 -417
  48. package/src/codegen/transforms/index.ts +0 -7
  49. package/src/codegen/transforms/list.ts +0 -484
  50. package/src/codegen/transforms/lists.test.ts +0 -530
  51. package/src/codegen/transforms/paginate.test.ts +0 -1528
  52. package/src/codegen/transforms/paginate.ts +0 -770
  53. package/src/codegen/transforms/schema.test.ts +0 -136
  54. package/src/codegen/transforms/schema.ts +0 -109
  55. package/src/codegen/transforms/typename.test.ts +0 -125
  56. package/src/codegen/transforms/typename.ts +0 -55
  57. package/src/codegen/utils/commonjs.ts +0 -26
  58. package/src/codegen/utils/flattenSelections.ts +0 -179
  59. package/src/codegen/utils/graphql.test.ts +0 -35
  60. package/src/codegen/utils/graphql.ts +0 -79
  61. package/src/codegen/utils/index.ts +0 -5
  62. package/src/codegen/utils/moduleExport.ts +0 -27
  63. package/src/codegen/utils/murmur.ts +0 -79
  64. package/src/codegen/validators/index.ts +0 -4
  65. package/src/codegen/validators/noIDAlias.test.ts +0 -71
  66. package/src/codegen/validators/noIDAlias.ts +0 -39
  67. package/src/codegen/validators/plugins.ts +0 -25
  68. package/src/codegen/validators/typeCheck.test.ts +0 -960
  69. package/src/codegen/validators/typeCheck.ts +0 -1086
  70. package/src/codegen/validators/uniqueNames.test.ts +0 -59
  71. package/src/codegen/validators/uniqueNames.ts +0 -39
  72. package/src/lib/cleanupFiles.ts +0 -20
  73. package/src/lib/config.test.ts +0 -13
  74. package/src/lib/config.ts +0 -954
  75. package/src/lib/constants.ts +0 -11
  76. package/src/lib/error.ts +0 -24
  77. package/src/lib/fs.ts +0 -285
  78. package/src/lib/graphql.test.ts +0 -211
  79. package/src/lib/graphql.ts +0 -200
  80. package/src/lib/imports.ts +0 -82
  81. package/src/lib/index.ts +0 -17
  82. package/src/lib/introspection.ts +0 -39
  83. package/src/lib/parse.test.ts +0 -75
  84. package/src/lib/parse.ts +0 -23
  85. package/src/lib/path.ts +0 -49
  86. package/src/lib/pipeline.ts +0 -17
  87. package/src/lib/types.ts +0 -34
  88. package/src/lib/walk.ts +0 -104
  89. package/src/runtime/cache/cache.ts +0 -1026
  90. package/src/runtime/cache/gc.ts +0 -56
  91. package/src/runtime/cache/index.ts +0 -3
  92. package/src/runtime/cache/lists.ts +0 -516
  93. package/src/runtime/cache/storage.ts +0 -574
  94. package/src/runtime/cache/stuff.ts +0 -77
  95. package/src/runtime/cache/subscription.ts +0 -329
  96. package/src/runtime/cache/tests/availability.test.ts +0 -408
  97. package/src/runtime/cache/tests/gc.test.ts +0 -319
  98. package/src/runtime/cache/tests/keys.test.ts +0 -36
  99. package/src/runtime/cache/tests/list.test.ts +0 -3854
  100. package/src/runtime/cache/tests/readwrite.test.ts +0 -1201
  101. package/src/runtime/cache/tests/scalars.test.ts +0 -218
  102. package/src/runtime/cache/tests/storage.test.ts +0 -426
  103. package/src/runtime/cache/tests/subscriptions.test.ts +0 -1757
  104. package/src/runtime/index.ts +0 -29
  105. package/src/runtime/lib/config.ts +0 -211
  106. package/src/runtime/lib/constants.ts +0 -17
  107. package/src/runtime/lib/deepEquals.ts +0 -32
  108. package/src/runtime/lib/errors.ts +0 -8
  109. package/src/runtime/lib/index.ts +0 -8
  110. package/src/runtime/lib/log.ts +0 -69
  111. package/src/runtime/lib/network.ts +0 -303
  112. package/src/runtime/lib/networkUtils.ts +0 -151
  113. package/src/runtime/lib/scalars.test.ts +0 -877
  114. package/src/runtime/lib/scalars.ts +0 -195
  115. package/src/runtime/lib/types.ts +0 -195
  116. package/src/test/index.ts +0 -294
  117. package/src/vite/ast.ts +0 -107
  118. package/src/vite/houdini.ts +0 -113
  119. package/src/vite/imports.ts +0 -129
  120. package/src/vite/index.ts +0 -55
  121. package/src/vite/schema.ts +0 -80
@@ -1,770 +0,0 @@
1
- import * as graphql from 'graphql'
2
-
3
- import { Config, HoudiniError, parentTypeFromAncestors, CollectedGraphQLDocument } from '../../lib'
4
- import { ArtifactKind, RefetchUpdateMode } from '../../runtime/lib/types'
5
- import { unwrapType, wrapType } from '../utils'
6
-
7
- // the paginate transform is responsible for preparing a fragment marked for pagination
8
- // to be embedded in the query that will be used to fetch additional data. That means it
9
- // is responsible for adding additional arguments to the paginated field and hoisting
10
- // all of the pagination args to arguments of the fragment itself. It then generates
11
- // a query that threads query variables to the updated fragment and lets the fragment
12
- // argument transform do the rest. This whole process happens in a few steps:
13
-
14
- // - walk through the document and look for a field marked for pagination. if one is found,
15
- // add the necessary arguments to the field, referencing variables that will be injected
16
- // and compute what kind of pagination (toggling an object of flags)
17
- // - if the @paginate directive was found, add the @arguments directive to the fragment
18
- // definition to pass new pagination arguments and use any fields that were previously
19
- // set as the default value. That will cause the fragment arguments directive to inline
20
- // the default values if one isn't given, preserving the original definition for the first query
21
- // - generate the query with the fragment embedded using @with to pass query variables through
22
-
23
- type PaginationFlags = {
24
- [fieldName: string]: {
25
- enabled: boolean
26
- type: string
27
- defaultValue?: any
28
- variableName?: string
29
- }
30
- }
31
-
32
- // paginate transform adds the necessary fields for a paginated field
33
- export default async function paginate(
34
- config: Config,
35
- documents: CollectedGraphQLDocument[]
36
- ): Promise<void> {
37
- // we're going to have to add documents to the list so collect them here and we'll add them when we're done
38
- const newDocs: CollectedGraphQLDocument[] = []
39
-
40
- // visit every document
41
- for (const doc of documents) {
42
- // remember if we ran into a paginate argument
43
- let paginated = false
44
-
45
- // store the pagination state to coordinate what we define as args to the field and the argument definitions of
46
- // the fragment and operation. we'll fill in the enabled state and default values once we encounter @paginate
47
- const flags: PaginationFlags = {
48
- first: {
49
- enabled: false,
50
- type: 'Int',
51
- },
52
- after: {
53
- enabled: false,
54
- type: 'String',
55
- },
56
- last: {
57
- enabled: false,
58
- type: 'Int',
59
- },
60
- before: {
61
- enabled: false,
62
- type: 'String',
63
- },
64
- limit: {
65
- enabled: false,
66
- type: 'Int',
67
- },
68
- offset: {
69
- enabled: false,
70
- type: 'Int',
71
- },
72
- }
73
-
74
- let cursorType = 'String'
75
-
76
- // we need to know the path where the paginate directive shows up so we can distinguish updated
77
- // values from data that needs to be added to the list
78
- let paginationPath: string[] = []
79
-
80
- // we need to add page info to the selection
81
- doc.document = graphql.visit(doc.document, {
82
- Field(node, _, __, ___, ancestors) {
83
- // if there's no paginate directive, ignore the field
84
- const paginateDirective = node.directives?.find(
85
- (directive) => directive.name.value === config.paginateDirective
86
- )
87
- if (!paginateDirective || !node.selectionSet) {
88
- return
89
- }
90
-
91
- // remember we saw this directive
92
- paginated = true
93
-
94
- // loop over the args of the field once so we can check their existence
95
- const fieldTypeFields = (
96
- parentTypeFromAncestors(config.schema, doc.filename, ancestors) as
97
- | graphql.GraphQLObjectType
98
- | graphql.GraphQLInterfaceType
99
- ).getFields()[node.name.value]
100
- const args = new Set(fieldTypeFields.args.map((arg) => arg.name))
101
-
102
- // also look to see if the user wants to do forward pagination
103
- const passedArgs = new Set(node.arguments?.map((arg) => arg.name.value))
104
- const specifiedForwards = passedArgs.has('first')
105
- const specifiedBackwards = passedArgs.has('last')
106
-
107
- cursorType =
108
- (
109
- fieldTypeFields.args?.find((arg) => ['before', 'after'].includes(arg.name))
110
- ?.type as graphql.GraphQLNamedType
111
- )?.name || 'String'
112
- flags.after.type = cursorType
113
- flags.before.type = cursorType
114
-
115
- // figure out what kind of pagination the field supports
116
- const forwardPagination =
117
- !specifiedBackwards && args.has('first') && args.has('after')
118
- const backwardsPagination =
119
- !specifiedForwards && args.has('last') && args.has('before')
120
- const offsetPagination =
121
- !forwardPagination &&
122
- !backwardsPagination &&
123
- args.has('offset') &&
124
- args.has('limit')
125
-
126
- // update the flags based on what the tagged field supports
127
- flags.first.enabled = forwardPagination
128
- flags.after.enabled = forwardPagination
129
- flags.last.enabled = backwardsPagination
130
- flags.before.enabled = backwardsPagination
131
- flags.offset.enabled = offsetPagination
132
- flags.limit.enabled = offsetPagination
133
-
134
- paginationPath = (
135
- ancestors
136
- .filter(
137
- (ancestor) =>
138
- // @ts-ignore
139
- !Array.isArray(ancestor) && ancestor.kind === graphql.Kind.FIELD
140
- )
141
- .concat(node) as graphql.FieldNode[]
142
- ).map((field) => field.alias?.value || field.name.value)
143
-
144
- // if the field supports cursor based pagination we need to make sure we have the
145
- // page info field
146
- return {
147
- ...node,
148
- // any pagination arguments we run into will need to be replaced with variables
149
- // since they will be hoisted into the arguments for the fragment or query
150
- arguments: replaceArgumentsWithVariables(node.arguments, flags),
151
- selectionSet: offsetPagination
152
- ? // no need to add any fields to the selection if we're dealing with offset pagination
153
- node.selectionSet
154
- : // add the page info if we are dealing with cursor-based pagination
155
- {
156
- ...node.selectionSet,
157
- selections: [...node.selectionSet.selections, ...pageInfoSelection],
158
- },
159
- }
160
- },
161
- })
162
-
163
- // if we saw the paginate directive we need to add arguments to the fragment or query that contain the
164
- // field that is marked for pagination
165
- if (paginated) {
166
- let fragmentName = ''
167
- let refetchQueryName = ''
168
- // check if we have to embed the fragment in Node
169
- let nodeQuery = false
170
-
171
- // figure out the right refetch
172
- let refetchUpdate = RefetchUpdateMode.append
173
- if (flags.last.enabled) {
174
- refetchUpdate = RefetchUpdateMode.prepend
175
- }
176
-
177
- // remember if we found a fragment or operation
178
- let fragment = ''
179
-
180
- doc.document = graphql.visit(doc.document, {
181
- // if we are dealing with a query, we'll need to add the variables to the definition
182
- OperationDefinition(node) {
183
- // make sure its a query
184
- if (node.operation !== 'query') {
185
- throw new HoudiniError({
186
- filepath: doc.filename,
187
- message: `@${config.paginateDirective} can only show up in a query or fragment document`,
188
- })
189
- }
190
-
191
- refetchQueryName = node.name?.value || ''
192
-
193
- // build a map from existing variables to their value so we can compare with the ones we need to inject
194
- const operationVariables: Record<string, graphql.VariableDefinitionNode> =
195
- node.variableDefinitions?.reduce(
196
- (vars, definition) => ({
197
- ...vars,
198
- [definition.variable.name.value]: definition,
199
- }),
200
- {}
201
- ) || {}
202
-
203
- // figure out the variables we want on the query
204
- let newVariables: Record<string, graphql.VariableDefinitionNode> =
205
- Object.fromEntries(
206
- Object.entries(flags)
207
- .filter(
208
- ([, spec]) =>
209
- // let's tale the spec enabled AND where we don't have a dedicated variable for it
210
- spec.enabled && spec.variableName === undefined
211
- )
212
- .map(([fieldName, spec]) => [
213
- fieldName,
214
- staticVariableDefinition(
215
- fieldName,
216
- spec.type,
217
- spec.defaultValue,
218
- spec.variableName
219
- ),
220
- ])
221
- )
222
-
223
- // the full list of variables comes from both source
224
- const variableNames = new Set<string>(
225
- Object.keys(operationVariables).concat(Object.keys(newVariables))
226
- )
227
-
228
- // we need to build a unique set of variable definitions
229
- const finalVariables = [...variableNames].map(
230
- (name) => operationVariables[name] || newVariables[name]
231
- )
232
-
233
- return {
234
- ...node,
235
- variableDefinitions: finalVariables,
236
- } as graphql.OperationDefinitionNode
237
- },
238
- // if we are dealing with a fragment definition we'll need to add the arguments directive if it doesn't exist
239
- FragmentDefinition(node) {
240
- fragment = node.typeCondition.name.value
241
-
242
- fragmentName = node.name.value
243
- refetchQueryName = config.paginationQueryName(fragmentName)
244
-
245
- // a fragment has to be embedded in Node if its not on the query type
246
- nodeQuery = node.typeCondition.name.value !== config.schema.getQueryType()?.name
247
-
248
- // look at the fragment definition for an arguments directive
249
- const argDirective = node.directives?.find(
250
- (directive) => directive.name.value === config.argumentsDirective
251
- )
252
-
253
- // if there isn't an arguments directive, add it and we'll add arguments to it when
254
- // we run into it again
255
- if (!argDirective) {
256
- return {
257
- ...node,
258
- directives: [
259
- ...(node.directives || []),
260
- {
261
- kind: graphql.Kind.DIRECTIVE,
262
- name: {
263
- kind: graphql.Kind.NAME,
264
- value: config.argumentsDirective,
265
- },
266
- },
267
- ] as graphql.DirectiveNode[],
268
- }
269
- }
270
- },
271
- Directive(node) {
272
- // if we are not looking at the arguments directive, ignore it
273
- if (node.name.value !== config.argumentsDirective) {
274
- return
275
- }
276
-
277
- // turn the set of enabled pagination args into arg definitions for the directive
278
- let newArgs = [
279
- ...Object.entries(flags)
280
- .filter(([, spec]) => spec.enabled)
281
- .map(([key, spec]) =>
282
- argumentNode(key, [spec.type, spec.defaultValue])
283
- ),
284
- ]
285
-
286
- // add non-null versions of the arguments we'll use to paginate
287
- return {
288
- ...node,
289
- arguments: [...(node.arguments || []), ...newArgs],
290
- } as graphql.DirectiveNode
291
- },
292
- })
293
-
294
- // now that we've mutated the document to be flexible for @paginate's needs
295
- // we need to add a document to perform the query if we are paginating on a
296
- // fragment
297
-
298
- // figure out the 'target' type of the refetch
299
- let targetType = config.schema.getQueryType()?.name || ''
300
- if (fragment) {
301
- const nodeInterface = config.schema.getType('Node') as graphql.GraphQLInterfaceType
302
- if (nodeInterface) {
303
- const { objects, interfaces } = config.schema.getImplementations(nodeInterface)
304
-
305
- if (
306
- objects.find((obj) => obj.name === fragment) ||
307
- interfaces.find((int) => int.name === fragment)
308
- ) {
309
- targetType = 'Node'
310
- } else {
311
- targetType = fragment
312
- }
313
- } else {
314
- targetType = fragment
315
- }
316
- }
317
-
318
- // add the paginate info to the collected document
319
- doc.refetch = {
320
- update: refetchUpdate,
321
- path: paginationPath,
322
- method: flags.first.enabled || flags.last.enabled ? 'cursor' : 'offset',
323
- pageSize: 0,
324
- embedded: nodeQuery,
325
- targetType,
326
- paginated: true,
327
- direction: flags.last.enabled ? 'backwards' : 'forward',
328
- }
329
-
330
- // add the correct default page size
331
- if (flags.first.enabled) {
332
- doc.refetch.pageSize = flags.first.defaultValue
333
- doc.refetch.start = flags.after.defaultValue
334
- } else if (flags.last.enabled) {
335
- doc.refetch.pageSize = flags.last.defaultValue
336
- doc.refetch.start = flags.before.defaultValue
337
- } else if (flags.limit.enabled) {
338
- doc.refetch.pageSize = flags.limit.defaultValue
339
- doc.refetch.start = flags.offset.defaultValue
340
- }
341
-
342
- // if we're not paginating a fragment, there's nothing more to do. we mutated
343
- // the query's definition to contain the arguments we need to get more data
344
- // and we can just use it for refetches
345
- if (!fragment) {
346
- continue
347
- }
348
- // grab the enabled fields to create the list of arguments for the directive
349
- const paginationArgs = Object.entries(flags)
350
- .filter(([_, { enabled }]) => enabled)
351
- .map(([key, value]) => ({ name: key, ...value }))
352
-
353
- const fragmentSpreadSelection = [
354
- {
355
- kind: graphql.Kind.FRAGMENT_SPREAD,
356
- name: {
357
- kind: graphql.Kind.NAME,
358
- value: fragmentName,
359
- },
360
- directives: [
361
- {
362
- kind: graphql.Kind.DIRECTIVE,
363
- name: {
364
- kind: graphql.Kind.NAME,
365
- value: config.withDirective,
366
- },
367
- ['arguments']: paginationArgs.map(({ name }) =>
368
- variableAsArgument(name)
369
- ),
370
- },
371
- ],
372
- },
373
- ] as graphql.SelectionNode[]
374
-
375
- // we are going to add arguments for every key the type is configured with
376
- const keys = config
377
- .keyFieldsForType(!nodeQuery ? config.schema.getQueryType()?.name || '' : fragment)
378
- .flatMap((key) => {
379
- // if we are looking at the query, don't add anything
380
- if (fragment === config.schema.getQueryType()?.name) {
381
- return []
382
- }
383
-
384
- // look up the type for each key
385
- const fragmentType = config.schema.getType(fragment) as
386
- | graphql.GraphQLObjectType
387
- | graphql.GraphQLInterfaceType
388
-
389
- const { type, wrappers } = unwrapType(
390
- config,
391
- fragmentType.getFields()[key].type
392
- )
393
-
394
- return [
395
- {
396
- name: key,
397
- type: wrapType({ type, wrappers }),
398
- },
399
- ]
400
- })
401
-
402
- const typeConfig = config.typeConfig?.[fragment]
403
-
404
- const queryDoc: graphql.DocumentNode = {
405
- kind: graphql.Kind.DOCUMENT,
406
- definitions: [
407
- {
408
- kind: graphql.Kind.OPERATION_DEFINITION,
409
- name: {
410
- kind: graphql.Kind.NAME,
411
- value: refetchQueryName,
412
- },
413
- operation: 'query',
414
- variableDefinitions: paginationArgs
415
- .map(
416
- (arg) =>
417
- ({
418
- kind: graphql.Kind.VARIABLE_DEFINITION,
419
- type: {
420
- kind: graphql.Kind.NAMED_TYPE,
421
- name: {
422
- kind: graphql.Kind.NAME,
423
- value: arg.type,
424
- },
425
- },
426
- variable: {
427
- kind: graphql.Kind.VARIABLE,
428
- name: {
429
- kind: graphql.Kind.NAME,
430
- value: arg.name,
431
- },
432
- },
433
- defaultValue: !flags[arg.name].defaultValue
434
- ? undefined
435
- : {
436
- kind: (arg.type + 'Value') as
437
- | 'IntValue'
438
- | 'StringValue',
439
- value: flags[arg.name].defaultValue,
440
- },
441
- } as graphql.VariableDefinitionNode)
442
- )
443
- .concat(
444
- !nodeQuery
445
- ? []
446
- : keys.map(
447
- (key) =>
448
- ({
449
- kind: graphql.Kind.VARIABLE_DEFINITION,
450
- type: key.type,
451
- variable: {
452
- kind: graphql.Kind.VARIABLE,
453
- name: {
454
- kind: graphql.Kind.NAME,
455
- value: key.name,
456
- },
457
- },
458
- } as graphql.VariableDefinitionNode)
459
- )
460
- ),
461
- selectionSet: {
462
- kind: graphql.Kind.SELECTION_SET,
463
- selections: !nodeQuery
464
- ? fragmentSpreadSelection
465
- : [
466
- {
467
- kind: graphql.Kind.FIELD,
468
- name: {
469
- kind: graphql.Kind.NAME,
470
- value: typeConfig?.resolve?.queryField || 'node',
471
- },
472
- ['arguments']: keys.map((key) => ({
473
- kind: graphql.Kind.ARGUMENT,
474
- name: {
475
- kind: graphql.Kind.NAME,
476
- value: key.name,
477
- },
478
- value: {
479
- kind: graphql.Kind.VARIABLE,
480
- name: {
481
- kind: graphql.Kind.NAME,
482
- value: key.name,
483
- },
484
- },
485
- })),
486
- selectionSet: {
487
- kind: graphql.Kind.SELECTION_SET,
488
- selections: [
489
- // make sure we look up the type of the result
490
- {
491
- kind: graphql.Kind.FIELD,
492
- name: {
493
- kind: graphql.Kind.NAME,
494
- value: '__typename',
495
- },
496
- },
497
- // make sure every key field is present
498
- ...(typeConfig?.keys || ['id']).map((key) => ({
499
- kind: graphql.Kind.FIELD,
500
- name: {
501
- kind: graphql.Kind.NAME,
502
- value: key,
503
- },
504
- })),
505
- ...fragmentSpreadSelection,
506
- ] as graphql.SelectionNode[],
507
- },
508
- },
509
- ],
510
- },
511
- },
512
- ],
513
- }
514
-
515
- // add a document to the list
516
- newDocs.push({
517
- kind: ArtifactKind.Query,
518
- filename: doc.filename,
519
- name: refetchQueryName,
520
- document: queryDoc,
521
- originalDocument: queryDoc,
522
- generateArtifact: true,
523
- generateStore: false,
524
- refetch: doc.refetch,
525
- originalString: '',
526
- })
527
- }
528
- }
529
-
530
- // add every new doc we generated to the list
531
- documents.push(...newDocs)
532
- }
533
-
534
- function replaceArgumentsWithVariables(
535
- args: readonly graphql.ArgumentNode[] | undefined,
536
- flags: PaginationFlags
537
- ): graphql.ArgumentNode[] {
538
- const seenArgs: Record<string, boolean> = {}
539
-
540
- const newArgs = (args || []).map((arg) => {
541
- // the specification for this variable
542
- const spec = flags[arg.name.value]
543
- // if the arg is not something we care about or is disabled we need to leave it alone
544
- if (!spec || !spec.enabled) {
545
- return arg
546
- }
547
-
548
- // if the argument isn't being passed a variable, we will need to set a default value
549
- if (arg.value.kind !== 'Variable') {
550
- const oldValue = (arg.value as graphql.StringValueNode).value
551
-
552
- // transform the value if we have to and save the default value
553
- flags[arg.name.value].defaultValue = spec.type === 'Int' ? parseInt(oldValue) : oldValue
554
- }
555
-
556
- // if we have a variable
557
- if (arg.value.kind === 'Variable') {
558
- flags[arg.name.value].variableName = arg.value.name.value
559
- }
560
-
561
- seenArgs[arg.name.value] = true
562
-
563
- // turn the field into a variable
564
- return variableAsArgument(arg.name.value, flags[arg.name.value].variableName)
565
- })
566
-
567
- // any fields that are enabled but don't have values need to have variable references add
568
- for (const name of Object.keys(flags)) {
569
- // the specification for this variable
570
- const spec = flags[name]
571
-
572
- // if we have a value or its disabled, ignore it
573
- if (flags[name].defaultValue || !spec.enabled || seenArgs[name]) {
574
- continue
575
- }
576
-
577
- // if we are looking at forward pagination args when backwards is enabled ignore it
578
- if (['first', 'after'].includes(name) && flags['before'].enabled) {
579
- continue
580
- }
581
- // same but opposite for backwards pagination
582
- if (['last', 'before'].includes(name) && flags['first'].enabled) {
583
- continue
584
- }
585
-
586
- // we need to add a variable referencing the argument
587
- newArgs.push(variableAsArgument(name))
588
- }
589
-
590
- return newArgs
591
- }
592
-
593
- function variableAsArgument(name: string, variable?: string): graphql.ArgumentNode {
594
- return {
595
- kind: graphql.Kind.ARGUMENT,
596
- name: {
597
- kind: graphql.Kind.NAME,
598
- value: name,
599
- },
600
- value: {
601
- kind: graphql.Kind.VARIABLE,
602
- name: {
603
- kind: graphql.Kind.NAME,
604
- value: variable ?? name,
605
- },
606
- },
607
- }
608
- }
609
-
610
- function staticVariableDefinition(
611
- name: string,
612
- type: string,
613
- defaultValue?: string,
614
- variableName?: string
615
- ) {
616
- return {
617
- kind: graphql.Kind.VARIABLE_DEFINITION,
618
- type: {
619
- kind: graphql.Kind.NAMED_TYPE,
620
- name: {
621
- kind: graphql.Kind.NAME,
622
- value: type,
623
- },
624
- },
625
- variable: {
626
- kind: graphql.Kind.VARIABLE,
627
- name: {
628
- kind: graphql.Kind.NAME,
629
- value: variableName ?? name,
630
- },
631
- },
632
- defaultValue: !defaultValue
633
- ? undefined
634
- : {
635
- kind: (type + 'Value') as 'IntValue' | 'StringValue',
636
- value: defaultValue,
637
- },
638
- } as graphql.VariableDefinitionNode
639
- }
640
-
641
- function argumentNode(
642
- name: string,
643
- value: [string, number | string | undefined]
644
- ): graphql.ArgumentNode {
645
- return {
646
- kind: graphql.Kind.ARGUMENT,
647
- name: {
648
- kind: graphql.Kind.NAME,
649
- value: name,
650
- },
651
- value: objectNode(value),
652
- }
653
- }
654
-
655
- function objectNode([type, defaultValue]: [
656
- string,
657
- number | string | undefined
658
- ]): graphql.ObjectValueNode {
659
- const node = {
660
- kind: graphql.Kind.OBJECT,
661
- fields: [
662
- {
663
- kind: graphql.Kind.OBJECT_FIELD,
664
- name: {
665
- kind: graphql.Kind.NAME,
666
- value: 'type',
667
- },
668
- value: {
669
- kind: graphql.Kind.STRING,
670
- value: type,
671
- },
672
- },
673
- ] as graphql.ObjectFieldNode[],
674
- }
675
-
676
- // if there's a default value, add it
677
- if (defaultValue) {
678
- node.fields.push({
679
- kind: graphql.Kind.OBJECT_FIELD,
680
- name: { kind: graphql.Kind.NAME, value: 'default' } as graphql.NameNode,
681
- value: {
682
- kind: typeof defaultValue === 'number' ? 'IntValue' : 'StringValue',
683
- value: defaultValue.toString(),
684
- },
685
- } as graphql.ObjectFieldNode)
686
- }
687
-
688
- return node
689
- }
690
-
691
- export const pageInfoSelection = [
692
- {
693
- kind: graphql.Kind.FIELD,
694
- name: {
695
- kind: graphql.Kind.NAME,
696
- value: 'edges',
697
- },
698
- selectionSet: {
699
- kind: graphql.Kind.SELECTION_SET,
700
- selections: [
701
- {
702
- kind: graphql.Kind.FIELD,
703
- name: {
704
- kind: graphql.Kind.NAME,
705
- value: 'cursor',
706
- },
707
- },
708
- {
709
- kind: graphql.Kind.FIELD,
710
- name: {
711
- kind: graphql.Kind.NAME,
712
- value: 'node',
713
- },
714
- selectionSet: {
715
- kind: graphql.Kind.SELECTION_SET,
716
- selections: [
717
- {
718
- kind: graphql.Kind.FIELD,
719
- name: {
720
- kind: graphql.Kind.NAME,
721
- value: '__typename',
722
- },
723
- },
724
- ],
725
- },
726
- },
727
- ],
728
- },
729
- },
730
- {
731
- kind: graphql.Kind.FIELD,
732
- name: {
733
- kind: graphql.Kind.NAME,
734
- value: 'pageInfo',
735
- },
736
- selectionSet: {
737
- kind: graphql.Kind.SELECTION_SET,
738
- selections: [
739
- {
740
- kind: graphql.Kind.FIELD,
741
- name: {
742
- kind: graphql.Kind.NAME,
743
- value: 'hasPreviousPage',
744
- },
745
- },
746
- {
747
- kind: graphql.Kind.FIELD,
748
- name: {
749
- kind: graphql.Kind.NAME,
750
- value: 'hasNextPage',
751
- },
752
- },
753
- {
754
- kind: graphql.Kind.FIELD,
755
- name: {
756
- kind: graphql.Kind.NAME,
757
- value: 'startCursor',
758
- },
759
- },
760
- {
761
- kind: graphql.Kind.FIELD,
762
- name: {
763
- kind: graphql.Kind.NAME,
764
- value: 'endCursor',
765
- },
766
- },
767
- ],
768
- },
769
- },
770
- ]