@khanacademy/graphql-flow 0.3.0 → 1.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/.github/workflows/pr-checks.yml +4 -6
- package/CHANGELOG.md +22 -0
- package/Readme.md +41 -167
- package/dist/__test__/example-schema.graphql +67 -0
- package/dist/__test__/generateTypeFileContents.test.js +157 -0
- package/dist/__test__/graphql-flow.test.js +639 -0
- package/dist/__test__/processPragmas.test.js +76 -0
- package/dist/cli/__test__/config.test.js +120 -0
- package/dist/cli/config.js +45 -106
- package/dist/cli/config.js.flow +37 -159
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/run.js +40 -36
- package/dist/cli/run.js.flow +56 -42
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/schema.json +91 -0
- package/dist/enums.js +9 -9
- package/dist/enums.js.flow +11 -11
- package/dist/enums.js.map +1 -1
- package/dist/generateResponseType.js +47 -47
- package/dist/generateResponseType.js.flow +55 -57
- package/dist/generateResponseType.js.map +1 -1
- package/dist/generateTypeFiles.js +13 -17
- package/dist/generateTypeFiles.js.flow +21 -43
- package/dist/generateTypeFiles.js.map +1 -1
- package/dist/generateVariablesType.js +24 -24
- package/dist/generateVariablesType.js.flow +25 -28
- package/dist/generateVariablesType.js.map +1 -1
- package/dist/index.js +0 -8
- package/dist/index.js.flow +4 -5
- package/dist/index.js.map +1 -1
- package/dist/parser/__test__/parse.test.js +247 -0
- package/dist/types.js.flow +26 -6
- package/package.json +3 -2
- package/src/__test__/generateTypeFileContents.test.js +3 -1
- package/src/__test__/graphql-flow.test.js +7 -7
- package/src/__test__/processPragmas.test.js +28 -15
- package/src/cli/__test__/config.test.js +110 -84
- package/src/cli/config.js +37 -159
- package/src/cli/run.js +56 -42
- package/src/cli/schema.json +91 -0
- package/src/enums.js +11 -11
- package/src/generateResponseType.js +55 -57
- package/src/generateTypeFiles.js +21 -43
- package/src/generateVariablesType.js +25 -28
- package/src/index.js +4 -5
- package/src/types.js +26 -6
- package/dist/cli/utils.js +0 -21
- package/dist/cli/utils.js.flow +0 -14
- package/dist/cli/utils.js.map +0 -1
- package/dist/jest-mock-graphql-tag.js +0 -88
- package/dist/jest-mock-graphql-tag.js.flow +0 -96
- package/dist/jest-mock-graphql-tag.js.map +0 -1
- package/src/cli/__test__/utils.test.js +0 -19
- package/src/cli/utils.js +0 -14
- package/src/jest-mock-graphql-tag.js +0 -96
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tests for our graphql flow generation!
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {getSchemas} from '../cli/config';
|
|
8
|
+
import {documentToFlowTypes} from '..';
|
|
9
|
+
import gql from 'graphql-tag';
|
|
10
|
+
|
|
11
|
+
import type {GenerateConfig} from '../types';
|
|
12
|
+
|
|
13
|
+
// This allows us to "snapshot" a string cleanly.
|
|
14
|
+
/* eslint-disable flowtype-errors/uncovered */
|
|
15
|
+
expect.addSnapshotSerializer({
|
|
16
|
+
test: (value) => value && typeof value === 'string',
|
|
17
|
+
print: (value, _, __) => value,
|
|
18
|
+
});
|
|
19
|
+
/* eslint-enable flowtype-errors/uncovered */
|
|
20
|
+
|
|
21
|
+
const [_, exampleSchema] = getSchemas(__dirname + '/example-schema.graphql');
|
|
22
|
+
|
|
23
|
+
const rawQueryToFlowTypes = (
|
|
24
|
+
query: string,
|
|
25
|
+
options?: $Partial<GenerateConfig>,
|
|
26
|
+
): string => {
|
|
27
|
+
const node = gql(query);
|
|
28
|
+
return documentToFlowTypes(node, exampleSchema, {
|
|
29
|
+
schemaFilePath: '',
|
|
30
|
+
scalars: {PositiveNumber: 'number'},
|
|
31
|
+
...options,
|
|
32
|
+
})
|
|
33
|
+
.map(
|
|
34
|
+
({typeName, code, extraTypes}) =>
|
|
35
|
+
`// ${typeName}.js\n${code}` +
|
|
36
|
+
Object.keys(extraTypes)
|
|
37
|
+
.sort()
|
|
38
|
+
.map((k) => `\nexport type ${k} = ${extraTypes[k]};`)
|
|
39
|
+
.join(''),
|
|
40
|
+
)
|
|
41
|
+
.join('\n\n');
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
describe('graphql-flow generation', () => {
|
|
45
|
+
it('should allow custom scalars as input', () => {
|
|
46
|
+
const result = rawQueryToFlowTypes(`
|
|
47
|
+
query SomeQuery($candies: PositiveNumber!) {
|
|
48
|
+
candies(number: $candies)
|
|
49
|
+
}
|
|
50
|
+
`);
|
|
51
|
+
|
|
52
|
+
expect(result).toMatchInlineSnapshot(`
|
|
53
|
+
// SomeQueryType.js
|
|
54
|
+
export type SomeQueryType = {|
|
|
55
|
+
variables: {|
|
|
56
|
+
candies: number
|
|
57
|
+
|},
|
|
58
|
+
response: {|
|
|
59
|
+
candies: ?string
|
|
60
|
+
|}
|
|
61
|
+
|};
|
|
62
|
+
`);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should split types', () => {
|
|
66
|
+
const result = rawQueryToFlowTypes(
|
|
67
|
+
`
|
|
68
|
+
query SomeQuery($id: String!) {
|
|
69
|
+
human(id: $id) { id }
|
|
70
|
+
}
|
|
71
|
+
`,
|
|
72
|
+
{splitTypes: true},
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
expect(result).toMatchInlineSnapshot(`
|
|
76
|
+
// SomeQueryType.js
|
|
77
|
+
export type SomeQueryType = {|
|
|
78
|
+
variables: {|
|
|
79
|
+
id: string
|
|
80
|
+
|},
|
|
81
|
+
response: {|
|
|
82
|
+
|
|
83
|
+
/** A human character*/
|
|
84
|
+
human: ?{|
|
|
85
|
+
id: string
|
|
86
|
+
|}
|
|
87
|
+
|}
|
|
88
|
+
|};
|
|
89
|
+
`);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should work with a basic query', () => {
|
|
93
|
+
const result = rawQueryToFlowTypes(`
|
|
94
|
+
query SomeQuery {
|
|
95
|
+
human(id: "Han Solo") {
|
|
96
|
+
id
|
|
97
|
+
name
|
|
98
|
+
homePlanet
|
|
99
|
+
friends {
|
|
100
|
+
name
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
`);
|
|
105
|
+
|
|
106
|
+
expect(result).toMatchInlineSnapshot(`
|
|
107
|
+
// SomeQueryType.js
|
|
108
|
+
export type SomeQueryType = {|
|
|
109
|
+
variables: {||},
|
|
110
|
+
response: {|
|
|
111
|
+
|
|
112
|
+
/** A human character*/
|
|
113
|
+
human: ?{|
|
|
114
|
+
friends: ?$ReadOnlyArray<?{|
|
|
115
|
+
name: ?string
|
|
116
|
+
|}>,
|
|
117
|
+
homePlanet: ?string,
|
|
118
|
+
id: string,
|
|
119
|
+
|
|
120
|
+
/** The person's name*/
|
|
121
|
+
name: ?string,
|
|
122
|
+
|}
|
|
123
|
+
|}
|
|
124
|
+
|};
|
|
125
|
+
`);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('renames', () => {
|
|
129
|
+
const result = rawQueryToFlowTypes(`
|
|
130
|
+
query SomeQuery {
|
|
131
|
+
human(id: "Han Solo") {
|
|
132
|
+
notDead: alive
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
`);
|
|
136
|
+
|
|
137
|
+
expect(result).toMatchInlineSnapshot(`
|
|
138
|
+
// SomeQueryType.js
|
|
139
|
+
export type SomeQueryType = {|
|
|
140
|
+
variables: {||},
|
|
141
|
+
response: {|
|
|
142
|
+
|
|
143
|
+
/** A human character*/
|
|
144
|
+
human: ?{|
|
|
145
|
+
notDead: ?boolean
|
|
146
|
+
|}
|
|
147
|
+
|}
|
|
148
|
+
|};
|
|
149
|
+
`);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should work with unions', () => {
|
|
153
|
+
const result = rawQueryToFlowTypes(`
|
|
154
|
+
query SomeQuery {
|
|
155
|
+
friend(id: "Han Solo") {
|
|
156
|
+
__typename
|
|
157
|
+
... on Human {
|
|
158
|
+
id
|
|
159
|
+
hands
|
|
160
|
+
}
|
|
161
|
+
... on Droid {
|
|
162
|
+
primaryFunction
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
`);
|
|
167
|
+
expect(result).toMatchInlineSnapshot(`
|
|
168
|
+
// SomeQueryType.js
|
|
169
|
+
export type SomeQueryType = {|
|
|
170
|
+
variables: {||},
|
|
171
|
+
response: {|
|
|
172
|
+
friend: ?({|
|
|
173
|
+
__typename: "Animal"
|
|
174
|
+
|} | {|
|
|
175
|
+
__typename: "Droid",
|
|
176
|
+
|
|
177
|
+
/** The robot's primary function*/
|
|
178
|
+
primaryFunction: string,
|
|
179
|
+
|} | {|
|
|
180
|
+
__typename: "Human",
|
|
181
|
+
hands: ?number,
|
|
182
|
+
id: string,
|
|
183
|
+
|})
|
|
184
|
+
|}
|
|
185
|
+
|};
|
|
186
|
+
`);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should work with fragments on interface', () => {
|
|
190
|
+
const result = rawQueryToFlowTypes(`
|
|
191
|
+
query SomeQuery {
|
|
192
|
+
human(id: "Han Solo") {
|
|
193
|
+
id
|
|
194
|
+
name
|
|
195
|
+
homePlanet
|
|
196
|
+
hands
|
|
197
|
+
alive
|
|
198
|
+
friends {
|
|
199
|
+
...Profile
|
|
200
|
+
... on Human {
|
|
201
|
+
hands
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
fragment Profile on Character {
|
|
208
|
+
__typename
|
|
209
|
+
id
|
|
210
|
+
name
|
|
211
|
+
friends {
|
|
212
|
+
id
|
|
213
|
+
}
|
|
214
|
+
appearsIn
|
|
215
|
+
}
|
|
216
|
+
`);
|
|
217
|
+
|
|
218
|
+
expect(result).toMatchInlineSnapshot(`
|
|
219
|
+
// SomeQueryType.js
|
|
220
|
+
export type SomeQueryType = {|
|
|
221
|
+
variables: {||},
|
|
222
|
+
response: {|
|
|
223
|
+
|
|
224
|
+
/** A human character*/
|
|
225
|
+
human: ?{|
|
|
226
|
+
alive: ?boolean,
|
|
227
|
+
friends: ?$ReadOnlyArray<?({|
|
|
228
|
+
__typename: "Droid",
|
|
229
|
+
appearsIn: ?$ReadOnlyArray<
|
|
230
|
+
/** - NEW_HOPE
|
|
231
|
+
- EMPIRE
|
|
232
|
+
- JEDI*/
|
|
233
|
+
?("NEW_HOPE" | "EMPIRE" | "JEDI")>,
|
|
234
|
+
friends: ?$ReadOnlyArray<?{|
|
|
235
|
+
id: string
|
|
236
|
+
|}>,
|
|
237
|
+
id: string,
|
|
238
|
+
name: ?string,
|
|
239
|
+
|} | {|
|
|
240
|
+
__typename: "Human",
|
|
241
|
+
appearsIn: ?$ReadOnlyArray<
|
|
242
|
+
/** - NEW_HOPE
|
|
243
|
+
- EMPIRE
|
|
244
|
+
- JEDI*/
|
|
245
|
+
?("NEW_HOPE" | "EMPIRE" | "JEDI")>,
|
|
246
|
+
friends: ?$ReadOnlyArray<?{|
|
|
247
|
+
id: string
|
|
248
|
+
|}>,
|
|
249
|
+
hands: ?number,
|
|
250
|
+
id: string,
|
|
251
|
+
name: ?string,
|
|
252
|
+
|})>,
|
|
253
|
+
hands: ?number,
|
|
254
|
+
homePlanet: ?string,
|
|
255
|
+
id: string,
|
|
256
|
+
|
|
257
|
+
/** The person's name*/
|
|
258
|
+
name: ?string,
|
|
259
|
+
|}
|
|
260
|
+
|}
|
|
261
|
+
|};
|
|
262
|
+
|
|
263
|
+
// Profile.js
|
|
264
|
+
export type Profile = {|
|
|
265
|
+
__typename: "Droid" | "Human",
|
|
266
|
+
appearsIn: ?$ReadOnlyArray<
|
|
267
|
+
/** - NEW_HOPE
|
|
268
|
+
- EMPIRE
|
|
269
|
+
- JEDI*/
|
|
270
|
+
?("NEW_HOPE" | "EMPIRE" | "JEDI")>,
|
|
271
|
+
friends: ?$ReadOnlyArray<?{|
|
|
272
|
+
id: string
|
|
273
|
+
|}>,
|
|
274
|
+
id: string,
|
|
275
|
+
name: ?string,
|
|
276
|
+
|};
|
|
277
|
+
`);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('should work with a readOnlyArray turned off', () => {
|
|
281
|
+
const result = rawQueryToFlowTypes(
|
|
282
|
+
`
|
|
283
|
+
query SomeQuery {
|
|
284
|
+
human(id: "Han Solo") {
|
|
285
|
+
friends {
|
|
286
|
+
name
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
`,
|
|
291
|
+
{readOnlyArray: false},
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
expect(result).toMatchInlineSnapshot(`
|
|
295
|
+
// SomeQueryType.js
|
|
296
|
+
export type SomeQueryType = {|
|
|
297
|
+
variables: {||},
|
|
298
|
+
response: {|
|
|
299
|
+
|
|
300
|
+
/** A human character*/
|
|
301
|
+
human: ?{|
|
|
302
|
+
friends: ?Array<?{|
|
|
303
|
+
name: ?string
|
|
304
|
+
|}>
|
|
305
|
+
|}
|
|
306
|
+
|}
|
|
307
|
+
|};
|
|
308
|
+
`);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
describe('Object properties', () => {
|
|
312
|
+
it('should reject invalid field', () => {
|
|
313
|
+
expect(() =>
|
|
314
|
+
rawQueryToFlowTypes(`
|
|
315
|
+
query SomeQuery {
|
|
316
|
+
human(id: "Me") {
|
|
317
|
+
invalidField
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
`),
|
|
321
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
322
|
+
`Graphql-flow type generation failed! Unknown field 'invalidField' for type 'Human'`,
|
|
323
|
+
);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should reject an unknown fragment', () => {
|
|
327
|
+
expect(() =>
|
|
328
|
+
rawQueryToFlowTypes(`
|
|
329
|
+
query SomeQuery {
|
|
330
|
+
human(id: "Me") {
|
|
331
|
+
...UnknownFragment
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
`),
|
|
335
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
336
|
+
`Graphql-flow type generation failed! No fragment named 'UnknownFragment'. Did you forget to include it in the template literal?`,
|
|
337
|
+
);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
describe('Fragments', () => {
|
|
342
|
+
it('should resolve correctly, and produce a type file for the fragment', () => {
|
|
343
|
+
const result = rawQueryToFlowTypes(
|
|
344
|
+
`query Hello {
|
|
345
|
+
hero(episode: JEDI) {
|
|
346
|
+
...onChar
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
fragment onChar on Character {
|
|
351
|
+
__typename
|
|
352
|
+
... on Droid {
|
|
353
|
+
primaryFunction
|
|
354
|
+
}
|
|
355
|
+
}`,
|
|
356
|
+
);
|
|
357
|
+
expect(result).toMatchInlineSnapshot(`
|
|
358
|
+
// HelloType.js
|
|
359
|
+
export type HelloType = {|
|
|
360
|
+
variables: {||},
|
|
361
|
+
response: {|
|
|
362
|
+
hero: ?({|
|
|
363
|
+
__typename: "Droid",
|
|
364
|
+
|
|
365
|
+
/** The robot's primary function*/
|
|
366
|
+
primaryFunction: string,
|
|
367
|
+
|} | {|
|
|
368
|
+
__typename: "Human"
|
|
369
|
+
|})
|
|
370
|
+
|}
|
|
371
|
+
|};
|
|
372
|
+
|
|
373
|
+
// onChar.js
|
|
374
|
+
export type onChar = {|
|
|
375
|
+
__typename: "Droid",
|
|
376
|
+
|
|
377
|
+
/** The robot's primary function*/
|
|
378
|
+
primaryFunction: string,
|
|
379
|
+
|} | {|
|
|
380
|
+
__typename: "Human"
|
|
381
|
+
|};
|
|
382
|
+
`);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it('Should specialize the fragment type correctly', () => {
|
|
386
|
+
const result = rawQueryToFlowTypes(
|
|
387
|
+
`query Deps {
|
|
388
|
+
droid(id: "hello") {
|
|
389
|
+
...Hello
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
fragment Hello on Character {
|
|
394
|
+
__typename
|
|
395
|
+
name
|
|
396
|
+
... on Droid {
|
|
397
|
+
primaryFunction
|
|
398
|
+
}
|
|
399
|
+
... on Human {
|
|
400
|
+
homePlanet
|
|
401
|
+
}
|
|
402
|
+
}`,
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
// Note how `homePlanet` is ommitted in
|
|
406
|
+
// `DepsType.response.droid`
|
|
407
|
+
expect(result).toMatchInlineSnapshot(`
|
|
408
|
+
// DepsType.js
|
|
409
|
+
export type DepsType = {|
|
|
410
|
+
variables: {||},
|
|
411
|
+
response: {|
|
|
412
|
+
|
|
413
|
+
/** A robot character*/
|
|
414
|
+
droid: ?{|
|
|
415
|
+
__typename: "Droid",
|
|
416
|
+
name: ?string,
|
|
417
|
+
|
|
418
|
+
/** The robot's primary function*/
|
|
419
|
+
primaryFunction: string,
|
|
420
|
+
|}
|
|
421
|
+
|}
|
|
422
|
+
|};
|
|
423
|
+
|
|
424
|
+
// Hello.js
|
|
425
|
+
export type Hello = {|
|
|
426
|
+
__typename: "Droid",
|
|
427
|
+
name: ?string,
|
|
428
|
+
|
|
429
|
+
/** The robot's primary function*/
|
|
430
|
+
primaryFunction: string,
|
|
431
|
+
|} | {|
|
|
432
|
+
__typename: "Human",
|
|
433
|
+
homePlanet: ?string,
|
|
434
|
+
name: ?string,
|
|
435
|
+
|};
|
|
436
|
+
`);
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it('should generate all types when exportAllObjectTypes is set', () => {
|
|
441
|
+
const result = rawQueryToFlowTypes(
|
|
442
|
+
`
|
|
443
|
+
query SomeQuery {
|
|
444
|
+
human(id: "Han Solo") {
|
|
445
|
+
id
|
|
446
|
+
name
|
|
447
|
+
homePlanet
|
|
448
|
+
hands
|
|
449
|
+
alive
|
|
450
|
+
friends {
|
|
451
|
+
__typename
|
|
452
|
+
... on Human {
|
|
453
|
+
hands
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
`,
|
|
459
|
+
{exportAllObjectTypes: true},
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
expect(result).toMatchInlineSnapshot(`
|
|
463
|
+
// SomeQueryType.js
|
|
464
|
+
export type SomeQueryType = {|
|
|
465
|
+
variables: {||},
|
|
466
|
+
response: {|
|
|
467
|
+
|
|
468
|
+
/** A human character*/
|
|
469
|
+
human: ?SomeQuery_human
|
|
470
|
+
|}
|
|
471
|
+
|};
|
|
472
|
+
export type SomeQuery_human = {|
|
|
473
|
+
alive: ?boolean,
|
|
474
|
+
friends: ?$ReadOnlyArray<?SomeQuery_human_friends>,
|
|
475
|
+
hands: ?number,
|
|
476
|
+
homePlanet: ?string,
|
|
477
|
+
id: string,
|
|
478
|
+
|
|
479
|
+
/** The person's name*/
|
|
480
|
+
name: ?string,
|
|
481
|
+
|};
|
|
482
|
+
export type SomeQuery_human_friends = SomeQuery_human_friends_Droid | SomeQuery_human_friends_Human;
|
|
483
|
+
export type SomeQuery_human_friends_Droid = {|
|
|
484
|
+
__typename: "Droid"
|
|
485
|
+
|};
|
|
486
|
+
export type SomeQuery_human_friends_Human = {|
|
|
487
|
+
__typename: "Human",
|
|
488
|
+
hands: ?number,
|
|
489
|
+
|};
|
|
490
|
+
`);
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
describe('Input variables', () => {
|
|
494
|
+
it('should generate a variables type', () => {
|
|
495
|
+
const result = rawQueryToFlowTypes(
|
|
496
|
+
`query SomeQuery($id: String!, $episode: Episode) {
|
|
497
|
+
human(id: $id) {
|
|
498
|
+
friends {
|
|
499
|
+
name
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
hero(episode: $episode) {
|
|
503
|
+
name
|
|
504
|
+
}
|
|
505
|
+
}`,
|
|
506
|
+
{readOnlyArray: false},
|
|
507
|
+
);
|
|
508
|
+
|
|
509
|
+
expect(result).toMatchInlineSnapshot(`
|
|
510
|
+
// SomeQueryType.js
|
|
511
|
+
export type SomeQueryType = {|
|
|
512
|
+
variables: {|
|
|
513
|
+
id: string,
|
|
514
|
+
|
|
515
|
+
/** - NEW_HOPE
|
|
516
|
+
- EMPIRE
|
|
517
|
+
- JEDI*/
|
|
518
|
+
episode?: ?("NEW_HOPE" | "EMPIRE" | "JEDI"),
|
|
519
|
+
|},
|
|
520
|
+
response: {|
|
|
521
|
+
hero: ?{|
|
|
522
|
+
name: ?string
|
|
523
|
+
|},
|
|
524
|
+
|
|
525
|
+
/** A human character*/
|
|
526
|
+
human: ?{|
|
|
527
|
+
friends: ?Array<?{|
|
|
528
|
+
name: ?string
|
|
529
|
+
|}>
|
|
530
|
+
|},
|
|
531
|
+
|}
|
|
532
|
+
|};
|
|
533
|
+
`);
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
it('should handle an inline fragment on an interface without a typeCondition', () => {
|
|
537
|
+
const result = rawQueryToFlowTypes(
|
|
538
|
+
`
|
|
539
|
+
query SomeQuery {
|
|
540
|
+
hero(episode: JEDI) {
|
|
541
|
+
id
|
|
542
|
+
... {
|
|
543
|
+
name
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}`,
|
|
547
|
+
{readOnlyArray: false},
|
|
548
|
+
);
|
|
549
|
+
expect(result).toMatchInlineSnapshot(`
|
|
550
|
+
// SomeQueryType.js
|
|
551
|
+
export type SomeQueryType = {|
|
|
552
|
+
variables: {||},
|
|
553
|
+
response: {|
|
|
554
|
+
hero: ?({|
|
|
555
|
+
id: string,
|
|
556
|
+
name: ?string,
|
|
557
|
+
|} | {|
|
|
558
|
+
id: string,
|
|
559
|
+
|
|
560
|
+
/** The person's name*/
|
|
561
|
+
name: ?string,
|
|
562
|
+
|})
|
|
563
|
+
|}
|
|
564
|
+
|};
|
|
565
|
+
`);
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
it('should handle an inline fragment on an object (not an interface)', () => {
|
|
569
|
+
const result = rawQueryToFlowTypes(
|
|
570
|
+
`
|
|
571
|
+
query SomeQuery {
|
|
572
|
+
human(id: "hi") {
|
|
573
|
+
id
|
|
574
|
+
... {
|
|
575
|
+
name
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}`,
|
|
579
|
+
{readOnlyArray: false},
|
|
580
|
+
);
|
|
581
|
+
expect(result).toMatchInlineSnapshot(`
|
|
582
|
+
// SomeQueryType.js
|
|
583
|
+
export type SomeQueryType = {|
|
|
584
|
+
variables: {||},
|
|
585
|
+
response: {|
|
|
586
|
+
|
|
587
|
+
/** A human character*/
|
|
588
|
+
human: ?{|
|
|
589
|
+
id: string,
|
|
590
|
+
|
|
591
|
+
/** The person's name*/
|
|
592
|
+
name: ?string,
|
|
593
|
+
|}
|
|
594
|
+
|}
|
|
595
|
+
|};
|
|
596
|
+
`);
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
it('should handle a complex input variable', () => {
|
|
600
|
+
const result = rawQueryToFlowTypes(
|
|
601
|
+
`mutation addCharacter($character: CharacterInput!) {
|
|
602
|
+
addCharacter(character: $character) {
|
|
603
|
+
id
|
|
604
|
+
}
|
|
605
|
+
}`,
|
|
606
|
+
{readOnlyArray: false},
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
expect(result).toMatchInlineSnapshot(`
|
|
610
|
+
// addCharacterType.js
|
|
611
|
+
export type addCharacterType = {|
|
|
612
|
+
variables: {|
|
|
613
|
+
|
|
614
|
+
/** A character to add*/
|
|
615
|
+
character: {|
|
|
616
|
+
|
|
617
|
+
/** The new character's name*/
|
|
618
|
+
name: string,
|
|
619
|
+
|
|
620
|
+
/** The character's friends*/
|
|
621
|
+
friends?: ?$ReadOnlyArray<string>,
|
|
622
|
+
appearsIn?: ?$ReadOnlyArray<
|
|
623
|
+
/** - NEW_HOPE
|
|
624
|
+
- EMPIRE
|
|
625
|
+
- JEDI*/
|
|
626
|
+
"NEW_HOPE" | "EMPIRE" | "JEDI">,
|
|
627
|
+
candies: number,
|
|
628
|
+
|}
|
|
629
|
+
|},
|
|
630
|
+
response: {|
|
|
631
|
+
addCharacter: ?{|
|
|
632
|
+
id: string
|
|
633
|
+
|}
|
|
634
|
+
|}
|
|
635
|
+
|};
|
|
636
|
+
`);
|
|
637
|
+
});
|
|
638
|
+
});
|
|
639
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type {CrawlConfig, GenerateConfig} from '../types';
|
|
3
|
+
|
|
4
|
+
import {processPragmas} from '../generateTypeFiles';
|
|
5
|
+
|
|
6
|
+
const pragma = '# @autogen\n';
|
|
7
|
+
const loosePragma = '# @autogen-loose\n';
|
|
8
|
+
|
|
9
|
+
const baseGenerate: GenerateConfig = {schemaFilePath: ''};
|
|
10
|
+
const baseCrawl: CrawlConfig = {root: ''};
|
|
11
|
+
|
|
12
|
+
describe('processPragmas', () => {
|
|
13
|
+
it('should work with no pragmas', () => {
|
|
14
|
+
expect(
|
|
15
|
+
processPragmas(baseGenerate, baseCrawl, `query X { Y }`),
|
|
16
|
+
).toEqual({
|
|
17
|
+
generate: true,
|
|
18
|
+
strict: undefined,
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should reject query without required pragma', () => {
|
|
23
|
+
expect(
|
|
24
|
+
processPragmas(
|
|
25
|
+
baseGenerate,
|
|
26
|
+
{...baseCrawl, pragma},
|
|
27
|
+
`query X { Y }`,
|
|
28
|
+
),
|
|
29
|
+
).toEqual({generate: false});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should accept query with required pragma', () => {
|
|
33
|
+
expect(
|
|
34
|
+
processPragmas(
|
|
35
|
+
baseGenerate,
|
|
36
|
+
{...baseCrawl, pragma},
|
|
37
|
+
`query X {
|
|
38
|
+
# @autogen
|
|
39
|
+
Y
|
|
40
|
+
}`,
|
|
41
|
+
),
|
|
42
|
+
).toEqual({
|
|
43
|
+
strict: true,
|
|
44
|
+
generate: true,
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should accept query with loose pragma', () => {
|
|
49
|
+
expect(
|
|
50
|
+
processPragmas(
|
|
51
|
+
baseGenerate,
|
|
52
|
+
{...baseCrawl, pragma, loosePragma},
|
|
53
|
+
`query X {
|
|
54
|
+
# @autogen-loose
|
|
55
|
+
Y
|
|
56
|
+
}`,
|
|
57
|
+
),
|
|
58
|
+
).toEqual({
|
|
59
|
+
strict: false,
|
|
60
|
+
generate: true,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should reject query with ignore pragma', () => {
|
|
65
|
+
expect(
|
|
66
|
+
processPragmas(
|
|
67
|
+
baseGenerate,
|
|
68
|
+
{...baseCrawl, ignorePragma: '# @ignore\n'},
|
|
69
|
+
`query X {
|
|
70
|
+
# @ignore
|
|
71
|
+
Y
|
|
72
|
+
}`,
|
|
73
|
+
),
|
|
74
|
+
).toEqual({generate: false});
|
|
75
|
+
});
|
|
76
|
+
});
|