@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.
- package/.flowconfig +1 -0
- package/.github/workflows/changeset-release.yml +3 -17
- package/.github/workflows/pr-checks.yml +13 -10
- package/CHANGELOG.md +35 -0
- package/Readme.md +41 -132
- package/dist/__test__/example-schema.graphql +67 -0
- package/dist/__test__/generateTypeFileContents.test.js +157 -0
- package/dist/__test__/graphql-flow.test.js +639 -0
- package/dist/__test__/processPragmas.test.js +76 -0
- package/dist/cli/__test__/config.test.js +120 -0
- package/dist/cli/config.js +51 -26
- package/dist/cli/config.js.flow +40 -68
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/run.js +41 -19
- package/dist/cli/run.js.flow +58 -22
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/schema.json +91 -0
- package/dist/enums.js +20 -7
- package/dist/enums.js.flow +44 -15
- package/dist/enums.js.map +1 -1
- package/dist/generateResponseType.js +47 -47
- package/dist/generateResponseType.js.flow +55 -57
- package/dist/generateResponseType.js.map +1 -1
- package/dist/generateTypeFiles.js +41 -22
- package/dist/generateTypeFiles.js.flow +86 -78
- package/dist/generateTypeFiles.js.map +1 -1
- package/dist/generateVariablesType.js +24 -24
- package/dist/generateVariablesType.js.flow +25 -28
- package/dist/generateVariablesType.js.map +1 -1
- package/dist/index.js +18 -20
- package/dist/index.js.flow +31 -16
- package/dist/index.js.map +1 -1
- package/dist/parser/__test__/parse.test.js +247 -0
- package/dist/types.js.flow +28 -5
- package/flow-typed/npm/@babel/types_vx.x.x.js +17 -3
- package/package.json +3 -2
- package/src/__test__/generateTypeFileContents.test.js +55 -1
- package/src/__test__/graphql-flow.test.js +7 -7
- package/src/__test__/processPragmas.test.js +28 -15
- package/src/cli/__test__/config.test.js +120 -0
- package/src/cli/config.js +40 -68
- package/src/cli/run.js +58 -22
- package/src/cli/schema.json +91 -0
- package/src/enums.js +44 -15
- package/src/generateResponseType.js +55 -57
- package/src/generateTypeFiles.js +86 -78
- package/src/generateVariablesType.js +25 -28
- package/src/index.js +31 -16
- package/src/types.js +28 -5
- 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/dist/jest-mock-graphql-tag.js +0 -88
- package/dist/jest-mock-graphql-tag.js.flow +0 -96
- package/dist/jest-mock-graphql-tag.js.map +0 -1
- package/src/jest-mock-graphql-tag.js +0 -96
|
@@ -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/dist/cli/config.js
CHANGED
|
@@ -3,45 +3,42 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.loadConfigFile = exports.getSchemas = void 0;
|
|
6
|
+
exports.validateOrThrow = exports.loadConfigFile = exports.getSchemas = exports.findApplicableConfig = void 0;
|
|
7
7
|
|
|
8
8
|
var _schemaFromIntrospectionData = require("../schemaFromIntrospectionData");
|
|
9
9
|
|
|
10
|
+
var _schema = _interopRequireDefault(require("./schema.json"));
|
|
11
|
+
|
|
10
12
|
var _fs = _interopRequireDefault(require("fs"));
|
|
11
13
|
|
|
12
14
|
var _graphql = require("graphql");
|
|
13
15
|
|
|
14
|
-
var
|
|
16
|
+
var _jsonschema = require("jsonschema");
|
|
15
17
|
|
|
16
18
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const toplevelKeys = ['excludes', 'schemaFilePath', 'options', 'dumpOperations'];
|
|
24
|
-
Object.keys(data).forEach(k => {
|
|
25
|
-
if (!toplevelKeys.includes(k)) {
|
|
26
|
-
throw new Error(`Invalid attribute in config file ${configFile}: ${k}. Allowed attributes: ${toplevelKeys.join(', ')}`);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
20
|
+
// eslint-disable-line flowtype-errors/uncovered
|
|
21
|
+
// eslint-disable-line flowtype-errors/uncovered
|
|
22
|
+
const validateOrThrow = (value, jsonSchema) => {
|
|
23
|
+
/* eslint-disable flowtype-errors/uncovered */
|
|
24
|
+
const result = (0, _jsonschema.validate)(value, jsonSchema);
|
|
29
25
|
|
|
30
|
-
if (
|
|
31
|
-
|
|
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
|
-
});
|
|
26
|
+
if (!result.valid) {
|
|
27
|
+
throw new Error(result.errors.map(error => error.toString()).join('\n'));
|
|
37
28
|
}
|
|
29
|
+
/* eslint-enable flowtype-errors/uncovered */
|
|
30
|
+
|
|
31
|
+
};
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
exports.validateOrThrow = validateOrThrow;
|
|
34
|
+
|
|
35
|
+
const loadConfigFile = configFile => {
|
|
36
|
+
// $FlowIgnore // eslint-disable-next-line flowtype-errors/uncovered
|
|
37
|
+
const data = require(configFile); // eslint-disable-next-line flowtype-errors/uncovered
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
validateOrThrow(data, _schema.default);
|
|
41
|
+
return data;
|
|
45
42
|
};
|
|
46
43
|
/**
|
|
47
44
|
* Loads a .json 'introspection query response', or a .graphql schema definition.
|
|
@@ -69,6 +66,34 @@ const getSchemas = schemaFilePath => {
|
|
|
69
66
|
return [schemaForValidation, schemaForTypeGeneration];
|
|
70
67
|
}
|
|
71
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* Find the first item of the `config.generate` array where both:
|
|
71
|
+
* - no item of `exclude` matches
|
|
72
|
+
* - at least one item of `match` matches
|
|
73
|
+
*/
|
|
74
|
+
|
|
72
75
|
|
|
73
76
|
exports.getSchemas = getSchemas;
|
|
77
|
+
|
|
78
|
+
const findApplicableConfig = (path, configs) => {
|
|
79
|
+
if (!Array.isArray(configs)) {
|
|
80
|
+
configs = [configs];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return configs.find(config => {
|
|
84
|
+
var _config$exclude;
|
|
85
|
+
|
|
86
|
+
if ((_config$exclude = config.exclude) !== null && _config$exclude !== void 0 && _config$exclude.some(exclude => new RegExp(exclude).test(path))) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!config.match) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return config.match.some(matcher => new RegExp(matcher).test(path));
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
exports.findApplicableConfig = findApplicableConfig;
|
|
74
99
|
//# sourceMappingURL=config.js.map
|
package/dist/cli/config.js.flow
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
|
|
16
|
+
import type {Config, GenerateConfig} from '../types';
|
|
17
|
+
import {validate} from 'jsonschema'; // eslint-disable-line flowtype-errors/uncovered
|
|
17
18
|
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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):
|
|
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
|
-
|
|
39
|
-
|
|
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/dist/cli/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/config.js"],"names":["
|
|
1
|
+
{"version":3,"sources":["../../src/cli/config.js"],"names":["validateOrThrow","value","jsonSchema","result","valid","Error","errors","map","error","toString","join","loadConfigFile","configFile","data","require","configSchema","getSchemas","schemaFilePath","raw","fs","readFileSync","endsWith","schemaForValidation","queryResponse","descriptions","schemaForTypeGeneration","introspectionData","JSON","parse","findApplicableConfig","path","configs","Array","isArray","find","config","exclude","some","RegExp","test","match","matcher"],"mappings":";;;;;;;AAIA;;AACA;;AAEA;;AACA;;AAQA;;;;AAX0C;AAWL;AAE9B,MAAMA,eAAe,GAAG,CAACC,KAAD,EAAeC,UAAf,KAAqC;AAChE;AACA,QAAMC,MAAM,GAAG,0BAASF,KAAT,EAAgBC,UAAhB,CAAf;;AACA,MAAI,CAACC,MAAM,CAACC,KAAZ,EAAmB;AACf,UAAM,IAAIC,KAAJ,CACFF,MAAM,CAACG,MAAP,CAAcC,GAAd,CAAmBC,KAAD,IAAWA,KAAK,CAACC,QAAN,EAA7B,EAA+CC,IAA/C,CAAoD,IAApD,CADE,CAAN;AAGH;AACD;;AACH,CATM;;;;AAWA,MAAMC,cAAc,GAAIC,UAAD,IAAgC;AAC1D;AACA,QAAMC,IAAY,GAAGC,OAAO,CAACF,UAAD,CAA5B,CAF0D,CAG1D;;;AACAZ,EAAAA,eAAe,CAACa,IAAD,EAAOE,eAAP,CAAf;AACA,SAAOF,IAAP;AACH,CANM;AAQP;AACA;AACA;;;;;AACO,MAAMG,UAAU,GAAIC,cAAD,IAAqD;AAC3E,QAAMC,GAAG,GAAGC,YAAGC,YAAH,CAAgBH,cAAhB,EAAgC,MAAhC,CAAZ;;AACA,MAAIA,cAAc,CAACI,QAAf,CAAwB,UAAxB,CAAJ,EAAyC;AACrC,UAAMC,mBAAmB,GAAG,0BAAYJ,GAAZ,CAA5B;AACA,UAAMK,aAAa,GAAG,0BAClBD,mBADkB,EAElB,oCAAsB;AAACE,MAAAA,YAAY,EAAE;AAAf,KAAtB,CAFkB,CAAtB;AAIA,UAAMC,uBAAuB,GAAG,+DAC5B;AACEF,IAAAA,aAAa,CAACV,IAFY,CAAhC;AAIA,WAAO,CAACS,mBAAD,EAAsBG,uBAAtB,CAAP;AACH,GAXD,MAWO;AACH;AACA,UAAMC,iBAAqC,GAAGC,IAAI,CAACC,KAAL,CAAWV,GAAX,CAA9C;AACA,UAAMI,mBAAmB,GAAG,gCAAkBI,iBAAlB,CAA5B;AACA,UAAMD,uBAAuB,GACzB,8DAA4BC,iBAA5B,CADJ;AAEA,WAAO,CAACJ,mBAAD,EAAsBG,uBAAtB,CAAP;AACH;AACJ,CArBM;AAuBP;AACA;AACA;AACA;AACA;;;;;AACO,MAAMI,oBAAoB,GAAG,CAChCC,IADgC,EAEhCC,OAFgC,KAGd;AAClB,MAAI,CAACC,KAAK,CAACC,OAAN,CAAcF,OAAd,CAAL,EAA6B;AACzBA,IAAAA,OAAO,GAAG,CAACA,OAAD,CAAV;AACH;;AACD,SAAOA,OAAO,CAACG,IAAR,CAAcC,MAAD,IAAY;AAAA;;AAC5B,2BAAIA,MAAM,CAACC,OAAX,4CAAI,gBAAgBC,IAAhB,CAAsBD,OAAD,IAAa,IAAIE,MAAJ,CAAWF,OAAX,EAAoBG,IAApB,CAAyBT,IAAzB,CAAlC,CAAJ,EAAuE;AACnE,aAAO,KAAP;AACH;;AACD,QAAI,CAACK,MAAM,CAACK,KAAZ,EAAmB;AACf,aAAO,IAAP;AACH;;AACD,WAAOL,MAAM,CAACK,KAAP,CAAaH,IAAb,CAAmBI,OAAD,IAAa,IAAIH,MAAJ,CAAWG,OAAX,EAAoBF,IAApB,CAAyBT,IAAzB,CAA/B,CAAP;AACH,GARM,CAAP;AASH,CAhBM","sourcesContent":["// @flow\nimport type {Schema} from '../types';\nimport type {GraphQLSchema} from 'graphql/type/schema';\n\nimport {schemaFromIntrospectionData} from '../schemaFromIntrospectionData';\nimport configSchema from './schema.json'; // eslint-disable-line flowtype-errors/uncovered\n\nimport fs from 'fs';\nimport {\n buildClientSchema,\n buildSchema,\n getIntrospectionQuery,\n graphqlSync,\n type IntrospectionQuery,\n} from 'graphql';\nimport type {Config, GenerateConfig} from '../types';\nimport {validate} from 'jsonschema'; // eslint-disable-line flowtype-errors/uncovered\n\nexport const validateOrThrow = (value: mixed, jsonSchema: mixed) => {\n /* eslint-disable flowtype-errors/uncovered */\n const result = validate(value, jsonSchema);\n if (!result.valid) {\n throw new Error(\n result.errors.map((error) => error.toString()).join('\\n'),\n );\n }\n /* eslint-enable flowtype-errors/uncovered */\n};\n\nexport const loadConfigFile = (configFile: string): Config => {\n // $FlowIgnore // eslint-disable-next-line flowtype-errors/uncovered\n const data: Config = require(configFile);\n // eslint-disable-next-line flowtype-errors/uncovered\n validateOrThrow(data, configSchema);\n return data;\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\n/**\n * Find the first item of the `config.generate` array where both:\n * - no item of `exclude` matches\n * - at least one item of `match` matches\n */\nexport const findApplicableConfig = (\n path: string,\n configs: Array<GenerateConfig> | GenerateConfig,\n): ?GenerateConfig => {\n if (!Array.isArray(configs)) {\n configs = [configs];\n }\n return configs.find((config) => {\n if (config.exclude?.some((exclude) => new RegExp(exclude).test(path))) {\n return false;\n }\n if (!config.match) {\n return true;\n }\n return config.match.some((matcher) => new RegExp(matcher).test(path));\n });\n};\n"],"file":"config.js"}
|
package/dist/cli/run.js
CHANGED
|
@@ -31,7 +31,7 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* This CLI tool executes the following steps:
|
|
34
|
-
* 1)
|
|
34
|
+
* 1) parse & validate config file
|
|
35
35
|
* 2) crawl files to find all operations and fragments, with
|
|
36
36
|
* tagged template literals and expressions.
|
|
37
37
|
* 3) resolve the found operations, passing the literals and
|
|
@@ -49,18 +49,22 @@ const findGraphqlTagReferences = root => {
|
|
|
49
49
|
return response.trim().split('\n').map(relative => _path.default.join(root, relative));
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
const [_, __,
|
|
52
|
+
const [_, __, configFilePath, ...cliFiles] = process.argv;
|
|
53
53
|
|
|
54
|
-
if (
|
|
54
|
+
if (configFilePath === '-h' || configFilePath === '--help' || configFilePath === 'help' || !configFilePath) {
|
|
55
55
|
console.log(`graphql-flow
|
|
56
56
|
|
|
57
57
|
Usage: graphql-flow [configFile.json] [filesToCrawl...]`);
|
|
58
58
|
process.exit(1); // eslint-disable-line flowtype-errors/uncovered
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
const makeAbsPath = (maybeRelativePath, basePath) => {
|
|
62
|
+
return _path.default.isAbsolute(maybeRelativePath) ? maybeRelativePath : _path.default.join(basePath, maybeRelativePath);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const absConfigPath = makeAbsPath(configFilePath, process.cwd());
|
|
66
|
+
const config = (0, _config.loadConfigFile)(absConfigPath);
|
|
67
|
+
const inputFiles = cliFiles.length ? cliFiles : findGraphqlTagReferences(makeAbsPath(config.crawl.root, _path.default.dirname(absConfigPath)));
|
|
64
68
|
/** Step (2) */
|
|
65
69
|
|
|
66
70
|
const files = (0, _parse.processFiles)(inputFiles, f => {
|
|
@@ -110,22 +114,34 @@ if (errors.length) {
|
|
|
110
114
|
console.log(Object.keys(resolved).length, 'resolved queries');
|
|
111
115
|
/** Step (4) */
|
|
112
116
|
|
|
117
|
+
const schemaCache = {};
|
|
118
|
+
|
|
119
|
+
const getCachedSchemas = schemaFilePath => {
|
|
120
|
+
if (!schemaCache[schemaFilePath]) {
|
|
121
|
+
schemaCache[schemaFilePath] = (0, _config.getSchemas)(makeAbsPath(schemaFilePath, _path.default.dirname(absConfigPath)));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return schemaCache[schemaFilePath];
|
|
125
|
+
};
|
|
126
|
+
|
|
113
127
|
let validationFailures = 0;
|
|
114
128
|
const printedOperations = [];
|
|
115
|
-
Object.keys(resolved).forEach(
|
|
129
|
+
Object.keys(resolved).forEach(filePathAndLine => {
|
|
116
130
|
const {
|
|
117
131
|
document,
|
|
118
132
|
raw
|
|
119
|
-
} = resolved[
|
|
120
|
-
|
|
121
|
-
if (config.excludes.some(rx => rx.test(raw.loc.path))) {
|
|
122
|
-
return; // skip
|
|
123
|
-
}
|
|
124
|
-
|
|
133
|
+
} = resolved[filePathAndLine];
|
|
125
134
|
const hasNonFragments = document.definitions.some(({
|
|
126
135
|
kind
|
|
127
136
|
}) => kind !== 'FragmentDefinition');
|
|
128
|
-
const rawSource = raw.literals[0];
|
|
137
|
+
const rawSource = raw.literals[0];
|
|
138
|
+
const generateConfig = (0, _config.findApplicableConfig)( // strip off the trailing line number, e.g. `:23`
|
|
139
|
+
filePathAndLine.split(':')[0], config.generate);
|
|
140
|
+
|
|
141
|
+
if (!generateConfig) {
|
|
142
|
+
return; // no generate config matches, bail
|
|
143
|
+
} // eslint-disable-next-line flowtype-errors/uncovered
|
|
144
|
+
|
|
129
145
|
|
|
130
146
|
const withTypeNames = (0, _apolloUtilities.addTypenameToDocument)(document);
|
|
131
147
|
const printed = (0, _printer.print)(withTypeNames);
|
|
@@ -134,12 +150,18 @@ Object.keys(resolved).forEach(k => {
|
|
|
134
150
|
printedOperations.push(printed);
|
|
135
151
|
}
|
|
136
152
|
|
|
137
|
-
const
|
|
153
|
+
const pragmaResult = (0, _generateTypeFiles.processPragmas)(generateConfig, config.crawl, rawSource);
|
|
138
154
|
|
|
139
|
-
if (!
|
|
155
|
+
if (!pragmaResult.generate) {
|
|
140
156
|
return;
|
|
141
157
|
}
|
|
142
158
|
|
|
159
|
+
if (pragmaResult.strict != null) {
|
|
160
|
+
generateConfig.strictNullability = pragmaResult.strict;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const [schemaForValidation, schemaForTypeGeneration] = getCachedSchemas(generateConfig.schemaFilePath);
|
|
164
|
+
|
|
143
165
|
if (hasNonFragments) {
|
|
144
166
|
/* eslint-disable flowtype-errors/uncovered */
|
|
145
167
|
const errors = (0, _validation.validate)(schemaForValidation, withTypeNames);
|
|
@@ -158,7 +180,7 @@ Object.keys(resolved).forEach(k => {
|
|
|
158
180
|
}
|
|
159
181
|
|
|
160
182
|
try {
|
|
161
|
-
(0, _generateTypeFiles.generateTypeFiles)(raw.loc.path, schemaForTypeGeneration, withTypeNames,
|
|
183
|
+
(0, _generateTypeFiles.generateTypeFiles)(raw.loc.path, schemaForTypeGeneration, withTypeNames, generateConfig); // eslint-disable-next-line flowtype-errors/uncovered
|
|
162
184
|
} catch (err) {
|
|
163
185
|
console.error(`Error while generating operation from ${raw.loc.path}`);
|
|
164
186
|
console.error(printed); // eslint-disable-next-line flowtype-errors/uncovered
|
|
@@ -174,8 +196,8 @@ if (validationFailures) {
|
|
|
174
196
|
process.exit(1);
|
|
175
197
|
}
|
|
176
198
|
|
|
177
|
-
if (config.dumpOperations) {
|
|
178
|
-
const dumpOperations = config.dumpOperations;
|
|
199
|
+
if (config.crawl.dumpOperations) {
|
|
200
|
+
const dumpOperations = config.crawl.dumpOperations;
|
|
179
201
|
const parent = (0, _path.dirname)(dumpOperations);
|
|
180
202
|
(0, _fs.mkdirSync)(parent, {
|
|
181
203
|
recursive: true
|
package/dist/cli/run.js.flow
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)
|
|
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 [_, __,
|
|
47
|
+
const [_, __, configFilePath, ...cliFiles] = process.argv;
|
|
47
48
|
|
|
48
49
|
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
!
|
|
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
|
|
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
|
|
63
|
-
config.schemaFilePath,
|
|
64
|
-
);
|
|
69
|
+
const config = loadConfigFile(absConfigPath);
|
|
65
70
|
|
|
66
71
|
const inputFiles = cliFiles.length
|
|
67
72
|
? cliFiles
|
|
68
|
-
: findGraphqlTagReferences(
|
|
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((
|
|
118
|
-
const {document, raw} = resolved[
|
|
119
|
-
|
|
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
|
|
135
|
-
|
|
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
|
-
|
|
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(
|