@khanacademy/graphql-flow 1.2.0 → 3.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 +8 -7
- 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 +9 -8
- 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/src/cli/{config.js → config.ts} +10 -15
- 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.flow +0 -84
- 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/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
package/src/parser/resolve.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import gql from 'graphql-tag';
|
|
3
|
-
import {getPathWithExtension} from './utils';
|
|
4
|
-
import type {DocumentNode} from 'graphql/language/ast';
|
|
5
|
-
import type {FileResult, Files, Import, Template, Document} from './parse';
|
|
6
|
-
|
|
7
|
-
export type Resolved = {
|
|
8
|
-
[key: string]: {
|
|
9
|
-
document: DocumentNode,
|
|
10
|
-
raw: Template,
|
|
11
|
-
},
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export const resolveDocuments = (
|
|
15
|
-
files: Files,
|
|
16
|
-
): {resolved: Resolved, errors: FileResult['errors']} => {
|
|
17
|
-
const resolved: Resolved = {};
|
|
18
|
-
const errors: FileResult['errors'] = [];
|
|
19
|
-
Object.keys(files).forEach((path) => {
|
|
20
|
-
const file = files[path];
|
|
21
|
-
file.operations.forEach((op) => {
|
|
22
|
-
resolveGqlTemplate(op.source, files, errors, resolved, {});
|
|
23
|
-
});
|
|
24
|
-
Object.keys(file.locals).forEach((k) => {
|
|
25
|
-
const local = file.locals[k];
|
|
26
|
-
if (local.type === 'document') {
|
|
27
|
-
resolveGqlTemplate(local.source, files, errors, resolved, {});
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
return {resolved, errors};
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const resolveImport = (
|
|
35
|
-
expr: Import,
|
|
36
|
-
files: Files,
|
|
37
|
-
errors: FileResult['errors'],
|
|
38
|
-
seen: {[key: string]: true},
|
|
39
|
-
): ?Document => {
|
|
40
|
-
const absPath: string = getPathWithExtension(expr.path);
|
|
41
|
-
if (seen[absPath]) {
|
|
42
|
-
errors.push({
|
|
43
|
-
loc: expr.loc,
|
|
44
|
-
message: `Circular import ${Object.keys(seen).join(
|
|
45
|
-
' -> ',
|
|
46
|
-
)} -> ${absPath}`,
|
|
47
|
-
});
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
seen[absPath] = true;
|
|
51
|
-
const res = files[absPath];
|
|
52
|
-
if (!res) {
|
|
53
|
-
errors.push({loc: expr.loc, message: `No file ${absPath}`});
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
if (!res.exports[expr.name]) {
|
|
57
|
-
errors.push({
|
|
58
|
-
loc: expr.loc,
|
|
59
|
-
message: `${absPath} has no valid gql export ${expr.name}`,
|
|
60
|
-
});
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
const value = res.exports[expr.name];
|
|
64
|
-
if (value.type === 'import') {
|
|
65
|
-
return resolveImport(value, files, errors, seen);
|
|
66
|
-
}
|
|
67
|
-
return value;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const resolveGqlTemplate = (
|
|
71
|
-
template: Template,
|
|
72
|
-
files: Files,
|
|
73
|
-
errors: FileResult['errors'],
|
|
74
|
-
resolved: Resolved,
|
|
75
|
-
seen: {[key: string]: Template},
|
|
76
|
-
): ?DocumentNode => {
|
|
77
|
-
const key = template.loc.path + ':' + template.loc.line;
|
|
78
|
-
if (seen[key]) {
|
|
79
|
-
errors.push({
|
|
80
|
-
loc: template.loc,
|
|
81
|
-
message: `Recursive template dependency! ${Object.keys(seen)
|
|
82
|
-
.map(
|
|
83
|
-
(k) =>
|
|
84
|
-
k +
|
|
85
|
-
' ~ ' +
|
|
86
|
-
seen[k].expressions.length +
|
|
87
|
-
',' +
|
|
88
|
-
seen[k].literals.length,
|
|
89
|
-
)
|
|
90
|
-
.join(' -> ')} -> ${key}`,
|
|
91
|
-
});
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
seen[key] = template;
|
|
95
|
-
if (resolved[key]) {
|
|
96
|
-
return resolved[key].document;
|
|
97
|
-
}
|
|
98
|
-
const expressions = template.expressions.map((expr) => {
|
|
99
|
-
if (expr.type === 'import') {
|
|
100
|
-
const document = resolveImport(expr, files, errors, {});
|
|
101
|
-
return document
|
|
102
|
-
? resolveGqlTemplate(document.source, files, errors, resolved, {
|
|
103
|
-
...seen,
|
|
104
|
-
})
|
|
105
|
-
: null;
|
|
106
|
-
}
|
|
107
|
-
return resolveGqlTemplate(expr.source, files, errors, resolved, {
|
|
108
|
-
...seen,
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
if (expressions.includes(null)) {
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
resolved[key] = {
|
|
115
|
-
document: gql(template.literals, ...expressions),
|
|
116
|
-
raw: template,
|
|
117
|
-
};
|
|
118
|
-
return resolved[key].document;
|
|
119
|
-
};
|
package/src/parser/utils.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
|
|
4
|
-
export const getPathWithExtension = (pathWithoutExtension: string): string => {
|
|
5
|
-
if (
|
|
6
|
-
/\.(less|css|png|gif|jpg|jpeg|js|jsx|ts|tsx|mjs)$/.test(
|
|
7
|
-
pathWithoutExtension,
|
|
8
|
-
)
|
|
9
|
-
) {
|
|
10
|
-
return pathWithoutExtension;
|
|
11
|
-
}
|
|
12
|
-
if (fs.existsSync(pathWithoutExtension + '.js')) {
|
|
13
|
-
return pathWithoutExtension + '.js';
|
|
14
|
-
}
|
|
15
|
-
if (fs.existsSync(pathWithoutExtension + '.jsx')) {
|
|
16
|
-
return pathWithoutExtension + '.jsx';
|
|
17
|
-
}
|
|
18
|
-
if (fs.existsSync(pathWithoutExtension + '.tsx')) {
|
|
19
|
-
return pathWithoutExtension + '.tsx';
|
|
20
|
-
}
|
|
21
|
-
if (fs.existsSync(pathWithoutExtension + '.ts')) {
|
|
22
|
-
return pathWithoutExtension + '.ts';
|
|
23
|
-
}
|
|
24
|
-
throw new Error("Can't find file at " + pathWithoutExtension);
|
|
25
|
-
};
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
/**
|
|
3
|
-
* Takes the introspectionQuery response and parses it into the "Schema"
|
|
4
|
-
* type that we use to look up types, interfaces, etc.
|
|
5
|
-
*/
|
|
6
|
-
import type {IntrospectionQuery} from 'graphql';
|
|
7
|
-
import type {Schema} from './types';
|
|
8
|
-
|
|
9
|
-
export const schemaFromIntrospectionData = (
|
|
10
|
-
schema: IntrospectionQuery,
|
|
11
|
-
): Schema => {
|
|
12
|
-
const result: Schema = {
|
|
13
|
-
interfacesByName: {},
|
|
14
|
-
typesByName: {},
|
|
15
|
-
inputObjectsByName: {},
|
|
16
|
-
unionsByName: {},
|
|
17
|
-
enumsByName: {},
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
schema.__schema.types.forEach((type) => {
|
|
21
|
-
if (type.kind === 'ENUM') {
|
|
22
|
-
result.enumsByName[type.name] = type;
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
if (type.kind === 'UNION') {
|
|
26
|
-
result.unionsByName[type.name] = type;
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
if (type.kind === 'INTERFACE') {
|
|
30
|
-
result.interfacesByName[type.name] = {
|
|
31
|
-
...type,
|
|
32
|
-
possibleTypesByName: {},
|
|
33
|
-
fieldsByName: {},
|
|
34
|
-
};
|
|
35
|
-
type.possibleTypes.forEach(
|
|
36
|
-
(p) =>
|
|
37
|
-
(result.interfacesByName[type.name].possibleTypesByName[
|
|
38
|
-
p.name
|
|
39
|
-
] = true),
|
|
40
|
-
);
|
|
41
|
-
type.fields.forEach((field) => {
|
|
42
|
-
result.interfacesByName[type.name].fieldsByName[field.name] =
|
|
43
|
-
field;
|
|
44
|
-
});
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
if (type.kind === 'INPUT_OBJECT') {
|
|
48
|
-
result.inputObjectsByName[type.name] = type;
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
if (type.kind === 'SCALAR') {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
result.typesByName[type.name] = {
|
|
55
|
-
...type,
|
|
56
|
-
fieldsByName: {},
|
|
57
|
-
};
|
|
58
|
-
if (!type.fields) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
type.fields.forEach((field) => {
|
|
63
|
-
result.typesByName[type.name].fieldsByName[field.name] = field;
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return result;
|
|
68
|
-
};
|
package/src/types.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
|
|
3
|
-
import type {BabelNode} from '@babel/types';
|
|
4
|
-
import type {
|
|
5
|
-
FragmentDefinitionNode,
|
|
6
|
-
IntrospectionEnumType,
|
|
7
|
-
IntrospectionField,
|
|
8
|
-
IntrospectionInputObjectType,
|
|
9
|
-
IntrospectionInterfaceType,
|
|
10
|
-
IntrospectionObjectType,
|
|
11
|
-
IntrospectionUnionType,
|
|
12
|
-
SelectionNode,
|
|
13
|
-
} from 'graphql';
|
|
14
|
-
|
|
15
|
-
export type Selections = $ReadOnlyArray<SelectionNode>;
|
|
16
|
-
|
|
17
|
-
export type GenerateConfig = {|
|
|
18
|
-
schemaFilePath: string,
|
|
19
|
-
match?: Array<RegExp | string>,
|
|
20
|
-
exclude?: Array<RegExp | string>,
|
|
21
|
-
|
|
22
|
-
typeScript?: boolean,
|
|
23
|
-
scalars?: Scalars,
|
|
24
|
-
strictNullability?: boolean,
|
|
25
|
-
/**
|
|
26
|
-
* The command that users should run to regenerate the types files.
|
|
27
|
-
*/
|
|
28
|
-
regenerateCommand?: string,
|
|
29
|
-
readOnlyArray?: boolean,
|
|
30
|
-
splitTypes?: boolean,
|
|
31
|
-
generatedDirectory?: string,
|
|
32
|
-
exportAllObjectTypes?: boolean,
|
|
33
|
-
typeFileName?: string,
|
|
34
|
-
experimentalEnums?: boolean,
|
|
35
|
-
omitFileExtensions?: boolean,
|
|
36
|
-
|};
|
|
37
|
-
|
|
38
|
-
export type CrawlConfig = {
|
|
39
|
-
root: string,
|
|
40
|
-
pragma?: string,
|
|
41
|
-
loosePragma?: string,
|
|
42
|
-
ignorePragma?: string,
|
|
43
|
-
dumpOperations?: string,
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export type Config = {
|
|
47
|
-
crawl: CrawlConfig,
|
|
48
|
-
generate: GenerateConfig | Array<GenerateConfig>,
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export type Schema = {
|
|
52
|
-
interfacesByName: {
|
|
53
|
-
[key: string]: IntrospectionInterfaceType & {
|
|
54
|
-
fieldsByName: {[key: string]: IntrospectionField},
|
|
55
|
-
possibleTypesByName: {[key: string]: boolean},
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
inputObjectsByName: {
|
|
59
|
-
[key: string]: IntrospectionInputObjectType,
|
|
60
|
-
},
|
|
61
|
-
typesByName: {
|
|
62
|
-
[key: string]: IntrospectionObjectType & {
|
|
63
|
-
fieldsByName: {[key: string]: IntrospectionField},
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
unionsByName: {
|
|
67
|
-
[key: string]: IntrospectionUnionType,
|
|
68
|
-
},
|
|
69
|
-
enumsByName: {
|
|
70
|
-
[key: string]: IntrospectionEnumType,
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export type Context = {
|
|
75
|
-
path: Array<string>,
|
|
76
|
-
strictNullability: boolean,
|
|
77
|
-
readOnlyArray: boolean,
|
|
78
|
-
fragments: {[key: string]: FragmentDefinitionNode},
|
|
79
|
-
|
|
80
|
-
schema: Schema,
|
|
81
|
-
scalars: Scalars,
|
|
82
|
-
errors: Array<string>,
|
|
83
|
-
allObjectTypes: null | {[key: string]: BabelNode},
|
|
84
|
-
typeScript: boolean,
|
|
85
|
-
|
|
86
|
-
experimentalEnumsMap?: {[key: string]: BabelNode}, // index signature that is populated with declarations
|
|
87
|
-
};
|
|
88
|
-
export type Scalars = {[key: string]: 'string' | 'number' | 'boolean'};
|
package/src/utils.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
|
|
3
|
-
import * as babelTypes from '@babel/types';
|
|
4
|
-
import {BabelNodeObjectTypeProperty} from '@babel/types';
|
|
5
|
-
|
|
6
|
-
export const liftLeadingPropertyComments = (
|
|
7
|
-
property: BabelNodeObjectTypeProperty,
|
|
8
|
-
): BabelNodeObjectTypeProperty => {
|
|
9
|
-
return transferLeadingComments(property.value, property);
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export const maybeAddDescriptionComment = <T: babelTypes.BabelNode>(
|
|
13
|
-
description: ?string,
|
|
14
|
-
node: T,
|
|
15
|
-
): T => {
|
|
16
|
-
if (description) {
|
|
17
|
-
addCommentAsLineComments(description, node);
|
|
18
|
-
}
|
|
19
|
-
return node;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export function addCommentAsLineComments(
|
|
23
|
-
description: string,
|
|
24
|
-
res: babelTypes.BabelNode,
|
|
25
|
-
) {
|
|
26
|
-
if (res.leadingComments?.length) {
|
|
27
|
-
res.leadingComments[0].value += '\n\n---\n\n' + description;
|
|
28
|
-
} else {
|
|
29
|
-
babelTypes.addComment(
|
|
30
|
-
res,
|
|
31
|
-
'leading',
|
|
32
|
-
'* ' + description,
|
|
33
|
-
false, // this specifies that it's a block comment, not a line comment
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const transferLeadingComments = <T: babelTypes.BabelNode>(
|
|
39
|
-
source: babelTypes.BabelNode,
|
|
40
|
-
dest: T,
|
|
41
|
-
): T => {
|
|
42
|
-
if (source.leadingComments?.length) {
|
|
43
|
-
dest.leadingComments = [
|
|
44
|
-
...(dest.leadingComments || []),
|
|
45
|
-
...source.leadingComments,
|
|
46
|
-
];
|
|
47
|
-
source.leadingComments = [];
|
|
48
|
-
}
|
|
49
|
-
return dest;
|
|
50
|
-
};
|
|
File without changes
|