@khanacademy/graphql-flow 0.0.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.
Files changed (48) hide show
  1. package/.babelrc +6 -0
  2. package/.changeset/README.md +8 -0
  3. package/.changeset/config.json +11 -0
  4. package/.eslintignore +2 -0
  5. package/.eslintrc.js +10 -0
  6. package/.flowconfig +13 -0
  7. package/.github/actions/filter-files/action.yml +37 -0
  8. package/.github/actions/full-or-limited/action.yml +27 -0
  9. package/.github/actions/json-args/action.yml +32 -0
  10. package/.github/actions/setup/action.yml +28 -0
  11. package/.github/workflows/changeset-release.yml +80 -0
  12. package/.github/workflows/pr-checks.yml +64 -0
  13. package/.prettierrc +7 -0
  14. package/CHANGELOG.md +14 -0
  15. package/Readme.md +172 -0
  16. package/build-copy-source.js +28 -0
  17. package/dist/enums.js +57 -0
  18. package/dist/enums.js.flow +69 -0
  19. package/dist/generateResponseType.js +267 -0
  20. package/dist/generateResponseType.js.flow +419 -0
  21. package/dist/generateVariablesType.js +132 -0
  22. package/dist/generateVariablesType.js.flow +153 -0
  23. package/dist/index.js +88 -0
  24. package/dist/index.js.flow +93 -0
  25. package/dist/jest-mock-graphql-tag.js +169 -0
  26. package/dist/jest-mock-graphql-tag.js.flow +191 -0
  27. package/dist/schemaFromIntrospectionData.js +69 -0
  28. package/dist/schemaFromIntrospectionData.js.flow +68 -0
  29. package/dist/types.js +1 -0
  30. package/dist/types.js.flow +54 -0
  31. package/dist/utils.js +53 -0
  32. package/dist/utils.js.flow +50 -0
  33. package/flow-typed/npm/@babel/types_vx.x.x.js +5317 -0
  34. package/flow-typed/npm/jest_v23.x.x.js +1155 -0
  35. package/flow-typed/overrides.js +435 -0
  36. package/package.json +41 -0
  37. package/src/__test__/example-schema.graphql +65 -0
  38. package/src/__test__/graphql-flow.test.js +364 -0
  39. package/src/__test__/jest-mock-graphql-tag.test.js +51 -0
  40. package/src/enums.js +69 -0
  41. package/src/generateResponseType.js +419 -0
  42. package/src/generateVariablesType.js +153 -0
  43. package/src/index.js +93 -0
  44. package/src/jest-mock-graphql-tag.js +191 -0
  45. package/src/schemaFromIntrospectionData.js +68 -0
  46. package/src/types.js +54 -0
  47. package/src/utils.js +50 -0
  48. package/tools/find-files-with-gql.js +40 -0
package/dist/index.js ADDED
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.documentToFlowTypes = exports.FlowGenerationError = void 0;
7
+ Object.defineProperty(exports, "spyOnGraphqlTagToCollectQueries", {
8
+ enumerable: true,
9
+ get: function () {
10
+ return _jestMockGraphqlTag.spyOnGraphqlTagToCollectQueries;
11
+ }
12
+ });
13
+
14
+ var _generateResponseType = require("./generateResponseType");
15
+
16
+ var _generateVariablesType = require("./generateVariablesType");
17
+
18
+ var _jestMockGraphqlTag = require("./jest-mock-graphql-tag");
19
+
20
+ /* eslint-disable no-console */
21
+
22
+ /* flow-uncovered-file */
23
+
24
+ /**
25
+ * This tool generates flowtype definitions from graphql queries.
26
+ *
27
+ * It relies on `introspection-query.json` existing in this directory,
28
+ * which is produced by running `./tools/graphql-flow/sendIntrospection.js`.
29
+ */
30
+ const optionsToConfig = (schema, definitions, options, errors = []) => {
31
+ const internalOptions = {
32
+ strictNullability: (options === null || options === void 0 ? void 0 : options.strictNullability) ?? true,
33
+ readOnlyArray: (options === null || options === void 0 ? void 0 : options.readOnlyArray) ?? true,
34
+ scalars: (options === null || options === void 0 ? void 0 : options.scalars) ?? {}
35
+ };
36
+ const fragments = {};
37
+ definitions.forEach(def => {
38
+ if (def.kind === 'FragmentDefinition') {
39
+ fragments[def.name.value] = def;
40
+ }
41
+ });
42
+ const config = {
43
+ fragments,
44
+ schema,
45
+ errors,
46
+ ...internalOptions
47
+ };
48
+ return config;
49
+ };
50
+
51
+ class FlowGenerationError extends Error {
52
+ constructor(errors) {
53
+ super(`Graphql-flow type generation failed! ${errors.join('; ')}`);
54
+ this.messages = errors;
55
+ }
56
+
57
+ }
58
+
59
+ exports.FlowGenerationError = FlowGenerationError;
60
+
61
+ const documentToFlowTypes = (document, schema, options) => {
62
+ const errors = [];
63
+ const config = optionsToConfig(schema, document.definitions, options, errors);
64
+ const result = document.definitions.map(item => {
65
+ if (item.kind === 'OperationDefinition' && (item.operation === 'query' || item.operation === 'mutation') && item.name) {
66
+ const name = item.name.value;
67
+ const response = (0, _generateResponseType.generateResponseType)(schema, item, config);
68
+ const variables = (0, _generateVariablesType.generateVariablesType)(schema, item, config);
69
+ const typeName = `${name}Type`; // TODO(jared): Maybe make this template configurable?
70
+ // We'll see what's required to get webapp on board.
71
+
72
+ const code = `export type ${typeName} = {|\n variables: ${variables},\n response: ${response}\n|};`;
73
+ return {
74
+ name,
75
+ typeName,
76
+ code
77
+ };
78
+ }
79
+ }).filter(Boolean);
80
+
81
+ if (errors.length) {
82
+ throw new FlowGenerationError(errors);
83
+ }
84
+
85
+ return result;
86
+ };
87
+
88
+ exports.documentToFlowTypes = documentToFlowTypes;
@@ -0,0 +1,93 @@
1
+ /* eslint-disable no-console */
2
+ /* flow-uncovered-file */
3
+ // @flow
4
+ /**
5
+ * This tool generates flowtype definitions from graphql queries.
6
+ *
7
+ * It relies on `introspection-query.json` existing in this directory,
8
+ * which is produced by running `./tools/graphql-flow/sendIntrospection.js`.
9
+ */
10
+ import type {DefinitionNode, DocumentNode} from 'graphql';
11
+
12
+ import {generateResponseType} from './generateResponseType';
13
+ import {generateVariablesType} from './generateVariablesType';
14
+ export {spyOnGraphqlTagToCollectQueries} from './jest-mock-graphql-tag';
15
+
16
+ import type {Config, Options, Schema} from './types';
17
+
18
+ const optionsToConfig = (
19
+ schema: Schema,
20
+ definitions: $ReadOnlyArray<DefinitionNode>,
21
+ options?: Options,
22
+ errors: Array<string> = [],
23
+ ): Config => {
24
+ const internalOptions = {
25
+ strictNullability: options?.strictNullability ?? true,
26
+ readOnlyArray: options?.readOnlyArray ?? true,
27
+ scalars: options?.scalars ?? {},
28
+ };
29
+ const fragments = {};
30
+ definitions.forEach((def) => {
31
+ if (def.kind === 'FragmentDefinition') {
32
+ fragments[def.name.value] = def;
33
+ }
34
+ });
35
+ const config = {
36
+ fragments,
37
+ schema,
38
+ errors,
39
+ ...internalOptions,
40
+ };
41
+
42
+ return config;
43
+ };
44
+
45
+ export class FlowGenerationError extends Error {
46
+ messages: Array<string>;
47
+ constructor(errors: Array<string>) {
48
+ super(`Graphql-flow type generation failed! ${errors.join('; ')}`);
49
+ this.messages = errors;
50
+ }
51
+ }
52
+
53
+ export const documentToFlowTypes = (
54
+ document: DocumentNode,
55
+ schema: Schema,
56
+ options?: Options,
57
+ ): $ReadOnlyArray<{
58
+ name: string,
59
+ typeName: string,
60
+ code: string,
61
+ }> => {
62
+ const errors: Array<string> = [];
63
+ const config = optionsToConfig(
64
+ schema,
65
+ document.definitions,
66
+ options,
67
+ errors,
68
+ );
69
+ const result = document.definitions
70
+ .map((item) => {
71
+ if (
72
+ item.kind === 'OperationDefinition' &&
73
+ (item.operation === 'query' || item.operation === 'mutation') &&
74
+ item.name
75
+ ) {
76
+ const name = item.name.value;
77
+ const response = generateResponseType(schema, item, config);
78
+ const variables = generateVariablesType(schema, item, config);
79
+
80
+ const typeName = `${name}Type`;
81
+ // TODO(jared): Maybe make this template configurable?
82
+ // We'll see what's required to get webapp on board.
83
+ const code = `export type ${typeName} = {|\n variables: ${variables},\n response: ${response}\n|};`;
84
+
85
+ return {name, typeName, code};
86
+ }
87
+ })
88
+ .filter(Boolean);
89
+ if (errors.length) {
90
+ throw new FlowGenerationError(errors);
91
+ }
92
+ return result;
93
+ };
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+
3
+ var _validation = require("graphql/validation");
4
+
5
+ var _graphql = require("graphql");
6
+
7
+ var _printer = require("graphql/language/printer");
8
+
9
+ var _apolloUtilities = require("apollo-utilities");
10
+
11
+ var _schemaFromIntrospectionData = require("./schemaFromIntrospectionData");
12
+
13
+ // Import this in your jest setup, to mock out graphql-tag!
14
+ // eslint-disable-line flowtype-errors/uncovered
15
+ const indexPrelude = `// @flow
16
+ //
17
+ // AUTOGENERATED
18
+ // NOTE: New response types are added to this file automatically.
19
+ // Outdated response types can be removed manually as they are deprecated.
20
+ //
21
+
22
+ `;
23
+
24
+ const generateTypeFiles = (schema, document, options) => {
25
+ const {
26
+ documentToFlowTypes
27
+ } = require('.');
28
+
29
+ const path = require('path');
30
+
31
+ const fs = require('fs');
32
+
33
+ const format = require('prettier-eslint'); // eslint-disable-line flowtype-errors/uncovered
34
+
35
+
36
+ const indexFile = generatedDir => path.join(generatedDir, 'index.js');
37
+
38
+ const maybeCreateGeneratedDir = generatedDir => {
39
+ if (!fs.existsSync(generatedDir)) {
40
+ fs.mkdirSync(generatedDir, {
41
+ recursive: true
42
+ }); // Now write an index.js for each __generated__ dir.
43
+
44
+ fs.writeFileSync(indexFile(generatedDir), indexPrelude);
45
+ }
46
+ }; /// Write export for __generated__/index.js if it doesn't exist
47
+
48
+
49
+ const writeToIndex = (filePath, typeName) => {
50
+ const index = indexFile(path.dirname(filePath));
51
+ const indexContents = fs.readFileSync(index, 'utf8');
52
+ const newLine = `export type {${typeName}} from './${path.basename(filePath)}';`;
53
+
54
+ if (indexContents.indexOf(path.basename(filePath)) === -1) {
55
+ fs.appendFileSync(index, newLine + '\n');
56
+ } else {
57
+ const lines = indexContents.split('\n').map(line => {
58
+ if (line.includes(path.basename(filePath))) {
59
+ return newLine;
60
+ }
61
+
62
+ return line;
63
+ });
64
+ fs.writeFileSync(index, lines.join('\n'));
65
+ }
66
+ }; // Get the name of the file that `gql` was called from
67
+
68
+
69
+ const errorLines = new Error().stack.split('\n');
70
+ const fileName = errorLines[3].split('(').slice(-1)[0].split(':')[0];
71
+ const generated = documentToFlowTypes(document, schema, options);
72
+ generated.forEach(({
73
+ name,
74
+ typeName,
75
+ code
76
+ }) => {
77
+ // We write all generated files to a `__generated__` subdir to keep
78
+ // things tidy.
79
+ const targetFileName = `${typeName}.js`;
80
+ const generatedDir = path.join(path.dirname(fileName), '__generated__');
81
+ const targetPath = path.join(generatedDir, targetFileName);
82
+ maybeCreateGeneratedDir(generatedDir); // NOTE: Uncomment this to write the query definitions to disk if
83
+ // you need to add new features to the flow type generation
84
+ // fs.writeFileSync(
85
+ // targetFileName + '.query',
86
+ // JSON.stringify(definitions, null, 2),
87
+ // );
88
+
89
+ const fileContents = format({
90
+ text: '// @' + `flow\n// AUTOGENERATED -- DO NOT EDIT\n` + `// Generated for operation '${name}' in file '../${path.basename(fileName)}'\n` + `// To regenerate, run 'yarn test queries'.\n` + code
91
+ });
92
+ fs.writeFileSync(targetPath, fileContents);
93
+ writeToIndex(targetPath, typeName);
94
+ });
95
+ };
96
+
97
+ // This function is expected to be called like so:
98
+ //
99
+ // jest.mock('graphql-tag', () => {
100
+ // const introspectionData = jest.requireActual(
101
+ // './our-introspection-query.json',
102
+ // );
103
+ // const {spyOnGraphqlTagToCollectQueries} = jest.requireActual(
104
+ // 'graphql-flow/jest-mock-graphql-tag.js');
105
+ //
106
+ // return spyOnGraphqlTagToCollectQueries(
107
+ // jest.requireActual('graphql-tag'),
108
+ // introspectionData,
109
+ // );
110
+ // });
111
+ //
112
+ // If both pragma and loosePragma are empty, then all graphql
113
+ // documents will be processed. Otherwise, only documents
114
+ // with one of the pragmas will be processed.
115
+ const spyOnGraphqlTagToCollectQueries = (realGraphqlTag, introspectionData, options = {}) => {
116
+ const collection = [];
117
+ const clientSchema = (0, _graphql.buildClientSchema)(introspectionData);
118
+ const schema = (0, _schemaFromIntrospectionData.schemaFromIntrospectionData)(introspectionData);
119
+
120
+ const wrapper = function gql() {
121
+ const document = realGraphqlTag.apply(this, arguments); // eslint-disable-line flowtype-errors/uncovered
122
+
123
+ const hasNonFragments = document.definitions.some(({
124
+ kind
125
+ }) => kind !== 'FragmentDefinition');
126
+
127
+ if (hasNonFragments) {
128
+ // eslint-disable-next-line flowtype-errors/uncovered
129
+ const withTypeNames = (0, _apolloUtilities.addTypenameToDocument)(document);
130
+ collection.push({
131
+ raw: (0, _printer.print)(withTypeNames),
132
+ errors: (0, _validation.validate)(clientSchema, document)
133
+ });
134
+ const rawSource = arguments[0].raw[0]; // eslint-disable-line flowtype-errors/uncovered
135
+
136
+ const processedOptions = processPragmas(options, rawSource);
137
+
138
+ if (processedOptions) {
139
+ generateTypeFiles(schema, withTypeNames, processedOptions);
140
+ }
141
+ }
142
+
143
+ return document;
144
+ };
145
+
146
+ wrapper.collectedQueries = collection;
147
+ return wrapper;
148
+ };
149
+
150
+ const processPragmas = (options, rawSource) => {
151
+ const autogen = options.loosePragma ? rawSource.includes(options.loosePragma) : false;
152
+ const autogenStrict = options.pragma ? rawSource.includes(options.pragma) : false;
153
+ const noPragmas = !options.loosePragma && !options.pragma;
154
+
155
+ if (autogen || autogenStrict || noPragmas) {
156
+ return {
157
+ strictNullability: noPragmas ? options.strictNullability : autogenStrict || !autogen,
158
+ readOnlyArray: options.readOnlyArray,
159
+ scalars: options.scalars
160
+ };
161
+ } else {
162
+ return null;
163
+ }
164
+ };
165
+
166
+ module.exports = {
167
+ processPragmas,
168
+ spyOnGraphqlTagToCollectQueries
169
+ };
@@ -0,0 +1,191 @@
1
+ // @flow
2
+ // Import this in your jest setup, to mock out graphql-tag!
3
+ import type {DocumentNode, IntrospectionQuery} from 'graphql';
4
+ import type {Schema, Options, Scalars} from './types';
5
+ import {validate} from 'graphql/validation';
6
+ import {buildClientSchema} from 'graphql';
7
+ import {print} from 'graphql/language/printer';
8
+ import {addTypenameToDocument} from 'apollo-utilities'; // eslint-disable-line flowtype-errors/uncovered
9
+ import {schemaFromIntrospectionData} from './schemaFromIntrospectionData';
10
+
11
+ const indexPrelude = `// @flow
12
+ //
13
+ // AUTOGENERATED
14
+ // NOTE: New response types are added to this file automatically.
15
+ // Outdated response types can be removed manually as they are deprecated.
16
+ //
17
+
18
+ `;
19
+
20
+ const generateTypeFiles = (
21
+ schema: Schema,
22
+ document: DocumentNode,
23
+ options: Options,
24
+ ) => {
25
+ const {documentToFlowTypes} = require('.');
26
+ const path = require('path');
27
+ const fs = require('fs');
28
+ const format: ({text: string}) => string = require('prettier-eslint'); // eslint-disable-line flowtype-errors/uncovered
29
+
30
+ const indexFile = (generatedDir) => path.join(generatedDir, 'index.js');
31
+
32
+ const maybeCreateGeneratedDir = (generatedDir) => {
33
+ if (!fs.existsSync(generatedDir)) {
34
+ fs.mkdirSync(generatedDir, {recursive: true});
35
+
36
+ // Now write an index.js for each __generated__ dir.
37
+ fs.writeFileSync(indexFile(generatedDir), indexPrelude);
38
+ }
39
+ };
40
+
41
+ /// Write export for __generated__/index.js if it doesn't exist
42
+ const writeToIndex = (filePath, typeName) => {
43
+ const index = indexFile(path.dirname(filePath));
44
+ const indexContents = fs.readFileSync(index, 'utf8');
45
+ const newLine = `export type {${typeName}} from './${path.basename(
46
+ filePath,
47
+ )}';`;
48
+ if (indexContents.indexOf(path.basename(filePath)) === -1) {
49
+ fs.appendFileSync(index, newLine + '\n');
50
+ } else {
51
+ const lines = indexContents.split('\n').map((line) => {
52
+ if (line.includes(path.basename(filePath))) {
53
+ return newLine;
54
+ }
55
+ return line;
56
+ });
57
+ fs.writeFileSync(index, lines.join('\n'));
58
+ }
59
+ };
60
+
61
+ // Get the name of the file that `gql` was called from
62
+ const errorLines = new Error().stack.split('\n');
63
+ const fileName = errorLines[3].split('(').slice(-1)[0].split(':')[0];
64
+
65
+ const generated = documentToFlowTypes(document, schema, options);
66
+ generated.forEach(({name, typeName, code}) => {
67
+ // We write all generated files to a `__generated__` subdir to keep
68
+ // things tidy.
69
+ const targetFileName = `${typeName}.js`;
70
+ const generatedDir = path.join(path.dirname(fileName), '__generated__');
71
+ const targetPath = path.join(generatedDir, targetFileName);
72
+
73
+ maybeCreateGeneratedDir(generatedDir);
74
+
75
+ // NOTE: Uncomment this to write the query definitions to disk if
76
+ // you need to add new features to the flow type generation
77
+ // fs.writeFileSync(
78
+ // targetFileName + '.query',
79
+ // JSON.stringify(definitions, null, 2),
80
+ // );
81
+ const fileContents = format({
82
+ text:
83
+ '// @' +
84
+ `flow\n// AUTOGENERATED -- DO NOT EDIT\n` +
85
+ `// Generated for operation '${name}' in file '../${path.basename(
86
+ fileName,
87
+ )}'\n` +
88
+ `// To regenerate, run 'yarn test queries'.\n` +
89
+ code,
90
+ });
91
+ fs.writeFileSync(targetPath, fileContents);
92
+
93
+ writeToIndex(targetPath, typeName);
94
+ });
95
+ };
96
+
97
+ type GraphqlTagFn = (raw: string, ...args: Array<any>) => DocumentNode;
98
+
99
+ type SpyOptions = {
100
+ pragma?: string,
101
+ loosePragma?: string,
102
+ scalars?: Scalars,
103
+ strictNullability?: boolean,
104
+ readOnlyArray?: boolean,
105
+ };
106
+
107
+ // This function is expected to be called like so:
108
+ //
109
+ // jest.mock('graphql-tag', () => {
110
+ // const introspectionData = jest.requireActual(
111
+ // './our-introspection-query.json',
112
+ // );
113
+ // const {spyOnGraphqlTagToCollectQueries} = jest.requireActual(
114
+ // 'graphql-flow/jest-mock-graphql-tag.js');
115
+ //
116
+ // return spyOnGraphqlTagToCollectQueries(
117
+ // jest.requireActual('graphql-tag'),
118
+ // introspectionData,
119
+ // );
120
+ // });
121
+ //
122
+ // If both pragma and loosePragma are empty, then all graphql
123
+ // documents will be processed. Otherwise, only documents
124
+ // with one of the pragmas will be processed.
125
+ const spyOnGraphqlTagToCollectQueries = (
126
+ realGraphqlTag: GraphqlTagFn,
127
+ introspectionData: IntrospectionQuery,
128
+ options: SpyOptions = {},
129
+ ): GraphqlTagFn => {
130
+ const collection: Array<{
131
+ raw: string,
132
+ errors: $ReadOnlyArray<Error>,
133
+ }> = [];
134
+
135
+ const clientSchema = buildClientSchema(introspectionData);
136
+ const schema = schemaFromIntrospectionData(introspectionData);
137
+
138
+ const wrapper = function gql() {
139
+ const document: DocumentNode = realGraphqlTag.apply(this, arguments); // eslint-disable-line flowtype-errors/uncovered
140
+ const hasNonFragments = document.definitions.some(
141
+ ({kind}) => kind !== 'FragmentDefinition',
142
+ );
143
+ if (hasNonFragments) {
144
+ // eslint-disable-next-line flowtype-errors/uncovered
145
+ const withTypeNames: DocumentNode = addTypenameToDocument(document);
146
+ collection.push({
147
+ raw: print(withTypeNames),
148
+ errors: validate(clientSchema, document),
149
+ });
150
+
151
+ const rawSource: string = arguments[0].raw[0]; // eslint-disable-line flowtype-errors/uncovered
152
+ const processedOptions = processPragmas(options, rawSource);
153
+ if (processedOptions) {
154
+ generateTypeFiles(schema, withTypeNames, processedOptions);
155
+ }
156
+ }
157
+ return document;
158
+ };
159
+ wrapper.collectedQueries = collection;
160
+ return wrapper;
161
+ };
162
+
163
+ const processPragmas = (
164
+ options: SpyOptions,
165
+ rawSource: string,
166
+ ): null | Options => {
167
+ const autogen = options.loosePragma
168
+ ? rawSource.includes(options.loosePragma)
169
+ : false;
170
+ const autogenStrict = options.pragma
171
+ ? rawSource.includes(options.pragma)
172
+ : false;
173
+ const noPragmas = !options.loosePragma && !options.pragma;
174
+
175
+ if (autogen || autogenStrict || noPragmas) {
176
+ return {
177
+ strictNullability: noPragmas
178
+ ? options.strictNullability
179
+ : autogenStrict || !autogen,
180
+ readOnlyArray: options.readOnlyArray,
181
+ scalars: options.scalars,
182
+ };
183
+ } else {
184
+ return null;
185
+ }
186
+ };
187
+
188
+ module.exports = {
189
+ processPragmas,
190
+ spyOnGraphqlTagToCollectQueries,
191
+ };
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.schemaFromIntrospectionData = void 0;
7
+
8
+ /**
9
+ * Takes the introspectionQuery response and parses it into the "Schema"
10
+ * type that we use to look up types, interfaces, etc.
11
+ */
12
+ const schemaFromIntrospectionData = schema => {
13
+ const result = {
14
+ interfacesByName: {},
15
+ typesByName: {},
16
+ inputObjectsByName: {},
17
+ unionsByName: {},
18
+ enumsByName: {}
19
+ };
20
+
21
+ schema.__schema.types.forEach(type => {
22
+ if (type.kind === 'ENUM') {
23
+ result.enumsByName[type.name] = type;
24
+ return;
25
+ }
26
+
27
+ if (type.kind === 'UNION') {
28
+ result.unionsByName[type.name] = type;
29
+ return;
30
+ }
31
+
32
+ if (type.kind === 'INTERFACE') {
33
+ result.interfacesByName[type.name] = { ...type,
34
+ possibleTypesByName: {},
35
+ fieldsByName: {}
36
+ };
37
+ type.possibleTypes.forEach(p => result.interfacesByName[type.name].possibleTypesByName[p.name] = true);
38
+ type.fields.forEach(field => {
39
+ result.interfacesByName[type.name].fieldsByName[field.name] = field;
40
+ });
41
+ return;
42
+ }
43
+
44
+ if (type.kind === 'INPUT_OBJECT') {
45
+ result.inputObjectsByName[type.name] = type;
46
+ return;
47
+ }
48
+
49
+ if (type.kind === 'SCALAR') {
50
+ return;
51
+ }
52
+
53
+ result.typesByName[type.name] = { ...type,
54
+ fieldsByName: {}
55
+ };
56
+
57
+ if (!type.fields) {
58
+ return;
59
+ }
60
+
61
+ type.fields.forEach(field => {
62
+ result.typesByName[type.name].fieldsByName[field.name] = field;
63
+ });
64
+ });
65
+
66
+ return result;
67
+ };
68
+
69
+ exports.schemaFromIntrospectionData = schemaFromIntrospectionData;
@@ -0,0 +1,68 @@
1
+ // @flow
2
+ /**
3
+ * Takes the introspectionQuery response and parses it into the "Schema"
4
+ * type that we use to look up types, interfaces, etc.
5
+ */
6
+ import type {IntrospectionQuery} from 'graphql';
7
+ import type {Schema} from './types';
8
+
9
+ export const schemaFromIntrospectionData = (
10
+ schema: IntrospectionQuery,
11
+ ): Schema => {
12
+ const result: Schema = {
13
+ interfacesByName: {},
14
+ typesByName: {},
15
+ inputObjectsByName: {},
16
+ unionsByName: {},
17
+ enumsByName: {},
18
+ };
19
+
20
+ schema.__schema.types.forEach((type) => {
21
+ if (type.kind === 'ENUM') {
22
+ result.enumsByName[type.name] = type;
23
+ return;
24
+ }
25
+ if (type.kind === 'UNION') {
26
+ result.unionsByName[type.name] = type;
27
+ return;
28
+ }
29
+ if (type.kind === 'INTERFACE') {
30
+ result.interfacesByName[type.name] = {
31
+ ...type,
32
+ possibleTypesByName: {},
33
+ fieldsByName: {},
34
+ };
35
+ type.possibleTypes.forEach(
36
+ (p) =>
37
+ (result.interfacesByName[type.name].possibleTypesByName[
38
+ p.name
39
+ ] = true),
40
+ );
41
+ type.fields.forEach((field) => {
42
+ result.interfacesByName[type.name].fieldsByName[field.name] =
43
+ field;
44
+ });
45
+ return;
46
+ }
47
+ if (type.kind === 'INPUT_OBJECT') {
48
+ result.inputObjectsByName[type.name] = type;
49
+ return;
50
+ }
51
+ if (type.kind === 'SCALAR') {
52
+ return;
53
+ }
54
+ result.typesByName[type.name] = {
55
+ ...type,
56
+ fieldsByName: {},
57
+ };
58
+ if (!type.fields) {
59
+ return;
60
+ }
61
+
62
+ type.fields.forEach((field) => {
63
+ result.typesByName[type.name].fieldsByName[field.name] = field;
64
+ });
65
+ });
66
+
67
+ return result;
68
+ };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";