@khanacademy/graphql-flow 0.2.5 → 0.3.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/.flowconfig +1 -0
- package/.github/workflows/changeset-release.yml +1 -1
- package/.github/workflows/pr-checks.yml +15 -10
- package/CHANGELOG.md +7 -0
- package/Readme.md +25 -0
- package/dist/cli/config.js +100 -14
- package/dist/cli/config.js.flow +119 -24
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/run.js +21 -3
- package/dist/cli/run.js.flow +25 -3
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/utils.js +21 -0
- package/dist/cli/utils.js.flow +14 -0
- package/dist/cli/utils.js.map +1 -0
- package/dist/enums.js +15 -2
- package/dist/enums.js.flow +38 -9
- package/dist/enums.js.map +1 -1
- package/dist/generateTypeFiles.js +15 -5
- package/dist/generateTypeFiles.js.flow +50 -34
- package/dist/generateTypeFiles.js.map +1 -1
- package/dist/index.js +18 -12
- package/dist/index.js.flow +27 -11
- package/dist/index.js.map +1 -1
- package/dist/types.js.flow +3 -0
- package/flow-typed/npm/@babel/types_vx.x.x.js +17 -3
- package/package.json +1 -1
- package/src/__test__/generateTypeFileContents.test.js +52 -0
- package/src/cli/__test__/config.test.js +94 -0
- package/src/cli/__test__/utils.test.js +19 -0
- package/src/cli/config.js +119 -24
- package/src/cli/run.js +25 -3
- package/src/cli/utils.js +14 -0
- package/src/enums.js +38 -9
- package/src/generateTypeFiles.js +50 -34
- package/src/index.js +27 -11
- package/src/types.js +3 -0
- package/.github/actions/filter-files/action.yml +0 -37
- package/.github/actions/full-or-limited/action.yml +0 -27
- package/.github/actions/json-args/action.yml +0 -32
- package/.github/actions/setup/action.yml +0 -28
package/src/generateTypeFiles.js
CHANGED
|
@@ -21,6 +21,7 @@ export type ExternalOptions = {
|
|
|
21
21
|
generatedDirectory?: string,
|
|
22
22
|
exportAllObjectTypes?: boolean,
|
|
23
23
|
typeFileName?: string,
|
|
24
|
+
experimentalEnums?: boolean,
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
export const indexPrelude = (regenerateCommand?: string): string => `// @flow
|
|
@@ -62,40 +63,54 @@ export const generateTypeFileContents = (
|
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
const generated = documentToFlowTypes(document, schema, options);
|
|
65
|
-
generated.forEach(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
66
|
+
generated.forEach(
|
|
67
|
+
({name, typeName, code, isFragment, extraTypes, experimentalEnums}) => {
|
|
68
|
+
// We write all generated files to a `__generated__` subdir to keep
|
|
69
|
+
// things tidy.
|
|
70
|
+
const targetFileName = options.typeFileName
|
|
71
|
+
? options.typeFileName.replace('[operationName]', name)
|
|
72
|
+
: `${name}.js`;
|
|
73
|
+
const targetPath = path.join(generatedDir, targetFileName);
|
|
74
|
+
|
|
75
|
+
let fileContents =
|
|
76
|
+
'// @' +
|
|
77
|
+
`flow\n// AUTOGENERATED -- DO NOT EDIT\n` +
|
|
78
|
+
`// Generated for operation '${name}' in file '../${path.basename(
|
|
79
|
+
fileName,
|
|
80
|
+
)}'\n` +
|
|
81
|
+
(options.regenerateCommand
|
|
82
|
+
? `// To regenerate, run '${options.regenerateCommand}'.\n`
|
|
83
|
+
: '') +
|
|
84
|
+
code;
|
|
85
|
+
if (options.splitTypes && !isFragment) {
|
|
86
|
+
fileContents +=
|
|
87
|
+
`\nexport type ${name} = ${typeName}['response'];\n` +
|
|
88
|
+
`export type ${name}Variables = ${typeName}['variables'];\n`;
|
|
89
|
+
}
|
|
90
|
+
Object.keys(extraTypes).forEach(
|
|
91
|
+
(name) =>
|
|
92
|
+
(fileContents += `\n\nexport type ${name} = ${extraTypes[name]};`),
|
|
93
|
+
);
|
|
94
|
+
const enumNames = Object.keys(experimentalEnums);
|
|
95
|
+
if (options.experimentalEnums && enumNames.length) {
|
|
96
|
+
// TODO(somewhatabstract, FEI-4172): Update to fixed eslint-plugin-flowtype
|
|
97
|
+
// and remove this disable.
|
|
98
|
+
fileContents += `\n\n/* eslint-disable no-undef */`;
|
|
99
|
+
enumNames.forEach(
|
|
100
|
+
(name) =>
|
|
101
|
+
(fileContents += `\nexport ${experimentalEnums[name]};\n`),
|
|
102
|
+
);
|
|
103
|
+
fileContents += `/* eslint-enable no-undef */`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
addToIndex(targetPath, typeName);
|
|
107
|
+
files[targetPath] =
|
|
108
|
+
fileContents
|
|
109
|
+
// Remove whitespace from the ends of lines; babel's generate sometimes
|
|
110
|
+
// leaves them hanging around.
|
|
111
|
+
.replace(/\s+$/gm, '') + '\n';
|
|
112
|
+
},
|
|
113
|
+
);
|
|
99
114
|
|
|
100
115
|
return {files, indexContents};
|
|
101
116
|
};
|
|
@@ -178,6 +193,7 @@ export const processPragmas = (
|
|
|
178
193
|
generatedDirectory: options.generatedDirectory,
|
|
179
194
|
exportAllObjectTypes: options.exportAllObjectTypes,
|
|
180
195
|
typeFileName: options.typeFileName,
|
|
196
|
+
experimentalEnums: options.experimentalEnums,
|
|
181
197
|
};
|
|
182
198
|
} else {
|
|
183
199
|
return null;
|
package/src/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
generateResponseType,
|
|
16
16
|
} from './generateResponseType';
|
|
17
17
|
import {generateVariablesType} from './generateVariablesType';
|
|
18
|
+
import type {BabelNode} from '@babel/types';
|
|
18
19
|
export {spyOnGraphqlTagToCollectQueries} from './jest-mock-graphql-tag';
|
|
19
20
|
|
|
20
21
|
import type {Config, Options, Schema} from './types';
|
|
@@ -42,6 +43,7 @@ const optionsToConfig = (
|
|
|
42
43
|
errors,
|
|
43
44
|
allObjectTypes: null,
|
|
44
45
|
path: [],
|
|
46
|
+
experimentalEnumsMap: options?.experimentalEnums ? {} : undefined,
|
|
45
47
|
...internalOptions,
|
|
46
48
|
};
|
|
47
49
|
|
|
@@ -66,6 +68,7 @@ export const documentToFlowTypes = (
|
|
|
66
68
|
code: string,
|
|
67
69
|
isFragment?: boolean,
|
|
68
70
|
extraTypes: {[key: string]: string},
|
|
71
|
+
experimentalEnums: {[key: string]: string},
|
|
69
72
|
}> => {
|
|
70
73
|
const errors: Array<string> = [];
|
|
71
74
|
const config = optionsToConfig(
|
|
@@ -90,17 +93,19 @@ export const documentToFlowTypes = (
|
|
|
90
93
|
: null,
|
|
91
94
|
},
|
|
92
95
|
)};`;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
|
|
97
|
+
const extraTypes = codegenExtraTypes(types);
|
|
98
|
+
const experimentalEnums = codegenExtraTypes(
|
|
99
|
+
config.experimentalEnumsMap || {},
|
|
100
|
+
);
|
|
101
|
+
|
|
98
102
|
return {
|
|
99
103
|
name,
|
|
100
104
|
typeName: name,
|
|
101
105
|
code,
|
|
102
106
|
isFragment: true,
|
|
103
107
|
extraTypes,
|
|
108
|
+
experimentalEnums,
|
|
104
109
|
};
|
|
105
110
|
}
|
|
106
111
|
if (
|
|
@@ -127,12 +132,12 @@ export const documentToFlowTypes = (
|
|
|
127
132
|
// We'll see what's required to get webapp on board.
|
|
128
133
|
const code = `export type ${typeName} = {|\n variables: ${variables},\n response: ${response}\n|};`;
|
|
129
134
|
|
|
130
|
-
const extraTypes
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return {name, typeName, code, extraTypes};
|
|
135
|
+
const extraTypes = codegenExtraTypes(types);
|
|
136
|
+
const experimentalEnums = codegenExtraTypes(
|
|
137
|
+
config.experimentalEnumsMap || {},
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
return {name, typeName, code, extraTypes, experimentalEnums};
|
|
136
141
|
}
|
|
137
142
|
})
|
|
138
143
|
.filter(Boolean);
|
|
@@ -141,3 +146,14 @@ export const documentToFlowTypes = (
|
|
|
141
146
|
}
|
|
142
147
|
return result;
|
|
143
148
|
};
|
|
149
|
+
|
|
150
|
+
function codegenExtraTypes(types: {[key: string]: BabelNode}): {
|
|
151
|
+
[key: string]: string,
|
|
152
|
+
} {
|
|
153
|
+
const extraTypes: {[key: string]: string} = {};
|
|
154
|
+
Object.keys(types).forEach((k: string) => {
|
|
155
|
+
// eslint-disable-next-line flowtype-errors/uncovered
|
|
156
|
+
extraTypes[k] = generate(types[k]).code;
|
|
157
|
+
});
|
|
158
|
+
return extraTypes;
|
|
159
|
+
}
|
package/src/types.js
CHANGED
|
@@ -23,6 +23,7 @@ export type Options = {|
|
|
|
23
23
|
generatedDirectory?: string,
|
|
24
24
|
exportAllObjectTypes?: boolean,
|
|
25
25
|
typeFileName?: string,
|
|
26
|
+
experimentalEnums?: boolean, // default false
|
|
26
27
|
|};
|
|
27
28
|
|
|
28
29
|
export type Schema = {
|
|
@@ -58,5 +59,7 @@ export type Config = {
|
|
|
58
59
|
scalars: Scalars,
|
|
59
60
|
errors: Array<string>,
|
|
60
61
|
allObjectTypes: null | {[key: string]: BabelNode},
|
|
62
|
+
|
|
63
|
+
experimentalEnumsMap?: {[key: string]: BabelNode}, // index signature that is populated with declarations
|
|
61
64
|
};
|
|
62
65
|
export type Scalars = {[key: string]: 'string' | 'number' | 'boolean'};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
name: 'Filter files'
|
|
2
|
-
description: 'Filter the list of changed files'
|
|
3
|
-
inputs:
|
|
4
|
-
changed-files:
|
|
5
|
-
description: 'jsonified list of changed files from setup'
|
|
6
|
-
required: true
|
|
7
|
-
files:
|
|
8
|
-
description: 'comma-separated list of files to check for'
|
|
9
|
-
required: false
|
|
10
|
-
extensions:
|
|
11
|
-
description: 'comma-separated list of extensions to check for'
|
|
12
|
-
required: false
|
|
13
|
-
outputs:
|
|
14
|
-
filtered:
|
|
15
|
-
description: 'The jsonified list of files that match'
|
|
16
|
-
value: ${{ steps.result.outputs.result }}
|
|
17
|
-
runs:
|
|
18
|
-
using: "composite"
|
|
19
|
-
steps:
|
|
20
|
-
- uses: actions/github-script@v6
|
|
21
|
-
id: result
|
|
22
|
-
with:
|
|
23
|
-
script: |
|
|
24
|
-
const extensionsRaw = "${{ inputs.extensions }}";
|
|
25
|
-
const exactFilesRaw = "${{ inputs.files }}";
|
|
26
|
-
const inputFiles = JSON.parse(`${{ inputs.changed-files }}`);
|
|
27
|
-
const extensions = extensionsRaw.trim() ? extensionsRaw.split(',') : [];
|
|
28
|
-
const exactFiles = exactFilesRaw.trim() ? exactFilesRaw.split(',') : [];
|
|
29
|
-
|
|
30
|
-
const result = inputFiles.filter(name => {
|
|
31
|
-
return extensions.some(ext => name.endsWith(ext)) || (
|
|
32
|
-
exactFiles.includes(name)
|
|
33
|
-
)
|
|
34
|
-
})
|
|
35
|
-
console.log(`Filtered Files: ${JSON.stringify(result)}`)
|
|
36
|
-
return result;
|
|
37
|
-
result-encoding: json
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
name: Full or Limited
|
|
2
|
-
description: Do a full run if certain files have changed, or a limited run of some others have changed
|
|
3
|
-
inputs:
|
|
4
|
-
full-trigger:
|
|
5
|
-
description: A jsonified Array of string files that would trigger a full run
|
|
6
|
-
required: true
|
|
7
|
-
limited-trigger:
|
|
8
|
-
description: A jsonified Array of string files that should be passed to a limited run
|
|
9
|
-
required: true
|
|
10
|
-
full:
|
|
11
|
-
description: The command to run if a full run is triggered
|
|
12
|
-
limited:
|
|
13
|
-
description: The command to run, with {} replaced with the list of files to run on.
|
|
14
|
-
runs:
|
|
15
|
-
using: "composite"
|
|
16
|
-
steps:
|
|
17
|
-
- name: Full run
|
|
18
|
-
if: inputs.full-trigger != '[]'
|
|
19
|
-
run: ${{ inputs.full }}
|
|
20
|
-
shell: bash
|
|
21
|
-
|
|
22
|
-
- name: Limited run
|
|
23
|
-
if: inputs.full-trigger == '[]' && inputs.limited-trigger != '[]'
|
|
24
|
-
uses: ./.github/actions/json-args
|
|
25
|
-
with:
|
|
26
|
-
list: ${{ inputs.limited-trigger }}
|
|
27
|
-
run: ${{ inputs.limited }}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
name: 'Pass a jsonified-list of files as shell arguments'
|
|
2
|
-
description: 'Because file names with spaces are the worst'
|
|
3
|
-
inputs:
|
|
4
|
-
list:
|
|
5
|
-
description: A jsonified Array of string file names
|
|
6
|
-
required: true
|
|
7
|
-
run:
|
|
8
|
-
description: "a command to run, where the literal '{}' will be replaced with the files as individual arguments. If no '{}' is provided, the files will be appended."
|
|
9
|
-
required: true
|
|
10
|
-
runs:
|
|
11
|
-
using: "composite"
|
|
12
|
-
steps:
|
|
13
|
-
- uses: actions/github-script@v6
|
|
14
|
-
with:
|
|
15
|
-
script: |
|
|
16
|
-
const listRaw = `${{ inputs.list }}`;
|
|
17
|
-
const files = JSON.parse(listRaw);
|
|
18
|
-
const {execSync} = require('child_process');
|
|
19
|
-
if (files.some(name => name.match(/['"]/))) {
|
|
20
|
-
throw new Error(`Not going to mess with file names that have quotes in them.`)
|
|
21
|
-
}
|
|
22
|
-
const filesList = files.map(name => `"${name}"`).join(' ')
|
|
23
|
-
let cmd = `${{ inputs.run }}`;
|
|
24
|
-
if (cmd.includes('{}')) {
|
|
25
|
-
cmd = cmd.replace('{}', filesList)
|
|
26
|
-
} else {
|
|
27
|
-
cmd += ' ' + filesList;
|
|
28
|
-
}
|
|
29
|
-
console.log(`Running: ${cmd}`);
|
|
30
|
-
execSync(cmd, {
|
|
31
|
-
stdio: 'inherit',
|
|
32
|
-
})
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
name: 'Setup'
|
|
2
|
-
description: 'Perform various shared setup tasks'
|
|
3
|
-
inputs:
|
|
4
|
-
node-version:
|
|
5
|
-
description: 'Node version to use'
|
|
6
|
-
required: false
|
|
7
|
-
default: '16.x'
|
|
8
|
-
outputs:
|
|
9
|
-
changed_files:
|
|
10
|
-
description: "List of files changed in this PR, in JSON format"
|
|
11
|
-
value: ${{ steps.changed.outputs.added_modified }}
|
|
12
|
-
runs:
|
|
13
|
-
using: "composite"
|
|
14
|
-
steps:
|
|
15
|
-
- name: Use Node.js ${{ inputs.node-version }}
|
|
16
|
-
uses: actions/setup-node@v3
|
|
17
|
-
id: node
|
|
18
|
-
with:
|
|
19
|
-
node-version: ${{ inputs.node-version }}
|
|
20
|
-
cache: yarn
|
|
21
|
-
- name: Install dependencies
|
|
22
|
-
run: yarn install --frozen-lockfile
|
|
23
|
-
shell: bash
|
|
24
|
-
- name: Get All Changed Files
|
|
25
|
-
uses: jaredly/get-changed-files@absolute
|
|
26
|
-
id: changed
|
|
27
|
-
with:
|
|
28
|
-
format: json
|