@graphql-codegen/cli 2.7.0-alpha-05066c85f.0 → 2.8.0-alpha-36b27f965.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/cjs/bin.js +13 -0
- package/cjs/cli.js +60 -0
- package/cjs/codegen.js +332 -0
- package/cjs/config.js +303 -0
- package/cjs/generate-and-save.js +110 -0
- package/cjs/graphql-config.js +69 -0
- package/cjs/hooks.js +87 -0
- package/cjs/index.js +13 -0
- package/cjs/init/helpers.js +64 -0
- package/cjs/init/index.js +60 -0
- package/cjs/init/plugins.js +163 -0
- package/cjs/init/questions.js +147 -0
- package/cjs/init/targets.js +44 -0
- package/cjs/init/types.js +14 -0
- package/cjs/load.js +93 -0
- package/cjs/package.json +1 -0
- package/cjs/plugins.js +45 -0
- package/cjs/presets.js +46 -0
- package/cjs/utils/cli-error.js +25 -0
- package/cjs/utils/debugging.js +27 -0
- package/cjs/utils/file-system.js +26 -0
- package/cjs/utils/indentString.js +37 -0
- package/cjs/utils/listr-renderer.js +136 -0
- package/cjs/utils/logger.js +25 -0
- package/cjs/utils/watcher.js +140 -0
- package/esm/bin.js +11 -0
- package/esm/cli.js +32 -0
- package/esm/codegen.js +327 -0
- package/esm/config.js +290 -0
- package/esm/generate-and-save.js +105 -0
- package/esm/graphql-config.js +64 -0
- package/esm/hooks.js +83 -0
- package/esm/index.js +7 -0
- package/esm/init/helpers.js +55 -0
- package/esm/init/index.js +55 -0
- package/esm/init/plugins.js +160 -0
- package/esm/init/questions.js +140 -0
- package/esm/init/targets.js +40 -0
- package/esm/init/types.js +11 -0
- package/esm/load.js +88 -0
- package/esm/plugins.js +41 -0
- package/esm/presets.js +42 -0
- package/esm/utils/cli-error.js +20 -0
- package/esm/utils/debugging.js +21 -0
- package/esm/utils/file-system.js +19 -0
- package/esm/utils/indentString.js +33 -0
- package/esm/utils/listr-renderer.js +130 -0
- package/esm/utils/logger.js +18 -0
- package/esm/utils/watcher.js +135 -0
- package/package.json +34 -26
- package/typings/bin.d.ts +2 -0
- package/{cli.d.ts → typings/cli.d.ts} +0 -0
- package/{codegen.d.ts → typings/codegen.d.ts} +1 -1
- package/{config.d.ts → typings/config.d.ts} +0 -0
- package/{generate-and-save.d.ts → typings/generate-and-save.d.ts} +1 -1
- package/{graphql-config.d.ts → typings/graphql-config.d.ts} +0 -0
- package/{hooks.d.ts → typings/hooks.d.ts} +0 -0
- package/typings/index.d.ts +7 -0
- package/{init → typings/init}/helpers.d.ts +1 -1
- package/{init → typings/init}/index.d.ts +0 -0
- package/{init → typings/init}/plugins.d.ts +1 -1
- package/{init → typings/init}/questions.d.ts +1 -1
- package/{init → typings/init}/targets.d.ts +1 -1
- package/{init → typings/init}/types.d.ts +0 -0
- package/{load.d.ts → typings/load.d.ts} +0 -0
- package/{plugins.d.ts → typings/plugins.d.ts} +0 -0
- package/{presets.d.ts → typings/presets.d.ts} +0 -0
- package/{utils → typings/utils}/cli-error.d.ts +0 -0
- package/{utils → typings/utils}/debugging.d.ts +0 -0
- package/{utils → typings/utils}/file-system.d.ts +0 -0
- package/{utils → typings/utils}/indentString.d.ts +0 -0
- package/{utils → typings/utils}/listr-renderer.d.ts +0 -0
- package/{utils → typings/utils}/logger.d.ts +0 -0
- package/{utils → typings/utils}/watcher.d.ts +1 -1
- package/bin.d.ts +0 -1
- package/bin.js +0 -1888
- package/index.d.ts +0 -7
- package/index.js +0 -1899
- package/index.mjs +0 -1855
- package/utils/try-to-build-schema.d.ts +0 -2
package/esm/codegen.js
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { DetailedError, normalizeOutputParam, normalizeInstanceOrArray, normalizeConfig, getCachedDocumentNodeFromSchema, isDetailedError, } from '@graphql-codegen/plugin-helpers';
|
|
2
|
+
import { codegen } from '@graphql-codegen/core';
|
|
3
|
+
import { AggregateError } from '@graphql-tools/utils';
|
|
4
|
+
import { Renderer, ErrorRenderer } from './utils/listr-renderer.js';
|
|
5
|
+
import { GraphQLError } from 'graphql';
|
|
6
|
+
import { getPluginByName } from './plugins.js';
|
|
7
|
+
import { getPresetByName } from './presets.js';
|
|
8
|
+
import { debugLog } from './utils/debugging.js';
|
|
9
|
+
import { ensureContext } from './config.js';
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { cpus } from 'os';
|
|
13
|
+
// eslint-disable-next-line
|
|
14
|
+
import { createRequire } from 'module';
|
|
15
|
+
import Listr from 'listr';
|
|
16
|
+
import { isListrError } from './utils/cli-error.js';
|
|
17
|
+
const makeDefaultLoader = (from) => {
|
|
18
|
+
if (fs.statSync(from).isDirectory()) {
|
|
19
|
+
from = path.join(from, '__fake.js');
|
|
20
|
+
}
|
|
21
|
+
const relativeRequire = createRequire(from);
|
|
22
|
+
return (mod) => {
|
|
23
|
+
return import(relativeRequire.resolve(mod));
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
function createCache() {
|
|
27
|
+
const cache = new Map();
|
|
28
|
+
return function ensure(namespace, key, factory) {
|
|
29
|
+
const cacheKey = `${namespace}:${key}`;
|
|
30
|
+
const cachedValue = cache.get(cacheKey);
|
|
31
|
+
if (cachedValue) {
|
|
32
|
+
return cachedValue;
|
|
33
|
+
}
|
|
34
|
+
const value = factory();
|
|
35
|
+
cache.set(cacheKey, value);
|
|
36
|
+
return value;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export async function executeCodegen(input) {
|
|
40
|
+
const context = ensureContext(input);
|
|
41
|
+
const config = context.getConfig();
|
|
42
|
+
const pluginContext = context.getPluginContext();
|
|
43
|
+
const result = [];
|
|
44
|
+
const commonListrOptions = {
|
|
45
|
+
exitOnError: true,
|
|
46
|
+
};
|
|
47
|
+
let listr;
|
|
48
|
+
if (process.env.VERBOSE) {
|
|
49
|
+
listr = new Listr({
|
|
50
|
+
...commonListrOptions,
|
|
51
|
+
renderer: 'verbose',
|
|
52
|
+
nonTTYRenderer: 'verbose',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
else if (process.env.NODE_ENV === 'test') {
|
|
56
|
+
listr = new Listr({
|
|
57
|
+
...commonListrOptions,
|
|
58
|
+
renderer: 'silent',
|
|
59
|
+
nonTTYRenderer: 'silent',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
listr = new Listr({
|
|
64
|
+
...commonListrOptions,
|
|
65
|
+
renderer: config.silent ? 'silent' : config.errorsOnly ? ErrorRenderer : Renderer,
|
|
66
|
+
nonTTYRenderer: config.silent ? 'silent' : 'default',
|
|
67
|
+
collapse: true,
|
|
68
|
+
clearOutput: false,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
let rootConfig = {};
|
|
72
|
+
let rootSchemas;
|
|
73
|
+
let rootDocuments;
|
|
74
|
+
const generates = {};
|
|
75
|
+
const cache = createCache();
|
|
76
|
+
function wrapTask(task, source, taskName) {
|
|
77
|
+
return () => {
|
|
78
|
+
return context.profiler.run(async () => {
|
|
79
|
+
try {
|
|
80
|
+
await Promise.resolve().then(() => task());
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (source && !(error instanceof GraphQLError)) {
|
|
84
|
+
error.source = source;
|
|
85
|
+
}
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}, taskName);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async function normalize() {
|
|
92
|
+
/* Load Require extensions */
|
|
93
|
+
const requireExtensions = normalizeInstanceOrArray(config.require);
|
|
94
|
+
const loader = makeDefaultLoader(context.cwd);
|
|
95
|
+
for (const mod of requireExtensions) {
|
|
96
|
+
await loader(mod);
|
|
97
|
+
}
|
|
98
|
+
/* Root plugin config */
|
|
99
|
+
rootConfig = config.config || {};
|
|
100
|
+
/* Normalize root "schema" field */
|
|
101
|
+
rootSchemas = normalizeInstanceOrArray(config.schema);
|
|
102
|
+
/* Normalize root "documents" field */
|
|
103
|
+
rootDocuments = normalizeInstanceOrArray(config.documents);
|
|
104
|
+
/* Normalize "generators" field */
|
|
105
|
+
const generateKeys = Object.keys(config.generates || {});
|
|
106
|
+
if (generateKeys.length === 0) {
|
|
107
|
+
throw new DetailedError('Invalid Codegen Configuration!', `
|
|
108
|
+
Please make sure that your codegen config file contains the "generates" field, with a specification for the plugins you need.
|
|
109
|
+
|
|
110
|
+
It should looks like that:
|
|
111
|
+
|
|
112
|
+
schema:
|
|
113
|
+
- my-schema.graphql
|
|
114
|
+
generates:
|
|
115
|
+
my-file.ts:
|
|
116
|
+
- plugin1
|
|
117
|
+
- plugin2
|
|
118
|
+
- plugin3
|
|
119
|
+
`);
|
|
120
|
+
}
|
|
121
|
+
for (const filename of generateKeys) {
|
|
122
|
+
const output = (generates[filename] = normalizeOutputParam(config.generates[filename]));
|
|
123
|
+
if (!output.preset && (!output.plugins || output.plugins.length === 0)) {
|
|
124
|
+
throw new DetailedError('Invalid Codegen Configuration!', `
|
|
125
|
+
Please make sure that your codegen config file has defined plugins list for output "${filename}".
|
|
126
|
+
|
|
127
|
+
It should looks like that:
|
|
128
|
+
|
|
129
|
+
schema:
|
|
130
|
+
- my-schema.graphql
|
|
131
|
+
generates:
|
|
132
|
+
my-file.ts:
|
|
133
|
+
- plugin1
|
|
134
|
+
- plugin2
|
|
135
|
+
- plugin3
|
|
136
|
+
`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (rootSchemas.length === 0 &&
|
|
140
|
+
Object.keys(generates).some(filename => !generates[filename].schema || generates[filename].schema.length === 0)) {
|
|
141
|
+
throw new DetailedError('Invalid Codegen Configuration!', `
|
|
142
|
+
Please make sure that your codegen config file contains either the "schema" field
|
|
143
|
+
or every generated file has its own "schema" field.
|
|
144
|
+
|
|
145
|
+
It should looks like that:
|
|
146
|
+
schema:
|
|
147
|
+
- my-schema.graphql
|
|
148
|
+
|
|
149
|
+
or:
|
|
150
|
+
generates:
|
|
151
|
+
path/to/output:
|
|
152
|
+
schema: my-schema.graphql
|
|
153
|
+
`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
listr.add({
|
|
157
|
+
title: 'Parse configuration',
|
|
158
|
+
task: () => normalize(),
|
|
159
|
+
});
|
|
160
|
+
listr.add({
|
|
161
|
+
title: 'Generate outputs',
|
|
162
|
+
task: () => {
|
|
163
|
+
return new Listr(Object.keys(generates).map(filename => {
|
|
164
|
+
const outputConfig = generates[filename];
|
|
165
|
+
const hasPreset = !!outputConfig.preset;
|
|
166
|
+
return {
|
|
167
|
+
title: hasPreset
|
|
168
|
+
? `Generate to ${filename} (using EXPERIMENTAL preset "${outputConfig.preset}")`
|
|
169
|
+
: `Generate ${filename}`,
|
|
170
|
+
task: () => {
|
|
171
|
+
let outputSchemaAst;
|
|
172
|
+
let outputSchema;
|
|
173
|
+
const outputFileTemplateConfig = outputConfig.config || {};
|
|
174
|
+
let outputDocuments = [];
|
|
175
|
+
const outputSpecificSchemas = normalizeInstanceOrArray(outputConfig.schema);
|
|
176
|
+
const outputSpecificDocuments = normalizeInstanceOrArray(outputConfig.documents);
|
|
177
|
+
return new Listr([
|
|
178
|
+
{
|
|
179
|
+
title: 'Load GraphQL schemas',
|
|
180
|
+
task: wrapTask(async () => {
|
|
181
|
+
debugLog(`[CLI] Loading Schemas`);
|
|
182
|
+
const schemaPointerMap = {};
|
|
183
|
+
const allSchemaUnnormalizedPointers = [...rootSchemas, ...outputSpecificSchemas];
|
|
184
|
+
for (const unnormalizedPtr of allSchemaUnnormalizedPointers) {
|
|
185
|
+
if (typeof unnormalizedPtr === 'string') {
|
|
186
|
+
schemaPointerMap[unnormalizedPtr] = {};
|
|
187
|
+
}
|
|
188
|
+
else if (typeof unnormalizedPtr === 'object') {
|
|
189
|
+
Object.assign(schemaPointerMap, unnormalizedPtr);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const hash = JSON.stringify(schemaPointerMap);
|
|
193
|
+
const result = await cache('schema', hash, async () => {
|
|
194
|
+
const outputSchemaAst = await context.loadSchema(schemaPointerMap);
|
|
195
|
+
const outputSchema = getCachedDocumentNodeFromSchema(outputSchemaAst);
|
|
196
|
+
return {
|
|
197
|
+
outputSchemaAst,
|
|
198
|
+
outputSchema,
|
|
199
|
+
};
|
|
200
|
+
});
|
|
201
|
+
outputSchemaAst = await result.outputSchemaAst;
|
|
202
|
+
outputSchema = result.outputSchema;
|
|
203
|
+
}, filename, `Load GraphQL schemas: ${filename}`),
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
title: 'Load GraphQL documents',
|
|
207
|
+
task: wrapTask(async () => {
|
|
208
|
+
debugLog(`[CLI] Loading Documents`);
|
|
209
|
+
// get different cache for shared docs and output specific docs
|
|
210
|
+
const documentPointerMap = {};
|
|
211
|
+
const allDocumentsUnnormalizedPointers = [...rootDocuments, ...outputSpecificDocuments];
|
|
212
|
+
for (const unnormalizedPtr of allDocumentsUnnormalizedPointers) {
|
|
213
|
+
if (typeof unnormalizedPtr === 'string') {
|
|
214
|
+
documentPointerMap[unnormalizedPtr] = {};
|
|
215
|
+
}
|
|
216
|
+
else if (typeof unnormalizedPtr === 'object') {
|
|
217
|
+
Object.assign(documentPointerMap, unnormalizedPtr);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const hash = JSON.stringify(documentPointerMap);
|
|
221
|
+
const result = await cache('documents', hash, async () => {
|
|
222
|
+
const documents = await context.loadDocuments(documentPointerMap);
|
|
223
|
+
return {
|
|
224
|
+
documents,
|
|
225
|
+
};
|
|
226
|
+
});
|
|
227
|
+
outputDocuments = await result.documents;
|
|
228
|
+
}, filename, `Load GraphQL documents: ${filename}`),
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
title: 'Generate',
|
|
232
|
+
task: wrapTask(async () => {
|
|
233
|
+
debugLog(`[CLI] Generating output`);
|
|
234
|
+
const normalizedPluginsArray = normalizeConfig(outputConfig.plugins);
|
|
235
|
+
const pluginLoader = config.pluginLoader || makeDefaultLoader(context.cwd);
|
|
236
|
+
const pluginPackages = await Promise.all(normalizedPluginsArray.map(plugin => getPluginByName(Object.keys(plugin)[0], pluginLoader)));
|
|
237
|
+
const pluginMap = {};
|
|
238
|
+
const preset = hasPreset
|
|
239
|
+
? typeof outputConfig.preset === 'string'
|
|
240
|
+
? await getPresetByName(outputConfig.preset, makeDefaultLoader(context.cwd))
|
|
241
|
+
: outputConfig.preset
|
|
242
|
+
: null;
|
|
243
|
+
pluginPackages.forEach((pluginPackage, i) => {
|
|
244
|
+
const plugin = normalizedPluginsArray[i];
|
|
245
|
+
const name = Object.keys(plugin)[0];
|
|
246
|
+
pluginMap[name] = pluginPackage;
|
|
247
|
+
});
|
|
248
|
+
const mergedConfig = {
|
|
249
|
+
...rootConfig,
|
|
250
|
+
...(typeof outputFileTemplateConfig === 'string'
|
|
251
|
+
? { value: outputFileTemplateConfig }
|
|
252
|
+
: outputFileTemplateConfig),
|
|
253
|
+
};
|
|
254
|
+
let outputs = [];
|
|
255
|
+
if (hasPreset) {
|
|
256
|
+
outputs = await context.profiler.run(async () => preset.buildGeneratesSection({
|
|
257
|
+
baseOutputDir: filename,
|
|
258
|
+
presetConfig: outputConfig.presetConfig || {},
|
|
259
|
+
plugins: normalizedPluginsArray,
|
|
260
|
+
schema: outputSchema,
|
|
261
|
+
schemaAst: outputSchemaAst,
|
|
262
|
+
documents: outputDocuments,
|
|
263
|
+
config: mergedConfig,
|
|
264
|
+
pluginMap,
|
|
265
|
+
pluginContext,
|
|
266
|
+
profiler: context.profiler,
|
|
267
|
+
}), `Build Generates Section: ${filename}`);
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
outputs = [
|
|
271
|
+
{
|
|
272
|
+
filename,
|
|
273
|
+
plugins: normalizedPluginsArray,
|
|
274
|
+
schema: outputSchema,
|
|
275
|
+
schemaAst: outputSchemaAst,
|
|
276
|
+
documents: outputDocuments,
|
|
277
|
+
config: mergedConfig,
|
|
278
|
+
pluginMap,
|
|
279
|
+
pluginContext,
|
|
280
|
+
profiler: context.profiler,
|
|
281
|
+
},
|
|
282
|
+
];
|
|
283
|
+
}
|
|
284
|
+
const process = async (outputArgs) => {
|
|
285
|
+
const output = await codegen({
|
|
286
|
+
...outputArgs,
|
|
287
|
+
cache,
|
|
288
|
+
});
|
|
289
|
+
result.push({
|
|
290
|
+
filename: outputArgs.filename,
|
|
291
|
+
content: output,
|
|
292
|
+
hooks: outputConfig.hooks || {},
|
|
293
|
+
});
|
|
294
|
+
};
|
|
295
|
+
await context.profiler.run(() => Promise.all(outputs.map(process)), `Codegen: ${filename}`);
|
|
296
|
+
}, filename, `Generate: ${filename}`),
|
|
297
|
+
},
|
|
298
|
+
], {
|
|
299
|
+
// it stops when one of tasks failed
|
|
300
|
+
exitOnError: true,
|
|
301
|
+
});
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
}), {
|
|
305
|
+
// it doesn't stop when one of tasks failed, to finish at least some of outputs
|
|
306
|
+
exitOnError: false,
|
|
307
|
+
concurrent: cpus().length,
|
|
308
|
+
});
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
try {
|
|
312
|
+
await listr.run();
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
if (isListrError(err)) {
|
|
316
|
+
const allErrs = err.errors.map(subErr => isDetailedError(subErr)
|
|
317
|
+
? `${subErr.message} for "${subErr.source}"${subErr.details}`
|
|
318
|
+
: subErr.message || subErr.toString());
|
|
319
|
+
const newErr = new AggregateError(err.errors, `${err.message} ${allErrs.join('\n\n')}`);
|
|
320
|
+
// Best-effort to all stack traces for debugging
|
|
321
|
+
newErr.stack = `${newErr.stack}\n\n${err.errors.map(subErr => subErr.stack).join('\n\n')}`;
|
|
322
|
+
throw newErr;
|
|
323
|
+
}
|
|
324
|
+
throw err;
|
|
325
|
+
}
|
|
326
|
+
return result;
|
|
327
|
+
}
|
package/esm/config.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { cosmiconfig, defaultLoaders } from 'cosmiconfig';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { DetailedError, createProfiler, createNoopProfiler, getCachedDocumentNodeFromSchema, } from '@graphql-codegen/plugin-helpers';
|
|
4
|
+
import { env } from 'string-env-interpolation';
|
|
5
|
+
import yargs from 'yargs';
|
|
6
|
+
import { findAndLoadGraphQLConfig } from './graphql-config.js';
|
|
7
|
+
import { loadSchema, loadDocuments, defaultSchemaLoadOptions, defaultDocumentsLoadOptions } from './load.js';
|
|
8
|
+
import { print } from 'graphql';
|
|
9
|
+
import yaml from 'yaml';
|
|
10
|
+
import { createRequire } from 'module';
|
|
11
|
+
import { promises } from 'fs';
|
|
12
|
+
import { createHash } from 'crypto';
|
|
13
|
+
const { lstat } = promises;
|
|
14
|
+
export function generateSearchPlaces(moduleName) {
|
|
15
|
+
const extensions = ['json', 'yaml', 'yml', 'js', 'config.js'];
|
|
16
|
+
// gives codegen.json...
|
|
17
|
+
const regular = extensions.map(ext => `${moduleName}.${ext}`);
|
|
18
|
+
// gives .codegenrc.json... but no .codegenrc.config.js
|
|
19
|
+
const dot = extensions.filter(ext => ext !== 'config.js').map(ext => `.${moduleName}rc.${ext}`);
|
|
20
|
+
return [...regular.concat(dot), 'package.json'];
|
|
21
|
+
}
|
|
22
|
+
function customLoader(ext) {
|
|
23
|
+
function loader(filepath, content) {
|
|
24
|
+
if (typeof process !== 'undefined' && 'env' in process) {
|
|
25
|
+
content = env(content);
|
|
26
|
+
}
|
|
27
|
+
if (ext === 'json') {
|
|
28
|
+
return defaultLoaders['.json'](filepath, content);
|
|
29
|
+
}
|
|
30
|
+
if (ext === 'yaml') {
|
|
31
|
+
try {
|
|
32
|
+
const result = yaml.parse(content, { prettyErrors: true, merge: true });
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
error.message = `YAML Error in ${filepath}:\n${error.message}`;
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (ext === 'js') {
|
|
41
|
+
return defaultLoaders['.js'](filepath, content);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return loader;
|
|
45
|
+
}
|
|
46
|
+
export async function loadCodegenConfig({ configFilePath, moduleName, searchPlaces: additionalSearchPlaces, packageProp, loaders: customLoaders, }) {
|
|
47
|
+
configFilePath = configFilePath || process.cwd();
|
|
48
|
+
moduleName = moduleName || 'codegen';
|
|
49
|
+
packageProp = packageProp || moduleName;
|
|
50
|
+
const cosmi = cosmiconfig(moduleName, {
|
|
51
|
+
searchPlaces: generateSearchPlaces(moduleName).concat(additionalSearchPlaces || []),
|
|
52
|
+
packageProp,
|
|
53
|
+
loaders: {
|
|
54
|
+
'.json': customLoader('json'),
|
|
55
|
+
'.yaml': customLoader('yaml'),
|
|
56
|
+
'.yml': customLoader('yaml'),
|
|
57
|
+
'.js': customLoader('js'),
|
|
58
|
+
noExt: customLoader('yaml'),
|
|
59
|
+
...customLoaders,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
const pathStats = await lstat(configFilePath);
|
|
63
|
+
return pathStats.isDirectory() ? cosmi.search(configFilePath) : cosmi.load(configFilePath);
|
|
64
|
+
}
|
|
65
|
+
export async function loadContext(configFilePath) {
|
|
66
|
+
const graphqlConfig = await findAndLoadGraphQLConfig(configFilePath);
|
|
67
|
+
if (graphqlConfig) {
|
|
68
|
+
return new CodegenContext({
|
|
69
|
+
graphqlConfig,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const result = await loadCodegenConfig({ configFilePath });
|
|
73
|
+
if (!result) {
|
|
74
|
+
if (configFilePath) {
|
|
75
|
+
throw new DetailedError(`Config ${configFilePath} does not exist`, `
|
|
76
|
+
Config ${configFilePath} does not exist.
|
|
77
|
+
|
|
78
|
+
$ graphql-codegen --config ${configFilePath}
|
|
79
|
+
|
|
80
|
+
Please make sure the --config points to a correct file.
|
|
81
|
+
`);
|
|
82
|
+
}
|
|
83
|
+
throw new DetailedError(`Unable to find Codegen config file!`, `
|
|
84
|
+
Please make sure that you have a configuration file under the current directory!
|
|
85
|
+
`);
|
|
86
|
+
}
|
|
87
|
+
if (result.isEmpty) {
|
|
88
|
+
throw new DetailedError(`Found Codegen config file but it was empty!`, `
|
|
89
|
+
Please make sure that you have a valid configuration file under the current directory!
|
|
90
|
+
`);
|
|
91
|
+
}
|
|
92
|
+
return new CodegenContext({
|
|
93
|
+
filepath: result.filepath,
|
|
94
|
+
config: result.config,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function getCustomConfigPath(cliFlags) {
|
|
98
|
+
const configFile = cliFlags.config;
|
|
99
|
+
return configFile ? resolve(process.cwd(), configFile) : null;
|
|
100
|
+
}
|
|
101
|
+
export function buildOptions() {
|
|
102
|
+
return {
|
|
103
|
+
c: {
|
|
104
|
+
alias: 'config',
|
|
105
|
+
type: 'string',
|
|
106
|
+
describe: 'Path to GraphQL codegen YAML config file, defaults to "codegen.yml" on the current directory',
|
|
107
|
+
},
|
|
108
|
+
w: {
|
|
109
|
+
alias: 'watch',
|
|
110
|
+
describe: 'Watch for changes and execute generation automatically. You can also specify a glob expreession for custom watch list.',
|
|
111
|
+
coerce: (watch) => {
|
|
112
|
+
if (watch === 'false') {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
if (typeof watch === 'string' || Array.isArray(watch)) {
|
|
116
|
+
return watch;
|
|
117
|
+
}
|
|
118
|
+
return !!watch;
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
r: {
|
|
122
|
+
alias: 'require',
|
|
123
|
+
describe: 'Loads specific require.extensions before running the codegen and reading the configuration',
|
|
124
|
+
type: 'array',
|
|
125
|
+
default: [],
|
|
126
|
+
},
|
|
127
|
+
o: {
|
|
128
|
+
alias: 'overwrite',
|
|
129
|
+
describe: 'Overwrites existing files',
|
|
130
|
+
type: 'boolean',
|
|
131
|
+
},
|
|
132
|
+
s: {
|
|
133
|
+
alias: 'silent',
|
|
134
|
+
describe: 'Suppresses printing errors',
|
|
135
|
+
type: 'boolean',
|
|
136
|
+
},
|
|
137
|
+
e: {
|
|
138
|
+
alias: 'errors-only',
|
|
139
|
+
describe: 'Only print errors',
|
|
140
|
+
type: 'boolean',
|
|
141
|
+
},
|
|
142
|
+
profile: {
|
|
143
|
+
describe: 'Use profiler to measure performance',
|
|
144
|
+
type: 'boolean',
|
|
145
|
+
},
|
|
146
|
+
p: {
|
|
147
|
+
alias: 'project',
|
|
148
|
+
describe: 'Name of a project in GraphQL Config',
|
|
149
|
+
type: 'string',
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
export function parseArgv(argv = process.argv) {
|
|
154
|
+
return yargs(argv).options(buildOptions()).parse(argv);
|
|
155
|
+
}
|
|
156
|
+
export async function createContext(cliFlags = parseArgv(process.argv)) {
|
|
157
|
+
if (cliFlags.require && cliFlags.require.length > 0) {
|
|
158
|
+
const relativeRequire = createRequire(process.cwd());
|
|
159
|
+
await Promise.all(cliFlags.require.map(mod => import(relativeRequire.resolve(mod, {
|
|
160
|
+
paths: [process.cwd()],
|
|
161
|
+
}))));
|
|
162
|
+
}
|
|
163
|
+
const customConfigPath = getCustomConfigPath(cliFlags);
|
|
164
|
+
const context = await loadContext(customConfigPath);
|
|
165
|
+
updateContextWithCliFlags(context, cliFlags);
|
|
166
|
+
return context;
|
|
167
|
+
}
|
|
168
|
+
export function updateContextWithCliFlags(context, cliFlags) {
|
|
169
|
+
const config = {
|
|
170
|
+
configFilePath: context.filepath,
|
|
171
|
+
};
|
|
172
|
+
if (cliFlags.watch) {
|
|
173
|
+
config.watch = cliFlags.watch;
|
|
174
|
+
}
|
|
175
|
+
if (cliFlags.overwrite === true) {
|
|
176
|
+
config.overwrite = cliFlags.overwrite;
|
|
177
|
+
}
|
|
178
|
+
if (cliFlags.silent === true) {
|
|
179
|
+
config.silent = cliFlags.silent;
|
|
180
|
+
}
|
|
181
|
+
if (cliFlags.errorsOnly === true) {
|
|
182
|
+
config.errorsOnly = cliFlags.errorsOnly;
|
|
183
|
+
}
|
|
184
|
+
if (cliFlags.project) {
|
|
185
|
+
context.useProject(cliFlags.project);
|
|
186
|
+
}
|
|
187
|
+
if (cliFlags.profile === true) {
|
|
188
|
+
context.useProfiler();
|
|
189
|
+
}
|
|
190
|
+
context.updateConfig(config);
|
|
191
|
+
}
|
|
192
|
+
export class CodegenContext {
|
|
193
|
+
constructor({ config, graphqlConfig, filepath, }) {
|
|
194
|
+
this._pluginContext = {};
|
|
195
|
+
this._config = config;
|
|
196
|
+
this._graphqlConfig = graphqlConfig;
|
|
197
|
+
this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath;
|
|
198
|
+
this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd();
|
|
199
|
+
this.profiler = createNoopProfiler();
|
|
200
|
+
}
|
|
201
|
+
useProject(name) {
|
|
202
|
+
this._project = name;
|
|
203
|
+
}
|
|
204
|
+
getConfig(extraConfig) {
|
|
205
|
+
if (!this.config) {
|
|
206
|
+
if (this._graphqlConfig) {
|
|
207
|
+
const project = this._graphqlConfig.getProject(this._project);
|
|
208
|
+
this.config = {
|
|
209
|
+
...project.extension('codegen'),
|
|
210
|
+
schema: project.schema,
|
|
211
|
+
documents: project.documents,
|
|
212
|
+
pluginContext: this._pluginContext,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
this.config = { ...this._config, pluginContext: this._pluginContext };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
...extraConfig,
|
|
221
|
+
...this.config,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
updateConfig(config) {
|
|
225
|
+
this.config = {
|
|
226
|
+
...this.getConfig(),
|
|
227
|
+
...config,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
useProfiler() {
|
|
231
|
+
this.profiler = createProfiler();
|
|
232
|
+
const now = new Date(); // 2011-10-05T14:48:00.000Z
|
|
233
|
+
const datetime = now.toISOString().split('.')[0]; // 2011-10-05T14:48:00
|
|
234
|
+
const datetimeNormalized = datetime.replace(/-|:/g, ''); // 20111005T144800
|
|
235
|
+
this.profilerOutput = `codegen-${datetimeNormalized}.json`;
|
|
236
|
+
}
|
|
237
|
+
getPluginContext() {
|
|
238
|
+
return this._pluginContext;
|
|
239
|
+
}
|
|
240
|
+
async loadSchema(pointer) {
|
|
241
|
+
const config = this.getConfig(defaultSchemaLoadOptions);
|
|
242
|
+
if (this._graphqlConfig) {
|
|
243
|
+
// TODO: SchemaWithLoader won't work here
|
|
244
|
+
return addHashToSchema(this._graphqlConfig.getProject(this._project).loadSchema(pointer, 'GraphQLSchema', config));
|
|
245
|
+
}
|
|
246
|
+
return addHashToSchema(loadSchema(pointer, config));
|
|
247
|
+
}
|
|
248
|
+
async loadDocuments(pointer) {
|
|
249
|
+
const config = this.getConfig(defaultDocumentsLoadOptions);
|
|
250
|
+
if (this._graphqlConfig) {
|
|
251
|
+
// TODO: pointer won't work here
|
|
252
|
+
return addHashToDocumentFiles(this._graphqlConfig.getProject(this._project).loadDocuments(pointer, config));
|
|
253
|
+
}
|
|
254
|
+
return addHashToDocumentFiles(loadDocuments(pointer, config));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
export function ensureContext(input) {
|
|
258
|
+
return input instanceof CodegenContext ? input : new CodegenContext({ config: input });
|
|
259
|
+
}
|
|
260
|
+
function hashContent(content) {
|
|
261
|
+
return createHash('sha256').update(content).digest('hex');
|
|
262
|
+
}
|
|
263
|
+
function hashSchema(schema) {
|
|
264
|
+
return hashContent(print(getCachedDocumentNodeFromSchema(schema)));
|
|
265
|
+
}
|
|
266
|
+
function addHashToSchema(schemaPromise) {
|
|
267
|
+
return schemaPromise.then(schema => {
|
|
268
|
+
// It's consumed later on. The general purpose is to use it for caching.
|
|
269
|
+
if (!schema.extensions) {
|
|
270
|
+
schema.extensions = {};
|
|
271
|
+
}
|
|
272
|
+
schema.extensions['hash'] = hashSchema(schema);
|
|
273
|
+
return schema;
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
function hashDocument(doc) {
|
|
277
|
+
if (doc.rawSDL) {
|
|
278
|
+
return hashContent(doc.rawSDL);
|
|
279
|
+
}
|
|
280
|
+
if (doc.document) {
|
|
281
|
+
return hashContent(print(doc.document));
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
function addHashToDocumentFiles(documentFilesPromise) {
|
|
286
|
+
return documentFilesPromise.then(documentFiles => documentFiles.map(doc => {
|
|
287
|
+
doc.hash = hashDocument(doc);
|
|
288
|
+
return doc;
|
|
289
|
+
}));
|
|
290
|
+
}
|