@khanacademy/graphql-flow 1.2.0 → 2.0.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 (78) hide show
  1. package/.babelrc +1 -1
  2. package/.eslintrc.js +0 -1
  3. package/.github/workflows/changeset-release.yml +1 -1
  4. package/CHANGELOG.md +10 -0
  5. package/dist/cli/config.js +2 -4
  6. package/dist/cli/run.js +1 -2
  7. package/dist/enums.js +8 -9
  8. package/dist/generateResponseType.js +33 -41
  9. package/dist/generateTypeFiles.js +9 -23
  10. package/dist/generateVariablesType.js +15 -31
  11. package/dist/index.js +8 -15
  12. package/dist/parser/parse.js +6 -7
  13. package/dist/parser/resolve.js +1 -2
  14. package/dist/parser/utils.js +1 -2
  15. package/dist/schemaFromIntrospectionData.js +1 -2
  16. package/dist/types.js +1 -2
  17. package/dist/utils.js +43 -3
  18. package/package.json +8 -7
  19. package/{dist/__test__/generateTypeFileContents.test.js → src/__test__/generateTypeFileContents.test.ts} +38 -41
  20. package/{dist/__test__/graphql-flow.test.js → src/__test__/graphql-flow.test.ts} +232 -235
  21. package/src/__test__/{processPragmas.test.js → processPragmas.test.ts} +0 -1
  22. package/{dist/cli/__test__/config.test.js → src/cli/__test__/config.test.ts} +5 -6
  23. package/{dist/cli/config.js.flow → src/cli/config.ts} +6 -11
  24. package/src/cli/{run.js → run.ts} +5 -4
  25. package/src/{enums.js → enums.ts} +20 -22
  26. package/src/{generateResponseType.js → generateResponseType.ts} +167 -182
  27. package/src/{generateTypeFiles.js → generateTypeFiles.ts} +20 -30
  28. package/src/{generateVariablesType.js → generateVariablesType.ts} +34 -44
  29. package/{dist/index.js.flow → src/index.ts} +32 -24
  30. package/{dist/parser/__test__/parse.test.js → src/parser/__test__/parse.test.ts} +12 -11
  31. package/src/parser/{parse.js → parse.ts} +65 -47
  32. package/{dist/parser/resolve.js.flow → src/parser/resolve.ts} +15 -11
  33. package/{dist/parser/utils.js.flow → src/parser/utils.ts} +0 -1
  34. package/{dist/schemaFromIntrospectionData.js.flow → src/schemaFromIntrospectionData.ts} +1 -4
  35. package/src/types.ts +97 -0
  36. package/src/utils.ts +73 -0
  37. package/tools/{find-files-with-gql.js → find-files-with-gql.ts} +2 -3
  38. package/tsconfig.json +110 -0
  39. package/types/flow-to-ts.d.ts +1 -0
  40. package/dist/__test__/example-schema.graphql +0 -67
  41. package/dist/__test__/processPragmas.test.js +0 -76
  42. package/dist/cli/config.js.map +0 -1
  43. package/dist/cli/run.js.flow +0 -236
  44. package/dist/cli/run.js.map +0 -1
  45. package/dist/enums.js.flow +0 -98
  46. package/dist/enums.js.map +0 -1
  47. package/dist/generateResponseType.js.flow +0 -583
  48. package/dist/generateResponseType.js.map +0 -1
  49. package/dist/generateTypeFiles.js.flow +0 -191
  50. package/dist/generateTypeFiles.js.map +0 -1
  51. package/dist/generateVariablesType.js.flow +0 -156
  52. package/dist/generateVariablesType.js.map +0 -1
  53. package/dist/index.js.map +0 -1
  54. package/dist/parser/parse.js.flow +0 -417
  55. package/dist/parser/parse.js.map +0 -1
  56. package/dist/parser/resolve.js.map +0 -1
  57. package/dist/parser/utils.js.map +0 -1
  58. package/dist/schemaFromIntrospectionData.js.map +0 -1
  59. package/dist/types.js.flow +0 -88
  60. package/dist/types.js.map +0 -1
  61. package/dist/utils.js.flow +0 -50
  62. package/dist/utils.js.map +0 -1
  63. package/flow-typed/npm/@babel/types_vx.x.x.js +0 -5331
  64. package/flow-typed/npm/jest_v23.x.x.js +0 -1155
  65. package/flow-typed/overrides.js +0 -435
  66. package/src/__test__/generateTypeFileContents.test.js +0 -157
  67. package/src/__test__/graphql-flow.test.js +0 -639
  68. package/src/cli/__test__/config.test.js +0 -120
  69. package/src/cli/config.js +0 -84
  70. package/src/cli/schema.json +0 -97
  71. package/src/index.js +0 -160
  72. package/src/parser/__test__/parse.test.js +0 -249
  73. package/src/parser/resolve.js +0 -119
  74. package/src/parser/utils.js +0 -25
  75. package/src/schemaFromIntrospectionData.js +0 -68
  76. package/src/types.js +0 -88
  77. package/src/utils.js +0 -50
  78. /package/{dist/cli/schema.json → schema.json} +0 -0
@@ -1,19 +1,21 @@
1
- // @flow
2
1
  /* eslint-disable no-console */
3
2
  import generate from '@babel/generator'; // eslint-disable-line flowtype-errors/uncovered
4
3
  import * as babelTypes from '@babel/types';
5
- import {type BabelNodeFlowType} from '@babel/types';
4
+ import {TSType} from '@babel/types';
6
5
  import type {
7
6
  FieldNode,
8
7
  IntrospectionOutputTypeRef,
9
8
  OperationDefinitionNode,
10
9
  FragmentDefinitionNode,
10
+ SelectionNode,
11
11
  } from 'graphql';
12
12
  import type {Context, Schema, Selections} from './types';
13
13
  import {
14
14
  liftLeadingPropertyComments,
15
15
  maybeAddDescriptionComment,
16
16
  transferLeadingComments,
17
+ nullableType,
18
+ objectTypeFromProperties,
17
19
  } from './utils';
18
20
  import {enumTypeToFlow, scalarTypeToFlow} from './enums';
19
21
  import type {
@@ -22,16 +24,8 @@ import type {
22
24
  IntrospectionObjectType,
23
25
  IntrospectionUnionType,
24
26
  } from 'graphql/utilities/introspectionQuery';
25
- import {
26
- BabelNodeObjectTypeProperty,
27
- BabelNodeObjectTypeSpreadProperty,
28
- } from '@babel/types';
29
27
 
30
- export const generateResponseType = (
31
- schema: Schema,
32
- query: OperationDefinitionNode,
33
- ctx: Context,
34
- ): string => {
28
+ export const generateResponseType = (schema: Schema, query: OperationDefinitionNode, ctx: Context): string => {
35
29
  const ast = querySelectionToObjectType(
36
30
  ctx,
37
31
  query.selectionSet.selections,
@@ -46,15 +40,13 @@ export const generateResponseType = (
46
40
 
47
41
  const sortedObjectTypeAnnotation = (
48
42
  ctx: Context,
49
- properties: Array<
50
- BabelNodeObjectTypeProperty | BabelNodeObjectTypeSpreadProperty,
51
- >,
52
- ) => {
53
- const obj = babelTypes.objectTypeAnnotation(
43
+ properties: Array<babelTypes.TSPropertySignature>,
44
+ ): babelTypes.TSType => {
45
+ const obj = objectTypeFromProperties(
54
46
  properties.sort((a, b) => {
55
47
  if (
56
- a.type === 'ObjectTypeProperty' &&
57
- b.type === 'ObjectTypeProperty'
48
+ a.type === 'TSPropertySignature' &&
49
+ b.type === 'TSPropertySignature'
58
50
  ) {
59
51
  const aName = a.key.type === 'Identifier' ? a.key.name : '';
60
52
  const bName = b.key.type === 'Identifier' ? b.key.name : '';
@@ -62,26 +54,18 @@ const sortedObjectTypeAnnotation = (
62
54
  }
63
55
  return 0;
64
56
  }),
65
- undefined /* indexers */,
66
- undefined /* callProperties */,
67
- undefined /* internalSlots */,
68
- true /* exact */,
69
57
  );
70
58
  const name = ctx.path.join('_');
71
59
  const isTopLevelType = ctx.path.length <= 1;
72
60
  if (ctx.allObjectTypes != null && !isTopLevelType) {
73
61
  ctx.allObjectTypes[name] = obj;
74
- return babelTypes.genericTypeAnnotation(babelTypes.identifier(name));
62
+ return babelTypes.tsTypeReference(babelTypes.identifier(name));
75
63
  } else {
76
64
  return obj;
77
65
  }
78
66
  };
79
67
 
80
- export const generateFragmentType = (
81
- schema: Schema,
82
- fragment: FragmentDefinitionNode,
83
- ctx: Context,
84
- ): string => {
68
+ export const generateFragmentType = (schema: Schema, fragment: FragmentDefinitionNode, ctx: Context): string => {
85
69
  const onType = fragment.typeCondition.name.value;
86
70
  let ast;
87
71
 
@@ -115,20 +99,16 @@ export const generateFragmentType = (
115
99
  return generate(ast).code;
116
100
  };
117
101
 
118
- const _typeToFlow = (
119
- ctx: Context,
120
- type,
121
- selection,
122
- ): babelTypes.BabelNodeFlowType => {
102
+ const _typeToFlow = (ctx: Context, type: any, selection: FieldNode): babelTypes.TSType => {
123
103
  if (type.kind === 'SCALAR') {
124
104
  return scalarTypeToFlow(ctx, type.name);
125
105
  }
126
106
  if (type.kind === 'LIST') {
127
- return babelTypes.genericTypeAnnotation(
107
+ return babelTypes.tsTypeReference(
128
108
  ctx.readOnlyArray
129
- ? babelTypes.identifier('$ReadOnlyArray')
109
+ ? babelTypes.identifier('ReadonlyArray')
130
110
  : babelTypes.identifier('Array'),
131
- babelTypes.typeParameterInstantiation([
111
+ babelTypes.tsTypeParameterInstantiation([
132
112
  typeToFlow(ctx, type.ofType, selection),
133
113
  ]),
134
114
  );
@@ -137,7 +117,7 @@ const _typeToFlow = (
137
117
  const union = ctx.schema.unionsByName[type.name];
138
118
  if (!selection.selectionSet) {
139
119
  console.log('no selection set', selection);
140
- return babelTypes.anyTypeAnnotation();
120
+ return babelTypes.tsAnyKeyword();
141
121
  }
142
122
  return unionOrInterfaceToFlow(
143
123
  ctx,
@@ -149,7 +129,7 @@ const _typeToFlow = (
149
129
  if (type.kind === 'INTERFACE') {
150
130
  if (!selection.selectionSet) {
151
131
  console.log('no selection set', selection);
152
- return babelTypes.anyTypeAnnotation();
132
+ return babelTypes.tsAnyKeyword();
153
133
  }
154
134
  return unionOrInterfaceToFlow(
155
135
  ctx,
@@ -162,18 +142,18 @@ const _typeToFlow = (
162
142
  }
163
143
  if (type.kind !== 'OBJECT') {
164
144
  console.log('not object', type);
165
- return babelTypes.anyTypeAnnotation();
145
+ return babelTypes.tsAnyKeyword();
166
146
  }
167
147
 
168
148
  const tname = type.name;
169
149
  if (!ctx.schema.typesByName[tname]) {
170
150
  console.log('unknown referenced type', tname);
171
- return babelTypes.anyTypeAnnotation();
151
+ return babelTypes.tsAnyKeyword();
172
152
  }
173
153
  const childType = ctx.schema.typesByName[tname];
174
154
  if (!selection.selectionSet) {
175
155
  console.log('no selection set', selection);
176
- return babelTypes.anyTypeAnnotation();
156
+ return babelTypes.tsAnyKeyword();
177
157
  }
178
158
  return maybeAddDescriptionComment(
179
159
  childType.description,
@@ -186,11 +166,7 @@ const _typeToFlow = (
186
166
  );
187
167
  };
188
168
 
189
- export const typeToFlow = (
190
- ctx: Context,
191
- type: IntrospectionOutputTypeRef,
192
- selection: FieldNode,
193
- ): babelTypes.BabelNodeFlowType => {
169
+ export const typeToFlow = (ctx: Context, type: IntrospectionOutputTypeRef, selection: FieldNode): babelTypes.TSType => {
194
170
  // throw new Error('npoe');
195
171
  if (type.kind === 'NON_NULL') {
196
172
  return _typeToFlow(ctx, type.ofType, selection);
@@ -200,23 +176,25 @@ export const typeToFlow = (
200
176
  return _typeToFlow(ctx, type, selection);
201
177
  }
202
178
  const inner = _typeToFlow(ctx, type, selection);
203
- const result = babelTypes.nullableTypeAnnotation(inner);
179
+ const result = nullableType(inner);
204
180
  return transferLeadingComments(inner, result);
205
181
  };
206
182
 
207
- const ensureOnlyOneTypenameProperty = (properties) => {
183
+ const ensureOnlyOneTypenameProperty = (properties: Array<babelTypes.TSPropertySignature>) => {
208
184
  let seenTypeName: false | string = false;
209
185
  return properties.filter((type) => {
210
186
  // The apollo-utilities "addTypeName" utility will add it
211
187
  // even if it's already specified :( so we have to filter out
212
188
  // the extra one here.
213
189
  if (
214
- type.type === 'ObjectTypeProperty' &&
190
+ type.type === 'TSPropertySignature' &&
191
+ type.key.type === "Identifier" &&
215
192
  type.key.name === '__typename'
216
193
  ) {
217
194
  const name =
218
- type.value.type === 'StringLiteralTypeAnnotation'
219
- ? type.value.value
195
+ type.typeAnnotation?.typeAnnotation.type === 'TSLiteralType' &&
196
+ type.typeAnnotation.typeAnnotation.literal.type === 'StringLiteral'
197
+ ? type.typeAnnotation.typeAnnotation.literal.value
220
198
  : 'INVALID';
221
199
  if (seenTypeName) {
222
200
  if (name !== seenTypeName) {
@@ -232,12 +210,7 @@ const ensureOnlyOneTypenameProperty = (properties) => {
232
210
  });
233
211
  };
234
212
 
235
- const querySelectionToObjectType = (
236
- ctx: Context,
237
- selections,
238
- type,
239
- typeName: string,
240
- ): BabelNodeFlowType => {
213
+ const querySelectionToObjectType = (ctx: Context, selections: any, type: any, typeName: string): babelTypes.TSType => {
241
214
  return sortedObjectTypeAnnotation(
242
215
  ctx,
243
216
  ensureOnlyOneTypenameProperty(
@@ -249,86 +222,96 @@ const querySelectionToObjectType = (
249
222
  export const objectPropertiesToFlow = (
250
223
  ctx: Context,
251
224
  type: IntrospectionObjectType & {
252
- fieldsByName: {[name: string]: IntrospectionField},
225
+ fieldsByName: {
226
+ [name: string]: IntrospectionField
227
+ }
253
228
  },
254
229
  typeName: string,
255
230
  selections: Selections,
256
- ): Array<BabelNodeObjectTypeProperty | BabelNodeObjectTypeSpreadProperty> => {
257
- return [].concat(
258
- ...selections.map((selection) => {
259
- switch (selection.kind) {
260
- case 'InlineFragment': {
261
- const newTypeName =
262
- selection.typeCondition?.name.value ?? typeName;
263
- if (newTypeName !== typeName) {
264
- return [];
265
- }
266
- return objectPropertiesToFlow(
267
- ctx,
268
- ctx.schema.typesByName[newTypeName],
269
- newTypeName,
270
- selection.selectionSet.selections,
271
- );
231
+ ): Array<babelTypes.TSPropertySignature> => {
232
+ return selections.flatMap((selection) => {
233
+ switch (selection.kind) {
234
+ case 'InlineFragment': {
235
+ const newTypeName =
236
+ selection.typeCondition?.name.value ?? typeName;
237
+ if (newTypeName !== typeName) {
238
+ return [];
272
239
  }
273
- case 'FragmentSpread':
274
- if (!ctx.fragments[selection.name.value]) {
275
- ctx.errors.push(
276
- `No fragment named '${selection.name.value}'. Did you forget to include it in the template literal?`,
277
- );
278
- return [
279
- babelTypes.objectTypeProperty(
280
- babelTypes.identifier(selection.name.value),
281
- babelTypes.genericTypeAnnotation(
240
+ return objectPropertiesToFlow(
241
+ ctx,
242
+ ctx.schema.typesByName[newTypeName],
243
+ newTypeName,
244
+ selection.selectionSet.selections,
245
+ );
246
+ }
247
+ case 'FragmentSpread':
248
+ if (!ctx.fragments[selection.name.value]) {
249
+ ctx.errors.push(
250
+ `No fragment named '${selection.name.value}'. Did you forget to include it in the template literal?`,
251
+ );
252
+ return [
253
+ babelTypes.tsPropertySignature(
254
+ babelTypes.identifier(selection.name.value),
255
+ babelTypes.tsTypeAnnotation(
256
+ babelTypes.tsTypeReference(
282
257
  babelTypes.identifier(`UNKNOWN_FRAGMENT`),
283
- ),
258
+ )
284
259
  ),
285
- ];
286
- }
260
+ ),
261
+ ];
262
+ }
287
263
 
288
- return objectPropertiesToFlow(
289
- ctx,
290
- type,
291
- typeName,
292
- ctx.fragments[selection.name.value].selectionSet
293
- .selections,
294
- );
264
+ return objectPropertiesToFlow(
265
+ ctx,
266
+ type,
267
+ typeName,
268
+ ctx.fragments[selection.name.value].selectionSet
269
+ .selections,
270
+ );
295
271
 
296
- case 'Field':
297
- const name = selection.name.value;
298
- const alias: string = selection.alias
299
- ? selection.alias.value
300
- : name;
301
- if (name === '__typename') {
302
- return [
303
- babelTypes.objectTypeProperty(
304
- babelTypes.identifier(alias),
305
- babelTypes.stringLiteralTypeAnnotation(
306
- typeName,
272
+ case 'Field':
273
+ const name = selection.name.value;
274
+ const alias: string = selection.alias
275
+ ? selection.alias.value
276
+ : name;
277
+ if (name === '__typename') {
278
+ return [
279
+ babelTypes.tsPropertySignature(
280
+ babelTypes.identifier(alias),
281
+ babelTypes.tsTypeAnnotation(
282
+ babelTypes.tsLiteralType(
283
+ babelTypes.stringLiteral(typeName),
307
284
  ),
308
285
  ),
309
- ];
310
- }
311
- if (!type.fieldsByName[name]) {
312
- ctx.errors.push(
313
- `Unknown field '${name}' for type '${typeName}'`,
314
- );
315
- return babelTypes.objectTypeProperty(
286
+ ),
287
+ ];
288
+ }
289
+ if (!type.fieldsByName[name]) {
290
+ ctx.errors.push(
291
+ `Unknown field '${name}' for type '${typeName}'`,
292
+ );
293
+ return [
294
+ babelTypes.tsPropertySignature(
316
295
  babelTypes.identifier(alias),
317
- babelTypes.genericTypeAnnotation(
318
- babelTypes.identifier(
319
- `UNKNOWN_FIELD["${name}"]`,
320
- ),
296
+ babelTypes.tsTypeAnnotation(
297
+ babelTypes.tsTypeReference(
298
+ babelTypes.identifier(
299
+ `UNKNOWN_FIELD["${name}"]`,
300
+ ),
301
+ )
321
302
  ),
322
- );
323
- }
324
- const typeField = type.fieldsByName[name];
303
+ )
304
+ ];
305
+ }
306
+ const typeField = type.fieldsByName[name];
325
307
 
326
- return [
327
- maybeAddDescriptionComment(
328
- typeField.description,
329
- liftLeadingPropertyComments(
330
- babelTypes.objectTypeProperty(
331
- babelTypes.identifier(alias),
308
+ return [
309
+ maybeAddDescriptionComment(
310
+ typeField.description,
311
+ liftLeadingPropertyComments(
312
+ babelTypes.tsPropertySignature(
313
+ babelTypes.identifier(alias),
314
+ babelTypes.tsTypeAnnotation(
332
315
  typeToFlow(
333
316
  {
334
317
  ...ctx,
@@ -337,46 +320,44 @@ export const objectPropertiesToFlow = (
337
320
  typeField.type,
338
321
  selection,
339
322
  ),
340
- ),
323
+ )
341
324
  ),
342
325
  ),
343
- ];
326
+ ),
327
+ ];
344
328
 
345
- default:
346
- ctx.errors.push(
347
- // eslint-disable-next-line flowtype-errors/uncovered
348
- `Unsupported selection kind '${selection.kind}'`,
349
- );
350
- return [];
351
- }
352
- }),
353
- );
329
+ default:
330
+ ctx.errors.push(
331
+ // @ts-expect-error: `selection` is `never` here
332
+ `Unsupported selection kind '${selection.kind}'`,
333
+ );
334
+ return [];
335
+ }
336
+ });
354
337
  };
355
338
 
356
339
  export const unionOrInterfaceToFlow = (
357
340
  ctx: Context,
358
- type:
359
- | IntrospectionUnionType
360
- | (IntrospectionInterfaceType & {
361
- fieldsByName: {[key: string]: IntrospectionField},
362
- }),
341
+ type: IntrospectionUnionType | IntrospectionInterfaceType & {
342
+ fieldsByName: {
343
+ [key: string]: IntrospectionField
344
+ }
345
+ },
363
346
  selections: Selections,
364
- ): BabelNodeFlowType => {
347
+ ): TSType => {
365
348
  const allFields = selections.every(
366
349
  (selection) => selection.kind === 'Field',
367
350
  );
368
351
  const selectedAttributes: Array<{
369
- attributes: Array<
370
- BabelNodeObjectTypeProperty | BabelNodeObjectTypeSpreadProperty,
371
- >,
372
- typeName: string,
352
+ attributes: Array<babelTypes.TSPropertySignature>
353
+ typeName: string
373
354
  }> = type.possibleTypes
374
355
  .slice()
375
356
  .sort((a, b) => {
376
357
  return a.name < b.name ? -1 : 1;
377
358
  })
378
359
  .map((possible) => {
379
- const configWithUpdatedPath = {
360
+ const configWithUpdatedPath: Context = {
380
361
  ...ctx,
381
362
  path: allFields ? ctx.path : ctx.path.concat([possible.name]),
382
363
  };
@@ -401,22 +382,23 @@ export const unionOrInterfaceToFlow = (
401
382
  const sharedAttributes = selectedAttributes[0].attributes.slice();
402
383
  const typeNameIndex = selectedAttributes[0].attributes.findIndex(
403
384
  (x) =>
404
- x.type === 'ObjectTypeProperty' &&
385
+ x.type === 'TSPropertySignature' &&
405
386
  x.key.type === 'Identifier' &&
406
387
  x.key.name === '__typename',
407
388
  );
408
389
  if (typeNameIndex !== -1) {
409
- sharedAttributes[typeNameIndex] = babelTypes.objectTypeProperty(
390
+ sharedAttributes[typeNameIndex] = babelTypes.tsPropertySignature(
410
391
  babelTypes.identifier('__typename'),
411
- babelTypes.unionTypeAnnotation(
412
- selectedAttributes.map(
413
- (attrs) =>
414
- // eslint-disable-next-line flowtype-errors/uncovered
415
- ((attrs.attributes[
416
- typeNameIndex
417
- ]: any): BabelNodeObjectTypeProperty).value,
392
+ babelTypes.tsTypeAnnotation(
393
+ babelTypes.tsUnionType(
394
+ selectedAttributes.map(
395
+ (attrs) =>
396
+ (attrs.attributes[
397
+ typeNameIndex
398
+ ] as babelTypes.TSPropertySignature).typeAnnotation!.typeAnnotation,
399
+ ),
418
400
  ),
419
- ),
401
+ )
420
402
  );
421
403
  }
422
404
  return sortedObjectTypeAnnotation(ctx, sharedAttributes);
@@ -457,7 +439,7 @@ export const unionOrInterfaceToFlow = (
457
439
  * ```
458
440
  * instead of e.g. `getHuman_me_Human`.
459
441
  */
460
- const result = babelTypes.unionTypeAnnotation(
442
+ const result = babelTypes.tsUnionType(
461
443
  selectedAttributes.map(({typeName, attributes}) =>
462
444
  sortedObjectTypeAnnotation(
463
445
  {...ctx, path: ctx.path.concat([typeName])},
@@ -468,24 +450,25 @@ export const unionOrInterfaceToFlow = (
468
450
  const name = ctx.path.join('_');
469
451
  if (ctx.allObjectTypes && ctx.path.length > 1) {
470
452
  ctx.allObjectTypes[name] = result;
471
- return babelTypes.genericTypeAnnotation(babelTypes.identifier(name));
453
+ return babelTypes.tsTypeReference(
454
+ babelTypes.identifier(name),
455
+ );
472
456
  }
473
457
  return result;
474
458
  };
475
- const unionOrInterfaceSelection = (
476
- config,
477
- type,
478
- possible,
479
- selection,
480
- ): Array<BabelNodeObjectTypeProperty | BabelNodeObjectTypeSpreadProperty> => {
459
+ const unionOrInterfaceSelection = (config: Context, type: any, possible: any, selection: SelectionNode): Array<babelTypes.TSPropertySignature> => {
481
460
  if (selection.kind === 'Field' && selection.name.value === '__typename') {
482
461
  const alias = selection.alias
483
462
  ? selection.alias.value
484
463
  : selection.name.value;
485
464
  return [
486
- babelTypes.objectTypeProperty(
465
+ babelTypes.tsPropertySignature(
487
466
  babelTypes.identifier(alias),
488
- babelTypes.stringLiteralTypeAnnotation(possible.name),
467
+ babelTypes.tsTypeAnnotation(
468
+ babelTypes.tsLiteralType(
469
+ babelTypes.stringLiteral(possible.name),
470
+ ),
471
+ ),
489
472
  ),
490
473
  ];
491
474
  }
@@ -503,10 +486,12 @@ const unionOrInterfaceSelection = (
503
486
  possible.name,
504
487
  );
505
488
  return [
506
- babelTypes.objectTypeProperty(
489
+ babelTypes.tsPropertySignature(
507
490
  babelTypes.identifier(alias),
508
- babelTypes.genericTypeAnnotation(
509
- babelTypes.identifier(`UNKNOWN_FIELD`),
491
+ babelTypes.tsTypeAnnotation(
492
+ babelTypes.tsTypeReference(
493
+ babelTypes.identifier(`UNKNOWN_FIELD`),
494
+ ),
510
495
  ),
511
496
  ),
512
497
  ];
@@ -514,12 +499,14 @@ const unionOrInterfaceSelection = (
514
499
  const typeField = type.fieldsByName[name];
515
500
  return [
516
501
  liftLeadingPropertyComments(
517
- babelTypes.objectTypeProperty(
502
+ babelTypes.tsPropertySignature(
518
503
  babelTypes.identifier(alias),
519
- typeToFlow(
520
- {...config, path: config.path.concat([name])},
521
- typeField.type,
522
- selection,
504
+ babelTypes.tsTypeAnnotation(
505
+ typeToFlow(
506
+ {...config, path: config.path.concat([name])},
507
+ typeField.type,
508
+ selection,
509
+ ),
523
510
  ),
524
511
  ),
525
512
  ),
@@ -538,14 +525,12 @@ const unionOrInterfaceSelection = (
538
525
  ]) ||
539
526
  typeName === possible.name
540
527
  ) {
541
- return [].concat(
542
- ...fragment.selectionSet.selections.map((selection) =>
543
- unionOrInterfaceSelection(
544
- config,
545
- config.schema.typesByName[possible.name],
546
- possible,
547
- selection,
548
- ),
528
+ return fragment.selectionSet.selections.flatMap((selection: SelectionNode) =>
529
+ unionOrInterfaceSelection(
530
+ config,
531
+ config.schema.typesByName[possible.name],
532
+ possible,
533
+ selection,
549
534
  ),
550
535
  );
551
536
  } else {
@@ -1,15 +1,10 @@
1
- // @flow
2
1
  import type {DocumentNode} from 'graphql';
3
2
  import type {GenerateConfig, CrawlConfig, Schema} from './types';
4
3
  import fs from 'fs';
5
4
  import path from 'path';
6
5
  import {documentToFlowTypes} from '.';
7
- // eslint-disable-next-line flowtype-errors/uncovered
8
- import {convert} from '@khanacademy/flow-to-ts/dist/convert.bundle';
9
6
 
10
- export const indexPrelude = (regenerateCommand?: string): string => `// @flow
11
- //
12
- // AUTOGENERATED
7
+ export const indexPrelude = (regenerateCommand?: string): string => `// AUTOGENERATED
13
8
  // NOTE: New response types are added to this file automatically.
14
9
  // Outdated response types can be removed manually as they are deprecated.
15
10
  //${regenerateCommand ? ' To regenerate, run ' + regenerateCommand : ''}
@@ -24,14 +19,19 @@ export const generateTypeFileContents = (
24
19
  options: GenerateConfig,
25
20
  generatedDir: string,
26
21
  indexContents: string,
27
- ): {indexContents: string, files: {[key: string]: string}} => {
28
- const files = {};
22
+ ): {
23
+ indexContents: string
24
+ files: {
25
+ [key: string]: string
26
+ }
27
+ } => {
28
+ const files: Record<string, any> = {};
29
29
 
30
- /// Write export for __generated__/index.js if it doesn't exist
31
- const addToIndex = (filePath, typeName) => {
30
+ /// Write export for __generated__/index.ts if it doesn't exist
31
+ const addToIndex = (filePath: string, typeName: unknown) => {
32
32
  if (options.typeScript || options.omitFileExtensions) {
33
33
  // Typescript doesn't like file extensions
34
- filePath = filePath.replace(/\.js$/, '');
34
+ filePath = filePath.replace(/\.ts$/, '');
35
35
  }
36
36
  const newLine = `export type {${typeName}} from './${path.basename(
37
37
  filePath,
@@ -50,12 +50,11 @@ export const generateTypeFileContents = (
50
50
  // things tidy.
51
51
  const targetFileName = options.typeFileName
52
52
  ? options.typeFileName.replace('[operationName]', name)
53
- : `${name}.js`;
53
+ : `${name}.ts`;
54
54
  const targetPath = path.join(generatedDir, targetFileName);
55
55
 
56
56
  let fileContents =
57
- '// @' +
58
- `flow\n// AUTOGENERATED -- DO NOT EDIT\n` +
57
+ `// AUTOGENERATED -- DO NOT EDIT\n` +
59
58
  `// Generated for operation '${name}' in file '../${path.basename(
60
59
  fileName,
61
60
  )}'\n` +
@@ -120,10 +119,7 @@ export const generateTypeFiles = (
120
119
  options: GenerateConfig,
121
120
  ) => {
122
121
  const generatedDir = getGeneratedDir(fileName, options);
123
- const indexFile = path.join(
124
- generatedDir,
125
- 'index' + (options.typeScript ? '.ts' : '.js'),
126
- );
122
+ const indexFile = path.join(generatedDir, 'index.ts');
127
123
 
128
124
  if (!fs.existsSync(generatedDir)) {
129
125
  fs.mkdirSync(generatedDir, {recursive: true});
@@ -142,17 +138,8 @@ export const generateTypeFiles = (
142
138
  );
143
139
 
144
140
  fs.writeFileSync(indexFile, indexContents);
145
- Object.keys(files).forEach((key) => {
146
- let fname = key;
147
- if (options.typeScript) {
148
- // eslint-disable-next-line flowtype-errors/uncovered
149
- files[key] = convert(files[key]).replace(
150
- `variables: {}`,
151
- `variables: Record<never, never>`,
152
- );
153
- fname = key.replace(/\.js$/, '.ts');
154
- }
155
- fs.writeFileSync(fname, files[key]);
141
+ Object.keys(files).forEach((fname) => {
142
+ fs.writeFileSync(fname, files[fname]);
156
143
  });
157
144
 
158
145
  fs.writeFileSync(indexFile, indexContents);
@@ -162,7 +149,10 @@ export const processPragmas = (
162
149
  generateConfig: GenerateConfig,
163
150
  crawlConfig: CrawlConfig,
164
151
  rawSource: string,
165
- ): {generate: boolean, strict?: boolean} => {
152
+ ): {
153
+ generate: boolean
154
+ strict?: boolean
155
+ } => {
166
156
  if (
167
157
  crawlConfig.ignorePragma &&
168
158
  rawSource.includes(crawlConfig.ignorePragma)