@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
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @flow
|
|
3
|
+
/* eslint-disable no-console */
|
|
4
|
+
import {generateTypeFiles, processPragmas} from '../generateTypeFiles';
|
|
5
|
+
import {processFiles} from '../parser/parse';
|
|
6
|
+
import {resolveDocuments} from '../parser/resolve';
|
|
7
|
+
import {getSchemas, loadConfigFile} from './config';
|
|
8
|
+
|
|
9
|
+
import {addTypenameToDocument} from 'apollo-utilities'; // eslint-disable-line flowtype-errors/uncovered
|
|
10
|
+
|
|
11
|
+
import {execSync} from 'child_process';
|
|
12
|
+
import {readFileSync} from 'fs';
|
|
13
|
+
import {type DocumentNode} from 'graphql';
|
|
14
|
+
import {print} from 'graphql/language/printer';
|
|
15
|
+
import {validate} from 'graphql/validation';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* This CLI tool executes the following steps:
|
|
20
|
+
* 1) process options
|
|
21
|
+
* 2) crawl files to find all operations and fragments, with
|
|
22
|
+
* tagged template literals and expressions.
|
|
23
|
+
* 3) resolve the found operations, passing the literals and
|
|
24
|
+
* fragments into the `graphql-tag` function to produce
|
|
25
|
+
* the DocumentNodes.
|
|
26
|
+
* 4) generate types for all resolved Queries & Mutations
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Step (1) */
|
|
30
|
+
|
|
31
|
+
const findGraphqlTagReferences = (root: string): Array<string> => {
|
|
32
|
+
const response = execSync(
|
|
33
|
+
"git grep -I --word-regexp --name-only --fixed-strings 'graphql-tag' -- '*.js' '*.jsx'",
|
|
34
|
+
{
|
|
35
|
+
encoding: 'utf8',
|
|
36
|
+
cwd: root,
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
return response
|
|
40
|
+
.trim()
|
|
41
|
+
.split('\n')
|
|
42
|
+
.map((relative) => path.join(root, relative));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const [_, __, configFile, ...cliFiles] = process.argv;
|
|
46
|
+
|
|
47
|
+
if (
|
|
48
|
+
configFile === '-h' ||
|
|
49
|
+
configFile === '--help' ||
|
|
50
|
+
configFile === 'help' ||
|
|
51
|
+
!configFile
|
|
52
|
+
) {
|
|
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 = loadConfigFile(configFile);
|
|
60
|
+
|
|
61
|
+
const [schemaForValidation, schemaForTypeGeneration] = getSchemas(
|
|
62
|
+
config.schemaFilePath,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const inputFiles = cliFiles.length
|
|
66
|
+
? cliFiles
|
|
67
|
+
: findGraphqlTagReferences(process.cwd());
|
|
68
|
+
|
|
69
|
+
/** Step (2) */
|
|
70
|
+
|
|
71
|
+
const files = processFiles(inputFiles, (f) => readFileSync(f, 'utf8'));
|
|
72
|
+
|
|
73
|
+
let filesHadErrors = false;
|
|
74
|
+
Object.keys(files).forEach((key) => {
|
|
75
|
+
const file = files[key];
|
|
76
|
+
if (file.errors.length) {
|
|
77
|
+
filesHadErrors = true;
|
|
78
|
+
console.error(`Errors in ${file.path}`);
|
|
79
|
+
file.errors.forEach((error) => {
|
|
80
|
+
console.error(` - ${error.message}`);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (filesHadErrors) {
|
|
86
|
+
console.error('Aborting');
|
|
87
|
+
process.exit(1); // eslint-disable-line flowtype-errors/uncovered
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Step (3) */
|
|
91
|
+
|
|
92
|
+
const {resolved, errors} = resolveDocuments(files);
|
|
93
|
+
if (errors.length) {
|
|
94
|
+
errors.forEach((error) => {
|
|
95
|
+
console.error(`Resolution error ${error.message} in ${error.loc.path}`);
|
|
96
|
+
});
|
|
97
|
+
console.error('Aborting');
|
|
98
|
+
process.exit(1); // eslint-disable-line flowtype-errors/uncovered
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log(Object.keys(resolved).length, 'resolved queries');
|
|
102
|
+
|
|
103
|
+
/** Step (4) */
|
|
104
|
+
|
|
105
|
+
let validationFailures: number = 0;
|
|
106
|
+
|
|
107
|
+
Object.keys(resolved).forEach((k) => {
|
|
108
|
+
const {document, raw} = resolved[k];
|
|
109
|
+
if (config.excludes.some((rx) => rx.test(raw.loc.path))) {
|
|
110
|
+
return; // skip
|
|
111
|
+
}
|
|
112
|
+
const hasNonFragments = document.definitions.some(
|
|
113
|
+
({kind}) => kind !== 'FragmentDefinition',
|
|
114
|
+
);
|
|
115
|
+
const rawSource: string = raw.literals[0];
|
|
116
|
+
const processedOptions = processPragmas(config.options, rawSource);
|
|
117
|
+
if (!processedOptions) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// eslint-disable-next-line flowtype-errors/uncovered
|
|
122
|
+
const withTypeNames: DocumentNode = addTypenameToDocument(document);
|
|
123
|
+
const printed = print(withTypeNames);
|
|
124
|
+
|
|
125
|
+
if (hasNonFragments) {
|
|
126
|
+
/* eslint-disable flowtype-errors/uncovered */
|
|
127
|
+
const errors = validate(schemaForValidation, withTypeNames);
|
|
128
|
+
/* eslint-disable flowtype-errors/uncovered */
|
|
129
|
+
if (errors.length) {
|
|
130
|
+
errors.forEach((error) => {
|
|
131
|
+
console.error(
|
|
132
|
+
`Schema validation found errors for ${raw.loc.path}!`,
|
|
133
|
+
);
|
|
134
|
+
console.error(printed);
|
|
135
|
+
console.error(error);
|
|
136
|
+
validationFailures++;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/* eslint-enable flowtype-errors/uncovered */
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
generateTypeFiles(
|
|
144
|
+
raw.loc.path,
|
|
145
|
+
schemaForTypeGeneration,
|
|
146
|
+
withTypeNames,
|
|
147
|
+
processedOptions,
|
|
148
|
+
);
|
|
149
|
+
// eslint-disable-next-line flowtype-errors/uncovered
|
|
150
|
+
} catch (err) {
|
|
151
|
+
console.error(`Error while generating operation from ${raw.loc.path}`);
|
|
152
|
+
console.error(printed);
|
|
153
|
+
// eslint-disable-next-line flowtype-errors/uncovered
|
|
154
|
+
console.error(err);
|
|
155
|
+
validationFailures++;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
if (validationFailures) {
|
|
160
|
+
console.error(
|
|
161
|
+
`Encountered ${validationFailures} validation failures while printing types.`,
|
|
162
|
+
);
|
|
163
|
+
// eslint-disable-next-line flowtype-errors/uncovered
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/run.js"],"names":["findGraphqlTagReferences","root","response","encoding","cwd","trim","split","map","relative","path","join","_","__","configFile","cliFiles","process","argv","console","log","exit","config","schemaForValidation","schemaForTypeGeneration","schemaFilePath","inputFiles","length","files","f","filesHadErrors","Object","keys","forEach","key","file","errors","error","message","resolved","loc","validationFailures","k","document","raw","excludes","some","rx","test","hasNonFragments","definitions","kind","rawSource","literals","processedOptions","options","withTypeNames","printed","err"],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n// @flow\n/* eslint-disable no-console */\nimport {generateTypeFiles, processPragmas} from '../generateTypeFiles';\nimport {processFiles} from '../parser/parse';\nimport {resolveDocuments} from '../parser/resolve';\nimport {getSchemas, loadConfigFile} from './config';\n\nimport {addTypenameToDocument} from 'apollo-utilities'; // eslint-disable-line flowtype-errors/uncovered\n\nimport {execSync} from 'child_process';\nimport {readFileSync} from 'fs';\nimport {type DocumentNode} from 'graphql';\nimport {print} from 'graphql/language/printer';\nimport {validate} from 'graphql/validation';\nimport path from 'path';\n\n/**\n * This CLI tool executes the following steps:\n * 1) process options\n * 2) crawl files to find all operations and fragments, with\n * tagged template literals and expressions.\n * 3) resolve the found operations, passing the literals and\n * fragments into the `graphql-tag` function to produce\n * the DocumentNodes.\n * 4) generate types for all resolved Queries & Mutations\n */\n\n/** Step (1) */\n\nconst findGraphqlTagReferences = (root: string): Array<string> => {\n const response = execSync(\n \"git grep -I --word-regexp --name-only --fixed-strings 'graphql-tag' -- '*.js' '*.jsx'\",\n {\n encoding: 'utf8',\n cwd: root,\n },\n );\n return response\n .trim()\n .split('\\n')\n .map((relative) => path.join(root, relative));\n};\n\nconst [_, __, configFile, ...cliFiles] = process.argv;\n\nif (\n configFile === '-h' ||\n configFile === '--help' ||\n configFile === 'help' ||\n !configFile\n) {\n console.log(`graphql-flow\n\nUsage: graphql-flow [configFile.json] [filesToCrawl...]`);\n process.exit(1); // eslint-disable-line flowtype-errors/uncovered\n}\n\nconst config = loadConfigFile(configFile);\n\nconst [schemaForValidation, schemaForTypeGeneration] = getSchemas(\n config.schemaFilePath,\n);\n\nconst inputFiles = cliFiles.length\n ? cliFiles\n : findGraphqlTagReferences(process.cwd());\n\n/** Step (2) */\n\nconst files = processFiles(inputFiles, (f) => readFileSync(f, 'utf8'));\n\nlet filesHadErrors = false;\nObject.keys(files).forEach((key) => {\n const file = files[key];\n if (file.errors.length) {\n filesHadErrors = true;\n console.error(`Errors in ${file.path}`);\n file.errors.forEach((error) => {\n console.error(` - ${error.message}`);\n });\n }\n});\n\nif (filesHadErrors) {\n console.error('Aborting');\n process.exit(1); // eslint-disable-line flowtype-errors/uncovered\n}\n\n/** Step (3) */\n\nconst {resolved, errors} = resolveDocuments(files);\nif (errors.length) {\n errors.forEach((error) => {\n console.error(`Resolution error ${error.message} in ${error.loc.path}`);\n });\n console.error('Aborting');\n process.exit(1); // eslint-disable-line flowtype-errors/uncovered\n}\n\nconsole.log(Object.keys(resolved).length, 'resolved queries');\n\n/** Step (4) */\n\nlet validationFailures: number = 0;\n\nObject.keys(resolved).forEach((k) => {\n const {document, raw} = resolved[k];\n if (config.excludes.some((rx) => rx.test(raw.loc.path))) {\n return; // skip\n }\n const hasNonFragments = document.definitions.some(\n ({kind}) => kind !== 'FragmentDefinition',\n );\n const rawSource: string = raw.literals[0];\n const processedOptions = processPragmas(config.options, rawSource);\n if (!processedOptions) {\n return;\n }\n\n // eslint-disable-next-line flowtype-errors/uncovered\n const withTypeNames: DocumentNode = addTypenameToDocument(document);\n const printed = print(withTypeNames);\n\n if (hasNonFragments) {\n /* eslint-disable flowtype-errors/uncovered */\n const errors = validate(schemaForValidation, withTypeNames);\n /* eslint-disable flowtype-errors/uncovered */\n if (errors.length) {\n errors.forEach((error) => {\n console.error(\n `Schema validation found errors for ${raw.loc.path}!`,\n );\n console.error(printed);\n console.error(error);\n validationFailures++;\n });\n }\n /* eslint-enable flowtype-errors/uncovered */\n }\n\n try {\n generateTypeFiles(\n raw.loc.path,\n schemaForTypeGeneration,\n withTypeNames,\n processedOptions,\n );\n // eslint-disable-next-line flowtype-errors/uncovered\n } catch (err) {\n console.error(`Error while generating operation from ${raw.loc.path}`);\n console.error(printed);\n // eslint-disable-next-line flowtype-errors/uncovered\n console.error(err);\n validationFailures++;\n }\n});\n\nif (validationFailures) {\n console.error(\n `Encountered ${validationFailures} validation failures while printing types.`,\n );\n // eslint-disable-next-line flowtype-errors/uncovered\n process.exit(1);\n}\n"],"file":"run.js"}
|
package/dist/enums.js
CHANGED
|
@@ -54,4 +54,5 @@ const scalarTypeToFlow = (config, name) => {
|
|
|
54
54
|
return babelTypes.genericTypeAnnotation(babelTypes.identifier(`UNKNOWN_SCALAR["${name}"]`));
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
exports.scalarTypeToFlow = scalarTypeToFlow;
|
|
57
|
+
exports.scalarTypeToFlow = scalarTypeToFlow;
|
|
58
|
+
//# sourceMappingURL=enums.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/enums.js"],"names":["enumTypeToFlow","config","name","enumConfig","schema","enumsByName","combinedDescription","enumValues","map","n","description","replace","join","babelTypes","unionTypeAnnotation","stringLiteralTypeAnnotation","builtinScalars","Boolean","String","DateTime","Date","ID","Int","Float","scalarTypeToFlow","genericTypeAnnotation","identifier","underlyingType","scalars","errors","push"],"mappings":";;;;;;;AAIA;;AAGA;;;;;;AANA;AACA;AACA;AAMO,MAAMA,cAAc,GAAG,CAC1BC,MAD0B,EAE1BC,IAF0B,KAGN;AACpB,QAAMC,UAAU,GAAGF,MAAM,CAACG,MAAP,CAAcC,WAAd,CAA0BH,IAA1B,CAAnB;AACA,MAAII,mBAAmB,GAAGH,UAAU,CAACI,UAAX,CACrBC,GADqB,CAEjBC,CAAD,IACK,KAAIA,CAAC,CAACP,IAAK,EAAZ,IACCO,CAAC,CAACC,WAAF,GACK,eAAeD,CAAC,CAACC,WAAF,CAAcC,OAAd,CAAsB,KAAtB,EAA6B,UAA7B,CADpB,GAEK,EAHN,CAHc,EAQrBC,IARqB,CAQhB,IARgB,CAA1B;;AASA,MAAIT,UAAU,CAACO,WAAf,EAA4B;AACxBJ,IAAAA,mBAAmB,GACfH,UAAU,CAACO,WAAX,GAAyB,MAAzB,GAAkCJ,mBADtC;AAEH;;AACD,SAAO,uCACHA,mBADG,EAEHO,UAAU,CAACC,mBAAX,CACIX,UAAU,CAACI,UAAX,CAAsBC,GAAtB,CAA2BC,CAAD,IACtBI,UAAU,CAACE,2BAAX,CAAuCN,CAAC,CAACP,IAAzC,CADJ,CADJ,CAFG,CAAP;AAQH,CA1BM;;;AA4BA,MAAMc,cAAuC,GAAG;AACnDC,EAAAA,OAAO,EAAE,SAD0C;AAEnDC,EAAAA,MAAM,EAAE,QAF2C;AAGnDC,EAAAA,QAAQ,EAAE,QAHyC;AAInDC,EAAAA,IAAI,EAAE,QAJ6C;AAKnDC,EAAAA,EAAE,EAAE,QAL+C;AAMnDC,EAAAA,GAAG,EAAE,QAN8C;AAOnDC,EAAAA,KAAK,EAAE;AAP4C,CAAhD;;;AAUA,MAAMC,gBAAgB,GAAG,CAC5BvB,MAD4B,EAE5BC,IAF4B,KAGR;AACpB,MAAIc,cAAc,CAACd,IAAD,CAAlB,EAA0B;AACtB,WAAOW,UAAU,CAACY,qBAAX,CACHZ,UAAU,CAACa,UAAX,CAAsBV,cAAc,CAACd,IAAD,CAApC,CADG,CAAP;AAGH;;AACD,QAAMyB,cAAc,GAAG1B,MAAM,CAAC2B,OAAP,CAAe1B,IAAf,CAAvB;;AACA,MAAIyB,cAAc,IAAI,IAAtB,EAA4B;AACxB,WAAOd,UAAU,CAACY,qBAAX,CACHZ,UAAU,CAACa,UAAX,CAAsBC,cAAtB,CADG,CAAP;AAGH;;AACD1B,EAAAA,MAAM,CAAC4B,MAAP,CAAcC,IAAd,CACK,sBAAqB5B,IAAK,sFAD/B;AAGA,SAAOW,UAAU,CAACY,qBAAX,CACHZ,UAAU,CAACa,UAAX,CAAuB,mBAAkBxB,IAAK,IAA9C,CADG,CAAP;AAGH,CArBM","sourcesContent":["// @flow\n/**\n * Both input & output types can have enums & scalars.\n */\nimport * as babelTypes from '@babel/types';\nimport {type BabelNodeFlowType} from '@babel/types';\nimport type {Config} from './types';\nimport {maybeAddDescriptionComment} from './utils';\n\nexport const enumTypeToFlow = (\n config: Config,\n name: string,\n): BabelNodeFlowType => {\n const enumConfig = config.schema.enumsByName[name];\n let combinedDescription = enumConfig.enumValues\n .map(\n (n) =>\n `- ${n.name}` +\n (n.description\n ? '\\n\\n ' + n.description.replace(/\\n/g, '\\n ')\n : ''),\n )\n .join('\\n');\n if (enumConfig.description) {\n combinedDescription =\n enumConfig.description + '\\n\\n' + combinedDescription;\n }\n return maybeAddDescriptionComment(\n combinedDescription,\n babelTypes.unionTypeAnnotation(\n enumConfig.enumValues.map((n) =>\n babelTypes.stringLiteralTypeAnnotation(n.name),\n ),\n ),\n );\n};\n\nexport const builtinScalars: {[key: string]: string} = {\n Boolean: 'boolean',\n String: 'string',\n DateTime: 'string',\n Date: 'string',\n ID: 'string',\n Int: 'number',\n Float: 'number',\n};\n\nexport const scalarTypeToFlow = (\n config: Config,\n name: string,\n): BabelNodeFlowType => {\n if (builtinScalars[name]) {\n return babelTypes.genericTypeAnnotation(\n babelTypes.identifier(builtinScalars[name]),\n );\n }\n const underlyingType = config.scalars[name];\n if (underlyingType != null) {\n return babelTypes.genericTypeAnnotation(\n babelTypes.identifier(underlyingType),\n );\n }\n config.errors.push(\n `Unexpected scalar '${name}'! Please add it to the \"scalars\" argument at the callsite of 'generateFlowTypes()'.`,\n );\n return babelTypes.genericTypeAnnotation(\n babelTypes.identifier(`UNKNOWN_SCALAR[\"${name}\"]`),\n );\n};\n"],"file":"enums.js"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.unionOrInterfaceToFlow = exports.typeToFlow = exports.objectPropertiesToFlow = exports.generateResponseType = void 0;
|
|
6
|
+
exports.unionOrInterfaceToFlow = exports.typeToFlow = exports.objectPropertiesToFlow = exports.generateResponseType = exports.generateFragmentType = void 0;
|
|
7
7
|
|
|
8
8
|
var _generator = _interopRequireDefault(require("@babel/generator"));
|
|
9
9
|
|
|
@@ -29,6 +29,55 @@ const generateResponseType = (schema, query, config) => {
|
|
|
29
29
|
|
|
30
30
|
exports.generateResponseType = generateResponseType;
|
|
31
31
|
|
|
32
|
+
const sortedObjectTypeAnnotation = (config, properties) => {
|
|
33
|
+
const obj = babelTypes.objectTypeAnnotation(properties.sort((a, b) => {
|
|
34
|
+
if (a.type === 'ObjectTypeProperty' && b.type === 'ObjectTypeProperty') {
|
|
35
|
+
const aName = a.key.type === 'Identifier' ? a.key.name : '';
|
|
36
|
+
const bName = b.key.type === 'Identifier' ? b.key.name : '';
|
|
37
|
+
return aName < bName ? -1 : 1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return 0;
|
|
41
|
+
}), undefined
|
|
42
|
+
/* indexers */
|
|
43
|
+
, undefined
|
|
44
|
+
/* callProperties */
|
|
45
|
+
, undefined
|
|
46
|
+
/* internalSlots */
|
|
47
|
+
, true
|
|
48
|
+
/* exact */
|
|
49
|
+
);
|
|
50
|
+
const name = config.path.join('_');
|
|
51
|
+
const isTopLevelType = config.path.length <= 1;
|
|
52
|
+
|
|
53
|
+
if (config.allObjectTypes != null && !isTopLevelType) {
|
|
54
|
+
config.allObjectTypes[name] = obj;
|
|
55
|
+
return babelTypes.genericTypeAnnotation(babelTypes.identifier(name));
|
|
56
|
+
} else {
|
|
57
|
+
return obj;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const generateFragmentType = (schema, fragment, config) => {
|
|
62
|
+
const onType = fragment.typeCondition.name.value;
|
|
63
|
+
let ast;
|
|
64
|
+
|
|
65
|
+
if (schema.typesByName[onType]) {
|
|
66
|
+
ast = sortedObjectTypeAnnotation(config, objectPropertiesToFlow(config, schema.typesByName[onType], onType, fragment.selectionSet.selections));
|
|
67
|
+
} else if (schema.interfacesByName[onType]) {
|
|
68
|
+
ast = unionOrInterfaceToFlow(config, config.schema.interfacesByName[onType], fragment.selectionSet.selections);
|
|
69
|
+
} else if (schema.unionsByName[onType]) {
|
|
70
|
+
ast = unionOrInterfaceToFlow(config, config.schema.unionsByName[onType], fragment.selectionSet.selections);
|
|
71
|
+
} else {
|
|
72
|
+
throw new Error(`Unknown ${onType}`);
|
|
73
|
+
} // eslint-disable-next-line flowtype-errors/uncovered
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
return (0, _generator.default)(ast).code;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
exports.generateFragmentType = generateFragmentType;
|
|
80
|
+
|
|
32
81
|
const _typeToFlow = (config, type, selection) => {
|
|
33
82
|
if (type.kind === 'SCALAR') {
|
|
34
83
|
return (0, _enums.scalarTypeToFlow)(config, type.name);
|
|
@@ -103,35 +152,50 @@ const typeToFlow = (config, type, selection) => {
|
|
|
103
152
|
|
|
104
153
|
exports.typeToFlow = typeToFlow;
|
|
105
154
|
|
|
106
|
-
const
|
|
155
|
+
const ensureOnlyOneTypenameProperty = properties => {
|
|
107
156
|
let seenTypeName = false;
|
|
108
|
-
return
|
|
157
|
+
return properties.filter(type => {
|
|
109
158
|
// The apollo-utilities "addTypeName" utility will add it
|
|
110
159
|
// even if it's already specified :( so we have to filter out
|
|
111
160
|
// the extra one here.
|
|
112
161
|
if (type.type === 'ObjectTypeProperty' && type.key.name === '__typename') {
|
|
162
|
+
const name = type.value.type === 'StringLiteralTypeAnnotation' ? type.value.value : 'INVALID';
|
|
163
|
+
|
|
113
164
|
if (seenTypeName) {
|
|
165
|
+
if (name !== seenTypeName) {
|
|
166
|
+
throw new Error(`Got two different type names ${name}, ${seenTypeName}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
114
169
|
return false;
|
|
115
170
|
}
|
|
116
171
|
|
|
117
|
-
seenTypeName =
|
|
172
|
+
seenTypeName = name;
|
|
118
173
|
}
|
|
119
174
|
|
|
120
175
|
return true;
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
,
|
|
126
|
-
/* internalSlots */
|
|
127
|
-
, true
|
|
128
|
-
/* exact */
|
|
129
|
-
);
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const querySelectionToObjectType = (config, selections, type, typeName) => {
|
|
180
|
+
return sortedObjectTypeAnnotation(config, ensureOnlyOneTypenameProperty(objectPropertiesToFlow(config, type, typeName, selections)));
|
|
130
181
|
};
|
|
131
182
|
|
|
132
183
|
const objectPropertiesToFlow = (config, type, typeName, selections) => {
|
|
133
184
|
return [].concat(...selections.map(selection => {
|
|
134
185
|
switch (selection.kind) {
|
|
186
|
+
case 'InlineFragment':
|
|
187
|
+
{
|
|
188
|
+
var _selection$typeCondit;
|
|
189
|
+
|
|
190
|
+
const newTypeName = ((_selection$typeCondit = selection.typeCondition) === null || _selection$typeCondit === void 0 ? void 0 : _selection$typeCondit.name.value) ?? typeName;
|
|
191
|
+
|
|
192
|
+
if (newTypeName !== typeName) {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return objectPropertiesToFlow(config, config.schema.typesByName[newTypeName], newTypeName, selection.selectionSet.selections);
|
|
197
|
+
}
|
|
198
|
+
|
|
135
199
|
case 'FragmentSpread':
|
|
136
200
|
if (!config.fragments[selection.name.value]) {
|
|
137
201
|
config.errors.push(`No fragment named '${selection.name.value}'. Did you forget to include it in the template literal?`);
|
|
@@ -154,10 +218,13 @@ const objectPropertiesToFlow = (config, type, typeName, selections) => {
|
|
|
154
218
|
}
|
|
155
219
|
|
|
156
220
|
const typeField = type.fieldsByName[name];
|
|
157
|
-
return [(0, _utils.maybeAddDescriptionComment)(typeField.description, (0, _utils.liftLeadingPropertyComments)(babelTypes.objectTypeProperty(babelTypes.identifier(alias), typeToFlow(config,
|
|
221
|
+
return [(0, _utils.maybeAddDescriptionComment)(typeField.description, (0, _utils.liftLeadingPropertyComments)(babelTypes.objectTypeProperty(babelTypes.identifier(alias), typeToFlow({ ...config,
|
|
222
|
+
path: config.path.concat([alias])
|
|
223
|
+
}, typeField.type, selection))))];
|
|
158
224
|
|
|
159
225
|
default:
|
|
160
|
-
config.errors.push(
|
|
226
|
+
config.errors.push( // eslint-disable-next-line flowtype-errors/uncovered
|
|
227
|
+
`Unsupported selection kind '${selection.kind}'`);
|
|
161
228
|
return [];
|
|
162
229
|
}
|
|
163
230
|
}));
|
|
@@ -166,46 +233,80 @@ const objectPropertiesToFlow = (config, type, typeName, selections) => {
|
|
|
166
233
|
exports.objectPropertiesToFlow = objectPropertiesToFlow;
|
|
167
234
|
|
|
168
235
|
const unionOrInterfaceToFlow = (config, type, selections) => {
|
|
169
|
-
const selectedAttributes = type.possibleTypes.map(possible => {
|
|
170
|
-
let seenTypeName = false;
|
|
171
|
-
return selections.map(selection => unionOrInterfaceSelection(config, type, possible, selection)).flat().filter(type => {
|
|
172
|
-
// The apollo-utilities "addTypeName" utility will add it
|
|
173
|
-
// even if it's already specified :( so we have to filter out
|
|
174
|
-
// the extra one here.
|
|
175
|
-
if (type.type === 'ObjectTypeProperty' && type.key.name === '__typename') {
|
|
176
|
-
if (seenTypeName) {
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
seenTypeName = true;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return true;
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
236
|
const allFields = selections.every(selection => selection.kind === 'Field');
|
|
237
|
+
const selectedAttributes = type.possibleTypes.slice().sort((a, b) => {
|
|
238
|
+
return a.name < b.name ? -1 : 1;
|
|
239
|
+
}).map(possible => {
|
|
240
|
+
const configWithUpdatedPath = { ...config,
|
|
241
|
+
path: allFields ? config.path : config.path.concat([possible.name])
|
|
242
|
+
};
|
|
243
|
+
return {
|
|
244
|
+
typeName: possible.name,
|
|
245
|
+
attributes: ensureOnlyOneTypenameProperty(selections.map(selection => unionOrInterfaceSelection(configWithUpdatedPath, type, possible, selection)).flat())
|
|
246
|
+
};
|
|
247
|
+
}); // If they're all fields, the only selection that could be different is __typename
|
|
248
|
+
|
|
249
|
+
if (allFields) {
|
|
250
|
+
const sharedAttributes = selectedAttributes[0].attributes.slice();
|
|
251
|
+
const typeNameIndex = selectedAttributes[0].attributes.findIndex(x => x.type === 'ObjectTypeProperty' && x.key.type === 'Identifier' && x.key.name === '__typename');
|
|
252
|
+
|
|
253
|
+
if (typeNameIndex !== -1) {
|
|
254
|
+
sharedAttributes[typeNameIndex] = babelTypes.objectTypeProperty(babelTypes.identifier('__typename'), babelTypes.unionTypeAnnotation(selectedAttributes.map(attrs => // eslint-disable-next-line flowtype-errors/uncovered
|
|
255
|
+
attrs.attributes[typeNameIndex].value)));
|
|
256
|
+
}
|
|
187
257
|
|
|
188
|
-
|
|
189
|
-
return babelTypes.objectTypeAnnotation(selectedAttributes[0], undefined
|
|
190
|
-
/* indexers */
|
|
191
|
-
, undefined
|
|
192
|
-
/* callProperties */
|
|
193
|
-
, undefined
|
|
194
|
-
/* internalSlots */
|
|
195
|
-
, true
|
|
196
|
-
/* exact */
|
|
197
|
-
);
|
|
258
|
+
return sortedObjectTypeAnnotation(config, sharedAttributes);
|
|
198
259
|
}
|
|
199
260
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
261
|
+
if (selectedAttributes.length === 1) {
|
|
262
|
+
return sortedObjectTypeAnnotation(config, selectedAttributes[0].attributes);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* When generating the objects for the sub-options of a union, the path needs
|
|
266
|
+
* to include the name of the object type.
|
|
267
|
+
* ```
|
|
268
|
+
* query getFriend {
|
|
269
|
+
* friend {
|
|
270
|
+
* ... on Human { id }
|
|
271
|
+
* ... on Droid { arms }
|
|
272
|
+
* }
|
|
273
|
+
* }
|
|
274
|
+
* ```
|
|
275
|
+
* produces
|
|
276
|
+
* ```
|
|
277
|
+
* type getFriend = {friend: getFriend_friend_Human | getFriend_friend_Droid }
|
|
278
|
+
* type getFriend_friend_Human = {id: string}
|
|
279
|
+
* type getFriend_friend_Droid = {arms: number}
|
|
280
|
+
* ```
|
|
281
|
+
* Note that this is different from when an attribute has a plain object type.
|
|
282
|
+
* ```
|
|
283
|
+
* query getHuman {
|
|
284
|
+
* me: human(id: "me") { id }
|
|
285
|
+
* }
|
|
286
|
+
* ```
|
|
287
|
+
* produces
|
|
288
|
+
* ```
|
|
289
|
+
* type getHuman = {me: getHuman_me}
|
|
290
|
+
* type getHuman_me = {id: string}
|
|
291
|
+
* ```
|
|
292
|
+
* instead of e.g. `getHuman_me_Human`.
|
|
293
|
+
*/
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
const result = babelTypes.unionTypeAnnotation(selectedAttributes.map(({
|
|
297
|
+
typeName,
|
|
298
|
+
attributes
|
|
299
|
+
}) => sortedObjectTypeAnnotation({ ...config,
|
|
300
|
+
path: config.path.concat([typeName])
|
|
301
|
+
}, attributes)));
|
|
302
|
+
const name = config.path.join('_');
|
|
303
|
+
|
|
304
|
+
if (config.allObjectTypes && config.path.length > 1) {
|
|
305
|
+
config.allObjectTypes[name] = result;
|
|
306
|
+
return babelTypes.genericTypeAnnotation(babelTypes.identifier(name));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return result;
|
|
209
310
|
};
|
|
210
311
|
|
|
211
312
|
exports.unionOrInterfaceToFlow = unionOrInterfaceToFlow;
|
|
@@ -227,11 +328,18 @@ const unionOrInterfaceSelection = (config, type, possible, selection) => {
|
|
|
227
328
|
}
|
|
228
329
|
|
|
229
330
|
const typeField = type.fieldsByName[name];
|
|
230
|
-
return [(0, _utils.liftLeadingPropertyComments)(babelTypes.objectTypeProperty(babelTypes.identifier(alias), typeToFlow(config,
|
|
331
|
+
return [(0, _utils.liftLeadingPropertyComments)(babelTypes.objectTypeProperty(babelTypes.identifier(alias), typeToFlow({ ...config,
|
|
332
|
+
path: config.path.concat([name])
|
|
333
|
+
}, typeField.type, selection)))];
|
|
231
334
|
}
|
|
232
335
|
|
|
233
336
|
if (selection.kind === 'FragmentSpread') {
|
|
234
337
|
const fragment = config.fragments[selection.name.value];
|
|
338
|
+
|
|
339
|
+
if (!fragment) {
|
|
340
|
+
throw new Error(`Unknown fragment ${selection.name.value}`);
|
|
341
|
+
}
|
|
342
|
+
|
|
235
343
|
const typeName = fragment.typeCondition.name.value;
|
|
236
344
|
|
|
237
345
|
if (config.schema.interfacesByName[typeName] && config.schema.interfacesByName[typeName].possibleTypesByName[possible.name] || typeName === possible.name) {
|
|
@@ -253,15 +361,17 @@ Try using an inline fragment "... on SomeType {}".`);
|
|
|
253
361
|
return [];
|
|
254
362
|
}
|
|
255
363
|
|
|
256
|
-
if (
|
|
257
|
-
|
|
258
|
-
}
|
|
364
|
+
if (selection.typeCondition) {
|
|
365
|
+
var _config$schema$interf;
|
|
259
366
|
|
|
260
|
-
|
|
367
|
+
const typeName = selection.typeCondition.name.value;
|
|
368
|
+
const indirectMatch = (_config$schema$interf = config.schema.interfacesByName[typeName]) === null || _config$schema$interf === void 0 ? void 0 : _config$schema$interf.possibleTypesByName[possible.name];
|
|
261
369
|
|
|
262
|
-
|
|
263
|
-
|
|
370
|
+
if (typeName !== possible.name && !indirectMatch) {
|
|
371
|
+
return [];
|
|
372
|
+
}
|
|
264
373
|
}
|
|
265
374
|
|
|
266
|
-
return [];
|
|
267
|
-
};
|
|
375
|
+
return objectPropertiesToFlow(config, config.schema.typesByName[possible.name], possible.name, selection.selectionSet.selections);
|
|
376
|
+
};
|
|
377
|
+
//# sourceMappingURL=generateResponseType.js.map
|