@khanacademy/graphql-flow 0.2.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/.flowconfig +1 -0
  2. package/.github/workflows/changeset-release.yml +3 -17
  3. package/.github/workflows/pr-checks.yml +13 -10
  4. package/CHANGELOG.md +35 -0
  5. package/Readme.md +41 -132
  6. package/dist/__test__/example-schema.graphql +67 -0
  7. package/dist/__test__/generateTypeFileContents.test.js +157 -0
  8. package/dist/__test__/graphql-flow.test.js +639 -0
  9. package/dist/__test__/processPragmas.test.js +76 -0
  10. package/dist/cli/__test__/config.test.js +120 -0
  11. package/dist/cli/config.js +51 -26
  12. package/dist/cli/config.js.flow +40 -68
  13. package/dist/cli/config.js.map +1 -1
  14. package/dist/cli/run.js +41 -19
  15. package/dist/cli/run.js.flow +58 -22
  16. package/dist/cli/run.js.map +1 -1
  17. package/dist/cli/schema.json +91 -0
  18. package/dist/enums.js +20 -7
  19. package/dist/enums.js.flow +44 -15
  20. package/dist/enums.js.map +1 -1
  21. package/dist/generateResponseType.js +47 -47
  22. package/dist/generateResponseType.js.flow +55 -57
  23. package/dist/generateResponseType.js.map +1 -1
  24. package/dist/generateTypeFiles.js +41 -22
  25. package/dist/generateTypeFiles.js.flow +86 -78
  26. package/dist/generateTypeFiles.js.map +1 -1
  27. package/dist/generateVariablesType.js +24 -24
  28. package/dist/generateVariablesType.js.flow +25 -28
  29. package/dist/generateVariablesType.js.map +1 -1
  30. package/dist/index.js +18 -20
  31. package/dist/index.js.flow +31 -16
  32. package/dist/index.js.map +1 -1
  33. package/dist/parser/__test__/parse.test.js +247 -0
  34. package/dist/types.js.flow +28 -5
  35. package/flow-typed/npm/@babel/types_vx.x.x.js +17 -3
  36. package/package.json +3 -2
  37. package/src/__test__/generateTypeFileContents.test.js +55 -1
  38. package/src/__test__/graphql-flow.test.js +7 -7
  39. package/src/__test__/processPragmas.test.js +28 -15
  40. package/src/cli/__test__/config.test.js +120 -0
  41. package/src/cli/config.js +40 -68
  42. package/src/cli/run.js +58 -22
  43. package/src/cli/schema.json +91 -0
  44. package/src/enums.js +44 -15
  45. package/src/generateResponseType.js +55 -57
  46. package/src/generateTypeFiles.js +86 -78
  47. package/src/generateVariablesType.js +25 -28
  48. package/src/index.js +31 -16
  49. package/src/types.js +28 -5
  50. package/.github/actions/filter-files/action.yml +0 -37
  51. package/.github/actions/full-or-limited/action.yml +0 -27
  52. package/.github/actions/json-args/action.yml +0 -32
  53. package/.github/actions/setup/action.yml +0 -28
  54. package/dist/jest-mock-graphql-tag.js +0 -88
  55. package/dist/jest-mock-graphql-tag.js.flow +0 -96
  56. package/dist/jest-mock-graphql-tag.js.map +0 -1
  57. package/src/jest-mock-graphql-tag.js +0 -96
@@ -4,12 +4,11 @@
4
4
  * Tests for our graphql flow generation!
5
5
  */
6
6
 
7
- import type {DocumentNode} from 'graphql';
8
-
9
7
  import {getSchemas} from '../cli/config';
10
8
  import {documentToFlowTypes} from '..';
9
+ import gql from 'graphql-tag';
11
10
 
12
- import type {Options} from '../types';
11
+ import type {GenerateConfig} from '../types';
13
12
 
14
13
  // This allows us to "snapshot" a string cleanly.
15
14
  /* eslint-disable flowtype-errors/uncovered */
@@ -21,12 +20,13 @@ expect.addSnapshotSerializer({
21
20
 
22
21
  const [_, exampleSchema] = getSchemas(__dirname + '/example-schema.graphql');
23
22
 
24
- const rawQueryToFlowTypes = (query: string, options?: Options): string => {
25
- // We need the "requireActual" because we mock graphql-tag in jest-setup.js
26
- // eslint-disable-next-line flowtype-errors/uncovered
27
- const gql: (string) => DocumentNode = jest.requireActual('graphql-tag');
23
+ const rawQueryToFlowTypes = (
24
+ query: string,
25
+ options?: $Partial<GenerateConfig>,
26
+ ): string => {
28
27
  const node = gql(query);
29
28
  return documentToFlowTypes(node, exampleSchema, {
29
+ schemaFilePath: '',
30
30
  scalars: {PositiveNumber: 'number'},
31
31
  ...options,
32
32
  })
@@ -1,63 +1,76 @@
1
1
  // @flow
2
+ import type {CrawlConfig, GenerateConfig} from '../types';
3
+
2
4
  import {processPragmas} from '../generateTypeFiles';
3
5
 
4
6
  const pragma = '# @autogen\n';
5
7
  const loosePragma = '# @autogen-loose\n';
6
8
 
9
+ const baseGenerate: GenerateConfig = {schemaFilePath: ''};
10
+ const baseCrawl: CrawlConfig = {root: ''};
11
+
7
12
  describe('processPragmas', () => {
8
13
  it('should work with no pragmas', () => {
9
- expect(processPragmas({}, `query X { Y }`)).toEqual({
10
- strictNullability: undefined,
11
- readOnlyArray: undefined,
12
- scalars: undefined,
14
+ expect(
15
+ processPragmas(baseGenerate, baseCrawl, `query X { Y }`),
16
+ ).toEqual({
17
+ generate: true,
18
+ strict: undefined,
13
19
  });
14
20
  });
15
21
 
16
22
  it('should reject query without required pragma', () => {
17
- expect(processPragmas({pragma}, `query X { Y }`)).toEqual(null);
23
+ expect(
24
+ processPragmas(
25
+ baseGenerate,
26
+ {...baseCrawl, pragma},
27
+ `query X { Y }`,
28
+ ),
29
+ ).toEqual({generate: false});
18
30
  });
19
31
 
20
32
  it('should accept query with required pragma', () => {
21
33
  expect(
22
34
  processPragmas(
23
- {pragma},
35
+ baseGenerate,
36
+ {...baseCrawl, pragma},
24
37
  `query X {
25
38
  # @autogen
26
39
  Y
27
40
  }`,
28
41
  ),
29
42
  ).toEqual({
30
- strictNullability: true,
31
- readOnlyArray: undefined,
32
- scalars: undefined,
43
+ strict: true,
44
+ generate: true,
33
45
  });
34
46
  });
35
47
 
36
48
  it('should accept query with loose pragma', () => {
37
49
  expect(
38
50
  processPragmas(
39
- {pragma, loosePragma},
51
+ baseGenerate,
52
+ {...baseCrawl, pragma, loosePragma},
40
53
  `query X {
41
54
  # @autogen-loose
42
55
  Y
43
56
  }`,
44
57
  ),
45
58
  ).toEqual({
46
- strictNullability: false,
47
- readOnlyArray: undefined,
48
- scalars: undefined,
59
+ strict: false,
60
+ generate: true,
49
61
  });
50
62
  });
51
63
 
52
64
  it('should reject query with ignore pragma', () => {
53
65
  expect(
54
66
  processPragmas(
55
- {ignorePragma: '# @ignore\n'},
67
+ baseGenerate,
68
+ {...baseCrawl, ignorePragma: '# @ignore\n'},
56
69
  `query X {
57
70
  # @ignore
58
71
  Y
59
72
  }`,
60
73
  ),
61
- ).toEqual(null);
74
+ ).toEqual({generate: false});
62
75
  });
63
76
  });
@@ -0,0 +1,120 @@
1
+ // @flow
2
+ import type {Config} from '../../types';
3
+
4
+ import {findApplicableConfig, validateOrThrow} from '../config';
5
+ import configSchema from '../schema.json'; // eslint-disable-line flowtype-errors/uncovered
6
+
7
+ describe('findApplicableConfig', () => {
8
+ it('should work with one that matches', () => {
9
+ const config = {
10
+ schemaFilePath: 'ok.graphql',
11
+ };
12
+ expect(findApplicableConfig('/hello', config)).toBe(config);
13
+ });
14
+
15
+ it('should be falsy if nothing matches', () => {
16
+ const config = {
17
+ schemaFilePath: 'ok.graphql',
18
+ exclude: [/hello$/],
19
+ };
20
+ expect(findApplicableConfig('/hello', config)).toBeUndefined();
21
+ });
22
+
23
+ it('should match & exclude with multiple configs', () => {
24
+ const configs = [
25
+ {schemaFilePath: 'one', match: [/\.jsx$/], exclude: [/^test/]},
26
+ {schemaFilePath: 'two', exclude: [/^hello/]},
27
+ {schemaFilePath: 'three'},
28
+ ];
29
+ expect(findApplicableConfig('hello.js', configs)).toBe(configs[2]);
30
+ expect(findApplicableConfig('goodbye.js', configs)).toBe(configs[1]);
31
+ expect(findApplicableConfig('hello.jsx', configs)).toBe(configs[0]);
32
+ expect(findApplicableConfig('test.jsx', configs)).toBe(configs[1]);
33
+ });
34
+ });
35
+
36
+ describe('jsonschema validation', () => {
37
+ it('should accept valid schema', () => {
38
+ const config: Config = {
39
+ crawl: {
40
+ root: '/here/we/crawl',
41
+ },
42
+ generate: {
43
+ match: [/\.fixture\.js$/],
44
+ exclude: [
45
+ '_test\\.js$',
46
+ '\\bcourse-editor-package\\b',
47
+ '\\.fixture\\.js$',
48
+ '\\b__flowtests__\\b',
49
+ '\\bcourse-editor\\b',
50
+ ],
51
+ readOnlyArray: false,
52
+ regenerateCommand: 'make gqlflow',
53
+ scalars: {
54
+ JSONString: 'string',
55
+ KALocale: 'string',
56
+ NaiveDateTime: 'string',
57
+ },
58
+ splitTypes: true,
59
+ generatedDirectory: '__graphql-types__',
60
+ exportAllObjectTypes: true,
61
+ schemaFilePath: './composed_schema.graphql',
62
+ },
63
+ };
64
+ validateOrThrow(
65
+ config,
66
+ configSchema, // eslint-disable-line flowtype-errors/uncovered
67
+ );
68
+ });
69
+
70
+ it('should accept a schema with multiple generate configs', () => {
71
+ const generate = {
72
+ match: [/\.fixture\.js$/],
73
+ exclude: [
74
+ '_test\\.js$',
75
+ '\\bcourse-editor-package\\b',
76
+ '\\.fixture\\.js$',
77
+ '\\b__flowtests__\\b',
78
+ '\\bcourse-editor\\b',
79
+ ],
80
+ readOnlyArray: false,
81
+ regenerateCommand: 'make gqlflow',
82
+ scalars: {
83
+ JSONString: 'string',
84
+ KALocale: 'string',
85
+ NaiveDateTime: 'string',
86
+ },
87
+ splitTypes: true,
88
+ generatedDirectory: '__graphql-types__',
89
+ exportAllObjectTypes: true,
90
+ schemaFilePath: './composed_schema.graphql',
91
+ };
92
+ const config: Config = {
93
+ crawl: {
94
+ root: '/here/we/crawl',
95
+ },
96
+ generate: [
97
+ {...generate, match: [/^static/], exportAllObjectTypes: false},
98
+ generate,
99
+ ],
100
+ };
101
+ validateOrThrow(
102
+ config,
103
+ configSchema, // eslint-disable-line flowtype-errors/uncovered
104
+ );
105
+ });
106
+
107
+ it('should reject invalid schema', () => {
108
+ expect(() =>
109
+ validateOrThrow(
110
+ {schemaFilePath: 10, options: {extraOption: 'hello'}},
111
+ configSchema, // eslint-disable-line flowtype-errors/uncovered
112
+ ),
113
+ ).toThrowErrorMatchingInlineSnapshot(`
114
+ "instance is not allowed to have the additional property \\"schemaFilePath\\"
115
+ instance is not allowed to have the additional property \\"options\\"
116
+ instance requires property \\"crawl\\"
117
+ instance requires property \\"generate\\""
118
+ `);
119
+ });
120
+ });
package/src/cli/config.js CHANGED
@@ -1,9 +1,9 @@
1
1
  // @flow
2
- import type {ExternalOptions} from '../generateTypeFiles';
3
2
  import type {Schema} from '../types';
4
3
  import type {GraphQLSchema} from 'graphql/type/schema';
5
4
 
6
5
  import {schemaFromIntrospectionData} from '../schemaFromIntrospectionData';
6
+ import configSchema from './schema.json'; // eslint-disable-line flowtype-errors/uncovered
7
7
 
8
8
  import fs from 'fs';
9
9
  import {
@@ -13,77 +13,26 @@ import {
13
13
  graphqlSync,
14
14
  type IntrospectionQuery,
15
15
  } from 'graphql';
16
- import path from 'path';
16
+ import type {Config, GenerateConfig} from '../types';
17
+ import {validate} from 'jsonschema'; // eslint-disable-line flowtype-errors/uncovered
17
18
 
18
- export type CliConfig = {
19
- excludes: Array<RegExp>,
20
- schemaFilePath: string,
21
- dumpOperations?: string,
22
- options: ExternalOptions,
23
- };
24
-
25
- /**
26
- * This is the json-compatible form of the config
27
- * object.
28
- */
29
- type JSONConfig = {
30
- excludes?: Array<string>,
31
- schemaFilePath: string,
32
- options?: ExternalOptions,
33
- dumpOperations?: string,
19
+ export const validateOrThrow = (value: mixed, jsonSchema: mixed) => {
20
+ /* eslint-disable flowtype-errors/uncovered */
21
+ const result = validate(value, jsonSchema);
22
+ if (!result.valid) {
23
+ throw new Error(
24
+ result.errors.map((error) => error.toString()).join('\n'),
25
+ );
26
+ }
27
+ /* eslint-enable flowtype-errors/uncovered */
34
28
  };
35
29
 
36
- export const loadConfigFile = (configFile: string): CliConfig => {
30
+ export const loadConfigFile = (configFile: string): Config => {
31
+ // $FlowIgnore // eslint-disable-next-line flowtype-errors/uncovered
32
+ const data: Config = require(configFile);
37
33
  // eslint-disable-next-line flowtype-errors/uncovered
38
- const data: JSONConfig = JSON.parse(fs.readFileSync(configFile, 'utf8'));
39
- const toplevelKeys = [
40
- 'excludes',
41
- 'schemaFilePath',
42
- 'options',
43
- 'dumpOperations',
44
- ];
45
- Object.keys(data).forEach((k) => {
46
- if (!toplevelKeys.includes(k)) {
47
- throw new Error(
48
- `Invalid attribute in config file ${configFile}: ${k}. Allowed attributes: ${toplevelKeys.join(
49
- ', ',
50
- )}`,
51
- );
52
- }
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
- }
78
- return {
79
- options: data.options ?? {},
80
- excludes: data.excludes?.map((string) => new RegExp(string)) ?? [],
81
- schemaFilePath: path.join(
82
- path.dirname(configFile),
83
- data.schemaFilePath,
84
- ),
85
- dumpOperations: data.dumpOperations,
86
- };
34
+ validateOrThrow(data, configSchema);
35
+ return data;
87
36
  };
88
37
 
89
38
  /**
@@ -111,3 +60,26 @@ export const getSchemas = (schemaFilePath: string): [GraphQLSchema, Schema] => {
111
60
  return [schemaForValidation, schemaForTypeGeneration];
112
61
  }
113
62
  };
63
+
64
+ /**
65
+ * Find the first item of the `config.generate` array where both:
66
+ * - no item of `exclude` matches
67
+ * - at least one item of `match` matches
68
+ */
69
+ export const findApplicableConfig = (
70
+ path: string,
71
+ configs: Array<GenerateConfig> | GenerateConfig,
72
+ ): ?GenerateConfig => {
73
+ if (!Array.isArray(configs)) {
74
+ configs = [configs];
75
+ }
76
+ return configs.find((config) => {
77
+ if (config.exclude?.some((exclude) => new RegExp(exclude).test(path))) {
78
+ return false;
79
+ }
80
+ if (!config.match) {
81
+ return true;
82
+ }
83
+ return config.match.some((matcher) => new RegExp(matcher).test(path));
84
+ });
85
+ };
package/src/cli/run.js CHANGED
@@ -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 {findApplicableConfig, getSchemas, loadConfigFile} from './config';
8
8
 
9
9
  import {addTypenameToDocument} from 'apollo-utilities'; // eslint-disable-line flowtype-errors/uncovered
10
10
 
@@ -15,10 +15,11 @@ 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 type {GenerateConfig} from '../types';
18
19
 
19
20
  /**
20
21
  * This CLI tool executes the following steps:
21
- * 1) process options
22
+ * 1) parse & validate config file
22
23
  * 2) crawl files to find all operations and fragments, with
23
24
  * tagged template literals and expressions.
24
25
  * 3) resolve the found operations, passing the literals and
@@ -43,13 +44,13 @@ const findGraphqlTagReferences = (root: string): Array<string> => {
43
44
  .map((relative) => path.join(root, relative));
44
45
  };
45
46
 
46
- const [_, __, configFile, ...cliFiles] = process.argv;
47
+ const [_, __, configFilePath, ...cliFiles] = process.argv;
47
48
 
48
49
  if (
49
- configFile === '-h' ||
50
- configFile === '--help' ||
51
- configFile === 'help' ||
52
- !configFile
50
+ configFilePath === '-h' ||
51
+ configFilePath === '--help' ||
52
+ configFilePath === 'help' ||
53
+ !configFilePath
53
54
  ) {
54
55
  console.log(`graphql-flow
55
56
 
@@ -57,15 +58,21 @@ Usage: graphql-flow [configFile.json] [filesToCrawl...]`);
57
58
  process.exit(1); // eslint-disable-line flowtype-errors/uncovered
58
59
  }
59
60
 
60
- const config = loadConfigFile(configFile);
61
+ const makeAbsPath = (maybeRelativePath: string, basePath: string) => {
62
+ return path.isAbsolute(maybeRelativePath)
63
+ ? maybeRelativePath
64
+ : path.join(basePath, maybeRelativePath);
65
+ };
66
+
67
+ const absConfigPath = makeAbsPath(configFilePath, process.cwd());
61
68
 
62
- const [schemaForValidation, schemaForTypeGeneration] = getSchemas(
63
- config.schemaFilePath,
64
- );
69
+ const config = loadConfigFile(absConfigPath);
65
70
 
66
71
  const inputFiles = cliFiles.length
67
72
  ? cliFiles
68
- : findGraphqlTagReferences(process.cwd());
73
+ : findGraphqlTagReferences(
74
+ makeAbsPath(config.crawl.root, path.dirname(absConfigPath)),
75
+ );
69
76
 
70
77
  /** Step (2) */
71
78
 
@@ -111,19 +118,37 @@ console.log(Object.keys(resolved).length, 'resolved queries');
111
118
 
112
119
  /** Step (4) */
113
120
 
121
+ const schemaCache = {};
122
+ const getCachedSchemas = (schemaFilePath: string) => {
123
+ if (!schemaCache[schemaFilePath]) {
124
+ schemaCache[schemaFilePath] = getSchemas(
125
+ makeAbsPath(schemaFilePath, path.dirname(absConfigPath)),
126
+ );
127
+ }
128
+
129
+ return schemaCache[schemaFilePath];
130
+ };
131
+
114
132
  let validationFailures: number = 0;
115
133
  const printedOperations: Array<string> = [];
116
134
 
117
- Object.keys(resolved).forEach((k) => {
118
- const {document, raw} = resolved[k];
119
- if (config.excludes.some((rx) => rx.test(raw.loc.path))) {
120
- return; // skip
121
- }
135
+ Object.keys(resolved).forEach((filePathAndLine) => {
136
+ const {document, raw} = resolved[filePathAndLine];
137
+
122
138
  const hasNonFragments = document.definitions.some(
123
139
  ({kind}) => kind !== 'FragmentDefinition',
124
140
  );
125
141
  const rawSource: string = raw.literals[0];
126
142
 
143
+ const generateConfig = findApplicableConfig(
144
+ // strip off the trailing line number, e.g. `:23`
145
+ filePathAndLine.split(':')[0],
146
+ config.generate,
147
+ );
148
+ if (!generateConfig) {
149
+ return; // no generate config matches, bail
150
+ }
151
+
127
152
  // eslint-disable-next-line flowtype-errors/uncovered
128
153
  const withTypeNames: DocumentNode = addTypenameToDocument(document);
129
154
  const printed = print(withTypeNames);
@@ -131,10 +156,21 @@ Object.keys(resolved).forEach((k) => {
131
156
  printedOperations.push(printed);
132
157
  }
133
158
 
134
- const processedOptions = processPragmas(config.options, rawSource);
135
- if (!processedOptions) {
159
+ const pragmaResult = processPragmas(
160
+ generateConfig,
161
+ config.crawl,
162
+ rawSource,
163
+ );
164
+ if (!pragmaResult.generate) {
136
165
  return;
137
166
  }
167
+ if (pragmaResult.strict != null) {
168
+ generateConfig.strictNullability = pragmaResult.strict;
169
+ }
170
+
171
+ const [schemaForValidation, schemaForTypeGeneration] = getCachedSchemas(
172
+ generateConfig.schemaFilePath,
173
+ );
138
174
 
139
175
  if (hasNonFragments) {
140
176
  /* eslint-disable flowtype-errors/uncovered */
@@ -158,7 +194,7 @@ Object.keys(resolved).forEach((k) => {
158
194
  raw.loc.path,
159
195
  schemaForTypeGeneration,
160
196
  withTypeNames,
161
- processedOptions,
197
+ generateConfig,
162
198
  );
163
199
  // eslint-disable-next-line flowtype-errors/uncovered
164
200
  } catch (err) {
@@ -178,8 +214,8 @@ if (validationFailures) {
178
214
  process.exit(1);
179
215
  }
180
216
 
181
- if (config.dumpOperations) {
182
- const dumpOperations = config.dumpOperations;
217
+ if (config.crawl.dumpOperations) {
218
+ const dumpOperations = config.crawl.dumpOperations;
183
219
  const parent = dirname(dumpOperations);
184
220
  mkdirSync(parent, {recursive: true});
185
221
  writeFileSync(
@@ -0,0 +1,91 @@
1
+ {
2
+ "$schema":"http://json-schema.org/draft-07/schema",
3
+ "type": "object",
4
+ "additionalProperties": false,
5
+ "definitions": {
6
+ "GenerateConfig": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "schemaFilePath": {
11
+ "type": "string"
12
+ },
13
+ "match": {
14
+ "type": "array",
15
+ "items": {
16
+ "oneOf": [
17
+ { "type": "object" },
18
+ { "type": "string" }
19
+ ]
20
+ }
21
+ },
22
+ "exclude": {
23
+ "type": "array",
24
+ "items": {
25
+ "oneOf": [
26
+ { "type": "object" },
27
+ { "type": "string" }
28
+ ]
29
+ }
30
+ },
31
+ "scalars": {
32
+ "type": "object"
33
+ },
34
+ "strictNullability": {
35
+ "type": "boolean"
36
+ },
37
+ "regenerateCommand": {
38
+ "type": "string"
39
+ },
40
+ "readOnlyArray": {
41
+ "type": "boolean"
42
+ },
43
+ "splitTypes": {
44
+ "type": "boolean"
45
+ },
46
+ "generatedDirectory": {
47
+ "type": "string"
48
+ },
49
+ "exportAllObjectTypes": {
50
+ "type": "boolean"
51
+ },
52
+ "typeFileName": {
53
+ "type": "string"
54
+ },
55
+ "experimentalEnums": {
56
+ "type": "boolean"
57
+ }
58
+ },
59
+ "required": [
60
+ "schemaFilePath"
61
+ ]
62
+ }
63
+ },
64
+ "properties": {
65
+ "crawl": {
66
+ "type": "object",
67
+ "additionalProperties": false,
68
+ "properties": {
69
+ "root": {"type": "string"},
70
+ "pragma": {
71
+ "type": "string"
72
+ },
73
+ "loosePragma": {
74
+ "type": "string"
75
+ },
76
+ "ignorePragma": {
77
+ "type": "string"
78
+ },
79
+ "dumpOperations": {
80
+ "type": "string"
81
+ }
82
+ },
83
+ "required": [ "root" ]
84
+ },
85
+ "generate": {"oneOf": [
86
+ {"$ref": "#/definitions/GenerateConfig"},
87
+ {"type": "array", "items": {"$ref": "#/definitions/GenerateConfig"}}
88
+ ]}
89
+ },
90
+ "required": [ "crawl", "generate" ]
91
+ }