@khanacademy/graphql-flow 0.0.2 → 0.2.1
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/CHANGELOG.md +29 -0
- package/Readme.md +64 -65
- package/dist/cli/config.js +73 -0
- package/dist/cli/config.js.flow +104 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/run.js +159 -0
- package/dist/cli/run.js.flow +165 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/enums.js +2 -1
- package/dist/enums.js.map +1 -0
- package/dist/generateResponseType.js +170 -60
- package/dist/generateResponseType.js.flow +248 -82
- package/dist/generateResponseType.js.map +1 -0
- package/dist/generateTypeFiles.js +141 -0
- package/dist/generateTypeFiles.js.flow +167 -0
- package/dist/generateTypeFiles.js.map +1 -0
- package/dist/generateVariablesType.js +2 -1
- package/dist/generateVariablesType.js.map +1 -0
- package/dist/index.js +45 -4
- package/dist/index.js.flow +54 -4
- package/dist/index.js.map +1 -0
- package/dist/jest-mock-graphql-tag.js +22 -107
- package/dist/jest-mock-graphql-tag.js.flow +30 -138
- package/dist/jest-mock-graphql-tag.js.map +1 -0
- package/dist/parser/parse.js +349 -0
- package/dist/parser/parse.js.flow +403 -0
- package/dist/parser/parse.js.map +1 -0
- package/dist/parser/resolve.js +111 -0
- package/dist/parser/resolve.js.flow +117 -0
- package/dist/parser/resolve.js.map +1 -0
- package/dist/schemaFromIntrospectionData.js +2 -1
- package/dist/schemaFromIntrospectionData.js.map +1 -0
- package/dist/types.js +2 -1
- package/dist/types.js.flow +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.js +2 -1
- package/dist/utils.js.map +1 -0
- package/package.json +9 -5
- package/src/__test__/example-schema.graphql +1 -1
- package/src/__test__/generateTypeFileContents.test.js +61 -0
- package/src/__test__/graphql-flow.test.js +309 -54
- package/src/__test__/{jest-mock-graphql-tag.test.js → processPragmas.test.js} +13 -1
- package/src/cli/config.js +104 -0
- package/src/cli/run.js +165 -0
- package/src/generateResponseType.js +248 -82
- package/src/generateTypeFiles.js +167 -0
- package/src/index.js +54 -4
- package/src/jest-mock-graphql-tag.js +30 -138
- package/src/parser/__test__/parse.test.js +247 -0
- package/src/parser/parse.js +403 -0
- package/src/parser/resolve.js +117 -0
- package/src/types.js +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @khanacademy/graphql-flow
|
|
2
2
|
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e8a8025: Add shebang to the exported binary, so that it runs
|
|
8
|
+
|
|
9
|
+
## 0.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- d9a8229: Generate types for fragments!
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 7497164: Fix a bug in index file generation that resulted in duplicate entries
|
|
18
|
+
- 26abf9b: Add options for specifying the name of the generated directory, and for exporting the response and variables types.
|
|
19
|
+
|
|
20
|
+
## 0.1.0
|
|
21
|
+
|
|
22
|
+
### Minor Changes
|
|
23
|
+
|
|
24
|
+
- b08ed1b: Build out a cli tool that does our own parsing of javascript files, dramatically speeding things up!
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- 8cdcdc2: Support inline fragments on objects
|
|
29
|
+
- fd5c6b7: Allow schema to be provided as a .graphql file, not just .json
|
|
30
|
+
- 6869203: Add 'ignorePragma' option, to allow skipping of documents
|
|
31
|
+
|
|
3
32
|
## 0.0.2
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
package/Readme.md
CHANGED
|
@@ -2,64 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
This is a tool for generating flow types from graphql queries in javascript frontends.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Using as a CLI tool
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Write a config file, with the following options:
|
|
8
8
|
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
homePlanet
|
|
22
|
-
friends {
|
|
23
|
-
name
|
|
24
|
-
}
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
// Response to the "introspection query" (see below), or a .graphql schema file.
|
|
12
|
+
// The file extension indicates the format, .json or .graphql (default .json).
|
|
13
|
+
// This path is resolved relative to the config file location.
|
|
14
|
+
"schemaFilePath": "../some/schema-file.json",
|
|
15
|
+
// List of regexes
|
|
16
|
+
"excludes": ["\\bsome-thing", "_test.jsx?$"],
|
|
17
|
+
// Options for type generation (see below)
|
|
18
|
+
"options": {
|
|
19
|
+
"scalars": {
|
|
20
|
+
"JSONString": "string"
|
|
25
21
|
}
|
|
26
22
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
name: ?string,
|
|
35
|
-
homePlanet: ?string,
|
|
36
|
-
friends: ?$ReadOnlyArray<?{|
|
|
37
|
-
name: ?string
|
|
38
|
-
|}>,
|
|
39
|
-
|}
|
|
40
|
-
|};
|
|
41
|
-
*/
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Then run from the CLI, like so:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
$ graphql-flow path/to/config.json
|
|
42
30
|
```
|
|
43
31
|
|
|
44
|
-
|
|
32
|
+
Files will be discovered relative to the current working directory.
|
|
45
33
|
|
|
46
|
-
|
|
34
|
+
To specify what file should be checked, pass them in as subsequent cli arguments.
|
|
47
35
|
|
|
48
|
-
## Options for
|
|
36
|
+
## Options (for the cli 'options' config item, or when running from jest):
|
|
49
37
|
|
|
50
|
-
```
|
|
51
|
-
{
|
|
52
|
-
//
|
|
53
|
-
// will probably remove once the mobile repo no longer needs it.
|
|
38
|
+
```ts
|
|
39
|
+
type Options = {
|
|
40
|
+
// These are from the `documentToFlowTypes` options object above
|
|
54
41
|
strictNullability: boolean = true,
|
|
55
|
-
// Output `$ReadOnlyArray<>` instead of `Array<>`, for stricter flow typing. On by default.
|
|
56
42
|
readOnlyArray: boolean = true,
|
|
57
|
-
// A mapping of custom scalar names to the underlying json representation.
|
|
58
43
|
scalars: {[key: string]: 'string' | 'boolean' | 'number'}
|
|
44
|
+
|
|
45
|
+
// Specify the name of the generated types directory
|
|
46
|
+
generatedDirectory: string = '__generated__',
|
|
47
|
+
|
|
48
|
+
// The default generated type contains both the types of the response
|
|
49
|
+
// and the variables, combined as [operatioName]Type. Setting
|
|
50
|
+
// `splitTypes = true` adds the additional exports [operationName]
|
|
51
|
+
// (for the response) and [operationName]Variables (for the variables).
|
|
52
|
+
splitTypes?: boolean,
|
|
53
|
+
|
|
54
|
+
// Specify an opt-in pragma that must be present in a graphql string source
|
|
55
|
+
// in order for it to be picked up and processed
|
|
56
|
+
// e.g. set this to `"# @autogen\n"` to only generate types for queries that
|
|
57
|
+
// have the comment `# @autogen` in them.
|
|
58
|
+
pragma?: string,
|
|
59
|
+
// Specify a pragma that will turn off `strictNullability` for that
|
|
60
|
+
// source file. e.g. `"# @autogen-loose\n"`.
|
|
61
|
+
loosePragma?: string,
|
|
62
|
+
// If neither pragma nor loosePragma are specified, all graphql documents
|
|
63
|
+
// that contain a query or mutation will be processed.
|
|
64
|
+
|
|
65
|
+
// Any graphql operations containing ignorePragma will be skipped
|
|
66
|
+
ignorePragma?: string,
|
|
67
|
+
|
|
68
|
+
// Set to true to mirror gqlgen's behavior of exporting all
|
|
69
|
+
// nested object types within the response type.
|
|
70
|
+
// Names are generated by concatenating the attribute names
|
|
71
|
+
// of the path to the object type, separated by underscores.
|
|
72
|
+
exportAllObjectTypes?: boolean,
|
|
59
73
|
}
|
|
60
74
|
```
|
|
61
75
|
|
|
62
|
-
## Using jest
|
|
76
|
+
## Using from jest
|
|
77
|
+
|
|
78
|
+
You can also use jest to do the heavy lifting, running all of your code and collecting queries
|
|
79
|
+
by mocking out the `graphql-tag` function itself. This requires that all graphql operations are
|
|
80
|
+
defined at the top level (no queries defined in functions or components, for example), but does
|
|
81
|
+
support complicated things like returning a fragment from a function (which is probably
|
|
82
|
+
not a great idea code-style-wise anyway).
|
|
63
83
|
|
|
64
84
|
### jest-setup.js
|
|
65
85
|
|
|
@@ -74,6 +94,7 @@ if (process.env.GRAPHQL_FLOW) {
|
|
|
74
94
|
|
|
75
95
|
return jest.requireActual('../tools/graphql-flow/jest-mock-graphql-tag.js')(
|
|
76
96
|
introspectionData,
|
|
97
|
+
// See "Options" type above
|
|
77
98
|
{
|
|
78
99
|
pragma: '# @autogen\n',
|
|
79
100
|
loosePragma: '# @autogen-loose\n',
|
|
@@ -126,28 +147,6 @@ And then `yarn generate-types` or `npm run generate-types` gets your types gener
|
|
|
126
147
|
|
|
127
148
|
🚀
|
|
128
149
|
|
|
129
|
-
### Options for the `jest-mock-graphql-tag.js` helper:
|
|
130
|
-
|
|
131
|
-
```js
|
|
132
|
-
{
|
|
133
|
-
// These are from the `documentToFlowTypes` options object above
|
|
134
|
-
strictNullability: boolean = true,
|
|
135
|
-
readOnlyArray: boolean = true,
|
|
136
|
-
scalars: {[key: string]: 'string' | 'boolean' | 'number'}
|
|
137
|
-
|
|
138
|
-
// Specify an opt-in pragma that must be present in a graphql string source
|
|
139
|
-
// in order for it to be picked up and processed
|
|
140
|
-
// e.g. set this to `"# @autogen\n"` to only generate types for queries that
|
|
141
|
-
// have the comment `# @autogen` in them.
|
|
142
|
-
pragma?: string,
|
|
143
|
-
// Specify a pragma that will turn off `strictNullability` for that
|
|
144
|
-
// source file. e.g. `"# @autogen-loose\n"`.
|
|
145
|
-
loosePragma?: string,
|
|
146
|
-
// If neither pragma nor loosePragma are specified, all graphql documents
|
|
147
|
-
// that contain a query or mutation will be processed.
|
|
148
|
-
}
|
|
149
|
-
```
|
|
150
|
-
|
|
151
150
|
## Introspecting your backend's graphql schema
|
|
152
151
|
Here's how to get your backend's schema in the way that this tool expects, using the builtin 'graphql introspection query':
|
|
153
152
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.loadConfigFile = exports.getSchemas = void 0;
|
|
7
|
+
|
|
8
|
+
var _schemaFromIntrospectionData = require("../schemaFromIntrospectionData");
|
|
9
|
+
|
|
10
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
11
|
+
|
|
12
|
+
var _graphql = require("graphql");
|
|
13
|
+
|
|
14
|
+
var _path = _interopRequireDefault(require("path"));
|
|
15
|
+
|
|
16
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
17
|
+
|
|
18
|
+
const loadConfigFile = configFile => {
|
|
19
|
+
var _data$excludes;
|
|
20
|
+
|
|
21
|
+
// eslint-disable-next-line flowtype-errors/uncovered
|
|
22
|
+
const data = JSON.parse(_fs.default.readFileSync(configFile, 'utf8'));
|
|
23
|
+
const toplevelKeys = ['excludes', 'schemaFilePath', 'options'];
|
|
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
|
+
});
|
|
29
|
+
|
|
30
|
+
if (data.options) {
|
|
31
|
+
const externalOptionsKeys = ['pragma', 'loosePragma', 'ignorePragma', 'scalars', 'strictNullability', 'regenerateCommand', 'readOnlyArray', 'splitTypes', 'generatedDirectory', 'exportAllObjectTypes'];
|
|
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
|
+
|
|
39
|
+
return {
|
|
40
|
+
options: data.options ?? {},
|
|
41
|
+
excludes: ((_data$excludes = data.excludes) === null || _data$excludes === void 0 ? void 0 : _data$excludes.map(string => new RegExp(string))) ?? [],
|
|
42
|
+
schemaFilePath: _path.default.join(_path.default.dirname(configFile), data.schemaFilePath)
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Loads a .json 'introspection query response', or a .graphql schema definition.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
exports.loadConfigFile = loadConfigFile;
|
|
51
|
+
|
|
52
|
+
const getSchemas = schemaFilePath => {
|
|
53
|
+
const raw = _fs.default.readFileSync(schemaFilePath, 'utf8');
|
|
54
|
+
|
|
55
|
+
if (schemaFilePath.endsWith('.graphql')) {
|
|
56
|
+
const schemaForValidation = (0, _graphql.buildSchema)(raw);
|
|
57
|
+
const queryResponse = (0, _graphql.graphqlSync)(schemaForValidation, (0, _graphql.getIntrospectionQuery)({
|
|
58
|
+
descriptions: true
|
|
59
|
+
}));
|
|
60
|
+
const schemaForTypeGeneration = (0, _schemaFromIntrospectionData.schemaFromIntrospectionData)( // eslint-disable-next-line flowtype-errors/uncovered
|
|
61
|
+
queryResponse.data);
|
|
62
|
+
return [schemaForValidation, schemaForTypeGeneration];
|
|
63
|
+
} else {
|
|
64
|
+
// eslint-disable-next-line flowtype-errors/uncovered
|
|
65
|
+
const introspectionData = JSON.parse(raw);
|
|
66
|
+
const schemaForValidation = (0, _graphql.buildClientSchema)(introspectionData);
|
|
67
|
+
const schemaForTypeGeneration = (0, _schemaFromIntrospectionData.schemaFromIntrospectionData)(introspectionData);
|
|
68
|
+
return [schemaForValidation, schemaForTypeGeneration];
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
exports.getSchemas = getSchemas;
|
|
73
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type {ExternalOptions} from '../generateTypeFiles';
|
|
3
|
+
import type {Schema} from '../types';
|
|
4
|
+
import type {GraphQLSchema} from 'graphql/type/schema';
|
|
5
|
+
|
|
6
|
+
import {schemaFromIntrospectionData} from '../schemaFromIntrospectionData';
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import {
|
|
10
|
+
buildClientSchema,
|
|
11
|
+
buildSchema,
|
|
12
|
+
getIntrospectionQuery,
|
|
13
|
+
graphqlSync,
|
|
14
|
+
type IntrospectionQuery,
|
|
15
|
+
} from 'graphql';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
|
|
18
|
+
export type CliConfig = {
|
|
19
|
+
excludes: Array<RegExp>,
|
|
20
|
+
schemaFilePath: string,
|
|
21
|
+
options: ExternalOptions,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* This is the json-compatible form of the config
|
|
26
|
+
* object.
|
|
27
|
+
*/
|
|
28
|
+
type JSONConfig = {
|
|
29
|
+
excludes?: Array<string>,
|
|
30
|
+
schemaFilePath: string,
|
|
31
|
+
options?: ExternalOptions,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const loadConfigFile = (configFile: string): CliConfig => {
|
|
35
|
+
// eslint-disable-next-line flowtype-errors/uncovered
|
|
36
|
+
const data: JSONConfig = JSON.parse(fs.readFileSync(configFile, 'utf8'));
|
|
37
|
+
const toplevelKeys = ['excludes', 'schemaFilePath', 'options'];
|
|
38
|
+
Object.keys(data).forEach((k) => {
|
|
39
|
+
if (!toplevelKeys.includes(k)) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Invalid attribute in config file ${configFile}: ${k}. Allowed attributes: ${toplevelKeys.join(
|
|
42
|
+
', ',
|
|
43
|
+
)}`,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
if (data.options) {
|
|
48
|
+
const externalOptionsKeys = [
|
|
49
|
+
'pragma',
|
|
50
|
+
'loosePragma',
|
|
51
|
+
'ignorePragma',
|
|
52
|
+
'scalars',
|
|
53
|
+
'strictNullability',
|
|
54
|
+
'regenerateCommand',
|
|
55
|
+
'readOnlyArray',
|
|
56
|
+
'splitTypes',
|
|
57
|
+
'generatedDirectory',
|
|
58
|
+
'exportAllObjectTypes',
|
|
59
|
+
];
|
|
60
|
+
Object.keys(data.options).forEach((k) => {
|
|
61
|
+
if (!externalOptionsKeys.includes(k)) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Invalid option in config file ${configFile}: ${k}. Allowed options: ${externalOptionsKeys.join(
|
|
64
|
+
', ',
|
|
65
|
+
)}`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
options: data.options ?? {},
|
|
72
|
+
excludes: data.excludes?.map((string) => new RegExp(string)) ?? [],
|
|
73
|
+
schemaFilePath: path.join(
|
|
74
|
+
path.dirname(configFile),
|
|
75
|
+
data.schemaFilePath,
|
|
76
|
+
),
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Loads a .json 'introspection query response', or a .graphql schema definition.
|
|
82
|
+
*/
|
|
83
|
+
export const getSchemas = (schemaFilePath: string): [GraphQLSchema, Schema] => {
|
|
84
|
+
const raw = fs.readFileSync(schemaFilePath, 'utf8');
|
|
85
|
+
if (schemaFilePath.endsWith('.graphql')) {
|
|
86
|
+
const schemaForValidation = buildSchema(raw);
|
|
87
|
+
const queryResponse = graphqlSync(
|
|
88
|
+
schemaForValidation,
|
|
89
|
+
getIntrospectionQuery({descriptions: true}),
|
|
90
|
+
);
|
|
91
|
+
const schemaForTypeGeneration = schemaFromIntrospectionData(
|
|
92
|
+
// eslint-disable-next-line flowtype-errors/uncovered
|
|
93
|
+
((queryResponse.data: any): IntrospectionQuery),
|
|
94
|
+
);
|
|
95
|
+
return [schemaForValidation, schemaForTypeGeneration];
|
|
96
|
+
} else {
|
|
97
|
+
// eslint-disable-next-line flowtype-errors/uncovered
|
|
98
|
+
const introspectionData: IntrospectionQuery = JSON.parse(raw);
|
|
99
|
+
const schemaForValidation = buildClientSchema(introspectionData);
|
|
100
|
+
const schemaForTypeGeneration =
|
|
101
|
+
schemaFromIntrospectionData(introspectionData);
|
|
102
|
+
return [schemaForValidation, schemaForTypeGeneration];
|
|
103
|
+
}
|
|
104
|
+
};
|
|
@@ -0,0 +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","dirname","getSchemas","raw","endsWith","schemaForValidation","queryResponse","descriptions","schemaForTypeGeneration","introspectionData"],"mappings":";;;;;;;AAKA;;AAEA;;AACA;;AAOA;;;;AAkBO,MAAMA,cAAc,GAAIC,UAAD,IAAmC;AAAA;;AAC7D;AACA,QAAMC,IAAgB,GAAGC,IAAI,CAACC,KAAL,CAAWC,YAAGC,YAAH,CAAgBL,UAAhB,EAA4B,MAA5B,CAAX,CAAzB;AACA,QAAMM,YAAY,GAAG,CAAC,UAAD,EAAa,gBAAb,EAA+B,SAA/B,CAArB;AACAC,EAAAA,MAAM,CAACC,IAAP,CAAYP,IAAZ,EAAkBQ,OAAlB,CAA2BC,CAAD,IAAO;AAC7B,QAAI,CAACJ,YAAY,CAACK,QAAb,CAAsBD,CAAtB,CAAL,EAA+B;AAC3B,YAAM,IAAIE,KAAJ,CACD,oCAAmCZ,UAAW,KAAIU,CAAE,yBAAwBJ,YAAY,CAACO,IAAb,CACzE,IADyE,CAE3E,EAHA,CAAN;AAKH;AACJ,GARD;;AASA,MAAIZ,IAAI,CAACa,OAAT,EAAkB;AACd,UAAMC,mBAAmB,GAAG,CACxB,QADwB,EAExB,aAFwB,EAGxB,cAHwB,EAIxB,SAJwB,EAKxB,mBALwB,EAMxB,mBANwB,EAOxB,eAPwB,EAQxB,YARwB,EASxB,oBATwB,EAUxB,sBAVwB,CAA5B;AAYAR,IAAAA,MAAM,CAACC,IAAP,CAAYP,IAAI,CAACa,OAAjB,EAA0BL,OAA1B,CAAmCC,CAAD,IAAO;AACrC,UAAI,CAACK,mBAAmB,CAACJ,QAApB,CAA6BD,CAA7B,CAAL,EAAsC;AAClC,cAAM,IAAIE,KAAJ,CACD,iCAAgCZ,UAAW,KAAIU,CAAE,sBAAqBK,mBAAmB,CAACF,IAApB,CACnE,IADmE,CAErE,EAHA,CAAN;AAKH;AACJ,KARD;AASH;;AACD,SAAO;AACHC,IAAAA,OAAO,EAAEb,IAAI,CAACa,OAAL,IAAgB,EADtB;AAEHE,IAAAA,QAAQ,EAAE,mBAAAf,IAAI,CAACe,QAAL,kEAAeC,GAAf,CAAoBC,MAAD,IAAY,IAAIC,MAAJ,CAAWD,MAAX,CAA/B,MAAsD,EAF7D;AAGHE,IAAAA,cAAc,EAAEC,cAAKR,IAAL,CACZQ,cAAKC,OAAL,CAAatB,UAAb,CADY,EAEZC,IAAI,CAACmB,cAFO;AAHb,GAAP;AAQH,CA5CM;AA8CP;AACA;AACA;;;;;AACO,MAAMG,UAAU,GAAIH,cAAD,IAAqD;AAC3E,QAAMI,GAAG,GAAGpB,YAAGC,YAAH,CAAgBe,cAAhB,EAAgC,MAAhC,CAAZ;;AACA,MAAIA,cAAc,CAACK,QAAf,CAAwB,UAAxB,CAAJ,EAAyC;AACrC,UAAMC,mBAAmB,GAAG,0BAAYF,GAAZ,CAA5B;AACA,UAAMG,aAAa,GAAG,0BAClBD,mBADkB,EAElB,oCAAsB;AAACE,MAAAA,YAAY,EAAE;AAAf,KAAtB,CAFkB,CAAtB;AAIA,UAAMC,uBAAuB,GAAG,+DAC5B;AACEF,IAAAA,aAAa,CAAC1B,IAFY,CAAhC;AAIA,WAAO,CAACyB,mBAAD,EAAsBG,uBAAtB,CAAP;AACH,GAXD,MAWO;AACH;AACA,UAAMC,iBAAqC,GAAG5B,IAAI,CAACC,KAAL,CAAWqB,GAAX,CAA9C;AACA,UAAME,mBAAmB,GAAG,gCAAkBI,iBAAlB,CAA5B;AACA,UAAMD,uBAAuB,GACzB,8DAA4BC,iBAA5B,CADJ;AAEA,WAAO,CAACJ,mBAAD,EAAsBG,uBAAtB,CAAP;AACH;AACJ,CArBM","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 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};\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 = ['excludes', 'schemaFilePath', 'options'];\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 ];\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.join(\n path.dirname(configFile),\n data.schemaFilePath,\n ),\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"}
|
package/dist/cli/run.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/* eslint-disable no-console */
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
var _generateTypeFiles = require("../generateTypeFiles");
|
|
7
|
+
|
|
8
|
+
var _parse = require("../parser/parse");
|
|
9
|
+
|
|
10
|
+
var _resolve = require("../parser/resolve");
|
|
11
|
+
|
|
12
|
+
var _config = require("./config");
|
|
13
|
+
|
|
14
|
+
var _apolloUtilities = require("apollo-utilities");
|
|
15
|
+
|
|
16
|
+
var _child_process = require("child_process");
|
|
17
|
+
|
|
18
|
+
var _fs = require("fs");
|
|
19
|
+
|
|
20
|
+
var _printer = require("graphql/language/printer");
|
|
21
|
+
|
|
22
|
+
var _validation = require("graphql/validation");
|
|
23
|
+
|
|
24
|
+
var _path = _interopRequireDefault(require("path"));
|
|
25
|
+
|
|
26
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
27
|
+
|
|
28
|
+
// eslint-disable-line flowtype-errors/uncovered
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* This CLI tool executes the following steps:
|
|
32
|
+
* 1) process options
|
|
33
|
+
* 2) crawl files to find all operations and fragments, with
|
|
34
|
+
* tagged template literals and expressions.
|
|
35
|
+
* 3) resolve the found operations, passing the literals and
|
|
36
|
+
* fragments into the `graphql-tag` function to produce
|
|
37
|
+
* the DocumentNodes.
|
|
38
|
+
* 4) generate types for all resolved Queries & Mutations
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/** Step (1) */
|
|
42
|
+
const findGraphqlTagReferences = root => {
|
|
43
|
+
const response = (0, _child_process.execSync)("git grep -I --word-regexp --name-only --fixed-strings 'graphql-tag' -- '*.js' '*.jsx'", {
|
|
44
|
+
encoding: 'utf8',
|
|
45
|
+
cwd: root
|
|
46
|
+
});
|
|
47
|
+
return response.trim().split('\n').map(relative => _path.default.join(root, relative));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const [_, __, configFile, ...cliFiles] = process.argv;
|
|
51
|
+
|
|
52
|
+
if (configFile === '-h' || configFile === '--help' || configFile === 'help' || !configFile) {
|
|
53
|
+
console.log(`graphql-flow
|
|
54
|
+
|
|
55
|
+
Usage: graphql-flow [configFile.json] [filesToCrawl...]`);
|
|
56
|
+
process.exit(1); // eslint-disable-line flowtype-errors/uncovered
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const config = (0, _config.loadConfigFile)(configFile);
|
|
60
|
+
const [schemaForValidation, schemaForTypeGeneration] = (0, _config.getSchemas)(config.schemaFilePath);
|
|
61
|
+
const inputFiles = cliFiles.length ? cliFiles : findGraphqlTagReferences(process.cwd());
|
|
62
|
+
/** Step (2) */
|
|
63
|
+
|
|
64
|
+
const files = (0, _parse.processFiles)(inputFiles, f => (0, _fs.readFileSync)(f, 'utf8'));
|
|
65
|
+
let filesHadErrors = false;
|
|
66
|
+
Object.keys(files).forEach(key => {
|
|
67
|
+
const file = files[key];
|
|
68
|
+
|
|
69
|
+
if (file.errors.length) {
|
|
70
|
+
filesHadErrors = true;
|
|
71
|
+
console.error(`Errors in ${file.path}`);
|
|
72
|
+
file.errors.forEach(error => {
|
|
73
|
+
console.error(` - ${error.message}`);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (filesHadErrors) {
|
|
79
|
+
console.error('Aborting');
|
|
80
|
+
process.exit(1); // eslint-disable-line flowtype-errors/uncovered
|
|
81
|
+
}
|
|
82
|
+
/** Step (3) */
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
const {
|
|
86
|
+
resolved,
|
|
87
|
+
errors
|
|
88
|
+
} = (0, _resolve.resolveDocuments)(files);
|
|
89
|
+
|
|
90
|
+
if (errors.length) {
|
|
91
|
+
errors.forEach(error => {
|
|
92
|
+
console.error(`Resolution error ${error.message} in ${error.loc.path}`);
|
|
93
|
+
});
|
|
94
|
+
console.error('Aborting');
|
|
95
|
+
process.exit(1); // eslint-disable-line flowtype-errors/uncovered
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(Object.keys(resolved).length, 'resolved queries');
|
|
99
|
+
/** Step (4) */
|
|
100
|
+
|
|
101
|
+
let validationFailures = 0;
|
|
102
|
+
Object.keys(resolved).forEach(k => {
|
|
103
|
+
const {
|
|
104
|
+
document,
|
|
105
|
+
raw
|
|
106
|
+
} = resolved[k];
|
|
107
|
+
|
|
108
|
+
if (config.excludes.some(rx => rx.test(raw.loc.path))) {
|
|
109
|
+
return; // skip
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const hasNonFragments = document.definitions.some(({
|
|
113
|
+
kind
|
|
114
|
+
}) => kind !== 'FragmentDefinition');
|
|
115
|
+
const rawSource = raw.literals[0];
|
|
116
|
+
const processedOptions = (0, _generateTypeFiles.processPragmas)(config.options, rawSource);
|
|
117
|
+
|
|
118
|
+
if (!processedOptions) {
|
|
119
|
+
return;
|
|
120
|
+
} // eslint-disable-next-line flowtype-errors/uncovered
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
const withTypeNames = (0, _apolloUtilities.addTypenameToDocument)(document);
|
|
124
|
+
const printed = (0, _printer.print)(withTypeNames);
|
|
125
|
+
|
|
126
|
+
if (hasNonFragments) {
|
|
127
|
+
/* eslint-disable flowtype-errors/uncovered */
|
|
128
|
+
const errors = (0, _validation.validate)(schemaForValidation, withTypeNames);
|
|
129
|
+
/* eslint-disable flowtype-errors/uncovered */
|
|
130
|
+
|
|
131
|
+
if (errors.length) {
|
|
132
|
+
errors.forEach(error => {
|
|
133
|
+
console.error(`Schema validation found errors for ${raw.loc.path}!`);
|
|
134
|
+
console.error(printed);
|
|
135
|
+
console.error(error);
|
|
136
|
+
validationFailures++;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/* eslint-enable flowtype-errors/uncovered */
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
(0, _generateTypeFiles.generateTypeFiles)(raw.loc.path, schemaForTypeGeneration, withTypeNames, processedOptions); // eslint-disable-next-line flowtype-errors/uncovered
|
|
145
|
+
} catch (err) {
|
|
146
|
+
console.error(`Error while generating operation from ${raw.loc.path}`);
|
|
147
|
+
console.error(printed); // eslint-disable-next-line flowtype-errors/uncovered
|
|
148
|
+
|
|
149
|
+
console.error(err);
|
|
150
|
+
validationFailures++;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
if (validationFailures) {
|
|
155
|
+
console.error(`Encountered ${validationFailures} validation failures while printing types.`); // eslint-disable-next-line flowtype-errors/uncovered
|
|
156
|
+
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=run.js.map
|