@khanacademy/graphql-flow 1.1.2 → 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 +16 -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 +13 -35
- package/dist/generateVariablesType.js +15 -31
- package/dist/index.js +11 -17
- package/dist/parser/parse.js +10 -8
- package/dist/parser/resolve.js +11 -8
- package/dist/parser/utils.js +36 -0
- package/dist/schemaFromIntrospectionData.js +1 -2
- package/dist/types.js +1 -2
- package/dist/utils.js +43 -3
- package/package.json +8 -7
- package/{src/cli/schema.json → schema.json} +3 -0
- 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/{dist/generateResponseType.js.flow → src/generateResponseType.ts} +167 -182
- package/src/{generateTypeFiles.js → generateTypeFiles.ts} +24 -40
- package/src/{generateVariablesType.js → generateVariablesType.ts} +34 -44
- package/{dist/index.js.flow → src/index.ts} +33 -24
- package/{dist/parser/__test__/parse.test.js → src/parser/__test__/parse.test.ts} +12 -11
- package/{dist/parser/parse.js.flow → src/parser/parse.ts} +69 -48
- package/{dist/parser/resolve.js.flow → src/parser/resolve.ts} +25 -19
- package/src/parser/utils.ts +24 -0
- 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/cli/schema.json +0 -94
- package/dist/enums.js.flow +0 -98
- package/dist/enums.js.map +0 -1
- package/dist/generateResponseType.js.map +0 -1
- package/dist/generateTypeFiles.js.flow +0 -197
- 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.map +0 -1
- package/dist/parser/resolve.js.map +0 -1
- package/dist/schemaFromIntrospectionData.js.map +0 -1
- package/dist/types.js.flow +0 -87
- 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/generateResponseType.js +0 -583
- package/src/index.js +0 -159
- package/src/parser/__test__/parse.test.js +0 -249
- package/src/parser/parse.js +0 -414
- package/src/parser/resolve.js +0 -117
- package/src/schemaFromIntrospectionData.js +0 -68
- package/src/types.js +0 -87
- package/src/utils.js +0 -50
|
@@ -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,28 +19,27 @@ 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) => {
|
|
32
|
-
if (options.typeScript) {
|
|
30
|
+
/// Write export for __generated__/index.ts if it doesn't exist
|
|
31
|
+
const addToIndex = (filePath: string, typeName: unknown) => {
|
|
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,
|
|
38
38
|
)}';`;
|
|
39
|
-
|
|
39
|
+
// We match the entire new line to avoid issues that can arise from
|
|
40
|
+
// prefix matches.
|
|
41
|
+
if (indexContents.indexOf(newLine) === -1) {
|
|
40
42
|
indexContents += newLine + '\n';
|
|
41
|
-
} else {
|
|
42
|
-
const lines = indexContents.split('\n').map((line) => {
|
|
43
|
-
if (line.includes('./' + path.basename(filePath))) {
|
|
44
|
-
return newLine;
|
|
45
|
-
}
|
|
46
|
-
return line;
|
|
47
|
-
});
|
|
48
|
-
indexContents = lines.join('\n');
|
|
49
43
|
}
|
|
50
44
|
};
|
|
51
45
|
|
|
@@ -56,12 +50,11 @@ export const generateTypeFileContents = (
|
|
|
56
50
|
// things tidy.
|
|
57
51
|
const targetFileName = options.typeFileName
|
|
58
52
|
? options.typeFileName.replace('[operationName]', name)
|
|
59
|
-
: `${name}.
|
|
53
|
+
: `${name}.ts`;
|
|
60
54
|
const targetPath = path.join(generatedDir, targetFileName);
|
|
61
55
|
|
|
62
56
|
let fileContents =
|
|
63
|
-
|
|
64
|
-
`flow\n// AUTOGENERATED -- DO NOT EDIT\n` +
|
|
57
|
+
`// AUTOGENERATED -- DO NOT EDIT\n` +
|
|
65
58
|
`// Generated for operation '${name}' in file '../${path.basename(
|
|
66
59
|
fileName,
|
|
67
60
|
)}'\n` +
|
|
@@ -126,10 +119,7 @@ export const generateTypeFiles = (
|
|
|
126
119
|
options: GenerateConfig,
|
|
127
120
|
) => {
|
|
128
121
|
const generatedDir = getGeneratedDir(fileName, options);
|
|
129
|
-
const indexFile = path.join(
|
|
130
|
-
generatedDir,
|
|
131
|
-
'index' + (options.typeScript ? '.ts' : '.js'),
|
|
132
|
-
);
|
|
122
|
+
const indexFile = path.join(generatedDir, 'index.ts');
|
|
133
123
|
|
|
134
124
|
if (!fs.existsSync(generatedDir)) {
|
|
135
125
|
fs.mkdirSync(generatedDir, {recursive: true});
|
|
@@ -148,17 +138,8 @@ export const generateTypeFiles = (
|
|
|
148
138
|
);
|
|
149
139
|
|
|
150
140
|
fs.writeFileSync(indexFile, indexContents);
|
|
151
|
-
Object.keys(files).forEach((
|
|
152
|
-
|
|
153
|
-
if (options.typeScript) {
|
|
154
|
-
// eslint-disable-next-line flowtype-errors/uncovered
|
|
155
|
-
files[key] = convert(files[key]).replace(
|
|
156
|
-
`variables: {}`,
|
|
157
|
-
`variables: Record<never, never>`,
|
|
158
|
-
);
|
|
159
|
-
fname = key.replace(/\.js$/, '.ts');
|
|
160
|
-
}
|
|
161
|
-
fs.writeFileSync(fname, files[key]);
|
|
141
|
+
Object.keys(files).forEach((fname) => {
|
|
142
|
+
fs.writeFileSync(fname, files[fname]);
|
|
162
143
|
});
|
|
163
144
|
|
|
164
145
|
fs.writeFileSync(indexFile, indexContents);
|
|
@@ -168,7 +149,10 @@ export const processPragmas = (
|
|
|
168
149
|
generateConfig: GenerateConfig,
|
|
169
150
|
crawlConfig: CrawlConfig,
|
|
170
151
|
rawSource: string,
|
|
171
|
-
): {
|
|
152
|
+
): {
|
|
153
|
+
generate: boolean
|
|
154
|
+
strict?: boolean
|
|
155
|
+
} => {
|
|
172
156
|
if (
|
|
173
157
|
crawlConfig.ignorePragma &&
|
|
174
158
|
rawSource.includes(crawlConfig.ignorePragma)
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
// @flow
|
|
2
1
|
import generate from '@babel/generator'; // eslint-disable-line flowtype-errors/uncovered
|
|
3
|
-
import type {
|
|
4
|
-
BabelNodeFlowType,
|
|
5
|
-
BabelNodeObjectTypeProperty,
|
|
6
|
-
} from '@babel/types';
|
|
7
2
|
import * as babelTypes from '@babel/types';
|
|
8
3
|
import type {OperationDefinitionNode, TypeNode} from 'graphql/language/ast';
|
|
9
4
|
import type {IntrospectionInputTypeRef} from 'graphql/utilities/introspectionQuery';
|
|
10
5
|
import {builtinScalars, enumTypeToFlow, scalarTypeToFlow} from './enums';
|
|
6
|
+
import {nullableType, isnNullableType, objectTypeFromProperties} from './utils';
|
|
11
7
|
import type {Context, Schema} from './types';
|
|
12
8
|
import {
|
|
13
9
|
liftLeadingPropertyComments,
|
|
@@ -18,18 +14,18 @@ import {
|
|
|
18
14
|
export const inputObjectToFlow = (
|
|
19
15
|
ctx: Context,
|
|
20
16
|
name: string,
|
|
21
|
-
):
|
|
17
|
+
): babelTypes.TSType => {
|
|
22
18
|
const inputObject = ctx.schema.inputObjectsByName[name];
|
|
23
19
|
if (!inputObject) {
|
|
24
20
|
ctx.errors.push(`Unknown input object ${name}`);
|
|
25
|
-
return babelTypes.
|
|
26
|
-
`Unknown input object ${name}
|
|
21
|
+
return babelTypes.tsLiteralType(
|
|
22
|
+
babelTypes.stringLiteral(`Unknown input object ${name}`),
|
|
27
23
|
);
|
|
28
24
|
}
|
|
29
25
|
|
|
30
26
|
return maybeAddDescriptionComment(
|
|
31
27
|
inputObject.description,
|
|
32
|
-
|
|
28
|
+
objectTypeFromProperties(
|
|
33
29
|
inputObject.inputFields.map((vbl) =>
|
|
34
30
|
maybeAddDescriptionComment(
|
|
35
31
|
vbl.description,
|
|
@@ -39,22 +35,21 @@ export const inputObjectToFlow = (
|
|
|
39
35
|
),
|
|
40
36
|
),
|
|
41
37
|
),
|
|
42
|
-
undefined /* indexers */,
|
|
43
|
-
undefined /* callProperties */,
|
|
44
|
-
undefined /* internalSlots */,
|
|
45
|
-
true /* exact */,
|
|
46
38
|
),
|
|
47
39
|
);
|
|
48
40
|
};
|
|
49
41
|
|
|
50
42
|
export const maybeOptionalObjectTypeProperty = (
|
|
51
43
|
name: string,
|
|
52
|
-
type: babelTypes.
|
|
53
|
-
):
|
|
44
|
+
type: babelTypes.TSType,
|
|
45
|
+
): babelTypes.TSPropertySignature => {
|
|
54
46
|
const prop = liftLeadingPropertyComments(
|
|
55
|
-
babelTypes.
|
|
47
|
+
babelTypes.tsPropertySignature(
|
|
48
|
+
babelTypes.identifier(name),
|
|
49
|
+
babelTypes.tsTypeAnnotation(type),
|
|
50
|
+
),
|
|
56
51
|
);
|
|
57
|
-
if (type
|
|
52
|
+
if (isnNullableType(type)) {
|
|
58
53
|
prop.optional = true;
|
|
59
54
|
}
|
|
60
55
|
return prop;
|
|
@@ -63,18 +58,18 @@ export const maybeOptionalObjectTypeProperty = (
|
|
|
63
58
|
export const inputRefToFlow = (
|
|
64
59
|
ctx: Context,
|
|
65
60
|
inputRef: IntrospectionInputTypeRef,
|
|
66
|
-
):
|
|
61
|
+
): babelTypes.TSType => {
|
|
67
62
|
if (inputRef.kind === 'NON_NULL') {
|
|
68
63
|
return _inputRefToFlow(ctx, inputRef.ofType);
|
|
69
64
|
}
|
|
70
65
|
const result = _inputRefToFlow(ctx, inputRef);
|
|
71
|
-
return transferLeadingComments(
|
|
72
|
-
result,
|
|
73
|
-
babelTypes.nullableTypeAnnotation(result),
|
|
74
|
-
);
|
|
66
|
+
return transferLeadingComments(result, nullableType(result));
|
|
75
67
|
};
|
|
76
68
|
|
|
77
|
-
const _inputRefToFlow = (
|
|
69
|
+
const _inputRefToFlow = (
|
|
70
|
+
ctx: Context,
|
|
71
|
+
inputRef: IntrospectionInputTypeRef,
|
|
72
|
+
): babelTypes.TSType => {
|
|
78
73
|
if (inputRef.kind === 'SCALAR') {
|
|
79
74
|
return scalarTypeToFlow(ctx, inputRef.name);
|
|
80
75
|
}
|
|
@@ -85,28 +80,27 @@ const _inputRefToFlow = (ctx: Context, inputRef: IntrospectionInputTypeRef) => {
|
|
|
85
80
|
return inputObjectToFlow(ctx, inputRef.name);
|
|
86
81
|
}
|
|
87
82
|
if (inputRef.kind === 'LIST') {
|
|
88
|
-
return babelTypes.
|
|
89
|
-
babelTypes.identifier('
|
|
90
|
-
babelTypes.
|
|
83
|
+
return babelTypes.tsTypeReference(
|
|
84
|
+
babelTypes.identifier('ReadonlyArray'),
|
|
85
|
+
babelTypes.tsTypeParameterInstantiation([
|
|
91
86
|
inputRefToFlow(ctx, inputRef.ofType),
|
|
92
87
|
]),
|
|
93
88
|
);
|
|
94
89
|
}
|
|
95
|
-
return babelTypes.
|
|
90
|
+
return babelTypes.tsLiteralType(
|
|
91
|
+
babelTypes.stringLiteral(JSON.stringify(inputRef)),
|
|
92
|
+
);
|
|
96
93
|
};
|
|
97
94
|
|
|
98
|
-
const variableToFlow = (ctx: Context, type: TypeNode) => {
|
|
95
|
+
const variableToFlow = (ctx: Context, type: TypeNode): babelTypes.TSType => {
|
|
99
96
|
if (type.kind === 'NonNullType') {
|
|
100
97
|
return _variableToFlow(ctx, type.type);
|
|
101
98
|
}
|
|
102
99
|
const result = _variableToFlow(ctx, type);
|
|
103
|
-
return transferLeadingComments(
|
|
104
|
-
result,
|
|
105
|
-
babelTypes.nullableTypeAnnotation(result),
|
|
106
|
-
);
|
|
100
|
+
return transferLeadingComments(result, nullableType(result));
|
|
107
101
|
};
|
|
108
102
|
|
|
109
|
-
const _variableToFlow = (ctx: Context, type: TypeNode) => {
|
|
103
|
+
const _variableToFlow = (ctx: Context, type: TypeNode): babelTypes.TSType => {
|
|
110
104
|
if (type.kind === 'NamedType') {
|
|
111
105
|
if (builtinScalars[type.name.value]) {
|
|
112
106
|
return scalarTypeToFlow(ctx, type.name.value);
|
|
@@ -116,22 +110,22 @@ const _variableToFlow = (ctx: Context, type: TypeNode) => {
|
|
|
116
110
|
}
|
|
117
111
|
const customScalarType = ctx.scalars[type.name.value];
|
|
118
112
|
if (customScalarType) {
|
|
119
|
-
return babelTypes.
|
|
113
|
+
return babelTypes.tsTypeReference(
|
|
120
114
|
babelTypes.identifier(customScalarType),
|
|
121
115
|
);
|
|
122
116
|
}
|
|
123
117
|
return inputObjectToFlow(ctx, type.name.value);
|
|
124
118
|
}
|
|
125
119
|
if (type.kind === 'ListType') {
|
|
126
|
-
return babelTypes.
|
|
127
|
-
babelTypes.identifier('
|
|
128
|
-
babelTypes.
|
|
120
|
+
return babelTypes.tsTypeReference(
|
|
121
|
+
babelTypes.identifier('ReadonlyArray'),
|
|
122
|
+
babelTypes.tsTypeParameterInstantiation([
|
|
129
123
|
variableToFlow(ctx, type.type),
|
|
130
124
|
]),
|
|
131
125
|
);
|
|
132
126
|
}
|
|
133
|
-
return babelTypes.
|
|
134
|
-
'UNKNOWN' + JSON.stringify(type),
|
|
127
|
+
return babelTypes.tsLiteralType(
|
|
128
|
+
babelTypes.stringLiteral('UNKNOWN' + JSON.stringify(type)),
|
|
135
129
|
);
|
|
136
130
|
};
|
|
137
131
|
|
|
@@ -140,17 +134,13 @@ export const generateVariablesType = (
|
|
|
140
134
|
item: OperationDefinitionNode,
|
|
141
135
|
ctx: Context,
|
|
142
136
|
): string => {
|
|
143
|
-
const variableObject =
|
|
137
|
+
const variableObject = objectTypeFromProperties(
|
|
144
138
|
(item.variableDefinitions || []).map((vbl) => {
|
|
145
139
|
return maybeOptionalObjectTypeProperty(
|
|
146
140
|
vbl.variable.name.value,
|
|
147
141
|
variableToFlow(ctx, vbl.type),
|
|
148
142
|
);
|
|
149
143
|
}),
|
|
150
|
-
undefined /* indexers */,
|
|
151
|
-
undefined /* callProperties */,
|
|
152
|
-
undefined /* internalSlots */,
|
|
153
|
-
true /* exact */,
|
|
154
144
|
);
|
|
155
145
|
return generate(variableObject).code; // eslint-disable-line flowtype-errors/uncovered
|
|
156
146
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import {isTruthy} from '@khanacademy/wonder-stuff-core';
|
|
1
2
|
/* eslint-disable no-console */
|
|
2
3
|
/* flow-uncovered-file */
|
|
3
|
-
// @flow
|
|
4
4
|
/**
|
|
5
5
|
* This tool generates flowtype definitions from graphql queries.
|
|
6
6
|
*
|
|
@@ -15,13 +15,13 @@ import {
|
|
|
15
15
|
generateResponseType,
|
|
16
16
|
} from './generateResponseType';
|
|
17
17
|
import {generateVariablesType} from './generateVariablesType';
|
|
18
|
-
import type {
|
|
18
|
+
import type {Node} from '@babel/types';
|
|
19
19
|
|
|
20
20
|
import type {Context, Schema, GenerateConfig} from './types';
|
|
21
21
|
|
|
22
22
|
const optionsToConfig = (
|
|
23
23
|
schema: Schema,
|
|
24
|
-
definitions:
|
|
24
|
+
definitions: ReadonlyArray<DefinitionNode>,
|
|
25
25
|
options?: GenerateConfig,
|
|
26
26
|
errors: Array<string> = [],
|
|
27
27
|
): Context => {
|
|
@@ -30,8 +30,9 @@ const optionsToConfig = (
|
|
|
30
30
|
readOnlyArray: options?.readOnlyArray ?? true,
|
|
31
31
|
scalars: options?.scalars ?? {},
|
|
32
32
|
typeScript: options?.typeScript ?? false,
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
omitFileExtensions: options?.omitFileExtensions ?? false,
|
|
34
|
+
} as const;
|
|
35
|
+
const fragments: Record<string, any> = {};
|
|
35
36
|
definitions.forEach((def) => {
|
|
36
37
|
if (def.kind === 'FragmentDefinition') {
|
|
37
38
|
fragments[def.name.value] = def;
|
|
@@ -45,8 +46,10 @@ const optionsToConfig = (
|
|
|
45
46
|
path: [],
|
|
46
47
|
experimentalEnumsMap: options?.experimentalEnums ? {} : undefined,
|
|
47
48
|
...internalOptions,
|
|
48
|
-
};
|
|
49
|
+
} as const;
|
|
49
50
|
|
|
51
|
+
// @ts-expect-error: TS2322 - The type 'readonly []' is 'readonly' and cannot be
|
|
52
|
+
// assigned to the mutable type 'string[]'.
|
|
50
53
|
return config;
|
|
51
54
|
};
|
|
52
55
|
|
|
@@ -58,17 +61,17 @@ export class FlowGenerationError extends Error {
|
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
|
|
61
|
-
export const documentToFlowTypes = (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
export const documentToFlowTypes = (document: DocumentNode, schema: Schema, options?: GenerateConfig): ReadonlyArray<{
|
|
65
|
+
name: string
|
|
66
|
+
typeName: string
|
|
67
|
+
code: string
|
|
68
|
+
isFragment?: boolean
|
|
69
|
+
extraTypes: {
|
|
70
|
+
[key: string]: string
|
|
71
|
+
}
|
|
72
|
+
experimentalEnums: {
|
|
73
|
+
[key: string]: string
|
|
74
|
+
}
|
|
72
75
|
}> => {
|
|
73
76
|
const errors: Array<string> = [];
|
|
74
77
|
const config = optionsToConfig(
|
|
@@ -81,7 +84,7 @@ export const documentToFlowTypes = (
|
|
|
81
84
|
.map((item) => {
|
|
82
85
|
if (item.kind === 'FragmentDefinition') {
|
|
83
86
|
const name = item.name.value;
|
|
84
|
-
const types = {};
|
|
87
|
+
const types: Record<string, any> = {};
|
|
85
88
|
const code = `export type ${name} = ${generateFragmentType(
|
|
86
89
|
schema,
|
|
87
90
|
item,
|
|
@@ -113,7 +116,7 @@ export const documentToFlowTypes = (
|
|
|
113
116
|
(item.operation === 'query' || item.operation === 'mutation') &&
|
|
114
117
|
item.name
|
|
115
118
|
) {
|
|
116
|
-
const types = {};
|
|
119
|
+
const types: Record<string, any> = {};
|
|
117
120
|
const name = item.name.value;
|
|
118
121
|
const response = generateResponseType(schema, item, {
|
|
119
122
|
...config,
|
|
@@ -130,7 +133,7 @@ export const documentToFlowTypes = (
|
|
|
130
133
|
const typeName = `${name}Type`;
|
|
131
134
|
// TODO(jared): Maybe make this template configurable?
|
|
132
135
|
// We'll see what's required to get webapp on board.
|
|
133
|
-
const code = `export type ${typeName} = {
|
|
136
|
+
const code = `export type ${typeName} = {\n variables: ${variables},\n response: ${response}\n};`;
|
|
134
137
|
|
|
135
138
|
const extraTypes = codegenExtraTypes(types);
|
|
136
139
|
const experimentalEnums = codegenExtraTypes(
|
|
@@ -140,17 +143,23 @@ export const documentToFlowTypes = (
|
|
|
140
143
|
return {name, typeName, code, extraTypes, experimentalEnums};
|
|
141
144
|
}
|
|
142
145
|
})
|
|
143
|
-
.filter(
|
|
146
|
+
.filter(isTruthy);
|
|
144
147
|
if (errors.length) {
|
|
145
148
|
throw new FlowGenerationError(errors);
|
|
146
149
|
}
|
|
147
150
|
return result;
|
|
148
151
|
};
|
|
149
152
|
|
|
150
|
-
function codegenExtraTypes(
|
|
151
|
-
|
|
153
|
+
function codegenExtraTypes(
|
|
154
|
+
types: {
|
|
155
|
+
[key: string]: Node
|
|
156
|
+
},
|
|
157
|
+
): {
|
|
158
|
+
[key: string]: string
|
|
152
159
|
} {
|
|
153
|
-
const extraTypes: {
|
|
160
|
+
const extraTypes: {
|
|
161
|
+
[key: string]: string
|
|
162
|
+
} = {};
|
|
154
163
|
Object.keys(types).forEach((k: string) => {
|
|
155
164
|
// eslint-disable-next-line flowtype-errors/uncovered
|
|
156
165
|
extraTypes[k] = generate(types[k]).code;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
|
|
3
1
|
import {processFiles} from '../parse';
|
|
4
2
|
import {resolveDocuments} from '../resolve';
|
|
5
3
|
|
|
6
4
|
import {print} from 'graphql/language/printer';
|
|
7
5
|
|
|
8
6
|
const fixtureFiles: {
|
|
9
|
-
[key: string]: string | {
|
|
7
|
+
[key: string]: string | {
|
|
8
|
+
text: string
|
|
9
|
+
resolvedPath: string
|
|
10
|
+
}
|
|
10
11
|
} = {
|
|
11
12
|
'/firstFile.js': `
|
|
12
13
|
// Note that you can import graphql-tag as
|
|
@@ -151,14 +152,14 @@ const getFileSource = (name: string) => {
|
|
|
151
152
|
describe('processing fragments in various ways', () => {
|
|
152
153
|
it('should work', () => {
|
|
153
154
|
const files = processFiles(['/thirdFile.js'], getFileSource);
|
|
154
|
-
Object.keys(files).forEach((k) => {
|
|
155
|
+
Object.keys(files).forEach((k: any) => {
|
|
155
156
|
expect(files[k].errors).toEqual([]);
|
|
156
157
|
});
|
|
157
158
|
const {resolved, errors} = resolveDocuments(files);
|
|
158
159
|
expect(errors).toEqual([]);
|
|
159
|
-
const printed = {};
|
|
160
|
+
const printed: Record<string, any> = {};
|
|
160
161
|
Object.keys(resolved).map(
|
|
161
|
-
(k) => (printed[k] = print(resolved[k].document).trim()),
|
|
162
|
+
(k: any) => (printed[k] = print(resolved[k].document).trim()),
|
|
162
163
|
);
|
|
163
164
|
expect(printed).toMatchInlineSnapshot(`
|
|
164
165
|
Object {
|
|
@@ -216,7 +217,7 @@ describe('processing fragments in various ways', () => {
|
|
|
216
217
|
|
|
217
218
|
it('should flag things it doesnt support', () => {
|
|
218
219
|
const files = processFiles(['/invalidThings.js'], getFileSource);
|
|
219
|
-
expect(files['/invalidThings.js'].errors.map((m) => m.message))
|
|
220
|
+
expect(files['/invalidThings.js'].errors.map((m: any) => m.message))
|
|
220
221
|
.toMatchInlineSnapshot(`
|
|
221
222
|
Array [
|
|
222
223
|
"Unable to resolve someExternalFragment",
|
|
@@ -228,11 +229,11 @@ describe('processing fragments in various ways', () => {
|
|
|
228
229
|
|
|
229
230
|
it('should flag resolution errors', () => {
|
|
230
231
|
const files = processFiles(['/invalidReferences.js'], getFileSource);
|
|
231
|
-
Object.keys(files).forEach((k) => {
|
|
232
|
+
Object.keys(files).forEach((k: any) => {
|
|
232
233
|
expect(files[k].errors).toEqual([]);
|
|
233
234
|
});
|
|
234
235
|
const {resolved, errors} = resolveDocuments(files);
|
|
235
|
-
expect(errors.map((m) => m.message)).toMatchInlineSnapshot(`
|
|
236
|
+
expect(errors.map((m: any) => m.message)).toMatchInlineSnapshot(`
|
|
236
237
|
Array [
|
|
237
238
|
"Circular import /circular.js -> /invalidReferences.js -> /circular.js",
|
|
238
239
|
"/circular.js has no valid gql export doesntExist",
|
|
@@ -240,9 +241,9 @@ describe('processing fragments in various ways', () => {
|
|
|
240
241
|
"Recursive template dependency! /circular.js:5 ~ 1,2 -> /invalidReferences.js:15 ~ 1,2 -> /circular.js:5",
|
|
241
242
|
]
|
|
242
243
|
`);
|
|
243
|
-
const printed = {};
|
|
244
|
+
const printed: Record<string, any> = {};
|
|
244
245
|
Object.keys(resolved).map(
|
|
245
|
-
(k) => (printed[k] = print(resolved[k].document).trim()),
|
|
246
|
+
(k: any) => (printed[k] = print(resolved[k].document).trim()),
|
|
246
247
|
);
|
|
247
248
|
expect(printed).toMatchInlineSnapshot(`Object {}`);
|
|
248
249
|
});
|