@khanacademy/graphql-flow 3.0.1 → 3.1.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/.eslintrc.js +15 -4
- package/.github/workflows/changeset-release.yml +3 -5
- package/.github/workflows/pr-checks.yml +17 -17
- package/.prettierrc +2 -2
- package/.vscode/settings.json +6 -0
- package/CHANGELOG.md +6 -0
- package/dist/cli/config.js +6 -15
- package/dist/cli/run.js +27 -36
- package/dist/enums.js +9 -9
- package/dist/generateResponseType.js +36 -40
- package/dist/generateTypeFiles.js +10 -10
- package/dist/generateVariablesType.js +12 -13
- package/dist/index.js +4 -6
- package/dist/parser/parse.js +43 -52
- package/dist/parser/resolve.js +16 -16
- package/dist/parser/utils.js +19 -9
- package/dist/schemaFromIntrospectionData.js +5 -5
- package/dist/utils.js +8 -8
- package/package.json +12 -13
- package/src/__test__/generateTypeFileContents.test.ts +26 -25
- package/src/__test__/graphql-flow.test.ts +32 -33
- package/src/__test__/processPragmas.test.ts +14 -13
- package/src/cli/__test__/config.test.ts +51 -56
- package/src/cli/config.ts +23 -20
- package/src/cli/run.ts +41 -45
- package/src/enums.ts +17 -17
- package/src/generateResponseType.ts +120 -91
- package/src/generateTypeFiles.ts +24 -22
- package/src/generateVariablesType.ts +20 -20
- package/src/index.ts +28 -29
- package/src/parser/__test__/parse.test.ts +114 -23
- package/src/parser/__test__/utils.test.ts +80 -0
- package/src/parser/parse.ts +119 -105
- package/src/parser/resolve.ts +61 -34
- package/src/parser/utils.ts +23 -10
- package/src/schemaFromIntrospectionData.ts +10 -8
- package/src/types.ts +57 -53
- package/src/utils.ts +30 -16
- package/tools/find-files-with-gql.ts +7 -11
package/.eslintrc.js
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
extends: ['@khanacademy'],
|
|
3
2
|
root: true,
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
plugins: ["prettier", "jest"],
|
|
4
|
+
extends: ["eslint:recommended", "prettier"],
|
|
5
|
+
parser: "@typescript-eslint/parser",
|
|
6
|
+
parserOptions: {
|
|
7
|
+
sourceType: "module",
|
|
8
|
+
ecmaVersion: 2020,
|
|
9
|
+
},
|
|
6
10
|
rules: {
|
|
7
|
-
|
|
11
|
+
"prettier/prettier": "error",
|
|
12
|
+
"no-unused-vars": "off",
|
|
13
|
+
"no-case-declarations": "off",
|
|
14
|
+
},
|
|
15
|
+
env: {
|
|
16
|
+
es6: true,
|
|
17
|
+
node: true,
|
|
18
|
+
jest: true,
|
|
8
19
|
},
|
|
9
20
|
};
|
|
@@ -31,12 +31,10 @@ jobs:
|
|
|
31
31
|
name: Release
|
|
32
32
|
runs-on: ubuntu-latest
|
|
33
33
|
steps:
|
|
34
|
-
- uses: actions/checkout@
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
- uses: Khan/actions@shared-node-cache-v2
|
|
35
36
|
with:
|
|
36
|
-
|
|
37
|
-
- uses: Khan/actions@shared-node-cache-v0.0.2
|
|
38
|
-
with:
|
|
39
|
-
node-version: 16.x
|
|
37
|
+
node-version: 20.x
|
|
40
38
|
|
|
41
39
|
- name: Create Release Pull Request or Publish to npm
|
|
42
40
|
id: changesets
|
|
@@ -14,45 +14,45 @@ jobs:
|
|
|
14
14
|
strategy:
|
|
15
15
|
matrix:
|
|
16
16
|
os: [ubuntu-latest]
|
|
17
|
-
node-version: [
|
|
17
|
+
node-version: [20.x]
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
20
|
-
- uses: Khan/actions@shared-node-cache-
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: Khan/actions@shared-node-cache-v2
|
|
21
21
|
with:
|
|
22
22
|
node-version: ${{ matrix.node-version }}
|
|
23
23
|
|
|
24
24
|
- name: Get All Changed Files
|
|
25
|
-
uses: Khan/actions@get-changed-files-
|
|
25
|
+
uses: Khan/actions@get-changed-files-v2
|
|
26
26
|
id: changed
|
|
27
27
|
|
|
28
|
-
- id:
|
|
29
|
-
name: Find .
|
|
30
|
-
uses: Khan/actions@filter-files-
|
|
28
|
+
- id: ts-files
|
|
29
|
+
name: Find .ts changed files
|
|
30
|
+
uses: Khan/actions@filter-files-v1
|
|
31
31
|
with:
|
|
32
32
|
changed-files: ${{ steps.changed.outputs.files }}
|
|
33
|
-
extensions: '.
|
|
33
|
+
extensions: '.ts'
|
|
34
34
|
|
|
35
|
-
- name: Run
|
|
36
|
-
if: steps.
|
|
37
|
-
run: yarn
|
|
35
|
+
- name: Run TypeScript
|
|
36
|
+
if: steps.ts-files.outputs.filtered != '[]'
|
|
37
|
+
run: yarn tsc
|
|
38
38
|
|
|
39
39
|
- id: eslint-reset
|
|
40
|
-
uses: Khan/actions@filter-files-
|
|
40
|
+
uses: Khan/actions@filter-files-v1
|
|
41
41
|
name: Files that would trigger a full eslint run
|
|
42
42
|
with:
|
|
43
43
|
changed-files: ${{ steps.changed.outputs.files }}
|
|
44
44
|
files: '.eslintrc.js,package.json,.eslintignore'
|
|
45
45
|
|
|
46
|
-
- name:
|
|
46
|
+
- name: ESlint
|
|
47
47
|
uses: Khan/actions@full-or-limited-v0
|
|
48
48
|
with:
|
|
49
49
|
full-trigger: ${{ steps.eslint-reset.outputs.filtered }}
|
|
50
|
-
full: yarn eslint
|
|
51
|
-
limited-trigger: ${{ steps.
|
|
50
|
+
full: yarn eslint src/**/*.ts
|
|
51
|
+
limited-trigger: ${{ steps.ts-files.outputs.filtered }}
|
|
52
52
|
limited: yarn eslint {}
|
|
53
53
|
|
|
54
54
|
- id: jest-reset
|
|
55
|
-
uses: Khan/actions@filter-files-
|
|
55
|
+
uses: Khan/actions@filter-files-v1
|
|
56
56
|
name: Files that would trigger a full jest run
|
|
57
57
|
with:
|
|
58
58
|
changed-files: ${{ steps.changed.outputs.files }}
|
|
@@ -63,5 +63,5 @@ jobs:
|
|
|
63
63
|
with:
|
|
64
64
|
full-trigger: ${{ steps.jest-reset.outputs.filtered }}
|
|
65
65
|
full: yarn jest
|
|
66
|
-
limited-trigger: ${{ steps.
|
|
66
|
+
limited-trigger: ${{ steps.ts-files.outputs.filtered }}
|
|
67
67
|
limited: yarn jest --findRelatedTests {}
|
package/.prettierrc
CHANGED
package/CHANGELOG.md
CHANGED
package/dist/cli/config.js
CHANGED
|
@@ -17,27 +17,20 @@ var _jsonschema = require("jsonschema");
|
|
|
17
17
|
|
|
18
18
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
19
|
|
|
20
|
-
// eslint-disable-line flowtype-errors/uncovered
|
|
21
|
-
// eslint-disable-line flowtype-errors/uncovered
|
|
22
20
|
const validateOrThrow = (value, jsonSchema) => {
|
|
23
|
-
/* eslint-disable flowtype-errors/uncovered */
|
|
24
21
|
const result = (0, _jsonschema.validate)(value, jsonSchema);
|
|
25
22
|
|
|
26
23
|
if (!result.valid) {
|
|
27
|
-
throw new Error(result.errors.map(error => error.toString()).join(
|
|
24
|
+
throw new Error(result.errors.map(error => error.toString()).join("\n"));
|
|
28
25
|
}
|
|
29
|
-
/* eslint-enable flowtype-errors/uncovered */
|
|
30
|
-
|
|
31
26
|
};
|
|
32
27
|
|
|
33
28
|
exports.validateOrThrow = validateOrThrow;
|
|
34
29
|
|
|
35
30
|
const loadConfigFile = configFile => {
|
|
36
|
-
const data = require(configFile);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
validateOrThrow(data, _schema.default); // eslint-disable-line flowtype-errors/uncovered
|
|
31
|
+
const data = require(configFile);
|
|
40
32
|
|
|
33
|
+
validateOrThrow(data, _schema.default);
|
|
41
34
|
return data;
|
|
42
35
|
};
|
|
43
36
|
/**
|
|
@@ -48,9 +41,9 @@ const loadConfigFile = configFile => {
|
|
|
48
41
|
exports.loadConfigFile = loadConfigFile;
|
|
49
42
|
|
|
50
43
|
const getSchemas = schemaFilePath => {
|
|
51
|
-
const raw = _fs.default.readFileSync(schemaFilePath,
|
|
44
|
+
const raw = _fs.default.readFileSync(schemaFilePath, "utf8");
|
|
52
45
|
|
|
53
|
-
if (schemaFilePath.endsWith(
|
|
46
|
+
if (schemaFilePath.endsWith(".graphql")) {
|
|
54
47
|
const schemaForValidation = (0, _graphql.buildSchema)(raw);
|
|
55
48
|
const queryResponse = (0, _graphql.graphqlSync)({
|
|
56
49
|
schema: schemaForValidation,
|
|
@@ -58,11 +51,9 @@ const getSchemas = schemaFilePath => {
|
|
|
58
51
|
descriptions: true
|
|
59
52
|
})
|
|
60
53
|
});
|
|
61
|
-
const schemaForTypeGeneration = (0, _schemaFromIntrospectionData.schemaFromIntrospectionData)(
|
|
62
|
-
queryResponse.data);
|
|
54
|
+
const schemaForTypeGeneration = (0, _schemaFromIntrospectionData.schemaFromIntrospectionData)(queryResponse.data);
|
|
63
55
|
return [schemaForValidation, schemaForTypeGeneration];
|
|
64
56
|
} else {
|
|
65
|
-
// eslint-disable-next-line flowtype-errors/uncovered
|
|
66
57
|
const introspectionData = JSON.parse(raw);
|
|
67
58
|
const schemaForValidation = (0, _graphql.buildClientSchema)(introspectionData);
|
|
68
59
|
const schemaForTypeGeneration = (0, _schemaFromIntrospectionData.schemaFromIntrospectionData)(introspectionData);
|
package/dist/cli/run.js
CHANGED
|
@@ -27,8 +27,6 @@ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "functio
|
|
|
27
27
|
|
|
28
28
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
29
29
|
|
|
30
|
-
// eslint-disable-line flowtype-errors/uncovered
|
|
31
|
-
|
|
32
30
|
/**
|
|
33
31
|
* This CLI tool executes the following steps:
|
|
34
32
|
* 1) parse & validate config file
|
|
@@ -46,19 +44,19 @@ const findGraphqlTagReferences = root => {
|
|
|
46
44
|
// generate types for them. This is useful for when we have a new file
|
|
47
45
|
// that we want to generate types for, but we haven't committed it yet.
|
|
48
46
|
const response = (0, _child_process.execSync)("git grep -I --word-regexp --name-only --fixed-strings --untracked 'graphql-tag' -- '*.js' '*.jsx' '*.ts' '*.tsx'", {
|
|
49
|
-
encoding:
|
|
47
|
+
encoding: "utf8",
|
|
50
48
|
cwd: root
|
|
51
49
|
});
|
|
52
|
-
return response.trim().split(
|
|
50
|
+
return response.trim().split("\n").map(relative => _path.default.join(root, relative));
|
|
53
51
|
};
|
|
54
52
|
|
|
55
53
|
const [_, __, configFilePath, ...cliFiles] = process.argv;
|
|
56
54
|
|
|
57
|
-
if (configFilePath ===
|
|
55
|
+
if (configFilePath === "-h" || configFilePath === "--help" || configFilePath === "help" || !configFilePath) {
|
|
58
56
|
console.log(`graphql-flow
|
|
59
57
|
|
|
60
58
|
Usage: graphql-flow [configFile.json] [filesToCrawl...]`);
|
|
61
|
-
process.exit(1);
|
|
59
|
+
process.exit(1);
|
|
62
60
|
}
|
|
63
61
|
|
|
64
62
|
const makeAbsPath = (maybeRelativePath, basePath) => {
|
|
@@ -70,29 +68,29 @@ const config = (0, _config.loadConfigFile)(absConfigPath);
|
|
|
70
68
|
const inputFiles = cliFiles.length ? cliFiles : findGraphqlTagReferences(makeAbsPath(config.crawl.root, _path.default.dirname(absConfigPath)));
|
|
71
69
|
/** Step (2) */
|
|
72
70
|
|
|
73
|
-
const files = (0, _parse.processFiles)(inputFiles, f => {
|
|
71
|
+
const files = (0, _parse.processFiles)(inputFiles, config, f => {
|
|
74
72
|
if ((0, _fs.existsSync)(f)) {
|
|
75
|
-
return (0, _fs.readFileSync)(f,
|
|
73
|
+
return (0, _fs.readFileSync)(f, "utf8");
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
if ((0, _fs.existsSync)(f +
|
|
76
|
+
if ((0, _fs.existsSync)(f + ".js")) {
|
|
79
77
|
return {
|
|
80
|
-
text: (0, _fs.readFileSync)(f +
|
|
81
|
-
resolvedPath: f +
|
|
78
|
+
text: (0, _fs.readFileSync)(f + ".js", "utf8"),
|
|
79
|
+
resolvedPath: f + ".js"
|
|
82
80
|
};
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
if ((0, _fs.existsSync)(f +
|
|
83
|
+
if ((0, _fs.existsSync)(f + ".ts")) {
|
|
86
84
|
return {
|
|
87
|
-
text: (0, _fs.readFileSync)(f +
|
|
88
|
-
resolvedPath: f +
|
|
85
|
+
text: (0, _fs.readFileSync)(f + ".ts", "utf8"),
|
|
86
|
+
resolvedPath: f + ".ts"
|
|
89
87
|
};
|
|
90
88
|
}
|
|
91
89
|
|
|
92
|
-
if ((0, _fs.existsSync)(f +
|
|
90
|
+
if ((0, _fs.existsSync)(f + ".tsx")) {
|
|
93
91
|
return {
|
|
94
|
-
text: (0, _fs.readFileSync)(f +
|
|
95
|
-
resolvedPath: f +
|
|
92
|
+
text: (0, _fs.readFileSync)(f + ".tsx", "utf8"),
|
|
93
|
+
resolvedPath: f + ".tsx"
|
|
96
94
|
};
|
|
97
95
|
}
|
|
98
96
|
|
|
@@ -112,8 +110,8 @@ Object.keys(files).forEach(key => {
|
|
|
112
110
|
});
|
|
113
111
|
|
|
114
112
|
if (filesHadErrors) {
|
|
115
|
-
console.error(
|
|
116
|
-
process.exit(1);
|
|
113
|
+
console.error("Aborting");
|
|
114
|
+
process.exit(1);
|
|
117
115
|
}
|
|
118
116
|
/** Step (3) */
|
|
119
117
|
|
|
@@ -121,17 +119,17 @@ if (filesHadErrors) {
|
|
|
121
119
|
const {
|
|
122
120
|
resolved,
|
|
123
121
|
errors
|
|
124
|
-
} = (0, _resolve.resolveDocuments)(files);
|
|
122
|
+
} = (0, _resolve.resolveDocuments)(files, config);
|
|
125
123
|
|
|
126
124
|
if (errors.length) {
|
|
127
125
|
errors.forEach(error => {
|
|
128
126
|
console.error(`Resolution error ${error.message} in ${error.loc.path}`);
|
|
129
127
|
});
|
|
130
|
-
console.error(
|
|
131
|
-
process.exit(1);
|
|
128
|
+
console.error("Aborting");
|
|
129
|
+
process.exit(1);
|
|
132
130
|
}
|
|
133
131
|
|
|
134
|
-
console.log(Object.keys(resolved).length,
|
|
132
|
+
console.log(Object.keys(resolved).length, "resolved queries");
|
|
135
133
|
/** Step (4) */
|
|
136
134
|
|
|
137
135
|
const schemaCache = {};
|
|
@@ -153,15 +151,14 @@ Object.keys(resolved).forEach(filePathAndLine => {
|
|
|
153
151
|
} = resolved[filePathAndLine];
|
|
154
152
|
const hasNonFragments = document.definitions.some(({
|
|
155
153
|
kind
|
|
156
|
-
}) => kind !==
|
|
154
|
+
}) => kind !== "FragmentDefinition");
|
|
157
155
|
const rawSource = raw.literals[0];
|
|
158
156
|
const generateConfig = (0, _config.findApplicableConfig)( // strip off the trailing line number, e.g. `:23`
|
|
159
|
-
filePathAndLine.split(
|
|
157
|
+
filePathAndLine.split(":")[0], config.generate);
|
|
160
158
|
|
|
161
159
|
if (!generateConfig) {
|
|
162
160
|
return; // no generate config matches, bail
|
|
163
|
-
}
|
|
164
|
-
|
|
161
|
+
}
|
|
165
162
|
|
|
166
163
|
const withTypeNames = (0, _apolloUtilities.addTypenameToDocument)(document);
|
|
167
164
|
const printed = (0, _printer.print)(withTypeNames);
|
|
@@ -183,9 +180,7 @@ Object.keys(resolved).forEach(filePathAndLine => {
|
|
|
183
180
|
const [schemaForValidation, schemaForTypeGeneration] = getCachedSchemas(generateConfig.schemaFilePath);
|
|
184
181
|
|
|
185
182
|
if (hasNonFragments) {
|
|
186
|
-
/* eslint-disable flowtype-errors/uncovered */
|
|
187
183
|
const errors = (0, _validation.validate)(schemaForValidation, withTypeNames);
|
|
188
|
-
/* eslint-disable flowtype-errors/uncovered */
|
|
189
184
|
|
|
190
185
|
if (errors.length) {
|
|
191
186
|
errors.forEach(error => {
|
|
@@ -195,24 +190,20 @@ Object.keys(resolved).forEach(filePathAndLine => {
|
|
|
195
190
|
validationFailures++;
|
|
196
191
|
});
|
|
197
192
|
}
|
|
198
|
-
/* eslint-enable flowtype-errors/uncovered */
|
|
199
|
-
|
|
200
193
|
}
|
|
201
194
|
|
|
202
195
|
try {
|
|
203
|
-
(0, _generateTypeFiles.generateTypeFiles)(raw.loc.path, schemaForTypeGeneration, withTypeNames, generateConfig);
|
|
196
|
+
(0, _generateTypeFiles.generateTypeFiles)(raw.loc.path, schemaForTypeGeneration, withTypeNames, generateConfig);
|
|
204
197
|
} catch (err) {
|
|
205
198
|
console.error(`Error while generating operation from ${raw.loc.path}`);
|
|
206
|
-
console.error(printed);
|
|
207
|
-
|
|
199
|
+
console.error(printed);
|
|
208
200
|
console.error(err);
|
|
209
201
|
validationFailures++;
|
|
210
202
|
}
|
|
211
203
|
});
|
|
212
204
|
|
|
213
205
|
if (validationFailures) {
|
|
214
|
-
console.error(`Encountered ${validationFailures} validation failures while printing types.`);
|
|
215
|
-
|
|
206
|
+
console.error(`Encountered ${validationFailures} validation failures while printing types.`);
|
|
216
207
|
process.exit(1);
|
|
217
208
|
}
|
|
218
209
|
|
package/dist/enums.js
CHANGED
|
@@ -31,10 +31,10 @@ exports.experimentalEnumTypeToFlow = experimentalEnumTypeToFlow;
|
|
|
31
31
|
|
|
32
32
|
const enumTypeToFlow = (ctx, name) => {
|
|
33
33
|
const enumConfig = ctx.schema.enumsByName[name];
|
|
34
|
-
let combinedDescription = enumConfig.enumValues.map(n => `- ${n.name}` + (n.description ?
|
|
34
|
+
let combinedDescription = enumConfig.enumValues.map(n => `- ${n.name}` + (n.description ? "\n\n " + n.description.replace(/\n/g, "\n ") : "")).join("\n");
|
|
35
35
|
|
|
36
36
|
if (enumConfig.description) {
|
|
37
|
-
combinedDescription = enumConfig.description +
|
|
37
|
+
combinedDescription = enumConfig.description + "\n\n" + combinedDescription;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
return ctx.experimentalEnumsMap ? experimentalEnumTypeToFlow(ctx, enumConfig, combinedDescription) : (0, _utils.maybeAddDescriptionComment)(combinedDescription, babelTypes.tsUnionType(enumConfig.enumValues.map(n => babelTypes.tsLiteralType(babelTypes.stringLiteral(n.name)))));
|
|
@@ -42,13 +42,13 @@ const enumTypeToFlow = (ctx, name) => {
|
|
|
42
42
|
|
|
43
43
|
exports.enumTypeToFlow = enumTypeToFlow;
|
|
44
44
|
const builtinScalars = {
|
|
45
|
-
Boolean:
|
|
46
|
-
String:
|
|
47
|
-
DateTime:
|
|
48
|
-
Date:
|
|
49
|
-
ID:
|
|
50
|
-
Int:
|
|
51
|
-
Float:
|
|
45
|
+
Boolean: "boolean",
|
|
46
|
+
String: "string",
|
|
47
|
+
DateTime: "string",
|
|
48
|
+
Date: "string",
|
|
49
|
+
ID: "string",
|
|
50
|
+
Int: "number",
|
|
51
|
+
Float: "number"
|
|
52
52
|
};
|
|
53
53
|
exports.builtinScalars = builtinScalars;
|
|
54
54
|
|
|
@@ -20,10 +20,8 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
|
|
|
20
20
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
21
21
|
|
|
22
22
|
/* eslint-disable no-console */
|
|
23
|
-
// eslint-disable-line flowtype-errors/uncovered
|
|
24
23
|
const generateResponseType = (schema, query, ctx) => {
|
|
25
|
-
const ast = querySelectionToObjectType(ctx, query.selectionSet.selections, query.operation ===
|
|
26
|
-
|
|
24
|
+
const ast = querySelectionToObjectType(ctx, query.selectionSet.selections, query.operation === "mutation" ? schema.typesByName.Mutation : schema.typesByName.Query, query.operation === "mutation" ? "mutation" : "query");
|
|
27
25
|
return (0, _generator.default)(ast).code;
|
|
28
26
|
};
|
|
29
27
|
|
|
@@ -31,15 +29,15 @@ exports.generateResponseType = generateResponseType;
|
|
|
31
29
|
|
|
32
30
|
const sortedObjectTypeAnnotation = (ctx, properties) => {
|
|
33
31
|
const obj = (0, _utils.objectTypeFromProperties)(properties.sort((a, b) => {
|
|
34
|
-
if (a.type ===
|
|
35
|
-
const aName = a.key.type ===
|
|
36
|
-
const bName = b.key.type ===
|
|
32
|
+
if (a.type === "TSPropertySignature" && b.type === "TSPropertySignature") {
|
|
33
|
+
const aName = a.key.type === "Identifier" ? a.key.name : "";
|
|
34
|
+
const bName = b.key.type === "Identifier" ? b.key.name : "";
|
|
37
35
|
return aName < bName ? -1 : 1;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
return 0;
|
|
41
39
|
}));
|
|
42
|
-
const name = ctx.path.join(
|
|
40
|
+
const name = ctx.path.join("_");
|
|
43
41
|
const isTopLevelType = ctx.path.length <= 1;
|
|
44
42
|
|
|
45
43
|
if (ctx.allObjectTypes != null && !isTopLevelType) {
|
|
@@ -62,8 +60,7 @@ const generateFragmentType = (schema, fragment, ctx) => {
|
|
|
62
60
|
ast = unionOrInterfaceToFlow(ctx, ctx.schema.unionsByName[onType], fragment.selectionSet.selections);
|
|
63
61
|
} else {
|
|
64
62
|
throw new Error(`Unknown ${onType}`);
|
|
65
|
-
}
|
|
66
|
-
|
|
63
|
+
}
|
|
67
64
|
|
|
68
65
|
return (0, _generator.default)(ast).code;
|
|
69
66
|
};
|
|
@@ -71,54 +68,54 @@ const generateFragmentType = (schema, fragment, ctx) => {
|
|
|
71
68
|
exports.generateFragmentType = generateFragmentType;
|
|
72
69
|
|
|
73
70
|
const _typeToFlow = (ctx, type, selection) => {
|
|
74
|
-
if (type.kind ===
|
|
71
|
+
if (type.kind === "SCALAR") {
|
|
75
72
|
return (0, _enums.scalarTypeToFlow)(ctx, type.name);
|
|
76
73
|
}
|
|
77
74
|
|
|
78
|
-
if (type.kind ===
|
|
79
|
-
return babelTypes.tsTypeReference(ctx.readOnlyArray ? babelTypes.identifier(
|
|
75
|
+
if (type.kind === "LIST") {
|
|
76
|
+
return babelTypes.tsTypeReference(ctx.readOnlyArray ? babelTypes.identifier("ReadonlyArray") : babelTypes.identifier("Array"), babelTypes.tsTypeParameterInstantiation([typeToFlow(ctx, type.ofType, selection)]));
|
|
80
77
|
}
|
|
81
78
|
|
|
82
|
-
if (type.kind ===
|
|
79
|
+
if (type.kind === "UNION") {
|
|
83
80
|
const union = ctx.schema.unionsByName[type.name];
|
|
84
81
|
|
|
85
82
|
if (!selection.selectionSet) {
|
|
86
|
-
console.log(
|
|
83
|
+
console.log("no selection set", selection);
|
|
87
84
|
return babelTypes.tsAnyKeyword();
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
return unionOrInterfaceToFlow(ctx, union, selection.selectionSet.selections);
|
|
91
88
|
}
|
|
92
89
|
|
|
93
|
-
if (type.kind ===
|
|
90
|
+
if (type.kind === "INTERFACE") {
|
|
94
91
|
if (!selection.selectionSet) {
|
|
95
|
-
console.log(
|
|
92
|
+
console.log("no selection set", selection);
|
|
96
93
|
return babelTypes.tsAnyKeyword();
|
|
97
94
|
}
|
|
98
95
|
|
|
99
96
|
return unionOrInterfaceToFlow(ctx, ctx.schema.interfacesByName[type.name], selection.selectionSet.selections);
|
|
100
97
|
}
|
|
101
98
|
|
|
102
|
-
if (type.kind ===
|
|
99
|
+
if (type.kind === "ENUM") {
|
|
103
100
|
return (0, _enums.enumTypeToFlow)(ctx, type.name);
|
|
104
101
|
}
|
|
105
102
|
|
|
106
|
-
if (type.kind !==
|
|
107
|
-
console.log(
|
|
103
|
+
if (type.kind !== "OBJECT") {
|
|
104
|
+
console.log("not object", type);
|
|
108
105
|
return babelTypes.tsAnyKeyword();
|
|
109
106
|
}
|
|
110
107
|
|
|
111
108
|
const tname = type.name;
|
|
112
109
|
|
|
113
110
|
if (!ctx.schema.typesByName[tname]) {
|
|
114
|
-
console.log(
|
|
111
|
+
console.log("unknown referenced type", tname);
|
|
115
112
|
return babelTypes.tsAnyKeyword();
|
|
116
113
|
}
|
|
117
114
|
|
|
118
115
|
const childType = ctx.schema.typesByName[tname];
|
|
119
116
|
|
|
120
117
|
if (!selection.selectionSet) {
|
|
121
|
-
console.log(
|
|
118
|
+
console.log("no selection set", selection);
|
|
122
119
|
return babelTypes.tsAnyKeyword();
|
|
123
120
|
}
|
|
124
121
|
|
|
@@ -127,7 +124,7 @@ const _typeToFlow = (ctx, type, selection) => {
|
|
|
127
124
|
|
|
128
125
|
const typeToFlow = (ctx, type, selection) => {
|
|
129
126
|
// throw new Error('npoe');
|
|
130
|
-
if (type.kind ===
|
|
127
|
+
if (type.kind === "NON_NULL") {
|
|
131
128
|
return _typeToFlow(ctx, type.ofType, selection);
|
|
132
129
|
} // If we don'babelTypes care about strict nullability checking, then pretend everything is non-null
|
|
133
130
|
|
|
@@ -150,10 +147,10 @@ const ensureOnlyOneTypenameProperty = properties => {
|
|
|
150
147
|
// The apollo-utilities "addTypeName" utility will add it
|
|
151
148
|
// even if it's already specified :( so we have to filter out
|
|
152
149
|
// the extra one here.
|
|
153
|
-
if (type.type ===
|
|
150
|
+
if (type.type === "TSPropertySignature" && type.key.type === "Identifier" && type.key.name === "__typename") {
|
|
154
151
|
var _type$typeAnnotation;
|
|
155
152
|
|
|
156
|
-
const name = ((_type$typeAnnotation = type.typeAnnotation) === null || _type$typeAnnotation === void 0 ? void 0 : _type$typeAnnotation.typeAnnotation.type) ===
|
|
153
|
+
const name = ((_type$typeAnnotation = type.typeAnnotation) === null || _type$typeAnnotation === void 0 ? void 0 : _type$typeAnnotation.typeAnnotation.type) === "TSLiteralType" && type.typeAnnotation.typeAnnotation.literal.type === "StringLiteral" ? type.typeAnnotation.typeAnnotation.literal.value : "INVALID";
|
|
157
154
|
|
|
158
155
|
if (seenTypeName) {
|
|
159
156
|
if (name !== seenTypeName) {
|
|
@@ -177,7 +174,7 @@ const querySelectionToObjectType = (ctx, selections, type, typeName) => {
|
|
|
177
174
|
const objectPropertiesToFlow = (ctx, type, typeName, selections) => {
|
|
178
175
|
return selections.flatMap(selection => {
|
|
179
176
|
switch (selection.kind) {
|
|
180
|
-
case
|
|
177
|
+
case "InlineFragment":
|
|
181
178
|
{
|
|
182
179
|
var _selection$typeCondit, _selection$typeCondit2;
|
|
183
180
|
|
|
@@ -190,7 +187,7 @@ const objectPropertiesToFlow = (ctx, type, typeName, selections) => {
|
|
|
190
187
|
return objectPropertiesToFlow(ctx, ctx.schema.typesByName[newTypeName], newTypeName, selection.selectionSet.selections);
|
|
191
188
|
}
|
|
192
189
|
|
|
193
|
-
case
|
|
190
|
+
case "FragmentSpread":
|
|
194
191
|
if (!ctx.fragments[selection.name.value]) {
|
|
195
192
|
ctx.errors.push(`No fragment named '${selection.name.value}'. Did you forget to include it in the template literal?`);
|
|
196
193
|
return [babelTypes.tsPropertySignature(babelTypes.identifier(selection.name.value), babelTypes.tsTypeAnnotation(babelTypes.tsTypeReference(babelTypes.identifier(`UNKNOWN_FRAGMENT`))))];
|
|
@@ -198,11 +195,11 @@ const objectPropertiesToFlow = (ctx, type, typeName, selections) => {
|
|
|
198
195
|
|
|
199
196
|
return objectPropertiesToFlow(ctx, type, typeName, ctx.fragments[selection.name.value].selectionSet.selections);
|
|
200
197
|
|
|
201
|
-
case
|
|
198
|
+
case "Field":
|
|
202
199
|
const name = selection.name.value;
|
|
203
200
|
const alias = selection.alias ? selection.alias.value : name;
|
|
204
201
|
|
|
205
|
-
if (name ===
|
|
202
|
+
if (name === "__typename") {
|
|
206
203
|
return [babelTypes.tsPropertySignature(babelTypes.identifier(alias), babelTypes.tsTypeAnnotation(babelTypes.tsLiteralType(babelTypes.stringLiteral(typeName))))];
|
|
207
204
|
}
|
|
208
205
|
|
|
@@ -217,8 +214,7 @@ const objectPropertiesToFlow = (ctx, type, typeName, selections) => {
|
|
|
217
214
|
}, typeField.type, selection)))))];
|
|
218
215
|
|
|
219
216
|
default:
|
|
220
|
-
ctx.errors.push(
|
|
221
|
-
`Unsupported selection kind '${selection.kind}'`);
|
|
217
|
+
ctx.errors.push(`Unsupported selection kind '${selection.kind}'`);
|
|
222
218
|
return [];
|
|
223
219
|
}
|
|
224
220
|
});
|
|
@@ -227,7 +223,7 @@ const objectPropertiesToFlow = (ctx, type, typeName, selections) => {
|
|
|
227
223
|
exports.objectPropertiesToFlow = objectPropertiesToFlow;
|
|
228
224
|
|
|
229
225
|
const unionOrInterfaceToFlow = (ctx, type, selections) => {
|
|
230
|
-
const allFields = selections.every(selection => selection.kind ===
|
|
226
|
+
const allFields = selections.every(selection => selection.kind === "Field");
|
|
231
227
|
const selectedAttributes = type.possibleTypes.slice().sort((a, b) => {
|
|
232
228
|
return a.name < b.name ? -1 : 1;
|
|
233
229
|
}).map(possible => {
|
|
@@ -242,10 +238,10 @@ const unionOrInterfaceToFlow = (ctx, type, selections) => {
|
|
|
242
238
|
|
|
243
239
|
if (allFields) {
|
|
244
240
|
const sharedAttributes = selectedAttributes[0].attributes.slice();
|
|
245
|
-
const typeNameIndex = selectedAttributes[0].attributes.findIndex(x => x.type ===
|
|
241
|
+
const typeNameIndex = selectedAttributes[0].attributes.findIndex(x => x.type === "TSPropertySignature" && x.key.type === "Identifier" && x.key.name === "__typename");
|
|
246
242
|
|
|
247
243
|
if (typeNameIndex !== -1) {
|
|
248
|
-
sharedAttributes[typeNameIndex] = babelTypes.tsPropertySignature(babelTypes.identifier(
|
|
244
|
+
sharedAttributes[typeNameIndex] = babelTypes.tsPropertySignature(babelTypes.identifier("__typename"), babelTypes.tsTypeAnnotation(babelTypes.tsUnionType(selectedAttributes.map(attrs => attrs.attributes[typeNameIndex].typeAnnotation.typeAnnotation))));
|
|
249
245
|
}
|
|
250
246
|
|
|
251
247
|
return sortedObjectTypeAnnotation(ctx, sharedAttributes);
|
|
@@ -292,7 +288,7 @@ const unionOrInterfaceToFlow = (ctx, type, selections) => {
|
|
|
292
288
|
}) => sortedObjectTypeAnnotation({ ...ctx,
|
|
293
289
|
path: ctx.path.concat([typeName])
|
|
294
290
|
}, attributes)));
|
|
295
|
-
const name = ctx.path.join(
|
|
291
|
+
const name = ctx.path.join("_");
|
|
296
292
|
|
|
297
293
|
if (ctx.allObjectTypes && ctx.path.length > 1) {
|
|
298
294
|
ctx.allObjectTypes[name] = result;
|
|
@@ -305,18 +301,18 @@ const unionOrInterfaceToFlow = (ctx, type, selections) => {
|
|
|
305
301
|
exports.unionOrInterfaceToFlow = unionOrInterfaceToFlow;
|
|
306
302
|
|
|
307
303
|
const unionOrInterfaceSelection = (config, type, possible, selection) => {
|
|
308
|
-
if (selection.kind ===
|
|
304
|
+
if (selection.kind === "Field" && selection.name.value === "__typename") {
|
|
309
305
|
const alias = selection.alias ? selection.alias.value : selection.name.value;
|
|
310
306
|
return [babelTypes.tsPropertySignature(babelTypes.identifier(alias), babelTypes.tsTypeAnnotation(babelTypes.tsLiteralType(babelTypes.stringLiteral(possible.name))))];
|
|
311
307
|
}
|
|
312
308
|
|
|
313
|
-
if (selection.kind ===
|
|
309
|
+
if (selection.kind === "Field" && type.kind !== "UNION") {
|
|
314
310
|
// this is an interface
|
|
315
311
|
const name = selection.name.value;
|
|
316
312
|
const alias = selection.alias ? selection.alias.value : name;
|
|
317
313
|
|
|
318
314
|
if (!type.fieldsByName[name]) {
|
|
319
|
-
config.errors.push(
|
|
315
|
+
config.errors.push("Unknown field: " + name + " on type " + type.name + " for possible " + possible.name);
|
|
320
316
|
return [babelTypes.tsPropertySignature(babelTypes.identifier(alias), babelTypes.tsTypeAnnotation(babelTypes.tsTypeReference(babelTypes.identifier(`UNKNOWN_FIELD`))))];
|
|
321
317
|
}
|
|
322
318
|
|
|
@@ -326,7 +322,7 @@ const unionOrInterfaceSelection = (config, type, possible, selection) => {
|
|
|
326
322
|
}, typeField.type, selection))))];
|
|
327
323
|
}
|
|
328
324
|
|
|
329
|
-
if (selection.kind ===
|
|
325
|
+
if (selection.kind === "FragmentSpread") {
|
|
330
326
|
const fragment = config.fragments[selection.name.value];
|
|
331
327
|
|
|
332
328
|
if (!fragment) {
|
|
@@ -342,10 +338,10 @@ const unionOrInterfaceSelection = (config, type, possible, selection) => {
|
|
|
342
338
|
}
|
|
343
339
|
}
|
|
344
340
|
|
|
345
|
-
if (selection.kind !==
|
|
341
|
+
if (selection.kind !== "InlineFragment") {
|
|
346
342
|
config.errors.push(`union selectors must be inline fragment: found ${selection.kind}`);
|
|
347
343
|
|
|
348
|
-
if (type.kind ===
|
|
344
|
+
if (type.kind === "UNION") {
|
|
349
345
|
config.errors.push(`You're trying to select a field from the union ${type.name},
|
|
350
346
|
but the only field you're allowed to select is "__typename".
|
|
351
347
|
Try using an inline fragment "... on SomeType {}".`);
|