1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', { value: true });
|
4 |
|
5 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
6 |
|
7 | function _interopNamespace(e) {
|
8 | if (e && e.__esModule) { return e; } else {
|
9 | var n = {};
|
10 | if (e) {
|
11 | Object.keys(e).forEach(function (k) {
|
12 | var d = Object.getOwnPropertyDescriptor(e, k);
|
13 | Object.defineProperty(n, k, d.get ? d : {
|
14 | enumerable: true,
|
15 | get: function () {
|
16 | return e[k];
|
17 | }
|
18 | });
|
19 | });
|
20 | }
|
21 | n['default'] = e;
|
22 | return n;
|
23 | }
|
24 | }
|
25 |
|
26 | const pluginHelpers = require('@graphql-codegen/plugin-helpers');
|
27 | const core = require('@graphql-codegen/core');
|
28 | const utils = require('@graphql-tools/utils');
|
29 | const chalk = _interopDefault(require('chalk'));
|
30 | const logSymbols = _interopDefault(require('log-symbols'));
|
31 | const ansiEscapes = _interopDefault(require('ansi-escapes'));
|
32 | const wrapAnsi = _interopDefault(require('wrap-ansi'));
|
33 | const commonTags = require('common-tags');
|
34 | const tsLog = require('ts-log');
|
35 | const UpdateRenderer = _interopDefault(require('listr-update-renderer'));
|
36 | const graphql = require('graphql');
|
37 | const path = require('path');
|
38 | const path__default = _interopDefault(path);
|
39 | const cosmiconfig = require('cosmiconfig');
|
40 | const stringEnvInterpolation = require('string-env-interpolation');
|
41 | const yargs = _interopDefault(require('yargs'));
|
42 | const graphqlConfig = require('graphql-config');
|
43 | const apolloEngineLoader = require('@graphql-tools/apollo-engine-loader');
|
44 | const codeFileLoader = require('@graphql-tools/code-file-loader');
|
45 | const gitLoader = require('@graphql-tools/git-loader');
|
46 | const githubLoader = require('@graphql-tools/github-loader');
|
47 | const prismaLoader = require('@graphql-tools/prisma-loader');
|
48 | const load = require('@graphql-tools/load');
|
49 | const graphqlFileLoader = require('@graphql-tools/graphql-file-loader');
|
50 | const jsonFileLoader = require('@graphql-tools/json-file-loader');
|
51 | const urlLoader = require('@graphql-tools/url-loader');
|
52 | const yaml = _interopDefault(require('yaml'));
|
53 | const module$1 = require('module');
|
54 | const fs = require('fs');
|
55 | const fs__default = _interopDefault(fs);
|
56 | const crypto = require('crypto');
|
57 | const os = require('os');
|
58 | const Listr = _interopDefault(require('listr'));
|
59 | const child_process = require('child_process');
|
60 | const isGlob = _interopDefault(require('is-glob'));
|
61 | const debounce = _interopDefault(require('debounce'));
|
62 | const mkdirp = _interopDefault(require('mkdirp'));
|
63 | const inquirer = _interopDefault(require('inquirer'));
|
64 | const detectIndent = _interopDefault(require('detect-indent'));
|
65 | const getLatestVersion = _interopDefault(require('latest-version'));
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | function indentString(string, count = 1, options = {}) {
|
81 | const { indent = ' ', includeEmptyLines = false } = options;
|
82 | if (typeof string !== 'string') {
|
83 | throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof string}\``);
|
84 | }
|
85 | if (typeof count !== 'number') {
|
86 | throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof count}\``);
|
87 | }
|
88 | if (count < 0) {
|
89 | throw new RangeError(`Expected \`count\` to be at least 0, got \`${count}\``);
|
90 | }
|
91 | if (typeof indent !== 'string') {
|
92 | throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof indent}\``);
|
93 | }
|
94 | if (count === 0) {
|
95 | return string;
|
96 | }
|
97 | const regex = includeEmptyLines ? /^/gm : /^(?!\s*$)/gm;
|
98 | return string.replace(regex, indent.repeat(count));
|
99 | }
|
100 |
|
101 | let logger;
|
102 | function getLogger() {
|
103 | return logger || tsLog.dummyLogger;
|
104 | }
|
105 | useWinstonLogger();
|
106 | function useWinstonLogger() {
|
107 | if (logger && logger.levels) {
|
108 | return;
|
109 | }
|
110 | logger = console;
|
111 | }
|
112 |
|
113 | let queue = [];
|
114 | function debugLog(message, ...meta) {
|
115 | if (!process.env.GQL_CODEGEN_NODEBUG && process.env.DEBUG !== undefined) {
|
116 | queue.push({
|
117 | message,
|
118 | meta,
|
119 | });
|
120 | }
|
121 | }
|
122 | function printLogs() {
|
123 | if (!process.env.GQL_CODEGEN_NODEBUG && process.env.DEBUG !== undefined) {
|
124 | queue.forEach(log => {
|
125 | getLogger().info(log.message, ...log.meta);
|
126 | });
|
127 | resetLogs();
|
128 | }
|
129 | }
|
130 | function resetLogs() {
|
131 | queue = [];
|
132 | }
|
133 |
|
134 | class Renderer {
|
135 | constructor(tasks, options) {
|
136 | this.updateRenderer = new UpdateRenderer(tasks, options);
|
137 | }
|
138 | render() {
|
139 | return this.updateRenderer.render();
|
140 | }
|
141 | end(err) {
|
142 | this.updateRenderer.end(err);
|
143 | if (typeof err === 'undefined') {
|
144 | logUpdate.clear();
|
145 | return;
|
146 | }
|
147 |
|
148 | logUpdate.done();
|
149 |
|
150 | if (err) {
|
151 | const errorCount = err.errors ? err.errors.length : 0;
|
152 | if (errorCount > 0) {
|
153 | const count = indentString(chalk.red.bold(`Found ${errorCount} error${errorCount > 1 ? 's' : ''}`), 1);
|
154 | const details = err.errors
|
155 | .map(error => {
|
156 | debugLog(`[CLI] Exited with an error`, error);
|
157 | return { msg: pluginHelpers.isDetailedError(error) ? error.details : null, rawError: error };
|
158 | })
|
159 | .map(({ msg, rawError }, i) => {
|
160 | const source = err.errors[i].source;
|
161 | msg = msg ? chalk.gray(indentString(commonTags.stripIndent(`${msg}`), 4)) : null;
|
162 | const stack = rawError.stack ? chalk.gray(indentString(commonTags.stripIndent(rawError.stack), 4)) : null;
|
163 | if (source) {
|
164 | const sourceOfError = typeof source === 'string' ? source : source.name;
|
165 | const title = indentString(`${logSymbols.error} ${sourceOfError}`, 2);
|
166 | return [title, msg, stack, stack].filter(Boolean).join('\n');
|
167 | }
|
168 | return [msg, stack].filter(Boolean).join('\n');
|
169 | })
|
170 | .join('\n\n');
|
171 | logUpdate.emit(['', count, details, ''].join('\n\n'));
|
172 | }
|
173 | else {
|
174 | const details = err.details ? err.details : '';
|
175 | logUpdate.emit(`${chalk.red.bold(`${indentString(err.message, 2)}`)}\n${details}\n${chalk.grey(err.stack)}`);
|
176 | }
|
177 | }
|
178 | logUpdate.done();
|
179 | printLogs();
|
180 | }
|
181 | }
|
182 | const render = tasks => {
|
183 | for (const task of tasks) {
|
184 | task.subscribe(event => {
|
185 | if (event.type === 'SUBTASKS') {
|
186 | render(task.subtasks);
|
187 | return;
|
188 | }
|
189 | if (event.type === 'DATA') {
|
190 | logUpdate.emit(chalk.dim(`${event.data}`));
|
191 | }
|
192 | logUpdate.done();
|
193 | }, err => {
|
194 | logUpdate.emit(err);
|
195 | logUpdate.done();
|
196 | });
|
197 | }
|
198 | };
|
199 | class ErrorRenderer {
|
200 | constructor(tasks, _options) {
|
201 | this.tasks = tasks;
|
202 | }
|
203 | render() {
|
204 | render(this.tasks);
|
205 | }
|
206 | static get nonTTY() {
|
207 | return true;
|
208 | }
|
209 | end() { }
|
210 | }
|
211 | class LogUpdate {
|
212 | constructor() {
|
213 | this.stream = process.stdout;
|
214 |
|
215 | this.previousLineCount = 0;
|
216 | this.previousOutput = '';
|
217 | this.previousWidth = this.getWidth();
|
218 | }
|
219 | emit(...args) {
|
220 | let output = args.join(' ') + '\n';
|
221 | const width = this.getWidth();
|
222 | if (output === this.previousOutput && this.previousWidth === width) {
|
223 | return;
|
224 | }
|
225 | this.previousOutput = output;
|
226 | this.previousWidth = width;
|
227 | output = wrapAnsi(output, width, {
|
228 | trim: false,
|
229 | hard: true,
|
230 | wordWrap: false,
|
231 | });
|
232 | this.stream.write(ansiEscapes.eraseLines(this.previousLineCount) + output);
|
233 | this.previousLineCount = output.split('\n').length;
|
234 | }
|
235 | clear() {
|
236 | this.stream.write(ansiEscapes.eraseLines(this.previousLineCount));
|
237 | this.previousOutput = '';
|
238 | this.previousWidth = this.getWidth();
|
239 | this.previousLineCount = 0;
|
240 | }
|
241 | done() {
|
242 | this.previousOutput = '';
|
243 | this.previousWidth = this.getWidth();
|
244 | this.previousLineCount = 0;
|
245 | }
|
246 | getWidth() {
|
247 | const { columns } = this.stream;
|
248 | if (!columns) {
|
249 | return 80;
|
250 | }
|
251 | return columns;
|
252 | }
|
253 | }
|
254 | const logUpdate = new LogUpdate();
|
255 |
|
256 | async function getPluginByName(name, pluginLoader) {
|
257 | const possibleNames = [
|
258 | `@graphql-codegen/${name}`,
|
259 | `@graphql-codegen/${name}-template`,
|
260 | `@graphql-codegen/${name}-plugin`,
|
261 | `graphql-codegen-${name}`,
|
262 | `graphql-codegen-${name}-template`,
|
263 | `graphql-codegen-${name}-plugin`,
|
264 | `codegen-${name}`,
|
265 | `codegen-${name}-template`,
|
266 | name,
|
267 | ];
|
268 | const possibleModules = possibleNames.concat(path.resolve(process.cwd(), name));
|
269 | for (const moduleName of possibleModules) {
|
270 | try {
|
271 | return await pluginLoader(moduleName);
|
272 | }
|
273 | catch (err) {
|
274 | if (err.code !== 'MODULE_NOT_FOUND') {
|
275 | throw new pluginHelpers.DetailedError(`Unable to load template plugin matching ${name}`, `
|
276 | Unable to load template plugin matching '${name}'.
|
277 | Reason:
|
278 | ${err.message}
|
279 | `);
|
280 | }
|
281 | }
|
282 | }
|
283 | const possibleNamesMsg = possibleNames
|
284 | .map(name => `
|
285 | - ${name}
|
286 | `.trimRight())
|
287 | .join('');
|
288 | throw new pluginHelpers.DetailedError(`Unable to find template plugin matching ${name}`, `
|
289 | Unable to find template plugin matching '${name}'
|
290 | Install one of the following packages:
|
291 |
|
292 | ${possibleNamesMsg}
|
293 | `);
|
294 | }
|
295 |
|
296 | async function getPresetByName(name, loader) {
|
297 | const possibleNames = [
|
298 | `@graphql-codegen/${name}`,
|
299 | `@graphql-codegen/${name}-preset`,
|
300 | name,
|
301 | path.resolve(process.cwd(), name),
|
302 | ];
|
303 | for (const moduleName of possibleNames) {
|
304 | try {
|
305 | const loaded = await loader(moduleName);
|
306 | if (loaded && loaded.preset) {
|
307 | return loaded.preset;
|
308 | }
|
309 | else if (loaded && loaded.default) {
|
310 | return loaded.default;
|
311 | }
|
312 | return loaded;
|
313 | }
|
314 | catch (err) {
|
315 | if (err.code !== 'MODULE_NOT_FOUND') {
|
316 | throw new pluginHelpers.DetailedError(`Unable to load preset matching ${name}`, `
|
317 | Unable to load preset matching '${name}'.
|
318 | Reason:
|
319 | ${err.message}
|
320 | `);
|
321 | }
|
322 | }
|
323 | }
|
324 | const possibleNamesMsg = possibleNames
|
325 | .map(name => `
|
326 | - ${name}
|
327 | `.trimRight())
|
328 | .join('');
|
329 | throw new pluginHelpers.DetailedError(`Unable to find preset matching ${name}`, `
|
330 | Unable to find preset matching '${name}'
|
331 | Install one of the following packages:
|
332 |
|
333 | ${possibleNamesMsg}
|
334 | `);
|
335 | }
|
336 |
|
337 | const CodegenExtension = (api) => {
|
338 |
|
339 | api.loaders.schema.register(new codeFileLoader.CodeFileLoader({
|
340 | pluckConfig: {
|
341 | skipIndent: true,
|
342 | },
|
343 | }));
|
344 | api.loaders.schema.register(new gitLoader.GitLoader());
|
345 | api.loaders.schema.register(new githubLoader.GithubLoader());
|
346 | api.loaders.schema.register(new apolloEngineLoader.ApolloEngineLoader());
|
347 | api.loaders.schema.register(new prismaLoader.PrismaLoader());
|
348 |
|
349 | api.loaders.documents.register(new codeFileLoader.CodeFileLoader({
|
350 | pluckConfig: {
|
351 | skipIndent: true,
|
352 | },
|
353 | }));
|
354 | api.loaders.documents.register(new gitLoader.GitLoader());
|
355 | api.loaders.documents.register(new githubLoader.GithubLoader());
|
356 | return {
|
357 | name: 'codegen',
|
358 | };
|
359 | };
|
360 | async function findAndLoadGraphQLConfig(filepath) {
|
361 | const config = await graphqlConfig.loadConfig({
|
362 | filepath,
|
363 | rootDir: process.cwd(),
|
364 | extensions: [CodegenExtension],
|
365 | throwOnEmpty: false,
|
366 | throwOnMissing: false,
|
367 | });
|
368 | if (isGraphQLConfig(config)) {
|
369 | return config;
|
370 | }
|
371 | }
|
372 |
|
373 |
|
374 | function isGraphQLConfig(config) {
|
375 | if (!config) {
|
376 | return false;
|
377 | }
|
378 | try {
|
379 | return config.getDefault().hasExtension('codegen');
|
380 | }
|
381 | catch (e) { }
|
382 | try {
|
383 | for (const projectName in config.projects) {
|
384 | if (config.projects.hasOwnProperty(projectName)) {
|
385 | const project = config.projects[projectName];
|
386 | if (project.hasExtension('codegen')) {
|
387 | return true;
|
388 | }
|
389 | }
|
390 | }
|
391 | }
|
392 | catch (e) { }
|
393 | return false;
|
394 | }
|
395 |
|
396 | const defaultSchemaLoadOptions = {
|
397 | assumeValidSDL: true,
|
398 | sort: true,
|
399 | convertExtensions: true,
|
400 | includeSources: true,
|
401 | };
|
402 | const defaultDocumentsLoadOptions = {
|
403 | sort: true,
|
404 | skipGraphQLImport: true,
|
405 | };
|
406 | async function loadSchema(schemaPointers, config) {
|
407 | try {
|
408 | const loaders = [
|
409 | new codeFileLoader.CodeFileLoader(),
|
410 | new gitLoader.GitLoader(),
|
411 | new githubLoader.GithubLoader(),
|
412 | new graphqlFileLoader.GraphQLFileLoader(),
|
413 | new jsonFileLoader.JsonFileLoader(),
|
414 | new urlLoader.UrlLoader(),
|
415 | new apolloEngineLoader.ApolloEngineLoader(),
|
416 | new prismaLoader.PrismaLoader(),
|
417 | ];
|
418 | const schema = await load.loadSchema(schemaPointers, {
|
419 | ...defaultSchemaLoadOptions,
|
420 | loaders,
|
421 | ...config,
|
422 | ...config.config,
|
423 | });
|
424 | return schema;
|
425 | }
|
426 | catch (e) {
|
427 | throw new pluginHelpers.DetailedError('Failed to load schema', `
|
428 | Failed to load schema from ${Object.keys(schemaPointers).join(',')}:
|
429 |
|
430 | ${e.message || e}
|
431 | ${e.stack || ''}
|
432 |
|
433 | GraphQL Code Generator supports:
|
434 | - ES Modules and CommonJS exports (export as default or named export "schema")
|
435 | - Introspection JSON File
|
436 | - URL of GraphQL endpoint
|
437 | - Multiple files with type definitions (glob expression)
|
438 | - String in config file
|
439 |
|
440 | Try to use one of above options and run codegen again.
|
441 |
|
442 | `);
|
443 | }
|
444 | }
|
445 | async function loadDocuments(documentPointers, config) {
|
446 | const loaders = [
|
447 | new codeFileLoader.CodeFileLoader({
|
448 | pluckConfig: {
|
449 | skipIndent: true,
|
450 | },
|
451 | }),
|
452 | new gitLoader.GitLoader(),
|
453 | new githubLoader.GithubLoader(),
|
454 | new graphqlFileLoader.GraphQLFileLoader(),
|
455 | ];
|
456 | const ignore = [];
|
457 | for (const generatePath of Object.keys(config.generates)) {
|
458 | if (path.extname(generatePath) === '') {
|
459 |
|
460 | continue;
|
461 | }
|
462 | ignore.push(path.join(process.cwd(), generatePath));
|
463 | }
|
464 | const loadedFromToolkit = await load.loadDocuments(documentPointers, {
|
465 | ...defaultDocumentsLoadOptions,
|
466 | ignore,
|
467 | loaders,
|
468 | ...config,
|
469 | ...config.config,
|
470 | });
|
471 | return loadedFromToolkit;
|
472 | }
|
473 |
|
474 | const { lstat } = fs.promises;
|
475 | function generateSearchPlaces(moduleName) {
|
476 | const extensions = ['json', 'yaml', 'yml', 'js', 'config.js'];
|
477 |
|
478 | const regular = extensions.map(ext => `${moduleName}.${ext}`);
|
479 |
|
480 | const dot = extensions.filter(ext => ext !== 'config.js').map(ext => `.${moduleName}rc.${ext}`);
|
481 | return [...regular.concat(dot), 'package.json'];
|
482 | }
|
483 | function customLoader(ext) {
|
484 | function loader(filepath, content) {
|
485 | if (typeof process !== 'undefined' && 'env' in process) {
|
486 | content = stringEnvInterpolation.env(content);
|
487 | }
|
488 | if (ext === 'json') {
|
489 | return cosmiconfig.defaultLoaders['.json'](filepath, content);
|
490 | }
|
491 | if (ext === 'yaml') {
|
492 | try {
|
493 | const result = yaml.parse(content, { prettyErrors: true, merge: true });
|
494 | return result;
|
495 | }
|
496 | catch (error) {
|
497 | error.message = `YAML Error in ${filepath}:\n${error.message}`;
|
498 | throw error;
|
499 | }
|
500 | }
|
501 | if (ext === 'js') {
|
502 | return cosmiconfig.defaultLoaders['.js'](filepath, content);
|
503 | }
|
504 | }
|
505 | return loader;
|
506 | }
|
507 | async function loadCodegenConfig({ configFilePath, moduleName, searchPlaces: additionalSearchPlaces, packageProp, loaders: customLoaders, }) {
|
508 | configFilePath = configFilePath || process.cwd();
|
509 | moduleName = moduleName || 'codegen';
|
510 | packageProp = packageProp || moduleName;
|
511 | const cosmi = cosmiconfig.cosmiconfig(moduleName, {
|
512 | searchPlaces: generateSearchPlaces(moduleName).concat(additionalSearchPlaces || []),
|
513 | packageProp,
|
514 | loaders: {
|
515 | '.json': customLoader('json'),
|
516 | '.yaml': customLoader('yaml'),
|
517 | '.yml': customLoader('yaml'),
|
518 | '.js': customLoader('js'),
|
519 | noExt: customLoader('yaml'),
|
520 | ...customLoaders,
|
521 | },
|
522 | });
|
523 | const pathStats = await lstat(configFilePath);
|
524 | return pathStats.isDirectory() ? cosmi.search(configFilePath) : cosmi.load(configFilePath);
|
525 | }
|
526 | async function loadContext(configFilePath) {
|
527 | const graphqlConfig = await findAndLoadGraphQLConfig(configFilePath);
|
528 | if (graphqlConfig) {
|
529 | return new CodegenContext({
|
530 | graphqlConfig,
|
531 | });
|
532 | }
|
533 | const result = await loadCodegenConfig({ configFilePath });
|
534 | if (!result) {
|
535 | if (configFilePath) {
|
536 | throw new pluginHelpers.DetailedError(`Config ${configFilePath} does not exist`, `
|
537 | Config ${configFilePath} does not exist.
|
538 |
|
539 | $ graphql-codegen --config ${configFilePath}
|
540 |
|
541 | Please make sure the --config points to a correct file.
|
542 | `);
|
543 | }
|
544 | throw new pluginHelpers.DetailedError(`Unable to find Codegen config file!`, `
|
545 | Please make sure that you have a configuration file under the current directory!
|
546 | `);
|
547 | }
|
548 | if (result.isEmpty) {
|
549 | throw new pluginHelpers.DetailedError(`Found Codegen config file but it was empty!`, `
|
550 | Please make sure that you have a valid configuration file under the current directory!
|
551 | `);
|
552 | }
|
553 | return new CodegenContext({
|
554 | filepath: result.filepath,
|
555 | config: result.config,
|
556 | });
|
557 | }
|
558 | function getCustomConfigPath(cliFlags) {
|
559 | const configFile = cliFlags.config;
|
560 | return configFile ? path.resolve(process.cwd(), configFile) : null;
|
561 | }
|
562 | function buildOptions() {
|
563 | return {
|
564 | c: {
|
565 | alias: 'config',
|
566 | type: 'string',
|
567 | describe: 'Path to GraphQL codegen YAML config file, defaults to "codegen.yml" on the current directory',
|
568 | },
|
569 | w: {
|
570 | alias: 'watch',
|
571 | describe: 'Watch for changes and execute generation automatically. You can also specify a glob expreession for custom watch list.',
|
572 | coerce: (watch) => {
|
573 | if (watch === 'false') {
|
574 | return false;
|
575 | }
|
576 | if (typeof watch === 'string' || Array.isArray(watch)) {
|
577 | return watch;
|
578 | }
|
579 | return !!watch;
|
580 | },
|
581 | },
|
582 | r: {
|
583 | alias: 'require',
|
584 | describe: 'Loads specific require.extensions before running the codegen and reading the configuration',
|
585 | type: 'array',
|
586 | default: [],
|
587 | },
|
588 | o: {
|
589 | alias: 'overwrite',
|
590 | describe: 'Overwrites existing files',
|
591 | type: 'boolean',
|
592 | },
|
593 | s: {
|
594 | alias: 'silent',
|
595 | describe: 'Suppresses printing errors',
|
596 | type: 'boolean',
|
597 | },
|
598 | e: {
|
599 | alias: 'errors-only',
|
600 | describe: 'Only print errors',
|
601 | type: 'boolean',
|
602 | },
|
603 | profile: {
|
604 | describe: 'Use profiler to measure performance',
|
605 | type: 'boolean',
|
606 | },
|
607 | p: {
|
608 | alias: 'project',
|
609 | describe: 'Name of a project in GraphQL Config',
|
610 | type: 'string',
|
611 | },
|
612 | };
|
613 | }
|
614 | function parseArgv(argv = process.argv) {
|
615 | return yargs.options(buildOptions()).parse(argv);
|
616 | }
|
617 | async function createContext(cliFlags = parseArgv(process.argv)) {
|
618 | if (cliFlags.require && cliFlags.require.length > 0) {
|
619 | const relativeRequire = module$1.createRequire(process.cwd());
|
620 | await Promise.all(cliFlags.require.map(mod => new Promise(function (resolve) { resolve(_interopNamespace(require(relativeRequire.resolve(mod, {
|
621 | paths: [process.cwd()],
|
622 | })))); })));
|
623 | }
|
624 | const customConfigPath = getCustomConfigPath(cliFlags);
|
625 | const context = await loadContext(customConfigPath);
|
626 | updateContextWithCliFlags(context, cliFlags);
|
627 | return context;
|
628 | }
|
629 | function updateContextWithCliFlags(context, cliFlags) {
|
630 | const config = {
|
631 | configFilePath: context.filepath,
|
632 | };
|
633 | if (cliFlags.watch) {
|
634 | config.watch = cliFlags.watch;
|
635 | }
|
636 | if (cliFlags.overwrite === true) {
|
637 | config.overwrite = cliFlags.overwrite;
|
638 | }
|
639 | if (cliFlags.silent === true) {
|
640 | config.silent = cliFlags.silent;
|
641 | }
|
642 | if (cliFlags.errorsOnly === true) {
|
643 | config.errorsOnly = cliFlags.errorsOnly;
|
644 | }
|
645 | if (cliFlags.project) {
|
646 | context.useProject(cliFlags.project);
|
647 | }
|
648 | if (cliFlags.profile === true) {
|
649 | context.useProfiler();
|
650 | }
|
651 | context.updateConfig(config);
|
652 | }
|
653 | class CodegenContext {
|
654 | constructor({ config, graphqlConfig, filepath, }) {
|
655 | this._pluginContext = {};
|
656 | this._config = config;
|
657 | this._graphqlConfig = graphqlConfig;
|
658 | this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath;
|
659 | this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd();
|
660 | this.profiler = pluginHelpers.createNoopProfiler();
|
661 | }
|
662 | useProject(name) {
|
663 | this._project = name;
|
664 | }
|
665 | getConfig(extraConfig) {
|
666 | if (!this.config) {
|
667 | if (this._graphqlConfig) {
|
668 | const project = this._graphqlConfig.getProject(this._project);
|
669 | this.config = {
|
670 | ...project.extension('codegen'),
|
671 | schema: project.schema,
|
672 | documents: project.documents,
|
673 | pluginContext: this._pluginContext,
|
674 | };
|
675 | }
|
676 | else {
|
677 | this.config = { ...this._config, pluginContext: this._pluginContext };
|
678 | }
|
679 | }
|
680 | return {
|
681 | ...extraConfig,
|
682 | ...this.config,
|
683 | };
|
684 | }
|
685 | updateConfig(config) {
|
686 | this.config = {
|
687 | ...this.getConfig(),
|
688 | ...config,
|
689 | };
|
690 | }
|
691 | useProfiler() {
|
692 | this.profiler = pluginHelpers.createProfiler();
|
693 | const now = new Date();
|
694 | const datetime = now.toISOString().split('.')[0];
|
695 | const datetimeNormalized = datetime.replace(/-|:/g, '');
|
696 | this.profilerOutput = `codegen-${datetimeNormalized}.json`;
|
697 | }
|
698 | getPluginContext() {
|
699 | return this._pluginContext;
|
700 | }
|
701 | async loadSchema(pointer) {
|
702 | const config = this.getConfig(defaultSchemaLoadOptions);
|
703 | if (this._graphqlConfig) {
|
704 |
|
705 | return addHashToSchema(this._graphqlConfig.getProject(this._project).loadSchema(pointer, 'GraphQLSchema', config));
|
706 | }
|
707 | return addHashToSchema(loadSchema(pointer, config));
|
708 | }
|
709 | async loadDocuments(pointer) {
|
710 | const config = this.getConfig(defaultDocumentsLoadOptions);
|
711 | if (this._graphqlConfig) {
|
712 |
|
713 | return addHashToDocumentFiles(this._graphqlConfig.getProject(this._project).loadDocuments(pointer, config));
|
714 | }
|
715 | return addHashToDocumentFiles(loadDocuments(pointer, config));
|
716 | }
|
717 | }
|
718 | function ensureContext(input) {
|
719 | return input instanceof CodegenContext ? input : new CodegenContext({ config: input });
|
720 | }
|
721 | function hashContent(content) {
|
722 | return crypto.createHash('sha256').update(content).digest('hex');
|
723 | }
|
724 | function hashSchema(schema) {
|
725 | return hashContent(graphql.print(pluginHelpers.getCachedDocumentNodeFromSchema(schema)));
|
726 | }
|
727 | function addHashToSchema(schemaPromise) {
|
728 | return schemaPromise.then(schema => {
|
729 |
|
730 | if (!schema.extensions) {
|
731 | schema.extensions = {};
|
732 | }
|
733 | schema.extensions['hash'] = hashSchema(schema);
|
734 | return schema;
|
735 | });
|
736 | }
|
737 | function hashDocument(doc) {
|
738 | if (doc.rawSDL) {
|
739 | return hashContent(doc.rawSDL);
|
740 | }
|
741 | if (doc.document) {
|
742 | return hashContent(graphql.print(doc.document));
|
743 | }
|
744 | return null;
|
745 | }
|
746 | function addHashToDocumentFiles(documentFilesPromise) {
|
747 | return documentFilesPromise.then(documentFiles => documentFiles.map(doc => {
|
748 | doc.hash = hashDocument(doc);
|
749 | return doc;
|
750 | }));
|
751 | }
|
752 |
|
753 | const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
754 | const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
|
755 |
|
756 | function isListrError(err) {
|
757 | return err.name === 'ListrError' && Array.isArray(err.errors) && err.errors.length > 0;
|
758 | }
|
759 | function cliError(err, exitOnError = true) {
|
760 | let msg;
|
761 | if (err instanceof Error) {
|
762 | msg = err.message || err.toString();
|
763 | }
|
764 | else if (typeof err === 'string') {
|
765 | msg = err;
|
766 | }
|
767 | else {
|
768 | msg = JSON.stringify(err);
|
769 | }
|
770 |
|
771 | console.error(msg);
|
772 | if (exitOnError && isNode) {
|
773 | process.exit(1);
|
774 | }
|
775 | else if (exitOnError && isBrowser) {
|
776 | throw err;
|
777 | }
|
778 | }
|
779 |
|
780 | const makeDefaultLoader = (from) => {
|
781 | if (fs__default.statSync(from).isDirectory()) {
|
782 | from = path__default.join(from, '__fake.js');
|
783 | }
|
784 | const relativeRequire = module$1.createRequire(from);
|
785 | return (mod) => {
|
786 | return new Promise(function (resolve) { resolve(_interopNamespace(require(relativeRequire.resolve(mod)))); });
|
787 | };
|
788 | };
|
789 | function createCache() {
|
790 | const cache = new Map();
|
791 | return function ensure(namespace, key, factory) {
|
792 | const cacheKey = `${namespace}:${key}`;
|
793 | const cachedValue = cache.get(cacheKey);
|
794 | if (cachedValue) {
|
795 | return cachedValue;
|
796 | }
|
797 | const value = factory();
|
798 | cache.set(cacheKey, value);
|
799 | return value;
|
800 | };
|
801 | }
|
802 | async function executeCodegen(input) {
|
803 | const context = ensureContext(input);
|
804 | const config = context.getConfig();
|
805 | const pluginContext = context.getPluginContext();
|
806 | const result = [];
|
807 | const commonListrOptions = {
|
808 | exitOnError: true,
|
809 | };
|
810 | let listr;
|
811 | if (process.env.VERBOSE) {
|
812 | listr = new Listr({
|
813 | ...commonListrOptions,
|
814 | renderer: 'verbose',
|
815 | nonTTYRenderer: 'verbose',
|
816 | });
|
817 | }
|
818 | else if (process.env.NODE_ENV === 'test') {
|
819 | listr = new Listr({
|
820 | ...commonListrOptions,
|
821 | renderer: 'silent',
|
822 | nonTTYRenderer: 'silent',
|
823 | });
|
824 | }
|
825 | else {
|
826 | listr = new Listr({
|
827 | ...commonListrOptions,
|
828 | renderer: config.silent ? 'silent' : config.errorsOnly ? ErrorRenderer : Renderer,
|
829 | nonTTYRenderer: config.silent ? 'silent' : 'default',
|
830 | collapse: true,
|
831 | clearOutput: false,
|
832 | });
|
833 | }
|
834 | let rootConfig = {};
|
835 | let rootSchemas;
|
836 | let rootDocuments;
|
837 | const generates = {};
|
838 | const cache = createCache();
|
839 | function wrapTask(task, source, taskName) {
|
840 | return () => {
|
841 | return context.profiler.run(async () => {
|
842 | try {
|
843 | await Promise.resolve().then(() => task());
|
844 | }
|
845 | catch (error) {
|
846 | if (source && !(error instanceof graphql.GraphQLError)) {
|
847 | error.source = source;
|
848 | }
|
849 | throw error;
|
850 | }
|
851 | }, taskName);
|
852 | };
|
853 | }
|
854 | async function normalize() {
|
855 |
|
856 | const requireExtensions = pluginHelpers.normalizeInstanceOrArray(config.require);
|
857 | const loader = makeDefaultLoader(context.cwd);
|
858 | for (const mod of requireExtensions) {
|
859 | await loader(mod);
|
860 | }
|
861 |
|
862 | rootConfig = config.config || {};
|
863 |
|
864 | rootSchemas = pluginHelpers.normalizeInstanceOrArray(config.schema);
|
865 |
|
866 | rootDocuments = pluginHelpers.normalizeInstanceOrArray(config.documents);
|
867 |
|
868 | const generateKeys = Object.keys(config.generates || {});
|
869 | if (generateKeys.length === 0) {
|
870 | throw new pluginHelpers.DetailedError('Invalid Codegen Configuration!', `
|
871 | Please make sure that your codegen config file contains the "generates" field, with a specification for the plugins you need.
|
872 |
|
873 | It should looks like that:
|
874 |
|
875 | schema:
|
876 | - my-schema.graphql
|
877 | generates:
|
878 | my-file.ts:
|
879 | - plugin1
|
880 | - plugin2
|
881 | - plugin3
|
882 | `);
|
883 | }
|
884 | for (const filename of generateKeys) {
|
885 | const output = (generates[filename] = pluginHelpers.normalizeOutputParam(config.generates[filename]));
|
886 | if (!output.preset && (!output.plugins || output.plugins.length === 0)) {
|
887 | throw new pluginHelpers.DetailedError('Invalid Codegen Configuration!', `
|
888 | Please make sure that your codegen config file has defined plugins list for output "${filename}".
|
889 |
|
890 | It should looks like that:
|
891 |
|
892 | schema:
|
893 | - my-schema.graphql
|
894 | generates:
|
895 | my-file.ts:
|
896 | - plugin1
|
897 | - plugin2
|
898 | - plugin3
|
899 | `);
|
900 | }
|
901 | }
|
902 | if (rootSchemas.length === 0 &&
|
903 | Object.keys(generates).some(filename => !generates[filename].schema || generates[filename].schema.length === 0)) {
|
904 | throw new pluginHelpers.DetailedError('Invalid Codegen Configuration!', `
|
905 | Please make sure that your codegen config file contains either the "schema" field
|
906 | or every generated file has its own "schema" field.
|
907 |
|
908 | It should looks like that:
|
909 | schema:
|
910 | - my-schema.graphql
|
911 |
|
912 | or:
|
913 | generates:
|
914 | path/to/output:
|
915 | schema: my-schema.graphql
|
916 | `);
|
917 | }
|
918 | }
|
919 | listr.add({
|
920 | title: 'Parse configuration',
|
921 | task: () => normalize(),
|
922 | });
|
923 | listr.add({
|
924 | title: 'Generate outputs',
|
925 | task: () => {
|
926 | return new Listr(Object.keys(generates).map(filename => {
|
927 | const outputConfig = generates[filename];
|
928 | const hasPreset = !!outputConfig.preset;
|
929 | return {
|
930 | title: hasPreset
|
931 | ? `Generate to ${filename} (using EXPERIMENTAL preset "${outputConfig.preset}")`
|
932 | : `Generate ${filename}`,
|
933 | task: () => {
|
934 | let outputSchemaAst;
|
935 | let outputSchema;
|
936 | const outputFileTemplateConfig = outputConfig.config || {};
|
937 | const outputDocuments = [];
|
938 | const outputSpecificSchemas = pluginHelpers.normalizeInstanceOrArray(outputConfig.schema);
|
939 | const outputSpecificDocuments = pluginHelpers.normalizeInstanceOrArray(outputConfig.documents);
|
940 | return new Listr([
|
941 | {
|
942 | title: 'Load GraphQL schemas',
|
943 | task: wrapTask(async () => {
|
944 | debugLog(`[CLI] Loading Schemas`);
|
945 | const schemaPointerMap = {};
|
946 | const allSchemaUnnormalizedPointers = [...rootSchemas, ...outputSpecificSchemas];
|
947 | for (const unnormalizedPtr of allSchemaUnnormalizedPointers) {
|
948 | if (typeof unnormalizedPtr === 'string') {
|
949 | schemaPointerMap[unnormalizedPtr] = {};
|
950 | }
|
951 | else if (typeof unnormalizedPtr === 'object') {
|
952 | Object.assign(schemaPointerMap, unnormalizedPtr);
|
953 | }
|
954 | }
|
955 | const hash = JSON.stringify(schemaPointerMap);
|
956 | const result = await cache('schema', hash, async () => {
|
957 | const outputSchemaAst = await context.loadSchema(schemaPointerMap);
|
958 | const outputSchema = pluginHelpers.getCachedDocumentNodeFromSchema(outputSchemaAst);
|
959 | return {
|
960 | outputSchemaAst: outputSchemaAst,
|
961 | outputSchema: outputSchema,
|
962 | };
|
963 | });
|
964 | outputSchemaAst = await result.outputSchemaAst;
|
965 | outputSchema = result.outputSchema;
|
966 | }, filename, `Load GraphQL schemas: ${filename}`),
|
967 | },
|
968 | {
|
969 | title: 'Load GraphQL documents',
|
970 | task: wrapTask(async () => {
|
971 | debugLog(`[CLI] Loading Documents`);
|
972 |
|
973 | const results = await Promise.all([rootDocuments, outputSpecificDocuments].map(docs => {
|
974 | const hash = JSON.stringify(docs);
|
975 | return cache('documents', hash, async () => {
|
976 | const documents = await context.loadDocuments(docs);
|
977 | return {
|
978 | documents: documents,
|
979 | };
|
980 | });
|
981 | }));
|
982 | const documents = [];
|
983 | results.forEach(source => documents.push(...source.documents));
|
984 | if (documents.length > 0) {
|
985 | outputDocuments.push(...documents);
|
986 | }
|
987 | }, filename, `Load GraphQL documents: ${filename}`),
|
988 | },
|
989 | {
|
990 | title: 'Generate',
|
991 | task: wrapTask(async () => {
|
992 | debugLog(`[CLI] Generating output`);
|
993 | const normalizedPluginsArray = pluginHelpers.normalizeConfig(outputConfig.plugins);
|
994 | const pluginLoader = config.pluginLoader || makeDefaultLoader(context.cwd);
|
995 | const pluginPackages = await Promise.all(normalizedPluginsArray.map(plugin => getPluginByName(Object.keys(plugin)[0], pluginLoader)));
|
996 | const pluginMap = {};
|
997 | const preset = hasPreset
|
998 | ? typeof outputConfig.preset === 'string'
|
999 | ? await getPresetByName(outputConfig.preset, makeDefaultLoader(context.cwd))
|
1000 | : outputConfig.preset
|
1001 | : null;
|
1002 | pluginPackages.forEach((pluginPackage, i) => {
|
1003 | const plugin = normalizedPluginsArray[i];
|
1004 | const name = Object.keys(plugin)[0];
|
1005 | pluginMap[name] = pluginPackage;
|
1006 | });
|
1007 | const mergedConfig = {
|
1008 | ...rootConfig,
|
1009 | ...(typeof outputFileTemplateConfig === 'string'
|
1010 | ? { value: outputFileTemplateConfig }
|
1011 | : outputFileTemplateConfig),
|
1012 | };
|
1013 | let outputs = [];
|
1014 | if (hasPreset) {
|
1015 | outputs = await context.profiler.run(async () => preset.buildGeneratesSection({
|
1016 | baseOutputDir: filename,
|
1017 | presetConfig: outputConfig.presetConfig || {},
|
1018 | plugins: normalizedPluginsArray,
|
1019 | schema: outputSchema,
|
1020 | schemaAst: outputSchemaAst,
|
1021 | documents: outputDocuments,
|
1022 | config: mergedConfig,
|
1023 | pluginMap,
|
1024 | pluginContext,
|
1025 | profiler: context.profiler,
|
1026 | }), `Build Generates Section: ${filename}`);
|
1027 | }
|
1028 | else {
|
1029 | outputs = [
|
1030 | {
|
1031 | filename,
|
1032 | plugins: normalizedPluginsArray,
|
1033 | schema: outputSchema,
|
1034 | schemaAst: outputSchemaAst,
|
1035 | documents: outputDocuments,
|
1036 | config: mergedConfig,
|
1037 | pluginMap,
|
1038 | pluginContext,
|
1039 | profiler: context.profiler,
|
1040 | },
|
1041 | ];
|
1042 | }
|
1043 | const process = async (outputArgs) => {
|
1044 | const output = await core.codegen({
|
1045 | ...outputArgs,
|
1046 | cache,
|
1047 | });
|
1048 | result.push({
|
1049 | filename: outputArgs.filename,
|
1050 | content: output,
|
1051 | hooks: outputConfig.hooks || {},
|
1052 | });
|
1053 | };
|
1054 | await context.profiler.run(() => Promise.all(outputs.map(process)), `Codegen: ${filename}`);
|
1055 | }, filename, `Generate: ${filename}`),
|
1056 | },
|
1057 | ], {
|
1058 |
|
1059 | exitOnError: true,
|
1060 | });
|
1061 | },
|
1062 | };
|
1063 | }), {
|
1064 |
|
1065 | exitOnError: false,
|
1066 | concurrent: os.cpus().length,
|
1067 | });
|
1068 | },
|
1069 | });
|
1070 | try {
|
1071 | await listr.run();
|
1072 | }
|
1073 | catch (err) {
|
1074 | if (isListrError(err)) {
|
1075 | const allErrs = err.errors.map(subErr => pluginHelpers.isDetailedError(subErr)
|
1076 | ? `${subErr.message} for "${subErr.source}"${subErr.details}`
|
1077 | : subErr.message || subErr.toString());
|
1078 | const newErr = new utils.AggregateError(err.errors, `${err.message} ${allErrs.join('\n\n')}`);
|
1079 |
|
1080 | newErr.stack = `${newErr.stack}\n\n${err.errors.map(subErr => subErr.stack).join('\n\n')}`;
|
1081 | throw newErr;
|
1082 | }
|
1083 | throw err;
|
1084 | }
|
1085 | return result;
|
1086 | }
|
1087 |
|
1088 | const DEFAULT_HOOKS = {
|
1089 | afterStart: [],
|
1090 | beforeDone: [],
|
1091 | onWatchTriggered: [],
|
1092 | onError: [],
|
1093 | afterOneFileWrite: [],
|
1094 | afterAllFileWrite: [],
|
1095 | beforeOneFileWrite: [],
|
1096 | beforeAllFileWrite: [],
|
1097 | };
|
1098 | function normalizeHooks(_hooks) {
|
1099 | const keys = Object.keys({
|
1100 | ...DEFAULT_HOOKS,
|
1101 | ...(_hooks || {}),
|
1102 | });
|
1103 | return keys.reduce((prev, hookName) => {
|
1104 | if (typeof _hooks[hookName] === 'string') {
|
1105 | return {
|
1106 | ...prev,
|
1107 | [hookName]: [_hooks[hookName]],
|
1108 | };
|
1109 | }
|
1110 | else if (typeof _hooks[hookName] === 'function') {
|
1111 | return {
|
1112 | ...prev,
|
1113 | [hookName]: [_hooks[hookName]],
|
1114 | };
|
1115 | }
|
1116 | else if (Array.isArray(_hooks[hookName])) {
|
1117 | return {
|
1118 | ...prev,
|
1119 | [hookName]: _hooks[hookName],
|
1120 | };
|
1121 | }
|
1122 | else {
|
1123 | return prev;
|
1124 | }
|
1125 | }, {});
|
1126 | }
|
1127 | function execShellCommand(cmd) {
|
1128 | return new Promise((resolve, reject) => {
|
1129 | child_process.exec(cmd, {
|
1130 | env: {
|
1131 | ...process.env,
|
1132 | PATH: `${process.env.PATH}${path.delimiter}${process.cwd()}${path.sep}node_modules${path.sep}.bin`,
|
1133 | },
|
1134 | }, (error, stdout, stderr) => {
|
1135 | if (error) {
|
1136 | reject(error);
|
1137 | }
|
1138 | else {
|
1139 | resolve(stdout || stderr);
|
1140 | }
|
1141 | });
|
1142 | });
|
1143 | }
|
1144 | async function executeHooks(hookName, scripts = [], args = []) {
|
1145 | debugLog(`Running lifecycle hook "${hookName}" scripts...`);
|
1146 | for (const script of scripts) {
|
1147 | if (typeof script === 'string') {
|
1148 | debugLog(`Running lifecycle hook "${hookName}" script: ${script} with args: ${args.join(' ')}...`);
|
1149 | await execShellCommand(`${script} ${args.join(' ')}`);
|
1150 | }
|
1151 | else {
|
1152 | debugLog(`Running lifecycle hook "${hookName}" script: ${script.name} with args: ${args.join(' ')}...`);
|
1153 | await script(...args);
|
1154 | }
|
1155 | }
|
1156 | }
|
1157 | const lifecycleHooks = (_hooks = {}) => {
|
1158 | const hooks = normalizeHooks(_hooks);
|
1159 | return {
|
1160 | afterStart: async () => executeHooks('afterStart', hooks.afterStart),
|
1161 | onWatchTriggered: async (event, path) => executeHooks('onWatchTriggered', hooks.onWatchTriggered, [event, path]),
|
1162 | onError: async (error) => executeHooks('onError', hooks.onError, [`"${error}"`]),
|
1163 | afterOneFileWrite: async (path) => executeHooks('afterOneFileWrite', hooks.afterOneFileWrite, [path]),
|
1164 | afterAllFileWrite: async (paths) => executeHooks('afterAllFileWrite', hooks.afterAllFileWrite, paths),
|
1165 | beforeOneFileWrite: async (path) => executeHooks('beforeOneFileWrite', hooks.beforeOneFileWrite, [path]),
|
1166 | beforeAllFileWrite: async (paths) => executeHooks('beforeAllFileWrite', hooks.beforeAllFileWrite, paths),
|
1167 | beforeDone: async () => executeHooks('beforeDone', hooks.beforeDone),
|
1168 | };
|
1169 | };
|
1170 |
|
1171 | function log(msg) {
|
1172 |
|
1173 | getLogger().info(` ${msg}`);
|
1174 | }
|
1175 | function emitWatching() {
|
1176 | log(`${logSymbols.info} Watching for changes...`);
|
1177 | }
|
1178 | const createWatcher = (initalContext, onNext) => {
|
1179 | debugLog(`[Watcher] Starting watcher...`);
|
1180 | let config = initalContext.getConfig();
|
1181 | const files = [initalContext.filepath].filter(a => a);
|
1182 | const documents = pluginHelpers.normalizeInstanceOrArray(config.documents);
|
1183 | const schemas = pluginHelpers.normalizeInstanceOrArray(config.schema);
|
1184 |
|
1185 | Object.keys(config.generates)
|
1186 | .map(filename => pluginHelpers.normalizeOutputParam(config.generates[filename]))
|
1187 | .forEach(conf => {
|
1188 | schemas.push(...pluginHelpers.normalizeInstanceOrArray(conf.schema));
|
1189 | documents.push(...pluginHelpers.normalizeInstanceOrArray(conf.documents));
|
1190 | });
|
1191 | if (documents) {
|
1192 | documents.forEach(doc => {
|
1193 | if (typeof doc === 'string') {
|
1194 | files.push(doc);
|
1195 | }
|
1196 | else {
|
1197 | files.push(...Object.keys(doc));
|
1198 | }
|
1199 | });
|
1200 | }
|
1201 | schemas.forEach((schema) => {
|
1202 | if (isGlob(schema) || utils.isValidPath(schema)) {
|
1203 | files.push(schema);
|
1204 | }
|
1205 | });
|
1206 | if (typeof config.watch !== 'boolean') {
|
1207 | files.push(...pluginHelpers.normalizeInstanceOrArray(config.watch));
|
1208 | }
|
1209 | let watcher;
|
1210 | const runWatcher = async () => {
|
1211 | var _a, _b;
|
1212 | const chokidar = await new Promise(function (resolve) { resolve(_interopNamespace(require('chokidar'))); });
|
1213 | let isShutdown = false;
|
1214 | const debouncedExec = debounce(() => {
|
1215 | if (!isShutdown) {
|
1216 | executeCodegen(initalContext)
|
1217 | .then(onNext, () => Promise.resolve())
|
1218 | .then(() => emitWatching());
|
1219 | }
|
1220 | }, 100);
|
1221 | emitWatching();
|
1222 | const ignored = [];
|
1223 | Object.keys(config.generates)
|
1224 | .map(filename => ({ filename, config: pluginHelpers.normalizeOutputParam(config.generates[filename]) }))
|
1225 | .forEach(entry => {
|
1226 | if (entry.config.preset) {
|
1227 | const extension = entry.config.presetConfig && entry.config.presetConfig.extension;
|
1228 | if (extension) {
|
1229 | ignored.push(path.join(entry.filename, '**', '*' + extension));
|
1230 | }
|
1231 | }
|
1232 | else {
|
1233 | ignored.push(entry.filename);
|
1234 | }
|
1235 | });
|
1236 | watcher = chokidar.watch(files, {
|
1237 | persistent: true,
|
1238 | ignoreInitial: true,
|
1239 | followSymlinks: true,
|
1240 | cwd: process.cwd(),
|
1241 | disableGlobbing: false,
|
1242 | usePolling: (_a = config.watchConfig) === null || _a === void 0 ? void 0 : _a.usePolling,
|
1243 | interval: (_b = config.watchConfig) === null || _b === void 0 ? void 0 : _b.interval,
|
1244 | depth: 99,
|
1245 | awaitWriteFinish: true,
|
1246 | ignorePermissionErrors: false,
|
1247 | atomic: true,
|
1248 | ignored,
|
1249 | });
|
1250 | debugLog(`[Watcher] Started`);
|
1251 | const shutdown = () => {
|
1252 | isShutdown = true;
|
1253 | debugLog(`[Watcher] Shutting down`);
|
1254 | log(`Shutting down watch...`);
|
1255 | watcher.close();
|
1256 | lifecycleHooks(config.hooks).beforeDone();
|
1257 | };
|
1258 |
|
1259 | watcher.on('all', async (eventName, path$1) => {
|
1260 | lifecycleHooks(config.hooks).onWatchTriggered(eventName, path$1);
|
1261 | debugLog(`[Watcher] triggered due to a file ${eventName} event: ${path$1}`);
|
1262 | const fullPath = path.join(process.cwd(), path$1);
|
1263 |
|
1264 | try {
|
1265 | delete require.cache[fullPath];
|
1266 | }
|
1267 | catch (err) { }
|
1268 | if (eventName === 'change' && config.configFilePath && fullPath === config.configFilePath) {
|
1269 | log(`${logSymbols.info} Config file has changed, reloading...`);
|
1270 | const context = await loadContext(config.configFilePath);
|
1271 | const newParsedConfig = context.getConfig();
|
1272 | newParsedConfig.watch = config.watch;
|
1273 | newParsedConfig.silent = config.silent;
|
1274 | newParsedConfig.overwrite = config.overwrite;
|
1275 | newParsedConfig.configFilePath = config.configFilePath;
|
1276 | config = newParsedConfig;
|
1277 | initalContext.updateConfig(config);
|
1278 | }
|
1279 | debouncedExec();
|
1280 | });
|
1281 | process.once('SIGINT', shutdown);
|
1282 | process.once('SIGTERM', shutdown);
|
1283 | };
|
1284 |
|
1285 | return new Promise((resolve, reject) => {
|
1286 | executeCodegen(initalContext)
|
1287 | .then(onNext, () => Promise.resolve())
|
1288 | .then(runWatcher)
|
1289 | .catch(err => {
|
1290 | watcher.close();
|
1291 | reject(err);
|
1292 | });
|
1293 | });
|
1294 | };
|
1295 |
|
1296 | const { writeFile: fsWriteFile, readFile: fsReadFile, stat: fsStat } = fs.promises;
|
1297 | function writeFile(filepath, content) {
|
1298 | return fsWriteFile(filepath, content);
|
1299 | }
|
1300 | function readFile(filepath) {
|
1301 | return fsReadFile(filepath, 'utf-8');
|
1302 | }
|
1303 | async function fileExists(filePath) {
|
1304 | try {
|
1305 | return (await fsStat(filePath)).isFile();
|
1306 | }
|
1307 | catch (err) {
|
1308 | return false;
|
1309 | }
|
1310 | }
|
1311 | function unlinkFile(filePath, cb) {
|
1312 | fs.unlink(filePath, cb);
|
1313 | }
|
1314 |
|
1315 | const hash = (content) => crypto.createHash('sha1').update(content).digest('base64');
|
1316 | async function generate(input, saveToFile = true) {
|
1317 | const context = ensureContext(input);
|
1318 | const config = context.getConfig();
|
1319 | await context.profiler.run(() => lifecycleHooks(config.hooks).afterStart(), 'Lifecycle: afterStart');
|
1320 | let previouslyGeneratedFilenames = [];
|
1321 | function removeStaleFiles(config, generationResult) {
|
1322 | const filenames = generationResult.map(o => o.filename);
|
1323 |
|
1324 | const staleFilenames = previouslyGeneratedFilenames.filter(f => !filenames.includes(f));
|
1325 | staleFilenames.forEach(filename => {
|
1326 | if (shouldOverwrite(config, filename)) {
|
1327 | return unlinkFile(filename, err => {
|
1328 | const prettyFilename = filename.replace(`${input.cwd || process.cwd()}/`, '');
|
1329 | if (err) {
|
1330 | debugLog(`Cannot remove stale file: ${prettyFilename}\n${err}`);
|
1331 | }
|
1332 | else {
|
1333 | debugLog(`Removed stale file: ${prettyFilename}`);
|
1334 | }
|
1335 | });
|
1336 | }
|
1337 | });
|
1338 | previouslyGeneratedFilenames = filenames;
|
1339 | }
|
1340 | const recentOutputHash = new Map();
|
1341 | async function writeOutput(generationResult) {
|
1342 | if (!saveToFile) {
|
1343 | return generationResult;
|
1344 | }
|
1345 | if (config.watch) {
|
1346 | removeStaleFiles(config, generationResult);
|
1347 | }
|
1348 | await context.profiler.run(async () => {
|
1349 | await lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename));
|
1350 | }, 'Lifecycle: beforeAllFileWrite');
|
1351 | await context.profiler.run(() => Promise.all(generationResult.map(async (result) => {
|
1352 | const exists = await fileExists(result.filename);
|
1353 | if (!shouldOverwrite(config, result.filename) && exists) {
|
1354 | return;
|
1355 | }
|
1356 | const content = result.content || '';
|
1357 | const currentHash = hash(content);
|
1358 | let previousHash = recentOutputHash.get(result.filename);
|
1359 | if (!previousHash && exists) {
|
1360 | previousHash = hash(await readFile(result.filename));
|
1361 | }
|
1362 | if (previousHash && currentHash === previousHash) {
|
1363 | debugLog(`Skipping file (${result.filename}) writing due to indentical hash...`);
|
1364 | return;
|
1365 | }
|
1366 | if (content.length === 0) {
|
1367 | return;
|
1368 | }
|
1369 | recentOutputHash.set(result.filename, currentHash);
|
1370 | const basedir = path.dirname(result.filename);
|
1371 | await lifecycleHooks(result.hooks).beforeOneFileWrite(result.filename);
|
1372 | await lifecycleHooks(config.hooks).beforeOneFileWrite(result.filename);
|
1373 | await mkdirp(basedir);
|
1374 | const absolutePath = path.isAbsolute(result.filename)
|
1375 | ? result.filename
|
1376 | : path.join(input.cwd || process.cwd(), result.filename);
|
1377 | await writeFile(absolutePath, result.content);
|
1378 | await lifecycleHooks(result.hooks).afterOneFileWrite(result.filename);
|
1379 | await lifecycleHooks(config.hooks).afterOneFileWrite(result.filename);
|
1380 | })), 'Write files');
|
1381 | await context.profiler.run(() => lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: afterAllFileWrite');
|
1382 | return generationResult;
|
1383 | }
|
1384 |
|
1385 | if (config.watch) {
|
1386 | return createWatcher(context, writeOutput);
|
1387 | }
|
1388 | const outputFiles = await context.profiler.run(() => executeCodegen(context), 'executeCodegen');
|
1389 | await context.profiler.run(() => writeOutput(outputFiles), 'writeOutput');
|
1390 | await context.profiler.run(() => lifecycleHooks(config.hooks).beforeDone(), 'Lifecycle: beforeDone');
|
1391 | if (context.profilerOutput) {
|
1392 | await writeFile(path.join(context.cwd, context.profilerOutput), JSON.stringify(context.profiler.collect()));
|
1393 | }
|
1394 | return outputFiles;
|
1395 | }
|
1396 | function shouldOverwrite(config, outputPath) {
|
1397 | const globalValue = config.overwrite === undefined ? true : !!config.overwrite;
|
1398 | const outputConfig = config.generates[outputPath];
|
1399 | if (!outputConfig) {
|
1400 | debugLog(`Couldn't find a config of ${outputPath}`);
|
1401 | return globalValue;
|
1402 | }
|
1403 | if (isConfiguredOutput(outputConfig) && typeof outputConfig.overwrite === 'boolean') {
|
1404 | return outputConfig.overwrite;
|
1405 | }
|
1406 | return globalValue;
|
1407 | }
|
1408 | function isConfiguredOutput(output) {
|
1409 | return typeof output.plugins !== 'undefined';
|
1410 | }
|
1411 |
|
1412 |
|
1413 | async function writeConfig(answers, config) {
|
1414 | const YAML = await new Promise(function (resolve) { resolve(_interopNamespace(require('json-to-pretty-yaml'))); }).then(m => ('default' in m ? m.default : m));
|
1415 | const ext = answers.config.toLocaleLowerCase().endsWith('.json') ? 'json' : 'yml';
|
1416 | const content = ext === 'json' ? JSON.stringify(config) : YAML.stringify(config);
|
1417 | const fullPath = path.resolve(process.cwd(), answers.config);
|
1418 | const relativePath = path.relative(process.cwd(), answers.config);
|
1419 | fs.writeFileSync(fullPath, content, {
|
1420 | encoding: 'utf-8',
|
1421 | });
|
1422 | return {
|
1423 | relativePath,
|
1424 | fullPath,
|
1425 | };
|
1426 | }
|
1427 |
|
1428 | async function writePackage(answers, configLocation) {
|
1429 |
|
1430 | const pkgPath = path.resolve(process.cwd(), 'package.json');
|
1431 | const pkgContent = fs.readFileSync(pkgPath, {
|
1432 | encoding: 'utf-8',
|
1433 | });
|
1434 | const pkg = JSON.parse(pkgContent);
|
1435 | const { indent } = detectIndent(pkgContent);
|
1436 | if (!pkg.scripts) {
|
1437 | pkg.scripts = {};
|
1438 | }
|
1439 | pkg.scripts[answers.script] = `graphql-codegen --config ${configLocation}`;
|
1440 |
|
1441 | if (!pkg.devDependencies) {
|
1442 | pkg.devDependencies = {};
|
1443 | }
|
1444 | await Promise.all(answers.plugins.map(async (plugin) => {
|
1445 | pkg.devDependencies[plugin.package] = await getLatestVersion(plugin.package);
|
1446 | }));
|
1447 | if (answers.introspection) {
|
1448 | pkg.devDependencies['@graphql-codegen/introspection'] = await getLatestVersion('@graphql-codegen/introspection');
|
1449 | }
|
1450 | pkg.devDependencies['@graphql-codegen/cli'] = await getLatestVersion('@graphql-codegen/cli');
|
1451 | fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, indent));
|
1452 | }
|
1453 | function bold(str) {
|
1454 | return chalk.bold(str);
|
1455 | }
|
1456 | function grey(str) {
|
1457 | return chalk.grey(str);
|
1458 | }
|
1459 | function italic(str) {
|
1460 | return chalk.italic(str);
|
1461 | }
|
1462 |
|
1463 | var Tags;
|
1464 | (function (Tags) {
|
1465 | Tags["browser"] = "Browser";
|
1466 | Tags["node"] = "Node";
|
1467 | Tags["typescript"] = "TypeScript";
|
1468 | Tags["flow"] = "Flow";
|
1469 | Tags["angular"] = "Angular";
|
1470 | Tags["stencil"] = "Stencil";
|
1471 | Tags["react"] = "React";
|
1472 | Tags["vue"] = "Vue";
|
1473 | })(Tags || (Tags = {}));
|
1474 |
|
1475 | const plugins = [
|
1476 | {
|
1477 | name: `TypeScript ${italic('(required by other typescript plugins)')}`,
|
1478 | package: '@graphql-codegen/typescript',
|
1479 | value: 'typescript',
|
1480 | pathInRepo: 'typescript/typescript',
|
1481 | available: hasTag(Tags.typescript),
|
1482 | shouldBeSelected: tags => oneOf(tags, Tags.angular, Tags.stencil) || allOf(tags, Tags.typescript, Tags.react) || noneOf(tags, Tags.flow),
|
1483 | defaultExtension: '.ts',
|
1484 | },
|
1485 | {
|
1486 | name: `TypeScript Operations ${italic('(operations and fragments)')}`,
|
1487 | package: '@graphql-codegen/typescript-operations',
|
1488 | value: 'typescript-operations',
|
1489 | pathInRepo: 'typescript/operations',
|
1490 | available: tags => allOf(tags, Tags.browser, Tags.typescript),
|
1491 | shouldBeSelected: tags => oneOf(tags, Tags.angular, Tags.stencil) || allOf(tags, Tags.typescript, Tags.react),
|
1492 | defaultExtension: '.ts',
|
1493 | },
|
1494 | {
|
1495 | name: `TypeScript Resolvers ${italic('(strongly typed resolve functions)')}`,
|
1496 | package: '@graphql-codegen/typescript-resolvers',
|
1497 | value: 'typescript-resolvers',
|
1498 | pathInRepo: 'typescript/resolvers',
|
1499 | available: tags => allOf(tags, Tags.node, Tags.typescript),
|
1500 | shouldBeSelected: tags => noneOf(tags, Tags.flow),
|
1501 | defaultExtension: '.ts',
|
1502 | },
|
1503 | {
|
1504 | name: `Flow ${italic('(required by other flow plugins)')}`,
|
1505 | package: '@graphql-codegen/flow',
|
1506 | value: 'flow',
|
1507 | pathInRepo: 'flow/flow',
|
1508 | available: hasTag(Tags.flow),
|
1509 | shouldBeSelected: tags => noneOf(tags, Tags.typescript),
|
1510 | defaultExtension: '.js',
|
1511 | },
|
1512 | {
|
1513 | name: `Flow Operations ${italic('(operations and fragments)')}`,
|
1514 | package: '@graphql-codegen/flow-operations',
|
1515 | value: 'flow-operations',
|
1516 | pathInRepo: 'flow/operations',
|
1517 | available: tags => allOf(tags, Tags.browser, Tags.flow),
|
1518 | shouldBeSelected: tags => noneOf(tags, Tags.typescript),
|
1519 | defaultExtension: '.js',
|
1520 | },
|
1521 | {
|
1522 | name: `Flow Resolvers ${italic('(strongly typed resolve functions)')}`,
|
1523 | package: '@graphql-codegen/flow-resolvers',
|
1524 | value: 'flow-resolvers',
|
1525 | pathInRepo: 'flow/resolvers',
|
1526 | available: tags => allOf(tags, Tags.node, Tags.flow),
|
1527 | shouldBeSelected: tags => noneOf(tags, Tags.typescript),
|
1528 | defaultExtension: '.js',
|
1529 | },
|
1530 | {
|
1531 | name: `TypeScript Apollo Angular ${italic('(typed GQL services)')}`,
|
1532 | package: '@graphql-codegen/typescript-apollo-angular',
|
1533 | value: 'typescript-apollo-angular',
|
1534 | pathInRepo: 'typescript/apollo-angular',
|
1535 | available: hasTag(Tags.angular),
|
1536 | shouldBeSelected: () => true,
|
1537 | defaultExtension: '.js',
|
1538 | },
|
1539 | {
|
1540 | name: `TypeScript Vue Apollo Composition API ${italic('(typed functions)')}`,
|
1541 | package: '@graphql-codegen/typescript-vue-apollo',
|
1542 | value: 'typescript-vue-apollo',
|
1543 | pathInRepo: 'typescript/vue-apollo',
|
1544 | available: tags => allOf(tags, Tags.vue, Tags.typescript),
|
1545 | shouldBeSelected: () => true,
|
1546 | defaultExtension: '.ts',
|
1547 | },
|
1548 | {
|
1549 | name: `TypeScript Vue Apollo Smart Operations ${italic('(typed functions)')}`,
|
1550 | package: '@graphql-codegen/typescript-vue-apollo-smart-ops',
|
1551 | value: 'typescript-vue-apollo-smart-ops',
|
1552 | pathInRepo: 'typescript/vue-apollo-smart-ops',
|
1553 | available: tags => allOf(tags, Tags.vue, Tags.typescript),
|
1554 | shouldBeSelected: () => true,
|
1555 | defaultExtension: '.ts',
|
1556 | },
|
1557 | {
|
1558 | name: `TypeScript React Apollo ${italic('(typed components and HOCs)')}`,
|
1559 | package: '@graphql-codegen/typescript-react-apollo',
|
1560 | value: 'typescript-react-apollo',
|
1561 | pathInRepo: 'typescript/react-apollo',
|
1562 | available: tags => allOf(tags, Tags.react, Tags.typescript),
|
1563 | shouldBeSelected: () => true,
|
1564 | defaultExtension: '.tsx',
|
1565 | },
|
1566 | {
|
1567 | name: `TypeScript Stencil Apollo ${italic('(typed components)')}`,
|
1568 | package: '@graphql-codegen/typescript-stencil-apollo',
|
1569 | value: 'typescript-stencil-apollo',
|
1570 | pathInRepo: 'typescript/stencil-apollo',
|
1571 | available: hasTag(Tags.stencil),
|
1572 | shouldBeSelected: () => true,
|
1573 | defaultExtension: '.tsx',
|
1574 | },
|
1575 | {
|
1576 | name: `TypeScript MongoDB ${italic('(typed MongoDB objects)')}`,
|
1577 | package: '@graphql-codegen/typescript-mongodb',
|
1578 | value: 'typescript-mongodb',
|
1579 | pathInRepo: 'typescript/mongodb',
|
1580 | available: tags => allOf(tags, Tags.node, Tags.typescript),
|
1581 | shouldBeSelected: () => false,
|
1582 | defaultExtension: '.ts',
|
1583 | },
|
1584 | {
|
1585 | name: `TypeScript GraphQL files modules ${italic('(declarations for .graphql files)')}`,
|
1586 | package: '@graphql-codegen/typescript-graphql-files-modules',
|
1587 | value: 'typescript-graphql-files-modules',
|
1588 | pathInRepo: 'typescript/graphql-files-modules',
|
1589 | available: tags => allOf(tags, Tags.browser, Tags.typescript),
|
1590 | shouldBeSelected: () => false,
|
1591 | defaultExtension: '.ts',
|
1592 | },
|
1593 | {
|
1594 | name: `TypeScript GraphQL document nodes ${italic('(embedded GraphQL document)')}`,
|
1595 | package: '@graphql-codegen/typescript-document-nodes',
|
1596 | value: 'typescript-document-nodes',
|
1597 | pathInRepo: 'typescript/document-nodes',
|
1598 | available: tags => allOf(tags, Tags.typescript),
|
1599 | shouldBeSelected: () => false,
|
1600 | defaultExtension: '.ts',
|
1601 | },
|
1602 | {
|
1603 | name: `Introspection Fragment Matcher ${italic('(for Apollo Client)')}`,
|
1604 | package: '@graphql-codegen/fragment-matcher',
|
1605 | value: 'fragment-matcher',
|
1606 | pathInRepo: 'other/fragment-matcher',
|
1607 | available: hasTag(Tags.browser),
|
1608 | shouldBeSelected: () => false,
|
1609 | defaultExtension: '.ts',
|
1610 | },
|
1611 | {
|
1612 | name: `Urql Introspection ${italic('(for Urql Client)')}`,
|
1613 | package: '@graphql-codegen/urql-introspection',
|
1614 | value: 'urql-introspection',
|
1615 | pathInRepo: 'other/urql-introspection',
|
1616 | available: hasTag(Tags.browser),
|
1617 | shouldBeSelected: () => false,
|
1618 | defaultExtension: '.ts',
|
1619 | },
|
1620 | ];
|
1621 | function hasTag(tag) {
|
1622 | return (tags) => tags.includes(tag);
|
1623 | }
|
1624 | function oneOf(list, ...items) {
|
1625 | return list.some(i => items.includes(i));
|
1626 | }
|
1627 | function noneOf(list, ...items) {
|
1628 | return !list.some(i => items.includes(i));
|
1629 | }
|
1630 | function allOf(list, ...items) {
|
1631 | return items.every(i => list.includes(i));
|
1632 | }
|
1633 |
|
1634 | function getQuestions(possibleTargets) {
|
1635 | return [
|
1636 | {
|
1637 | type: 'checkbox',
|
1638 | name: 'targets',
|
1639 | message: `What type of application are you building?`,
|
1640 | choices: getApplicationTypeChoices(possibleTargets),
|
1641 | validate: ((targets) => targets.length > 0),
|
1642 | },
|
1643 | {
|
1644 | type: 'input',
|
1645 | name: 'schema',
|
1646 | message: 'Where is your schema?:',
|
1647 | suffix: grey(' (path or url)'),
|
1648 | default: 'http://localhost:4000',
|
1649 | validate: (str) => str.length > 0,
|
1650 | },
|
1651 | {
|
1652 | type: 'input',
|
1653 | name: 'documents',
|
1654 | message: 'Where are your operations and fragments?:',
|
1655 | when: answers => {
|
1656 |
|
1657 |
|
1658 | answers.targets = normalizeTargets(answers.targets);
|
1659 | return answers.targets.includes(Tags.browser);
|
1660 | },
|
1661 | default: 'src/**/*.graphql',
|
1662 | validate: (str) => str.length > 0,
|
1663 | },
|
1664 | {
|
1665 | type: 'checkbox',
|
1666 | name: 'plugins',
|
1667 | message: 'Pick plugins:',
|
1668 | choices: getPluginChoices,
|
1669 | validate: ((plugins) => plugins.length > 0),
|
1670 | },
|
1671 | {
|
1672 | type: 'input',
|
1673 | name: 'output',
|
1674 | message: 'Where to write the output:',
|
1675 | default: getOutputDefaultValue,
|
1676 | validate: (str) => str.length > 0,
|
1677 | },
|
1678 | {
|
1679 | type: 'confirm',
|
1680 | name: 'introspection',
|
1681 | message: 'Do you want to generate an introspection file?',
|
1682 | },
|
1683 | {
|
1684 | type: 'input',
|
1685 | name: 'config',
|
1686 | message: 'How to name the config file?',
|
1687 | default: 'codegen.yml',
|
1688 | validate: (str) => {
|
1689 | const isNotEmpty = str.length > 0;
|
1690 | const hasCorrectExtension = ['json', 'yml', 'yaml'].some(ext => str.toLocaleLowerCase().endsWith(`.${ext}`));
|
1691 | return isNotEmpty && hasCorrectExtension;
|
1692 | },
|
1693 | },
|
1694 | {
|
1695 | type: 'input',
|
1696 | name: 'script',
|
1697 | message: 'What script in package.json should run the codegen?',
|
1698 | validate: (str) => str.length > 0,
|
1699 | },
|
1700 | ];
|
1701 | }
|
1702 | function getApplicationTypeChoices(possibleTargets) {
|
1703 | function withFlowOrTypescript(tags) {
|
1704 | if (possibleTargets.TypeScript) {
|
1705 | tags.push(Tags.typescript);
|
1706 | }
|
1707 | else if (possibleTargets.Flow) {
|
1708 | tags.push(Tags.flow);
|
1709 | }
|
1710 | else {
|
1711 | tags.push(Tags.flow, Tags.typescript);
|
1712 | }
|
1713 | return tags;
|
1714 | }
|
1715 | return [
|
1716 | {
|
1717 | name: 'Backend - API or server',
|
1718 | key: 'backend',
|
1719 | value: withFlowOrTypescript([Tags.node]),
|
1720 | checked: possibleTargets.Node,
|
1721 | },
|
1722 | {
|
1723 | name: 'Application built with Angular',
|
1724 | key: 'angular',
|
1725 | value: [Tags.angular, Tags.browser, Tags.typescript],
|
1726 | checked: possibleTargets.Angular,
|
1727 | },
|
1728 | {
|
1729 | name: 'Application built with React',
|
1730 | key: 'react',
|
1731 | value: withFlowOrTypescript([Tags.react, Tags.browser]),
|
1732 | checked: possibleTargets.React,
|
1733 | },
|
1734 | {
|
1735 | name: 'Application built with Stencil',
|
1736 | key: 'stencil',
|
1737 | value: [Tags.stencil, Tags.browser, Tags.typescript],
|
1738 | checked: possibleTargets.Stencil,
|
1739 | },
|
1740 | {
|
1741 | name: 'Application built with other framework or vanilla JS',
|
1742 | key: 'client',
|
1743 | value: [Tags.browser, Tags.typescript, Tags.flow],
|
1744 | checked: possibleTargets.Browser && !possibleTargets.Angular && !possibleTargets.React && !possibleTargets.Stencil,
|
1745 | },
|
1746 | ];
|
1747 | }
|
1748 | function getPluginChoices(answers) {
|
1749 | return plugins
|
1750 | .filter(p => p.available(answers.targets))
|
1751 | .map(p => {
|
1752 | return {
|
1753 | name: p.name,
|
1754 | value: p,
|
1755 | checked: p.shouldBeSelected(answers.targets),
|
1756 | };
|
1757 | });
|
1758 | }
|
1759 | function normalizeTargets(targets) {
|
1760 | return [].concat(...targets);
|
1761 | }
|
1762 | function getOutputDefaultValue(answers) {
|
1763 | if (answers.plugins.some(plugin => plugin.defaultExtension === '.tsx')) {
|
1764 | return 'src/generated/graphql.tsx';
|
1765 | }
|
1766 | else if (answers.plugins.some(plugin => plugin.defaultExtension === '.ts')) {
|
1767 | return 'src/generated/graphql.ts';
|
1768 | }
|
1769 | else {
|
1770 | return 'src/generated/graphql.js';
|
1771 | }
|
1772 | }
|
1773 |
|
1774 | async function guessTargets() {
|
1775 | const pkg = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), 'package.json'), {
|
1776 | encoding: 'utf-8',
|
1777 | }));
|
1778 | const dependencies = Object.keys({
|
1779 | ...pkg.dependencies,
|
1780 | ...pkg.devDependencies,
|
1781 | });
|
1782 | return {
|
1783 | [Tags.angular]: isAngular(dependencies),
|
1784 | [Tags.react]: isReact(dependencies),
|
1785 | [Tags.stencil]: isStencil(dependencies),
|
1786 | [Tags.vue]: isVue(dependencies),
|
1787 | [Tags.browser]: false,
|
1788 | [Tags.node]: false,
|
1789 | [Tags.typescript]: isTypescript(dependencies),
|
1790 | [Tags.flow]: isFlow(dependencies),
|
1791 | };
|
1792 | }
|
1793 | function isAngular(dependencies) {
|
1794 | return dependencies.includes('@angular/core');
|
1795 | }
|
1796 | function isReact(dependencies) {
|
1797 | return dependencies.includes('react');
|
1798 | }
|
1799 | function isStencil(dependencies) {
|
1800 | return dependencies.includes('@stencil/core');
|
1801 | }
|
1802 | function isVue(dependencies) {
|
1803 | return dependencies.includes('vue') || dependencies.includes('nuxt');
|
1804 | }
|
1805 | function isTypescript(dependencies) {
|
1806 | return dependencies.includes('typescript');
|
1807 | }
|
1808 | function isFlow(dependencies) {
|
1809 | return dependencies.includes('flow');
|
1810 | }
|
1811 |
|
1812 | function log$1(...msgs) {
|
1813 |
|
1814 | console.log(...msgs);
|
1815 | }
|
1816 | async function init() {
|
1817 | log$1(`
|
1818 | Welcome to ${bold('GraphQL Code Generator')}!
|
1819 | Answer few questions and we will setup everything for you.
|
1820 | `);
|
1821 | const possibleTargets = await guessTargets();
|
1822 | const answers = await inquirer.prompt(getQuestions(possibleTargets));
|
1823 |
|
1824 | const config = {
|
1825 | overwrite: true,
|
1826 | schema: answers.schema,
|
1827 | documents: answers.targets.includes(Tags.browser) ? answers.documents : null,
|
1828 | generates: {
|
1829 | [answers.output]: {
|
1830 | plugins: answers.plugins.map(p => p.value),
|
1831 | },
|
1832 | },
|
1833 | };
|
1834 |
|
1835 | if (answers.introspection) {
|
1836 | addIntrospection(config);
|
1837 | }
|
1838 |
|
1839 | const { relativePath } = await writeConfig(answers, config);
|
1840 | log$1(`Fetching latest versions of selected plugins...`);
|
1841 |
|
1842 | await writePackage(answers, relativePath);
|
1843 |
|
1844 | log$1(`
|
1845 | Config file generated at ${bold(relativePath)}
|
1846 |
|
1847 | ${bold('$ npm install')}
|
1848 |
|
1849 | To install the plugins.
|
1850 |
|
1851 | ${bold(`$ npm run ${answers.script}`)}
|
1852 |
|
1853 | To run GraphQL Code Generator.
|
1854 | `);
|
1855 | }
|
1856 |
|
1857 | function addIntrospection(config) {
|
1858 | config.generates['./graphql.schema.json'] = {
|
1859 | plugins: ['introspection'],
|
1860 | };
|
1861 | }
|
1862 |
|
1863 | async function runCli(cmd) {
|
1864 | await ensureGraphQlPackage();
|
1865 | switch (cmd) {
|
1866 | case 'init':
|
1867 | return init();
|
1868 | default: {
|
1869 | return createContext().then(context => {
|
1870 | return generate(context).catch(async (error) => {
|
1871 | await lifecycleHooks(context.getConfig().hooks).onError(error.toString());
|
1872 | throw error;
|
1873 | });
|
1874 | });
|
1875 | }
|
1876 | }
|
1877 | }
|
1878 | async function ensureGraphQlPackage() {
|
1879 | try {
|
1880 | await new Promise(function (resolve) { resolve(_interopNamespace(require('graphql'))); });
|
1881 | }
|
1882 | catch (e) {
|
1883 | throw new pluginHelpers.DetailedError(`Unable to load "graphql" package. Please make sure to install "graphql" as a dependency!`, `
|
1884 | To install "graphql", run:
|
1885 | yarn add graphql
|
1886 | Or, with NPM:
|
1887 | npm install --save graphql
|
1888 | `);
|
1889 | }
|
1890 | }
|
1891 |
|
1892 | exports.CodegenContext = CodegenContext;
|
1893 | exports.CodegenExtension = CodegenExtension;
|
1894 | exports.buildOptions = buildOptions;
|
1895 | exports.cliError = cliError;
|
1896 | exports.createContext = createContext;
|
1897 | exports.ensureContext = ensureContext;
|
1898 | exports.ensureGraphQlPackage = ensureGraphQlPackage;
|
1899 | exports.executeCodegen = executeCodegen;
|
1900 | exports.findAndLoadGraphQLConfig = findAndLoadGraphQLConfig;
|
1901 | exports.generate = generate;
|
1902 | exports.generateSearchPlaces = generateSearchPlaces;
|
1903 | exports.init = init;
|
1904 | exports.isListrError = isListrError;
|
1905 | exports.loadCodegenConfig = loadCodegenConfig;
|
1906 | exports.loadContext = loadContext;
|
1907 | exports.parseArgv = parseArgv;
|
1908 | exports.runCli = runCli;
|
1909 | exports.updateContextWithCliFlags = updateContextWithCliFlags;
|