@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
package/.flowconfig CHANGED
@@ -9,5 +9,6 @@ flow-typed/
9
9
  [lints]
10
10
 
11
11
  [options]
12
+ enums=true
12
13
 
13
14
  [strict]
@@ -34,7 +34,7 @@ jobs:
34
34
  - uses: actions/checkout@v2
35
35
  with:
36
36
  fetch-depth: 0
37
- - uses: ./.github/actions/setup
37
+ - uses: Khan/actions@shared-node-cache-v0.0.2
38
38
  with:
39
39
  node-version: 12.x
40
40
 
@@ -17,16 +17,21 @@ jobs:
17
17
  node-version: [16.x]
18
18
  steps:
19
19
  - uses: actions/checkout@v2
20
- - uses: ./.github/actions/setup
21
- id: setup
20
+ - uses: Khan/actions@shared-node-cache-v0
22
21
  with:
23
22
  node-version: ${{ matrix.node-version }}
24
23
 
24
+ - name: Get All Changed Files
25
+ uses: jaredly/get-changed-files@absolute
26
+ id: changed
27
+ with:
28
+ format: 'json'
29
+
25
30
  - id: js-files
26
31
  name: Find .js changed files
27
- uses: ./.github/actions/filter-files
32
+ uses: Khan/actions@filter-files-v0
28
33
  with:
29
- changed-files: ${{ steps.setup.outputs.changed_files }}
34
+ changed-files: ${{ steps.changed.outputs.added_modified }}
30
35
  extensions: '.js'
31
36
 
32
37
  - name: Run Flow
@@ -34,14 +39,14 @@ jobs:
34
39
  run: yarn flow
35
40
 
36
41
  - id: eslint-reset
37
- uses: ./.github/actions/filter-files
42
+ uses: Khan/actions@filter-files-v0
38
43
  name: Files that would trigger a full eslint run
39
44
  with:
40
- changed-files: ${{ steps.setup.outputs.changed_files }}
45
+ changed-files: ${{ steps.changed.outputs.added_modified }}
41
46
  files: '.eslintrc.js,package.json,.eslintignore'
42
47
 
43
48
  - name: Eslint
44
- uses: ./.github/actions/full-or-limited
49
+ uses: Khan/actions@full-or-limited-v0
45
50
  with:
46
51
  full-trigger: ${{ steps.eslint-reset.outputs.filtered }}
47
52
  full: yarn eslint
@@ -49,14 +54,14 @@ jobs:
49
54
  limited: yarn eslint {}
50
55
 
51
56
  - id: jest-reset
52
- uses: ./.github/actions/filter-files
57
+ uses: Khan/actions@filter-files-v0
53
58
  name: Files that would trigger a full jest run
54
59
  with:
55
- changed-files: ${{ steps.setup.outputs.changed_files }}
60
+ changed-files: ${{ steps.changed.outputs.added_modified }}
56
61
  files: 'package.json,package-lock.json'
57
62
 
58
63
  - name: Jest
59
- uses: ./.github/actions/full-or-limited
64
+ uses: Khan/actions@full-or-limited-v0
60
65
  with:
61
66
  full-trigger: ${{ steps.jest-reset.outputs.filtered }}
62
67
  full: yarn jest
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @khanacademy/graphql-flow
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 093fa5f: Enable `experimentalEnums` in a config or subconfig file in to enable the export of flow enum types, which replace the default string union literals. The type currently comes with eslint decorators to skirt a bug in eslint and flow.
8
+ - 5078624: Users can add files with the name ending in `graphql-flow.config.js` with a subset of the config fields (`options`, `excludes`) in order to have more granular control of the behavior. Another field, `extends`, takes the path of another config file to use as a base and extends/overrides fields. If no `extends` is provided, the file completely overwrites any other config files (as far as `options` and `excludes`).
9
+
3
10
  ## 0.2.5
4
11
 
5
12
  ### Patch Changes
package/Readme.md CHANGED
@@ -23,6 +23,26 @@ Write a config file, with the following options:
23
23
  }
24
24
  ```
25
25
 
26
+ Optionally add subconfig files to subdirectories for granular control of behavior, with the following options:
27
+
28
+ ```json
29
+ {
30
+ // Note that this file must be named, or end with, "graphql-flow.config.json"
31
+ // I.e., "my-service.graphql.config.json" would also work.
32
+ // These files will affect the directory in which they are located and all subdirectories, unless overridden by a deeper subconfig.
33
+
34
+ // Optionally add the path of another config file. Can be the root config (provided when running the script) or any other subconfig to merge options.
35
+ // If a chain of extends are provided, will resolve in order. Be sure not to extend in a circle-- currently, this will just cause a stack overflow error.
36
+ // Cannot currently override `schemaFilePath`.
37
+ "extends": "./another/config/from/root.config.json",
38
+ // Can extend or override `excludes` and `options`.
39
+ "excludes": ["\\bsome-thing", "_test.jsx?$"],
40
+ "options": {
41
+ ...
42
+ }
43
+ }
44
+ ```
45
+
26
46
  Then run from the CLI, like so:
27
47
 
28
48
  ```bash
@@ -84,6 +104,11 @@ type Options = {
84
104
  // A template for the name of generated files
85
105
  // default: [operationName].js
86
106
  typeFileName?: string,
107
+
108
+ // Generate flow enums to replace literal unions in generated types. Exports
109
+ // each set of enums from each file regardless of other options. Designated
110
+ // "experimental" because of bug in eslint that requires config comments.
111
+ experimentalEnums?: boolean,
87
112
  }
88
113
  ```
89
114
 
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.loadConfigFile = exports.getSchemas = void 0;
6
+ exports.loadSubConfigFile = exports.loadDirConfigFiles = exports.loadConfigFile = exports.getSchemas = void 0;
7
7
 
8
8
  var _schemaFromIntrospectionData = require("../schemaFromIntrospectionData");
9
9
 
@@ -16,7 +16,7 @@ var _path = _interopRequireDefault(require("path"));
16
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
17
 
18
18
  const loadConfigFile = configFile => {
19
- var _data$options, _data$excludes$map, _data$excludes;
19
+ var _data$options, _data$options2, _data$excludes$map, _data$excludes;
20
20
 
21
21
  // eslint-disable-next-line flowtype-errors/uncovered
22
22
  const data = JSON.parse(_fs.default.readFileSync(configFile, 'utf8'));
@@ -26,30 +26,105 @@ const loadConfigFile = configFile => {
26
26
  throw new Error(`Invalid attribute in config file ${configFile}: ${k}. Allowed attributes: ${toplevelKeys.join(', ')}`);
27
27
  }
28
28
  });
29
-
30
- if (data.options) {
31
- const externalOptionsKeys = ['pragma', 'loosePragma', 'ignorePragma', 'scalars', 'strictNullability', 'regenerateCommand', 'readOnlyArray', 'splitTypes', 'generatedDirectory', 'exportAllObjectTypes', 'typeFileName'];
32
- Object.keys(data.options).forEach(k => {
33
- if (!externalOptionsKeys.includes(k)) {
34
- throw new Error(`Invalid option in config file ${configFile}: ${k}. Allowed options: ${externalOptionsKeys.join(', ')}`);
35
- }
36
- });
37
- }
38
-
29
+ validateOptions(configFile, (_data$options = data.options) !== null && _data$options !== void 0 ? _data$options : {});
39
30
  return {
40
- options: (_data$options = data.options) !== null && _data$options !== void 0 ? _data$options : {},
31
+ options: (_data$options2 = data.options) !== null && _data$options2 !== void 0 ? _data$options2 : {},
41
32
  excludes: (_data$excludes$map = (_data$excludes = data.excludes) === null || _data$excludes === void 0 ? void 0 : _data$excludes.map(string => new RegExp(string))) !== null && _data$excludes$map !== void 0 ? _data$excludes$map : [],
42
33
  schemaFilePath: _path.default.isAbsolute(data.schemaFilePath) ? data.schemaFilePath : _path.default.join(_path.default.dirname(configFile), data.schemaFilePath),
43
34
  dumpOperations: data.dumpOperations
44
35
  };
45
36
  };
46
37
  /**
47
- * Loads a .json 'introspection query response', or a .graphql schema definition.
38
+ * Subdirectory config to extend or overwrite higher-level config.
39
+ * @param {string} extends - Path from root; optional field for a config file in a subdirectory. If left blank, config file will overwrite root for directory.
48
40
  */
49
41
 
50
42
 
51
43
  exports.loadConfigFile = loadConfigFile;
52
44
 
45
+ const loadSubConfigFile = configFile => {
46
+ var _data$options3, _data$excludes$map2, _data$excludes2, _data$options4, _data$extends;
47
+
48
+ const jsonData = _fs.default.readFileSync(configFile, 'utf8'); // eslint-disable-next-line flowtype-errors/uncovered
49
+
50
+
51
+ const data = JSON.parse(jsonData);
52
+ const toplevelKeys = ['excludes', 'options', 'extends'];
53
+ Object.keys(data).forEach(k => {
54
+ if (!toplevelKeys.includes(k)) {
55
+ throw new Error(`Invalid attribute in non-root config file ${configFile}: ${k}. Allowed attributes: ${toplevelKeys.join(', ')}`);
56
+ }
57
+ });
58
+ validateOptions(configFile, (_data$options3 = data.options) !== null && _data$options3 !== void 0 ? _data$options3 : {});
59
+ return {
60
+ excludes: (_data$excludes$map2 = (_data$excludes2 = data.excludes) === null || _data$excludes2 === void 0 ? void 0 : _data$excludes2.map(string => new RegExp(string))) !== null && _data$excludes$map2 !== void 0 ? _data$excludes$map2 : [],
61
+ options: (_data$options4 = data.options) !== null && _data$options4 !== void 0 ? _data$options4 : {},
62
+ extends: (_data$extends = data.extends) !== null && _data$extends !== void 0 ? _data$extends : ''
63
+ };
64
+ };
65
+
66
+ exports.loadSubConfigFile = loadSubConfigFile;
67
+
68
+ const loadDirConfigFiles = (filesResponse, rootConfig) => {
69
+ const dirConfigMap = {}; // TODO: circular extends will cause infinite loop... consider instrumenting code to monitor for loops in the future?
70
+
71
+ const loadExtendedConfig = configPath => {
72
+ let dirConfig = loadSubConfigFile(configPath);
73
+
74
+ if (dirConfig.extends) {
75
+ const isRootConfig = dirConfig.extends === rootConfig.path;
76
+ const {
77
+ options,
78
+ excludes
79
+ } = isRootConfig ? rootConfig.config : addConfig(dirConfig.extends);
80
+ dirConfig = extendConfig({
81
+ options,
82
+ excludes
83
+ }, dirConfig);
84
+ }
85
+
86
+ return dirConfig;
87
+ };
88
+
89
+ const addConfig = configPath => {
90
+ const {
91
+ dir
92
+ } = _path.default.parse(configPath);
93
+
94
+ if (dirConfigMap[dir]) {
95
+ return dirConfigMap[dir];
96
+ }
97
+
98
+ dirConfigMap[dir] = loadExtendedConfig(configPath);
99
+ return dirConfigMap[dir];
100
+ };
101
+
102
+ const extendConfig = (toExtend, current) => ({
103
+ // $FlowFixMe[exponential-spread]
104
+ options: { ...toExtend.options,
105
+ ...current.options
106
+ },
107
+ excludes: Array.from(new Set([...toExtend.excludes, ...current.excludes]))
108
+ });
109
+
110
+ filesResponse.trim().split('\n').forEach(configPath => {
111
+ const {
112
+ dir
113
+ } = _path.default.parse(configPath);
114
+
115
+ if (dir && !dirConfigMap[dir]) {
116
+ dirConfigMap[dir] = loadExtendedConfig(configPath);
117
+ }
118
+ });
119
+ return dirConfigMap;
120
+ };
121
+ /**
122
+ * Loads a .json 'introspection query response', or a .graphql schema definition.
123
+ */
124
+
125
+
126
+ exports.loadDirConfigFiles = loadDirConfigFiles;
127
+
53
128
  const getSchemas = schemaFilePath => {
54
129
  const raw = _fs.default.readFileSync(schemaFilePath, 'utf8');
55
130
 
@@ -71,4 +146,15 @@ const getSchemas = schemaFilePath => {
71
146
  };
72
147
 
73
148
  exports.getSchemas = getSchemas;
149
+
150
+ const validateOptions = (configFile, options) => {
151
+ if (options) {
152
+ const externalOptionsKeys = ['pragma', 'loosePragma', 'ignorePragma', 'scalars', 'strictNullability', 'regenerateCommand', 'readOnlyArray', 'splitTypes', 'generatedDirectory', 'exportAllObjectTypes', 'typeFileName', 'experimentalEnums'];
153
+ Object.keys(options).forEach(k => {
154
+ if (!externalOptionsKeys.includes(k)) {
155
+ throw new Error(`Invalid option in config file ${configFile}: ${k}. Allowed options: ${externalOptionsKeys.join(', ')}`);
156
+ }
157
+ });
158
+ }
159
+ };
74
160
  //# sourceMappingURL=config.js.map
@@ -51,30 +51,7 @@ export const loadConfigFile = (configFile: string): CliConfig => {
51
51
  );
52
52
  }
53
53
  });
54
- if (data.options) {
55
- const externalOptionsKeys = [
56
- 'pragma',
57
- 'loosePragma',
58
- 'ignorePragma',
59
- 'scalars',
60
- 'strictNullability',
61
- 'regenerateCommand',
62
- 'readOnlyArray',
63
- 'splitTypes',
64
- 'generatedDirectory',
65
- 'exportAllObjectTypes',
66
- 'typeFileName',
67
- ];
68
- Object.keys(data.options).forEach((k) => {
69
- if (!externalOptionsKeys.includes(k)) {
70
- throw new Error(
71
- `Invalid option in config file ${configFile}: ${k}. Allowed options: ${externalOptionsKeys.join(
72
- ', ',
73
- )}`,
74
- );
75
- }
76
- });
77
- }
54
+ validateOptions(configFile, data.options ?? {});
78
55
  return {
79
56
  options: data.options ?? {},
80
57
  excludes: data.excludes?.map((string) => new RegExp(string)) ?? [],
@@ -85,6 +62,93 @@ export const loadConfigFile = (configFile: string): CliConfig => {
85
62
  };
86
63
  };
87
64
 
65
+ /**
66
+ * Subdirectory config to extend or overwrite higher-level config.
67
+ * @param {string} extends - Path from root; optional field for a config file in a subdirectory. If left blank, config file will overwrite root for directory.
68
+ */
69
+ type JSONSubConfig = {
70
+ excludes?: Array<string>,
71
+ options?: ExternalOptions,
72
+ extends?: string,
73
+ };
74
+
75
+ type SubConfig = {
76
+ excludes: Array<RegExp>,
77
+ options: ExternalOptions,
78
+ extends?: string,
79
+ };
80
+
81
+ export const loadSubConfigFile = (configFile: string): SubConfig => {
82
+ const jsonData = fs.readFileSync(configFile, 'utf8');
83
+ // eslint-disable-next-line flowtype-errors/uncovered
84
+ const data: JSONSubConfig = JSON.parse(jsonData);
85
+ const toplevelKeys = ['excludes', 'options', 'extends'];
86
+ Object.keys(data).forEach((k) => {
87
+ if (!toplevelKeys.includes(k)) {
88
+ throw new Error(
89
+ `Invalid attribute in non-root config file ${configFile}: ${k}. Allowed attributes: ${toplevelKeys.join(
90
+ ', ',
91
+ )}`,
92
+ );
93
+ }
94
+ });
95
+ validateOptions(configFile, data.options ?? {});
96
+ return {
97
+ excludes: data.excludes?.map((string) => new RegExp(string)) ?? [],
98
+ options: data.options ?? {},
99
+ extends: data.extends ?? '',
100
+ };
101
+ };
102
+
103
+ export const loadDirConfigFiles = (
104
+ filesResponse: string,
105
+ rootConfig: {path: string, config: CliConfig},
106
+ ): {[dir: string]: SubConfig} => {
107
+ const dirConfigMap: {[key: string]: SubConfig} = {};
108
+
109
+ // TODO: circular extends will cause infinite loop... consider instrumenting code to monitor for loops in the future?
110
+ const loadExtendedConfig = (configPath: string): SubConfig => {
111
+ let dirConfig = loadSubConfigFile(configPath);
112
+ if (dirConfig.extends) {
113
+ const isRootConfig = dirConfig.extends === rootConfig.path;
114
+ const {options, excludes} = isRootConfig
115
+ ? rootConfig.config
116
+ : addConfig(dirConfig.extends);
117
+ dirConfig = extendConfig({options, excludes}, dirConfig);
118
+ }
119
+ return dirConfig;
120
+ };
121
+ const addConfig = (configPath) => {
122
+ const {dir} = path.parse(configPath);
123
+ if (dirConfigMap[dir]) {
124
+ return dirConfigMap[dir];
125
+ }
126
+ dirConfigMap[dir] = loadExtendedConfig(configPath);
127
+ return dirConfigMap[dir];
128
+ };
129
+ const extendConfig = (
130
+ toExtend: SubConfig,
131
+ current: SubConfig,
132
+ ): SubConfig => ({
133
+ // $FlowFixMe[exponential-spread]
134
+ options: {...toExtend.options, ...current.options},
135
+ excludes: Array.from(
136
+ new Set([...toExtend.excludes, ...current.excludes]),
137
+ ),
138
+ });
139
+
140
+ filesResponse
141
+ .trim()
142
+ .split('\n')
143
+ .forEach((configPath) => {
144
+ const {dir} = path.parse(configPath);
145
+ if (dir && !dirConfigMap[dir]) {
146
+ dirConfigMap[dir] = loadExtendedConfig(configPath);
147
+ }
148
+ });
149
+ return dirConfigMap;
150
+ };
151
+
88
152
  /**
89
153
  * Loads a .json 'introspection query response', or a .graphql schema definition.
90
154
  */
@@ -110,3 +174,34 @@ export const getSchemas = (schemaFilePath: string): [GraphQLSchema, Schema] => {
110
174
  return [schemaForValidation, schemaForTypeGeneration];
111
175
  }
112
176
  };
177
+
178
+ const validateOptions = (
179
+ configFile: string,
180
+ options: ExternalOptions,
181
+ ): void => {
182
+ if (options) {
183
+ const externalOptionsKeys = [
184
+ 'pragma',
185
+ 'loosePragma',
186
+ 'ignorePragma',
187
+ 'scalars',
188
+ 'strictNullability',
189
+ 'regenerateCommand',
190
+ 'readOnlyArray',
191
+ 'splitTypes',
192
+ 'generatedDirectory',
193
+ 'exportAllObjectTypes',
194
+ 'typeFileName',
195
+ 'experimentalEnums',
196
+ ];
197
+ Object.keys(options).forEach((k) => {
198
+ if (!externalOptionsKeys.includes(k)) {
199
+ throw new Error(
200
+ `Invalid option in config file ${configFile}: ${k}. Allowed options: ${externalOptionsKeys.join(
201
+ ', ',
202
+ )}`,
203
+ );
204
+ }
205
+ });
206
+ }
207
+ };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/config.js"],"names":["loadConfigFile","configFile","data","JSON","parse","fs","readFileSync","toplevelKeys","Object","keys","forEach","k","includes","Error","join","options","externalOptionsKeys","excludes","map","string","RegExp","schemaFilePath","path","isAbsolute","dirname","dumpOperations","getSchemas","raw","endsWith","schemaForValidation","queryResponse","descriptions","schemaForTypeGeneration","introspectionData"],"mappings":"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","sourcesContent":["// @flow\nimport type {ExternalOptions} from '../generateTypeFiles';\nimport type {Schema} from '../types';\nimport type {GraphQLSchema} from 'graphql/type/schema';\n\nimport {schemaFromIntrospectionData} from '../schemaFromIntrospectionData';\n\nimport fs from 'fs';\nimport {\n buildClientSchema,\n buildSchema,\n getIntrospectionQuery,\n graphqlSync,\n type IntrospectionQuery,\n} from 'graphql';\nimport path from 'path';\n\nexport type CliConfig = {\n excludes: Array<RegExp>,\n schemaFilePath: string,\n dumpOperations?: string,\n options: ExternalOptions,\n};\n\n/**\n * This is the json-compatible form of the config\n * object.\n */\ntype JSONConfig = {\n excludes?: Array<string>,\n schemaFilePath: string,\n options?: ExternalOptions,\n dumpOperations?: string,\n};\n\nexport const loadConfigFile = (configFile: string): CliConfig => {\n // eslint-disable-next-line flowtype-errors/uncovered\n const data: JSONConfig = JSON.parse(fs.readFileSync(configFile, 'utf8'));\n const toplevelKeys = [\n 'excludes',\n 'schemaFilePath',\n 'options',\n 'dumpOperations',\n ];\n Object.keys(data).forEach((k) => {\n if (!toplevelKeys.includes(k)) {\n throw new Error(\n `Invalid attribute in config file ${configFile}: ${k}. Allowed attributes: ${toplevelKeys.join(\n ', ',\n )}`,\n );\n }\n });\n if (data.options) {\n const externalOptionsKeys = [\n 'pragma',\n 'loosePragma',\n 'ignorePragma',\n 'scalars',\n 'strictNullability',\n 'regenerateCommand',\n 'readOnlyArray',\n 'splitTypes',\n 'generatedDirectory',\n 'exportAllObjectTypes',\n 'typeFileName',\n ];\n Object.keys(data.options).forEach((k) => {\n if (!externalOptionsKeys.includes(k)) {\n throw new Error(\n `Invalid option in config file ${configFile}: ${k}. Allowed options: ${externalOptionsKeys.join(\n ', ',\n )}`,\n );\n }\n });\n }\n return {\n options: data.options ?? {},\n excludes: data.excludes?.map((string) => new RegExp(string)) ?? [],\n schemaFilePath: path.isAbsolute(data.schemaFilePath)\n ? data.schemaFilePath\n : path.join(path.dirname(configFile), data.schemaFilePath),\n dumpOperations: data.dumpOperations,\n };\n};\n\n/**\n * Loads a .json 'introspection query response', or a .graphql schema definition.\n */\nexport const getSchemas = (schemaFilePath: string): [GraphQLSchema, Schema] => {\n const raw = fs.readFileSync(schemaFilePath, 'utf8');\n if (schemaFilePath.endsWith('.graphql')) {\n const schemaForValidation = buildSchema(raw);\n const queryResponse = graphqlSync(\n schemaForValidation,\n getIntrospectionQuery({descriptions: true}),\n );\n const schemaForTypeGeneration = schemaFromIntrospectionData(\n // eslint-disable-next-line flowtype-errors/uncovered\n ((queryResponse.data: any): IntrospectionQuery),\n );\n return [schemaForValidation, schemaForTypeGeneration];\n } else {\n // eslint-disable-next-line flowtype-errors/uncovered\n const introspectionData: IntrospectionQuery = JSON.parse(raw);\n const schemaForValidation = buildClientSchema(introspectionData);\n const schemaForTypeGeneration =\n schemaFromIntrospectionData(introspectionData);\n return [schemaForValidation, schemaForTypeGeneration];\n }\n};\n"],"file":"config.js"}
1
+ {"version":3,"sources":["../../src/cli/config.js"],"names":["loadConfigFile","configFile","data","JSON","parse","fs","readFileSync","toplevelKeys","Object","keys","forEach","k","includes","Error","join","validateOptions","options","excludes","map","string","RegExp","schemaFilePath","path","isAbsolute","dirname","dumpOperations","loadSubConfigFile","jsonData","extends","loadDirConfigFiles","filesResponse","rootConfig","dirConfigMap","loadExtendedConfig","configPath","dirConfig","isRootConfig","config","addConfig","extendConfig","dir","toExtend","current","Array","from","Set","trim","split","getSchemas","raw","endsWith","schemaForValidation","queryResponse","descriptions","schemaForTypeGeneration","introspectionData","externalOptionsKeys"],"mappings":"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","sourcesContent":["// @flow\nimport type {ExternalOptions} from '../generateTypeFiles';\nimport type {Schema} from '../types';\nimport type {GraphQLSchema} from 'graphql/type/schema';\n\nimport {schemaFromIntrospectionData} from '../schemaFromIntrospectionData';\n\nimport fs from 'fs';\nimport {\n buildClientSchema,\n buildSchema,\n getIntrospectionQuery,\n graphqlSync,\n type IntrospectionQuery,\n} from 'graphql';\nimport path from 'path';\n\nexport type CliConfig = {\n excludes: Array<RegExp>,\n schemaFilePath: string,\n dumpOperations?: string,\n options: ExternalOptions,\n};\n\n/**\n * This is the json-compatible form of the config\n * object.\n */\ntype JSONConfig = {\n excludes?: Array<string>,\n schemaFilePath: string,\n options?: ExternalOptions,\n dumpOperations?: string,\n};\n\nexport const loadConfigFile = (configFile: string): CliConfig => {\n // eslint-disable-next-line flowtype-errors/uncovered\n const data: JSONConfig = JSON.parse(fs.readFileSync(configFile, 'utf8'));\n const toplevelKeys = [\n 'excludes',\n 'schemaFilePath',\n 'options',\n 'dumpOperations',\n ];\n Object.keys(data).forEach((k) => {\n if (!toplevelKeys.includes(k)) {\n throw new Error(\n `Invalid attribute in config file ${configFile}: ${k}. Allowed attributes: ${toplevelKeys.join(\n ', ',\n )}`,\n );\n }\n });\n validateOptions(configFile, data.options ?? {});\n return {\n options: data.options ?? {},\n excludes: data.excludes?.map((string) => new RegExp(string)) ?? [],\n schemaFilePath: path.isAbsolute(data.schemaFilePath)\n ? data.schemaFilePath\n : path.join(path.dirname(configFile), data.schemaFilePath),\n dumpOperations: data.dumpOperations,\n };\n};\n\n/**\n * Subdirectory config to extend or overwrite higher-level config.\n * @param {string} extends - Path from root; optional field for a config file in a subdirectory. If left blank, config file will overwrite root for directory.\n */\ntype JSONSubConfig = {\n excludes?: Array<string>,\n options?: ExternalOptions,\n extends?: string,\n};\n\ntype SubConfig = {\n excludes: Array<RegExp>,\n options: ExternalOptions,\n extends?: string,\n};\n\nexport const loadSubConfigFile = (configFile: string): SubConfig => {\n const jsonData = fs.readFileSync(configFile, 'utf8');\n // eslint-disable-next-line flowtype-errors/uncovered\n const data: JSONSubConfig = JSON.parse(jsonData);\n const toplevelKeys = ['excludes', 'options', 'extends'];\n Object.keys(data).forEach((k) => {\n if (!toplevelKeys.includes(k)) {\n throw new Error(\n `Invalid attribute in non-root config file ${configFile}: ${k}. Allowed attributes: ${toplevelKeys.join(\n ', ',\n )}`,\n );\n }\n });\n validateOptions(configFile, data.options ?? {});\n return {\n excludes: data.excludes?.map((string) => new RegExp(string)) ?? [],\n options: data.options ?? {},\n extends: data.extends ?? '',\n };\n};\n\nexport const loadDirConfigFiles = (\n filesResponse: string,\n rootConfig: {path: string, config: CliConfig},\n): {[dir: string]: SubConfig} => {\n const dirConfigMap: {[key: string]: SubConfig} = {};\n\n // TODO: circular extends will cause infinite loop... consider instrumenting code to monitor for loops in the future?\n const loadExtendedConfig = (configPath: string): SubConfig => {\n let dirConfig = loadSubConfigFile(configPath);\n if (dirConfig.extends) {\n const isRootConfig = dirConfig.extends === rootConfig.path;\n const {options, excludes} = isRootConfig\n ? rootConfig.config\n : addConfig(dirConfig.extends);\n dirConfig = extendConfig({options, excludes}, dirConfig);\n }\n return dirConfig;\n };\n const addConfig = (configPath) => {\n const {dir} = path.parse(configPath);\n if (dirConfigMap[dir]) {\n return dirConfigMap[dir];\n }\n dirConfigMap[dir] = loadExtendedConfig(configPath);\n return dirConfigMap[dir];\n };\n const extendConfig = (\n toExtend: SubConfig,\n current: SubConfig,\n ): SubConfig => ({\n // $FlowFixMe[exponential-spread]\n options: {...toExtend.options, ...current.options},\n excludes: Array.from(\n new Set([...toExtend.excludes, ...current.excludes]),\n ),\n });\n\n filesResponse\n .trim()\n .split('\\n')\n .forEach((configPath) => {\n const {dir} = path.parse(configPath);\n if (dir && !dirConfigMap[dir]) {\n dirConfigMap[dir] = loadExtendedConfig(configPath);\n }\n });\n return dirConfigMap;\n};\n\n/**\n * Loads a .json 'introspection query response', or a .graphql schema definition.\n */\nexport const getSchemas = (schemaFilePath: string): [GraphQLSchema, Schema] => {\n const raw = fs.readFileSync(schemaFilePath, 'utf8');\n if (schemaFilePath.endsWith('.graphql')) {\n const schemaForValidation = buildSchema(raw);\n const queryResponse = graphqlSync(\n schemaForValidation,\n getIntrospectionQuery({descriptions: true}),\n );\n const schemaForTypeGeneration = schemaFromIntrospectionData(\n // eslint-disable-next-line flowtype-errors/uncovered\n ((queryResponse.data: any): IntrospectionQuery),\n );\n return [schemaForValidation, schemaForTypeGeneration];\n } else {\n // eslint-disable-next-line flowtype-errors/uncovered\n const introspectionData: IntrospectionQuery = JSON.parse(raw);\n const schemaForValidation = buildClientSchema(introspectionData);\n const schemaForTypeGeneration =\n schemaFromIntrospectionData(introspectionData);\n return [schemaForValidation, schemaForTypeGeneration];\n }\n};\n\nconst validateOptions = (\n configFile: string,\n options: ExternalOptions,\n): void => {\n if (options) {\n const externalOptionsKeys = [\n 'pragma',\n 'loosePragma',\n 'ignorePragma',\n 'scalars',\n 'strictNullability',\n 'regenerateCommand',\n 'readOnlyArray',\n 'splitTypes',\n 'generatedDirectory',\n 'exportAllObjectTypes',\n 'typeFileName',\n 'experimentalEnums',\n ];\n Object.keys(options).forEach((k) => {\n if (!externalOptionsKeys.includes(k)) {\n throw new Error(\n `Invalid option in config file ${configFile}: ${k}. Allowed options: ${externalOptionsKeys.join(\n ', ',\n )}`,\n );\n }\n });\n }\n};\n"],"file":"config.js"}
package/dist/cli/run.js CHANGED
@@ -23,6 +23,8 @@ var _validation = require("graphql/validation");
23
23
 
24
24
  var _path = _interopRequireWildcard(require("path"));
25
25
 
26
+ var _utils = require("./utils");
27
+
26
28
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
27
29
 
28
30
  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; }
@@ -58,7 +60,17 @@ Usage: graphql-flow [configFile.json] [filesToCrawl...]`);
58
60
  process.exit(1); // eslint-disable-line flowtype-errors/uncovered
59
61
  }
60
62
 
61
- const config = (0, _config.loadConfigFile)(configFile);
63
+ const config = (0, _config.loadConfigFile)(configFile); // find file paths ending with "graphql-flow.config.json"
64
+
65
+ const subConfigsQuery = () => (0, _child_process.execSync)('git ls-files "*graphql-flow.config.json"', {
66
+ encoding: 'utf8',
67
+ cwd: process.cwd()
68
+ });
69
+
70
+ const subConfigMap = (0, _config.loadDirConfigFiles)(subConfigsQuery(), {
71
+ config,
72
+ path: configFile
73
+ });
62
74
  const [schemaForValidation, schemaForTypeGeneration] = (0, _config.getSchemas)(config.schemaFilePath);
63
75
  const inputFiles = cliFiles.length ? cliFiles : findGraphqlTagReferences(process.cwd());
64
76
  /** Step (2) */
@@ -117,8 +129,14 @@ Object.keys(resolved).forEach(k => {
117
129
  document,
118
130
  raw
119
131
  } = resolved[k];
132
+ let fileConfig = config;
133
+ const closestConfigPath = (0, _utils.longestMatchingPath)(raw.loc.path, Object.keys(subConfigMap)); // get longest match in the case of nested subconfigs
134
+
135
+ if (closestConfigPath) {
136
+ fileConfig = subConfigMap[closestConfigPath];
137
+ }
120
138
 
121
- if (config.excludes.some(rx => rx.test(raw.loc.path))) {
139
+ if (fileConfig.excludes.some(rx => rx.test(raw.loc.path))) {
122
140
  return; // skip
123
141
  }
124
142
 
@@ -134,7 +152,7 @@ Object.keys(resolved).forEach(k => {
134
152
  printedOperations.push(printed);
135
153
  }
136
154
 
137
- const processedOptions = (0, _generateTypeFiles.processPragmas)(config.options, rawSource);
155
+ const processedOptions = (0, _generateTypeFiles.processPragmas)(fileConfig.options, rawSource);
138
156
 
139
157
  if (!processedOptions) {
140
158
  return;
@@ -4,7 +4,7 @@
4
4
  import {generateTypeFiles, processPragmas} from '../generateTypeFiles';
5
5
  import {processFiles} from '../parser/parse';
6
6
  import {resolveDocuments} from '../parser/resolve';
7
- import {getSchemas, loadConfigFile} from './config';
7
+ import {loadDirConfigFiles, getSchemas, loadConfigFile} from './config';
8
8
 
9
9
  import {addTypenameToDocument} from 'apollo-utilities'; // eslint-disable-line flowtype-errors/uncovered
10
10
 
@@ -15,6 +15,7 @@ import {print} from 'graphql/language/printer';
15
15
  import {validate} from 'graphql/validation';
16
16
  import path from 'path';
17
17
  import {dirname} from 'path';
18
+ import {longestMatchingPath} from './utils';
18
19
 
19
20
  /**
20
21
  * This CLI tool executes the following steps:
@@ -59,6 +60,17 @@ Usage: graphql-flow [configFile.json] [filesToCrawl...]`);
59
60
 
60
61
  const config = loadConfigFile(configFile);
61
62
 
63
+ // find file paths ending with "graphql-flow.config.json"
64
+ const subConfigsQuery = () =>
65
+ execSync('git ls-files "*graphql-flow.config.json"', {
66
+ encoding: 'utf8',
67
+ cwd: process.cwd(),
68
+ });
69
+ const subConfigMap = loadDirConfigFiles(subConfigsQuery(), {
70
+ config,
71
+ path: configFile,
72
+ });
73
+
62
74
  const [schemaForValidation, schemaForTypeGeneration] = getSchemas(
63
75
  config.schemaFilePath,
64
76
  );
@@ -116,7 +128,17 @@ const printedOperations: Array<string> = [];
116
128
 
117
129
  Object.keys(resolved).forEach((k) => {
118
130
  const {document, raw} = resolved[k];
119
- if (config.excludes.some((rx) => rx.test(raw.loc.path))) {
131
+
132
+ let fileConfig = config;
133
+ const closestConfigPath = longestMatchingPath(
134
+ raw.loc.path,
135
+ Object.keys(subConfigMap),
136
+ ); // get longest match in the case of nested subconfigs
137
+ if (closestConfigPath) {
138
+ fileConfig = subConfigMap[closestConfigPath];
139
+ }
140
+
141
+ if (fileConfig.excludes.some((rx) => rx.test(raw.loc.path))) {
120
142
  return; // skip
121
143
  }
122
144
  const hasNonFragments = document.definitions.some(
@@ -131,7 +153,7 @@ Object.keys(resolved).forEach((k) => {
131
153
  printedOperations.push(printed);
132
154
  }
133
155
 
134
- const processedOptions = processPragmas(config.options, rawSource);
156
+ const processedOptions = processPragmas(fileConfig.options, rawSource);
135
157
  if (!processedOptions) {
136
158
  return;
137
159
  }