@graphql-codegen/cli 2.4.1-alpha-5081829d6.0 → 2.5.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/bin.js CHANGED
@@ -28,6 +28,7 @@ const path = require('path');
28
28
  const path__default = _interopDefault(path);
29
29
  const pluginHelpers = require('@graphql-codegen/plugin-helpers');
30
30
  const core = require('@graphql-codegen/core');
31
+ const utils = require('@graphql-tools/utils');
31
32
  const chalk = _interopDefault(require('chalk'));
32
33
  const logSymbols = _interopDefault(require('log-symbols'));
33
34
  const ansiEscapes = _interopDefault(require('ansi-escapes'));
@@ -55,7 +56,6 @@ const fs__default = _interopDefault(fs);
55
56
  const Listr = _interopDefault(require('listr'));
56
57
  const isGlob = _interopDefault(require('is-glob'));
57
58
  const debounce = _interopDefault(require('debounce'));
58
- const utils = require('@graphql-tools/utils');
59
59
  const mkdirp = _interopDefault(require('mkdirp'));
60
60
  const crypto = require('crypto');
61
61
  const inquirer = _interopDefault(require('inquirer'));
@@ -676,6 +676,10 @@ function buildOptions() {
676
676
  describe: 'Only print errors',
677
677
  type: 'boolean',
678
678
  },
679
+ profile: {
680
+ describe: 'Use profiler to measure performance',
681
+ type: 'boolean',
682
+ },
679
683
  p: {
680
684
  alias: 'project',
681
685
  describe: 'Name of a project in GraphQL Config',
@@ -717,6 +721,9 @@ function updateContextWithCliFlags(context, cliFlags) {
717
721
  if (cliFlags.project) {
718
722
  context.useProject(cliFlags.project);
719
723
  }
724
+ if (cliFlags.profile === true) {
725
+ context.useProfiler();
726
+ }
720
727
  context.updateConfig(config);
721
728
  }
722
729
  class CodegenContext {
@@ -726,6 +733,7 @@ class CodegenContext {
726
733
  this._graphqlConfig = graphqlConfig;
727
734
  this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath;
728
735
  this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd();
736
+ this.profiler = pluginHelpers.createNoopProfiler();
729
737
  }
730
738
  useProject(name) {
731
739
  this._project = name;
@@ -756,6 +764,13 @@ class CodegenContext {
756
764
  ...config,
757
765
  };
758
766
  }
767
+ useProfiler() {
768
+ this.profiler = pluginHelpers.createProfiler();
769
+ const now = new Date(); // 2011-10-05T14:48:00.000Z
770
+ const datetime = now.toISOString().split('.')[0]; // 2011-10-05T14:48:00
771
+ const datetimeNormalized = datetime.replace(/-|:/g, ''); // 20111005T144800
772
+ this.profilerOutput = `codegen-${datetimeNormalized}.json`;
773
+ }
759
774
  getPluginContext() {
760
775
  return this._pluginContext;
761
776
  }
@@ -781,6 +796,33 @@ function ensureContext(input) {
781
796
  return input instanceof CodegenContext ? input : new CodegenContext({ config: input });
782
797
  }
783
798
 
799
+ const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
800
+ const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
801
+
802
+ function isListrError(err) {
803
+ return err.name === 'ListrError' && Array.isArray(err.errors) && err.errors.length > 0;
804
+ }
805
+ function cliError(err, exitOnError = true) {
806
+ let msg;
807
+ if (err instanceof Error) {
808
+ msg = err.message || err.toString();
809
+ }
810
+ else if (typeof err === 'string') {
811
+ msg = err;
812
+ }
813
+ else {
814
+ msg = JSON.stringify(err);
815
+ }
816
+ // eslint-disable-next-line no-console
817
+ console.error(msg);
818
+ if (exitOnError && isNode) {
819
+ process.exit(1);
820
+ }
821
+ else if (exitOnError && isBrowser) {
822
+ throw err;
823
+ }
824
+ }
825
+
784
826
  const makeDefaultLoader = (from) => {
785
827
  if (fs__default.statSync(from).isDirectory()) {
786
828
  from = path__default.join(from, '__fake.js');
@@ -805,19 +847,6 @@ function createCache(loader) {
805
847
  };
806
848
  }
807
849
  async function executeCodegen(input) {
808
- function wrapTask(task, source) {
809
- return async () => {
810
- try {
811
- await Promise.resolve().then(() => task());
812
- }
813
- catch (error) {
814
- if (source && !(error instanceof graphql.GraphQLError)) {
815
- error.source = source;
816
- }
817
- throw error;
818
- }
819
- };
820
- }
821
850
  const context = ensureContext(input);
822
851
  const config = context.getConfig();
823
852
  const pluginContext = context.getPluginContext();
@@ -867,6 +896,21 @@ async function executeCodegen(input) {
867
896
  documents: documents,
868
897
  };
869
898
  });
899
+ function wrapTask(task, source, taskName) {
900
+ return () => {
901
+ return context.profiler.run(async () => {
902
+ try {
903
+ await Promise.resolve().then(() => task());
904
+ }
905
+ catch (error) {
906
+ if (source && !(error instanceof graphql.GraphQLError)) {
907
+ error.source = source;
908
+ }
909
+ throw error;
910
+ }
911
+ }, taskName);
912
+ };
913
+ }
870
914
  async function normalize() {
871
915
  /* Load Require extensions */
872
916
  const requireExtensions = pluginHelpers.normalizeInstanceOrArray(config.require);
@@ -972,7 +1016,7 @@ async function executeCodegen(input) {
972
1016
  const result = await schemaLoadingCache.load(hash);
973
1017
  outputSchemaAst = await result.outputSchemaAst;
974
1018
  outputSchema = result.outputSchema;
975
- }, filename),
1019
+ }, filename, `Load GraphQL schemas: ${filename}`),
976
1020
  },
977
1021
  {
978
1022
  title: 'Load GraphQL documents',
@@ -988,7 +1032,7 @@ async function executeCodegen(input) {
988
1032
  if (documents.length > 0) {
989
1033
  outputDocuments.push(...documents);
990
1034
  }
991
- }, filename),
1035
+ }, filename, `Load GraphQL documents: ${filename}`),
992
1036
  },
993
1037
  {
994
1038
  title: 'Generate',
@@ -1016,7 +1060,7 @@ async function executeCodegen(input) {
1016
1060
  };
1017
1061
  let outputs = [];
1018
1062
  if (hasPreset) {
1019
- outputs = await preset.buildGeneratesSection({
1063
+ outputs = await context.profiler.run(async () => preset.buildGeneratesSection({
1020
1064
  baseOutputDir: filename,
1021
1065
  presetConfig: outputConfig.presetConfig || {},
1022
1066
  plugins: normalizedPluginsArray,
@@ -1026,7 +1070,8 @@ async function executeCodegen(input) {
1026
1070
  config: mergedConfig,
1027
1071
  pluginMap,
1028
1072
  pluginContext,
1029
- });
1073
+ profiler: context.profiler,
1074
+ }), `Build Generates Section: ${filename}`);
1030
1075
  }
1031
1076
  else {
1032
1077
  outputs = [
@@ -1039,6 +1084,7 @@ async function executeCodegen(input) {
1039
1084
  config: mergedConfig,
1040
1085
  pluginMap,
1041
1086
  pluginContext,
1087
+ profiler: context.profiler,
1042
1088
  },
1043
1089
  ];
1044
1090
  }
@@ -1050,8 +1096,8 @@ async function executeCodegen(input) {
1050
1096
  hooks: outputConfig.hooks || {},
1051
1097
  });
1052
1098
  };
1053
- await Promise.all(outputs.map(process));
1054
- }, filename),
1099
+ await context.profiler.run(() => Promise.all(outputs.map(process)), `Codegen: ${filename}`);
1100
+ }, filename, `Generate: ${filename}`),
1055
1101
  },
1056
1102
  ], {
1057
1103
  // it stops when one of tasks failed
@@ -1067,7 +1113,21 @@ async function executeCodegen(input) {
1067
1113
  });
1068
1114
  },
1069
1115
  });
1070
- await listr.run();
1116
+ try {
1117
+ await listr.run();
1118
+ }
1119
+ catch (err) {
1120
+ if (isListrError(err)) {
1121
+ const allErrs = err.errors.map(subErr => pluginHelpers.isDetailedError(subErr)
1122
+ ? `${subErr.message} for "${subErr.source}"${subErr.details}`
1123
+ : subErr.message || subErr.toString());
1124
+ const newErr = new utils.AggregateError(err.errors, `${err.message} ${allErrs.join('\n\n')}`);
1125
+ // Best-effort to all stack traces for debugging
1126
+ newErr.stack = `${newErr.stack}\n\n${err.errors.map(subErr => subErr.stack).join('\n\n')}`;
1127
+ throw newErr;
1128
+ }
1129
+ throw err;
1130
+ }
1071
1131
  return result;
1072
1132
  }
1073
1133
 
@@ -1218,7 +1278,7 @@ const hash = (content) => crypto.createHash('sha1').update(content).digest('base
1218
1278
  async function generate(input, saveToFile = true) {
1219
1279
  const context = ensureContext(input);
1220
1280
  const config = context.getConfig();
1221
- await lifecycleHooks(config.hooks).afterStart();
1281
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterStart(), 'Lifecycle: afterStart');
1222
1282
  let previouslyGeneratedFilenames = [];
1223
1283
  function removeStaleFiles(config, generationResult) {
1224
1284
  const filenames = generationResult.map(o => o.filename);
@@ -1247,8 +1307,8 @@ async function generate(input, saveToFile = true) {
1247
1307
  if (config.watch) {
1248
1308
  removeStaleFiles(config, generationResult);
1249
1309
  }
1250
- await lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename));
1251
- await Promise.all(generationResult.map(async (result) => {
1310
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: beforeAllFileWrite');
1311
+ await context.profiler.run(() => Promise.all(generationResult.map(async (result) => {
1252
1312
  const exists = fileExists(result.filename);
1253
1313
  if (!shouldOverwrite(config, result.filename) && exists) {
1254
1314
  return;
@@ -1260,7 +1320,7 @@ async function generate(input, saveToFile = true) {
1260
1320
  previousHash = hash(readSync(result.filename));
1261
1321
  }
1262
1322
  if (previousHash && currentHash === previousHash) {
1263
- debugLog(`Skipping file (${result.filename}) writing due to indentical hash...`);
1323
+ debugLog(`Skipping file (${result.filename}) writing due to identical hash...`);
1264
1324
  return;
1265
1325
  }
1266
1326
  if (content.length === 0) {
@@ -1277,17 +1337,20 @@ async function generate(input, saveToFile = true) {
1277
1337
  writeSync(absolutePath, result.content);
1278
1338
  await lifecycleHooks(result.hooks).afterOneFileWrite(result.filename);
1279
1339
  await lifecycleHooks(config.hooks).afterOneFileWrite(result.filename);
1280
- }));
1281
- await lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename));
1340
+ })), 'Write files');
1341
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: afterAllFileWrite');
1282
1342
  return generationResult;
1283
1343
  }
1284
1344
  // watch mode
1285
1345
  if (config.watch) {
1286
1346
  return createWatcher(context, writeOutput);
1287
1347
  }
1288
- const outputFiles = await executeCodegen(context);
1289
- await writeOutput(outputFiles);
1290
- lifecycleHooks(config.hooks).beforeDone();
1348
+ const outputFiles = await context.profiler.run(() => executeCodegen(context), 'executeCodegen');
1349
+ await context.profiler.run(() => writeOutput(outputFiles), 'writeOutput');
1350
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeDone(), 'Lifecycle: beforeDone');
1351
+ if (context.profilerOutput) {
1352
+ writeSync(path.join(context.cwd, context.profilerOutput), JSON.stringify(context.profiler.collect()));
1353
+ }
1291
1354
  return outputFiles;
1292
1355
  }
1293
1356
  function shouldOverwrite(config, outputPath) {
@@ -1786,30 +1849,6 @@ async function ensureGraphQlPackage() {
1786
1849
  }
1787
1850
  }
1788
1851
 
1789
- const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
1790
- const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
1791
-
1792
- function cliError(err, exitOnError = true) {
1793
- let msg;
1794
- if (err instanceof Error) {
1795
- msg = err.message || err.toString();
1796
- }
1797
- else if (typeof err === 'string') {
1798
- msg = err;
1799
- }
1800
- else {
1801
- msg = JSON.stringify(err);
1802
- }
1803
- // eslint-disable-next-line no-console
1804
- console.error(msg);
1805
- if (exitOnError && isNode) {
1806
- process.exit(1);
1807
- }
1808
- else if (exitOnError && isBrowser) {
1809
- throw err;
1810
- }
1811
- }
1812
-
1813
1852
  const [, , cmd] = process.argv;
1814
1853
  runCli(cmd)
1815
1854
  .then(() => {
package/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Types } from '@graphql-codegen/plugin-helpers';
1
+ import { Types, Profiler } from '@graphql-codegen/plugin-helpers';
2
2
  import { GraphQLConfig } from 'graphql-config';
3
3
  import { GraphQLSchema } from 'graphql';
4
4
  export declare type YamlCliFlags = {
@@ -9,6 +9,7 @@ export declare type YamlCliFlags = {
9
9
  project: string;
10
10
  silent: boolean;
11
11
  errorsOnly: boolean;
12
+ profile: boolean;
12
13
  };
13
14
  export declare function generateSearchPlaces(moduleName: string): string[];
14
15
  export interface LoadCodegenConfigOptions {
@@ -74,6 +75,10 @@ export declare function buildOptions(): {
74
75
  describe: string;
75
76
  type: "boolean";
76
77
  };
78
+ profile: {
79
+ describe: string;
80
+ type: "boolean";
81
+ };
77
82
  p: {
78
83
  alias: string;
79
84
  describe: string;
@@ -91,6 +96,8 @@ export declare class CodegenContext {
91
96
  private _pluginContext;
92
97
  cwd: string;
93
98
  filepath: string;
99
+ profiler: Profiler;
100
+ profilerOutput?: string;
94
101
  constructor({ config, graphqlConfig, filepath, }: {
95
102
  config?: Types.Config;
96
103
  graphqlConfig?: GraphQLConfig;
@@ -99,6 +106,7 @@ export declare class CodegenContext {
99
106
  useProject(name?: string): void;
100
107
  getConfig<T>(extraConfig?: T): T & Types.Config;
101
108
  updateConfig(config: Partial<Types.Config>): void;
109
+ useProfiler(): void;
102
110
  getPluginContext(): {
103
111
  [key: string]: any;
104
112
  };
package/index.js CHANGED
@@ -25,6 +25,7 @@ function _interopNamespace(e) {
25
25
 
26
26
  const pluginHelpers = require('@graphql-codegen/plugin-helpers');
27
27
  const core = require('@graphql-codegen/core');
28
+ const utils = require('@graphql-tools/utils');
28
29
  const chalk = _interopDefault(require('chalk'));
29
30
  const logSymbols = _interopDefault(require('log-symbols'));
30
31
  const ansiEscapes = _interopDefault(require('ansi-escapes'));
@@ -56,7 +57,6 @@ const Listr = _interopDefault(require('listr'));
56
57
  const child_process = require('child_process');
57
58
  const isGlob = _interopDefault(require('is-glob'));
58
59
  const debounce = _interopDefault(require('debounce'));
59
- const utils = require('@graphql-tools/utils');
60
60
  const mkdirp = _interopDefault(require('mkdirp'));
61
61
  const crypto = require('crypto');
62
62
  const inquirer = _interopDefault(require('inquirer'));
@@ -594,6 +594,10 @@ function buildOptions() {
594
594
  describe: 'Only print errors',
595
595
  type: 'boolean',
596
596
  },
597
+ profile: {
598
+ describe: 'Use profiler to measure performance',
599
+ type: 'boolean',
600
+ },
597
601
  p: {
598
602
  alias: 'project',
599
603
  describe: 'Name of a project in GraphQL Config',
@@ -635,6 +639,9 @@ function updateContextWithCliFlags(context, cliFlags) {
635
639
  if (cliFlags.project) {
636
640
  context.useProject(cliFlags.project);
637
641
  }
642
+ if (cliFlags.profile === true) {
643
+ context.useProfiler();
644
+ }
638
645
  context.updateConfig(config);
639
646
  }
640
647
  class CodegenContext {
@@ -644,6 +651,7 @@ class CodegenContext {
644
651
  this._graphqlConfig = graphqlConfig;
645
652
  this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath;
646
653
  this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd();
654
+ this.profiler = pluginHelpers.createNoopProfiler();
647
655
  }
648
656
  useProject(name) {
649
657
  this._project = name;
@@ -674,6 +682,13 @@ class CodegenContext {
674
682
  ...config,
675
683
  };
676
684
  }
685
+ useProfiler() {
686
+ this.profiler = pluginHelpers.createProfiler();
687
+ const now = new Date(); // 2011-10-05T14:48:00.000Z
688
+ const datetime = now.toISOString().split('.')[0]; // 2011-10-05T14:48:00
689
+ const datetimeNormalized = datetime.replace(/-|:/g, ''); // 20111005T144800
690
+ this.profilerOutput = `codegen-${datetimeNormalized}.json`;
691
+ }
677
692
  getPluginContext() {
678
693
  return this._pluginContext;
679
694
  }
@@ -699,6 +714,33 @@ function ensureContext(input) {
699
714
  return input instanceof CodegenContext ? input : new CodegenContext({ config: input });
700
715
  }
701
716
 
717
+ const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
718
+ const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
719
+
720
+ function isListrError(err) {
721
+ return err.name === 'ListrError' && Array.isArray(err.errors) && err.errors.length > 0;
722
+ }
723
+ function cliError(err, exitOnError = true) {
724
+ let msg;
725
+ if (err instanceof Error) {
726
+ msg = err.message || err.toString();
727
+ }
728
+ else if (typeof err === 'string') {
729
+ msg = err;
730
+ }
731
+ else {
732
+ msg = JSON.stringify(err);
733
+ }
734
+ // eslint-disable-next-line no-console
735
+ console.error(msg);
736
+ if (exitOnError && isNode) {
737
+ process.exit(1);
738
+ }
739
+ else if (exitOnError && isBrowser) {
740
+ throw err;
741
+ }
742
+ }
743
+
702
744
  const makeDefaultLoader = (from) => {
703
745
  if (fs__default.statSync(from).isDirectory()) {
704
746
  from = path__default.join(from, '__fake.js');
@@ -723,19 +765,6 @@ function createCache(loader) {
723
765
  };
724
766
  }
725
767
  async function executeCodegen(input) {
726
- function wrapTask(task, source) {
727
- return async () => {
728
- try {
729
- await Promise.resolve().then(() => task());
730
- }
731
- catch (error) {
732
- if (source && !(error instanceof graphql.GraphQLError)) {
733
- error.source = source;
734
- }
735
- throw error;
736
- }
737
- };
738
- }
739
768
  const context = ensureContext(input);
740
769
  const config = context.getConfig();
741
770
  const pluginContext = context.getPluginContext();
@@ -785,6 +814,21 @@ async function executeCodegen(input) {
785
814
  documents: documents,
786
815
  };
787
816
  });
817
+ function wrapTask(task, source, taskName) {
818
+ return () => {
819
+ return context.profiler.run(async () => {
820
+ try {
821
+ await Promise.resolve().then(() => task());
822
+ }
823
+ catch (error) {
824
+ if (source && !(error instanceof graphql.GraphQLError)) {
825
+ error.source = source;
826
+ }
827
+ throw error;
828
+ }
829
+ }, taskName);
830
+ };
831
+ }
788
832
  async function normalize() {
789
833
  /* Load Require extensions */
790
834
  const requireExtensions = pluginHelpers.normalizeInstanceOrArray(config.require);
@@ -890,7 +934,7 @@ async function executeCodegen(input) {
890
934
  const result = await schemaLoadingCache.load(hash);
891
935
  outputSchemaAst = await result.outputSchemaAst;
892
936
  outputSchema = result.outputSchema;
893
- }, filename),
937
+ }, filename, `Load GraphQL schemas: ${filename}`),
894
938
  },
895
939
  {
896
940
  title: 'Load GraphQL documents',
@@ -906,7 +950,7 @@ async function executeCodegen(input) {
906
950
  if (documents.length > 0) {
907
951
  outputDocuments.push(...documents);
908
952
  }
909
- }, filename),
953
+ }, filename, `Load GraphQL documents: ${filename}`),
910
954
  },
911
955
  {
912
956
  title: 'Generate',
@@ -934,7 +978,7 @@ async function executeCodegen(input) {
934
978
  };
935
979
  let outputs = [];
936
980
  if (hasPreset) {
937
- outputs = await preset.buildGeneratesSection({
981
+ outputs = await context.profiler.run(async () => preset.buildGeneratesSection({
938
982
  baseOutputDir: filename,
939
983
  presetConfig: outputConfig.presetConfig || {},
940
984
  plugins: normalizedPluginsArray,
@@ -944,7 +988,8 @@ async function executeCodegen(input) {
944
988
  config: mergedConfig,
945
989
  pluginMap,
946
990
  pluginContext,
947
- });
991
+ profiler: context.profiler,
992
+ }), `Build Generates Section: ${filename}`);
948
993
  }
949
994
  else {
950
995
  outputs = [
@@ -957,6 +1002,7 @@ async function executeCodegen(input) {
957
1002
  config: mergedConfig,
958
1003
  pluginMap,
959
1004
  pluginContext,
1005
+ profiler: context.profiler,
960
1006
  },
961
1007
  ];
962
1008
  }
@@ -968,8 +1014,8 @@ async function executeCodegen(input) {
968
1014
  hooks: outputConfig.hooks || {},
969
1015
  });
970
1016
  };
971
- await Promise.all(outputs.map(process));
972
- }, filename),
1017
+ await context.profiler.run(() => Promise.all(outputs.map(process)), `Codegen: ${filename}`);
1018
+ }, filename, `Generate: ${filename}`),
973
1019
  },
974
1020
  ], {
975
1021
  // it stops when one of tasks failed
@@ -985,7 +1031,21 @@ async function executeCodegen(input) {
985
1031
  });
986
1032
  },
987
1033
  });
988
- await listr.run();
1034
+ try {
1035
+ await listr.run();
1036
+ }
1037
+ catch (err) {
1038
+ if (isListrError(err)) {
1039
+ const allErrs = err.errors.map(subErr => pluginHelpers.isDetailedError(subErr)
1040
+ ? `${subErr.message} for "${subErr.source}"${subErr.details}`
1041
+ : subErr.message || subErr.toString());
1042
+ const newErr = new utils.AggregateError(err.errors, `${err.message} ${allErrs.join('\n\n')}`);
1043
+ // Best-effort to all stack traces for debugging
1044
+ newErr.stack = `${newErr.stack}\n\n${err.errors.map(subErr => subErr.stack).join('\n\n')}`;
1045
+ throw newErr;
1046
+ }
1047
+ throw err;
1048
+ }
989
1049
  return result;
990
1050
  }
991
1051
 
@@ -1219,7 +1279,7 @@ const hash = (content) => crypto.createHash('sha1').update(content).digest('base
1219
1279
  async function generate(input, saveToFile = true) {
1220
1280
  const context = ensureContext(input);
1221
1281
  const config = context.getConfig();
1222
- await lifecycleHooks(config.hooks).afterStart();
1282
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterStart(), 'Lifecycle: afterStart');
1223
1283
  let previouslyGeneratedFilenames = [];
1224
1284
  function removeStaleFiles(config, generationResult) {
1225
1285
  const filenames = generationResult.map(o => o.filename);
@@ -1248,8 +1308,8 @@ async function generate(input, saveToFile = true) {
1248
1308
  if (config.watch) {
1249
1309
  removeStaleFiles(config, generationResult);
1250
1310
  }
1251
- await lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename));
1252
- await Promise.all(generationResult.map(async (result) => {
1311
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: beforeAllFileWrite');
1312
+ await context.profiler.run(() => Promise.all(generationResult.map(async (result) => {
1253
1313
  const exists = fileExists(result.filename);
1254
1314
  if (!shouldOverwrite(config, result.filename) && exists) {
1255
1315
  return;
@@ -1261,7 +1321,7 @@ async function generate(input, saveToFile = true) {
1261
1321
  previousHash = hash(readSync(result.filename));
1262
1322
  }
1263
1323
  if (previousHash && currentHash === previousHash) {
1264
- debugLog(`Skipping file (${result.filename}) writing due to indentical hash...`);
1324
+ debugLog(`Skipping file (${result.filename}) writing due to identical hash...`);
1265
1325
  return;
1266
1326
  }
1267
1327
  if (content.length === 0) {
@@ -1278,17 +1338,20 @@ async function generate(input, saveToFile = true) {
1278
1338
  writeSync(absolutePath, result.content);
1279
1339
  await lifecycleHooks(result.hooks).afterOneFileWrite(result.filename);
1280
1340
  await lifecycleHooks(config.hooks).afterOneFileWrite(result.filename);
1281
- }));
1282
- await lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename));
1341
+ })), 'Write files');
1342
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: afterAllFileWrite');
1283
1343
  return generationResult;
1284
1344
  }
1285
1345
  // watch mode
1286
1346
  if (config.watch) {
1287
1347
  return createWatcher(context, writeOutput);
1288
1348
  }
1289
- const outputFiles = await executeCodegen(context);
1290
- await writeOutput(outputFiles);
1291
- lifecycleHooks(config.hooks).beforeDone();
1349
+ const outputFiles = await context.profiler.run(() => executeCodegen(context), 'executeCodegen');
1350
+ await context.profiler.run(() => writeOutput(outputFiles), 'writeOutput');
1351
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeDone(), 'Lifecycle: beforeDone');
1352
+ if (context.profilerOutput) {
1353
+ writeSync(path.join(context.cwd, context.profilerOutput), JSON.stringify(context.profiler.collect()));
1354
+ }
1292
1355
  return outputFiles;
1293
1356
  }
1294
1357
  function shouldOverwrite(config, outputPath) {
@@ -1758,30 +1821,6 @@ function addIntrospection(config) {
1758
1821
  };
1759
1822
  }
1760
1823
 
1761
- const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
1762
- const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
1763
-
1764
- function cliError(err, exitOnError = true) {
1765
- let msg;
1766
- if (err instanceof Error) {
1767
- msg = err.message || err.toString();
1768
- }
1769
- else if (typeof err === 'string') {
1770
- msg = err;
1771
- }
1772
- else {
1773
- msg = JSON.stringify(err);
1774
- }
1775
- // eslint-disable-next-line no-console
1776
- console.error(msg);
1777
- if (exitOnError && isNode) {
1778
- process.exit(1);
1779
- }
1780
- else if (exitOnError && isBrowser) {
1781
- throw err;
1782
- }
1783
- }
1784
-
1785
1824
  async function runCli(cmd) {
1786
1825
  await ensureGraphQlPackage();
1787
1826
  switch (cmd) {
@@ -1823,6 +1862,7 @@ exports.findAndLoadGraphQLConfig = findAndLoadGraphQLConfig;
1823
1862
  exports.generate = generate;
1824
1863
  exports.generateSearchPlaces = generateSearchPlaces;
1825
1864
  exports.init = init;
1865
+ exports.isListrError = isListrError;
1826
1866
  exports.loadCodegenConfig = loadCodegenConfig;
1827
1867
  exports.loadContext = loadContext;
1828
1868
  exports.parseArgv = parseArgv;
package/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { isDetailedError, DetailedError, normalizeInstanceOrArray, normalizeConfig, normalizeOutputParam, getCachedDocumentNodeFromSchema } from '@graphql-codegen/plugin-helpers';
1
+ import { isDetailedError, DetailedError, createNoopProfiler, createProfiler, normalizeInstanceOrArray, normalizeConfig, normalizeOutputParam, getCachedDocumentNodeFromSchema } from '@graphql-codegen/plugin-helpers';
2
2
  import { codegen } from '@graphql-codegen/core';
3
+ import { AggregateError, isValidPath } from '@graphql-tools/utils';
3
4
  import chalk from 'chalk';
4
5
  import logSymbols from 'log-symbols';
5
6
  import ansiEscapes from 'ansi-escapes';
@@ -24,12 +25,11 @@ import { JsonFileLoader } from '@graphql-tools/json-file-loader';
24
25
  import { UrlLoader } from '@graphql-tools/url-loader';
25
26
  import yaml from 'yaml';
26
27
  import { createRequire } from 'module';
27
- import fs, { promises, readFileSync, writeFileSync, statSync, unlink } from 'fs';
28
+ import fs, { promises, writeFileSync, readFileSync, statSync, unlink } from 'fs';
28
29
  import Listr from 'listr';
29
30
  import { exec } from 'child_process';
30
31
  import isGlob from 'is-glob';
31
32
  import debounce from 'debounce';
32
- import { isValidPath } from '@graphql-tools/utils';
33
33
  import mkdirp from 'mkdirp';
34
34
  import { createHash } from 'crypto';
35
35
  import inquirer from 'inquirer';
@@ -567,6 +567,10 @@ function buildOptions() {
567
567
  describe: 'Only print errors',
568
568
  type: 'boolean',
569
569
  },
570
+ profile: {
571
+ describe: 'Use profiler to measure performance',
572
+ type: 'boolean',
573
+ },
570
574
  p: {
571
575
  alias: 'project',
572
576
  describe: 'Name of a project in GraphQL Config',
@@ -608,6 +612,9 @@ function updateContextWithCliFlags(context, cliFlags) {
608
612
  if (cliFlags.project) {
609
613
  context.useProject(cliFlags.project);
610
614
  }
615
+ if (cliFlags.profile === true) {
616
+ context.useProfiler();
617
+ }
611
618
  context.updateConfig(config);
612
619
  }
613
620
  class CodegenContext {
@@ -617,6 +624,7 @@ class CodegenContext {
617
624
  this._graphqlConfig = graphqlConfig;
618
625
  this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath;
619
626
  this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd();
627
+ this.profiler = createNoopProfiler();
620
628
  }
621
629
  useProject(name) {
622
630
  this._project = name;
@@ -647,6 +655,13 @@ class CodegenContext {
647
655
  ...config,
648
656
  };
649
657
  }
658
+ useProfiler() {
659
+ this.profiler = createProfiler();
660
+ const now = new Date(); // 2011-10-05T14:48:00.000Z
661
+ const datetime = now.toISOString().split('.')[0]; // 2011-10-05T14:48:00
662
+ const datetimeNormalized = datetime.replace(/-|:/g, ''); // 20111005T144800
663
+ this.profilerOutput = `codegen-${datetimeNormalized}.json`;
664
+ }
650
665
  getPluginContext() {
651
666
  return this._pluginContext;
652
667
  }
@@ -672,6 +687,33 @@ function ensureContext(input) {
672
687
  return input instanceof CodegenContext ? input : new CodegenContext({ config: input });
673
688
  }
674
689
 
690
+ const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
691
+ const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
692
+
693
+ function isListrError(err) {
694
+ return err.name === 'ListrError' && Array.isArray(err.errors) && err.errors.length > 0;
695
+ }
696
+ function cliError(err, exitOnError = true) {
697
+ let msg;
698
+ if (err instanceof Error) {
699
+ msg = err.message || err.toString();
700
+ }
701
+ else if (typeof err === 'string') {
702
+ msg = err;
703
+ }
704
+ else {
705
+ msg = JSON.stringify(err);
706
+ }
707
+ // eslint-disable-next-line no-console
708
+ console.error(msg);
709
+ if (exitOnError && isNode) {
710
+ process.exit(1);
711
+ }
712
+ else if (exitOnError && isBrowser) {
713
+ throw err;
714
+ }
715
+ }
716
+
675
717
  const makeDefaultLoader = (from) => {
676
718
  if (fs.statSync(from).isDirectory()) {
677
719
  from = path.join(from, '__fake.js');
@@ -696,19 +738,6 @@ function createCache(loader) {
696
738
  };
697
739
  }
698
740
  async function executeCodegen(input) {
699
- function wrapTask(task, source) {
700
- return async () => {
701
- try {
702
- await Promise.resolve().then(() => task());
703
- }
704
- catch (error) {
705
- if (source && !(error instanceof GraphQLError)) {
706
- error.source = source;
707
- }
708
- throw error;
709
- }
710
- };
711
- }
712
741
  const context = ensureContext(input);
713
742
  const config = context.getConfig();
714
743
  const pluginContext = context.getPluginContext();
@@ -758,6 +787,21 @@ async function executeCodegen(input) {
758
787
  documents: documents,
759
788
  };
760
789
  });
790
+ function wrapTask(task, source, taskName) {
791
+ return () => {
792
+ return context.profiler.run(async () => {
793
+ try {
794
+ await Promise.resolve().then(() => task());
795
+ }
796
+ catch (error) {
797
+ if (source && !(error instanceof GraphQLError)) {
798
+ error.source = source;
799
+ }
800
+ throw error;
801
+ }
802
+ }, taskName);
803
+ };
804
+ }
761
805
  async function normalize() {
762
806
  /* Load Require extensions */
763
807
  const requireExtensions = normalizeInstanceOrArray(config.require);
@@ -863,7 +907,7 @@ async function executeCodegen(input) {
863
907
  const result = await schemaLoadingCache.load(hash);
864
908
  outputSchemaAst = await result.outputSchemaAst;
865
909
  outputSchema = result.outputSchema;
866
- }, filename),
910
+ }, filename, `Load GraphQL schemas: ${filename}`),
867
911
  },
868
912
  {
869
913
  title: 'Load GraphQL documents',
@@ -879,7 +923,7 @@ async function executeCodegen(input) {
879
923
  if (documents.length > 0) {
880
924
  outputDocuments.push(...documents);
881
925
  }
882
- }, filename),
926
+ }, filename, `Load GraphQL documents: ${filename}`),
883
927
  },
884
928
  {
885
929
  title: 'Generate',
@@ -907,7 +951,7 @@ async function executeCodegen(input) {
907
951
  };
908
952
  let outputs = [];
909
953
  if (hasPreset) {
910
- outputs = await preset.buildGeneratesSection({
954
+ outputs = await context.profiler.run(async () => preset.buildGeneratesSection({
911
955
  baseOutputDir: filename,
912
956
  presetConfig: outputConfig.presetConfig || {},
913
957
  plugins: normalizedPluginsArray,
@@ -917,7 +961,8 @@ async function executeCodegen(input) {
917
961
  config: mergedConfig,
918
962
  pluginMap,
919
963
  pluginContext,
920
- });
964
+ profiler: context.profiler,
965
+ }), `Build Generates Section: ${filename}`);
921
966
  }
922
967
  else {
923
968
  outputs = [
@@ -930,6 +975,7 @@ async function executeCodegen(input) {
930
975
  config: mergedConfig,
931
976
  pluginMap,
932
977
  pluginContext,
978
+ profiler: context.profiler,
933
979
  },
934
980
  ];
935
981
  }
@@ -941,8 +987,8 @@ async function executeCodegen(input) {
941
987
  hooks: outputConfig.hooks || {},
942
988
  });
943
989
  };
944
- await Promise.all(outputs.map(process));
945
- }, filename),
990
+ await context.profiler.run(() => Promise.all(outputs.map(process)), `Codegen: ${filename}`);
991
+ }, filename, `Generate: ${filename}`),
946
992
  },
947
993
  ], {
948
994
  // it stops when one of tasks failed
@@ -958,7 +1004,21 @@ async function executeCodegen(input) {
958
1004
  });
959
1005
  },
960
1006
  });
961
- await listr.run();
1007
+ try {
1008
+ await listr.run();
1009
+ }
1010
+ catch (err) {
1011
+ if (isListrError(err)) {
1012
+ const allErrs = err.errors.map(subErr => isDetailedError(subErr)
1013
+ ? `${subErr.message} for "${subErr.source}"${subErr.details}`
1014
+ : subErr.message || subErr.toString());
1015
+ const newErr = new AggregateError(err.errors, `${err.message} ${allErrs.join('\n\n')}`);
1016
+ // Best-effort to all stack traces for debugging
1017
+ newErr.stack = `${newErr.stack}\n\n${err.errors.map(subErr => subErr.stack).join('\n\n')}`;
1018
+ throw newErr;
1019
+ }
1020
+ throw err;
1021
+ }
962
1022
  return result;
963
1023
  }
964
1024
 
@@ -1192,7 +1252,7 @@ const hash = (content) => createHash('sha1').update(content).digest('base64');
1192
1252
  async function generate(input, saveToFile = true) {
1193
1253
  const context = ensureContext(input);
1194
1254
  const config = context.getConfig();
1195
- await lifecycleHooks(config.hooks).afterStart();
1255
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterStart(), 'Lifecycle: afterStart');
1196
1256
  let previouslyGeneratedFilenames = [];
1197
1257
  function removeStaleFiles(config, generationResult) {
1198
1258
  const filenames = generationResult.map(o => o.filename);
@@ -1221,8 +1281,8 @@ async function generate(input, saveToFile = true) {
1221
1281
  if (config.watch) {
1222
1282
  removeStaleFiles(config, generationResult);
1223
1283
  }
1224
- await lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename));
1225
- await Promise.all(generationResult.map(async (result) => {
1284
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: beforeAllFileWrite');
1285
+ await context.profiler.run(() => Promise.all(generationResult.map(async (result) => {
1226
1286
  const exists = fileExists(result.filename);
1227
1287
  if (!shouldOverwrite(config, result.filename) && exists) {
1228
1288
  return;
@@ -1234,7 +1294,7 @@ async function generate(input, saveToFile = true) {
1234
1294
  previousHash = hash(readSync(result.filename));
1235
1295
  }
1236
1296
  if (previousHash && currentHash === previousHash) {
1237
- debugLog(`Skipping file (${result.filename}) writing due to indentical hash...`);
1297
+ debugLog(`Skipping file (${result.filename}) writing due to identical hash...`);
1238
1298
  return;
1239
1299
  }
1240
1300
  if (content.length === 0) {
@@ -1251,17 +1311,20 @@ async function generate(input, saveToFile = true) {
1251
1311
  writeSync(absolutePath, result.content);
1252
1312
  await lifecycleHooks(result.hooks).afterOneFileWrite(result.filename);
1253
1313
  await lifecycleHooks(config.hooks).afterOneFileWrite(result.filename);
1254
- }));
1255
- await lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename));
1314
+ })), 'Write files');
1315
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: afterAllFileWrite');
1256
1316
  return generationResult;
1257
1317
  }
1258
1318
  // watch mode
1259
1319
  if (config.watch) {
1260
1320
  return createWatcher(context, writeOutput);
1261
1321
  }
1262
- const outputFiles = await executeCodegen(context);
1263
- await writeOutput(outputFiles);
1264
- lifecycleHooks(config.hooks).beforeDone();
1322
+ const outputFiles = await context.profiler.run(() => executeCodegen(context), 'executeCodegen');
1323
+ await context.profiler.run(() => writeOutput(outputFiles), 'writeOutput');
1324
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeDone(), 'Lifecycle: beforeDone');
1325
+ if (context.profilerOutput) {
1326
+ writeSync(join(context.cwd, context.profilerOutput), JSON.stringify(context.profiler.collect()));
1327
+ }
1265
1328
  return outputFiles;
1266
1329
  }
1267
1330
  function shouldOverwrite(config, outputPath) {
@@ -1731,30 +1794,6 @@ function addIntrospection(config) {
1731
1794
  };
1732
1795
  }
1733
1796
 
1734
- const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
1735
- const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
1736
-
1737
- function cliError(err, exitOnError = true) {
1738
- let msg;
1739
- if (err instanceof Error) {
1740
- msg = err.message || err.toString();
1741
- }
1742
- else if (typeof err === 'string') {
1743
- msg = err;
1744
- }
1745
- else {
1746
- msg = JSON.stringify(err);
1747
- }
1748
- // eslint-disable-next-line no-console
1749
- console.error(msg);
1750
- if (exitOnError && isNode) {
1751
- process.exit(1);
1752
- }
1753
- else if (exitOnError && isBrowser) {
1754
- throw err;
1755
- }
1756
- }
1757
-
1758
1797
  async function runCli(cmd) {
1759
1798
  await ensureGraphQlPackage();
1760
1799
  switch (cmd) {
@@ -1784,4 +1823,4 @@ async function ensureGraphQlPackage() {
1784
1823
  }
1785
1824
  }
1786
1825
 
1787
- export { CodegenContext, CodegenExtension, buildOptions, cliError, createContext, ensureContext, ensureGraphQlPackage, executeCodegen, findAndLoadGraphQLConfig, generate, generateSearchPlaces, init, loadCodegenConfig, loadContext, parseArgv, runCli, updateContextWithCliFlags };
1826
+ export { CodegenContext, CodegenExtension, buildOptions, cliError, createContext, ensureContext, ensureGraphQlPackage, executeCodegen, findAndLoadGraphQLConfig, generate, generateSearchPlaces, init, isListrError, loadCodegenConfig, loadContext, parseArgv, runCli, updateContextWithCliFlags };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@graphql-codegen/cli",
3
- "version": "2.4.1-alpha-5081829d6.0",
3
+ "version": "2.5.0",
4
4
  "peerDependencies": {
5
5
  "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
6
6
  },
7
7
  "dependencies": {
8
- "@graphql-codegen/core": "2.4.0",
9
- "@graphql-codegen/plugin-helpers": "^2.3.2",
8
+ "@graphql-codegen/core": "2.5.0",
9
+ "@graphql-codegen/plugin-helpers": "^2.4.0",
10
10
  "@graphql-tools/apollo-engine-loader": "^7.0.5",
11
11
  "@graphql-tools/code-file-loader": "^7.0.6",
12
12
  "@graphql-tools/git-loader": "^7.0.5",
@@ -1 +1,11 @@
1
+ import { DetailedError } from '@graphql-codegen/plugin-helpers';
2
+ declare type CompositeError = Error | DetailedError;
3
+ declare type ListrError = Error & {
4
+ errors: CompositeError[];
5
+ };
6
+ export declare function isListrError(err: Error & {
7
+ name?: unknown;
8
+ errors?: unknown;
9
+ }): err is ListrError;
1
10
  export declare function cliError(err: any, exitOnError?: boolean): void;
11
+ export {};