@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.
- package/.babelrc +1 -1
- package/.eslintrc.js +0 -1
- package/.github/workflows/changeset-release.yml +1 -1
- package/CHANGELOG.md +10 -0
- package/dist/cli/config.js +2 -4
- package/dist/cli/run.js +1 -2
- package/dist/enums.js +8 -9
- package/dist/generateResponseType.js +33 -41
- package/dist/generateTypeFiles.js +9 -23
- package/dist/generateVariablesType.js +15 -31
- package/dist/index.js +8 -15
- package/dist/parser/parse.js +6 -7
- package/dist/parser/resolve.js +1 -2
- package/dist/parser/utils.js +1 -2
- package/dist/schemaFromIntrospectionData.js +1 -2
- package/dist/types.js +1 -2
- package/dist/utils.js +43 -3
- package/package.json +8 -7
- package/{dist/__test__/generateTypeFileContents.test.js → src/__test__/generateTypeFileContents.test.ts} +38 -41
- package/{dist/__test__/graphql-flow.test.js → src/__test__/graphql-flow.test.ts} +232 -235
- package/src/__test__/{processPragmas.test.js → processPragmas.test.ts} +0 -1
- package/{dist/cli/__test__/config.test.js → src/cli/__test__/config.test.ts} +5 -6
- package/{dist/cli/config.js.flow → src/cli/config.ts} +6 -11
- package/src/cli/{run.js → run.ts} +5 -4
- package/src/{enums.js → enums.ts} +20 -22
- package/src/{generateResponseType.js → generateResponseType.ts} +167 -182
- package/src/{generateTypeFiles.js → generateTypeFiles.ts} +20 -30
- package/src/{generateVariablesType.js → generateVariablesType.ts} +34 -44
- package/{dist/index.js.flow → src/index.ts} +32 -24
- package/{dist/parser/__test__/parse.test.js → src/parser/__test__/parse.test.ts} +12 -11
- package/src/parser/{parse.js → parse.ts} +65 -47
- package/{dist/parser/resolve.js.flow → src/parser/resolve.ts} +15 -11
- package/{dist/parser/utils.js.flow → src/parser/utils.ts} +0 -1
- package/{dist/schemaFromIntrospectionData.js.flow → src/schemaFromIntrospectionData.ts} +1 -4
- package/src/types.ts +97 -0
- package/src/utils.ts +73 -0
- package/tools/{find-files-with-gql.js → find-files-with-gql.ts} +2 -3
- package/tsconfig.json +110 -0
- package/types/flow-to-ts.d.ts +1 -0
- package/dist/__test__/example-schema.graphql +0 -67
- package/dist/__test__/processPragmas.test.js +0 -76
- package/dist/cli/config.js.map +0 -1
- package/dist/cli/run.js.flow +0 -236
- package/dist/cli/run.js.map +0 -1
- package/dist/enums.js.flow +0 -98
- package/dist/enums.js.map +0 -1
- package/dist/generateResponseType.js.flow +0 -583
- package/dist/generateResponseType.js.map +0 -1
- package/dist/generateTypeFiles.js.flow +0 -191
- package/dist/generateTypeFiles.js.map +0 -1
- package/dist/generateVariablesType.js.flow +0 -156
- package/dist/generateVariablesType.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/parser/parse.js.flow +0 -417
- package/dist/parser/parse.js.map +0 -1
- package/dist/parser/resolve.js.map +0 -1
- package/dist/parser/utils.js.map +0 -1
- package/dist/schemaFromIntrospectionData.js.map +0 -1
- package/dist/types.js.flow +0 -88
- package/dist/types.js.map +0 -1
- package/dist/utils.js.flow +0 -50
- package/dist/utils.js.map +0 -1
- package/flow-typed/npm/@babel/types_vx.x.x.js +0 -5331
- package/flow-typed/npm/jest_v23.x.x.js +0 -1155
- package/flow-typed/overrides.js +0 -435
- package/src/__test__/generateTypeFileContents.test.js +0 -157
- package/src/__test__/graphql-flow.test.js +0 -639
- package/src/cli/__test__/config.test.js +0 -120
- package/src/cli/config.js +0 -84
- package/src/cli/schema.json +0 -97
- package/src/index.js +0 -160
- package/src/parser/__test__/parse.test.js +0 -249
- package/src/parser/resolve.js +0 -119
- package/src/parser/utils.js +0 -25
- package/src/schemaFromIntrospectionData.js +0 -68
- package/src/types.js +0 -88
- package/src/utils.js +0 -50
- /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 {
|
|
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
|
-
|
|
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 === '
|
|
57
|
-
b.type === '
|
|
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.
|
|
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.
|
|
107
|
+
return babelTypes.tsTypeReference(
|
|
128
108
|
ctx.readOnlyArray
|
|
129
|
-
? babelTypes.identifier('
|
|
109
|
+
? babelTypes.identifier('ReadonlyArray')
|
|
130
110
|
: babelTypes.identifier('Array'),
|
|
131
|
-
babelTypes.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 =
|
|
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 === '
|
|
190
|
+
type.type === 'TSPropertySignature' &&
|
|
191
|
+
type.key.type === "Identifier" &&
|
|
215
192
|
type.key.name === '__typename'
|
|
216
193
|
) {
|
|
217
194
|
const name =
|
|
218
|
-
type.
|
|
219
|
-
|
|
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: {
|
|
225
|
+
fieldsByName: {
|
|
226
|
+
[name: string]: IntrospectionField
|
|
227
|
+
}
|
|
253
228
|
},
|
|
254
229
|
typeName: string,
|
|
255
230
|
selections: Selections,
|
|
256
|
-
): Array<
|
|
257
|
-
return
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
264
|
+
return objectPropertiesToFlow(
|
|
265
|
+
ctx,
|
|
266
|
+
type,
|
|
267
|
+
typeName,
|
|
268
|
+
ctx.fragments[selection.name.value].selectionSet
|
|
269
|
+
.selections,
|
|
270
|
+
);
|
|
295
271
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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.
|
|
318
|
-
babelTypes.
|
|
319
|
-
|
|
320
|
-
|
|
296
|
+
babelTypes.tsTypeAnnotation(
|
|
297
|
+
babelTypes.tsTypeReference(
|
|
298
|
+
babelTypes.identifier(
|
|
299
|
+
`UNKNOWN_FIELD["${name}"]`,
|
|
300
|
+
),
|
|
301
|
+
)
|
|
321
302
|
),
|
|
322
|
-
)
|
|
323
|
-
|
|
324
|
-
|
|
303
|
+
)
|
|
304
|
+
];
|
|
305
|
+
}
|
|
306
|
+
const typeField = type.fieldsByName[name];
|
|
325
307
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
341
|
+
type: IntrospectionUnionType | IntrospectionInterfaceType & {
|
|
342
|
+
fieldsByName: {
|
|
343
|
+
[key: string]: IntrospectionField
|
|
344
|
+
}
|
|
345
|
+
},
|
|
363
346
|
selections: Selections,
|
|
364
|
-
):
|
|
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
|
-
|
|
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 === '
|
|
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.
|
|
390
|
+
sharedAttributes[typeNameIndex] = babelTypes.tsPropertySignature(
|
|
410
391
|
babelTypes.identifier('__typename'),
|
|
411
|
-
babelTypes.
|
|
412
|
-
|
|
413
|
-
(
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
465
|
+
babelTypes.tsPropertySignature(
|
|
487
466
|
babelTypes.identifier(alias),
|
|
488
|
-
babelTypes.
|
|
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.
|
|
489
|
+
babelTypes.tsPropertySignature(
|
|
507
490
|
babelTypes.identifier(alias),
|
|
508
|
-
babelTypes.
|
|
509
|
-
babelTypes.
|
|
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.
|
|
502
|
+
babelTypes.tsPropertySignature(
|
|
518
503
|
babelTypes.identifier(alias),
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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 => `//
|
|
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
|
-
): {
|
|
28
|
-
|
|
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.
|
|
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(/\.
|
|
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}.
|
|
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((
|
|
146
|
-
|
|
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
|
-
): {
|
|
152
|
+
): {
|
|
153
|
+
generate: boolean
|
|
154
|
+
strict?: boolean
|
|
155
|
+
} => {
|
|
166
156
|
if (
|
|
167
157
|
crawlConfig.ignorePragma &&
|
|
168
158
|
rawSource.includes(crawlConfig.ignorePragma)
|