@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.
Files changed (40) hide show
  1. package/.flowconfig +1 -0
  2. package/.github/workflows/changeset-release.yml +1 -1
  3. package/.github/workflows/pr-checks.yml +15 -10
  4. package/CHANGELOG.md +7 -0
  5. package/Readme.md +25 -0
  6. package/dist/cli/config.js +100 -14
  7. package/dist/cli/config.js.flow +119 -24
  8. package/dist/cli/config.js.map +1 -1
  9. package/dist/cli/run.js +21 -3
  10. package/dist/cli/run.js.flow +25 -3
  11. package/dist/cli/run.js.map +1 -1
  12. package/dist/cli/utils.js +21 -0
  13. package/dist/cli/utils.js.flow +14 -0
  14. package/dist/cli/utils.js.map +1 -0
  15. package/dist/enums.js +15 -2
  16. package/dist/enums.js.flow +38 -9
  17. package/dist/enums.js.map +1 -1
  18. package/dist/generateTypeFiles.js +15 -5
  19. package/dist/generateTypeFiles.js.flow +50 -34
  20. package/dist/generateTypeFiles.js.map +1 -1
  21. package/dist/index.js +18 -12
  22. package/dist/index.js.flow +27 -11
  23. package/dist/index.js.map +1 -1
  24. package/dist/types.js.flow +3 -0
  25. package/flow-typed/npm/@babel/types_vx.x.x.js +17 -3
  26. package/package.json +1 -1
  27. package/src/__test__/generateTypeFileContents.test.js +52 -0
  28. package/src/cli/__test__/config.test.js +94 -0
  29. package/src/cli/__test__/utils.test.js +19 -0
  30. package/src/cli/config.js +119 -24
  31. package/src/cli/run.js +25 -3
  32. package/src/cli/utils.js +14 -0
  33. package/src/enums.js +38 -9
  34. package/src/generateTypeFiles.js +50 -34
  35. package/src/index.js +27 -11
  36. package/src/types.js +3 -0
  37. package/.github/actions/filter-files/action.yml +0 -37
  38. package/.github/actions/full-or-limited/action.yml +0 -27
  39. package/.github/actions/json-args/action.yml +0 -32
  40. package/.github/actions/setup/action.yml +0 -28
@@ -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(({name, typeName, code, isFragment, extraTypes}) => {
66
- // We write all generated files to a `__generated__` subdir to keep
67
- // things tidy.
68
- const targetFileName = options.typeFileName
69
- ? options.typeFileName.replace('[operationName]', name)
70
- : `${name}.js`;
71
- const targetPath = path.join(generatedDir, targetFileName);
72
-
73
- let fileContents =
74
- '// @' +
75
- `flow\n// AUTOGENERATED -- DO NOT EDIT\n` +
76
- `// Generated for operation '${name}' in file '../${path.basename(
77
- fileName,
78
- )}'\n` +
79
- (options.regenerateCommand
80
- ? `// To regenerate, run '${options.regenerateCommand}'.\n`
81
- : '') +
82
- code;
83
- if (options.splitTypes && !isFragment) {
84
- fileContents +=
85
- `\nexport type ${name} = ${typeName}['response'];\n` +
86
- `export type ${name}Variables = ${typeName}['variables'];\n`;
87
- }
88
- Object.keys(extraTypes).forEach((name) => {
89
- fileContents += `\n\nexport type ${name} = ${extraTypes[name]};`;
90
- });
91
-
92
- addToIndex(targetPath, typeName);
93
- files[targetPath] =
94
- fileContents
95
- // Remove whitespace from the ends of lines; babel's generate sometimes
96
- // leaves them hanging around.
97
- .replace(/\s+$/gm, '') + '\n';
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
- const extraTypes: {[key: string]: string} = {};
94
- Object.keys(types).forEach((k) => {
95
- // eslint-disable-next-line flowtype-errors/uncovered
96
- extraTypes[k] = generate(types[k]).code;
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: {[key: string]: string} = {};
131
- Object.keys(types).forEach((k) => {
132
- // eslint-disable-next-line flowtype-errors/uncovered
133
- extraTypes[k] = generate(types[k]).code;
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