@graphql-codegen/cli 2.3.0-alpha-5ed8c1163.0 → 2.4.0-alpha-23d229715.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.
Files changed (5) hide show
  1. package/bin.js +61 -34
  2. package/config.d.ts +36 -3
  3. package/index.js +62 -34
  4. package/index.mjs +64 -37
  5. package/package.json +7 -6
package/bin.js CHANGED
@@ -547,6 +547,7 @@ async function loadDocuments(documentPointers, config) {
547
547
  return loadedFromToolkit;
548
548
  }
549
549
 
550
+ const { lstat } = fs.promises;
550
551
  function generateSearchPlaces(moduleName) {
551
552
  const extensions = ['json', 'yaml', 'yml', 'js', 'config.js'];
552
553
  // gives codegen.json...
@@ -579,20 +580,24 @@ function customLoader(ext) {
579
580
  }
580
581
  return loader;
581
582
  }
582
- function loadCodegenConfig(configFilePath) {
583
- const moduleName = 'codegen';
583
+ async function loadCodegenConfig({ configFilePath, moduleName, searchPlaces: additionalSearchPlaces, packageProp, loaders: customLoaders, }) {
584
+ configFilePath = configFilePath || process.cwd();
585
+ moduleName = moduleName || 'codegen';
586
+ packageProp = packageProp || moduleName;
584
587
  const cosmi = cosmiconfig.cosmiconfig(moduleName, {
585
- searchPlaces: generateSearchPlaces(moduleName),
586
- packageProp: moduleName,
588
+ searchPlaces: generateSearchPlaces(moduleName).concat(additionalSearchPlaces || []),
589
+ packageProp,
587
590
  loaders: {
588
591
  '.json': customLoader('json'),
589
592
  '.yaml': customLoader('yaml'),
590
593
  '.yml': customLoader('yaml'),
591
594
  '.js': customLoader('js'),
592
595
  noExt: customLoader('yaml'),
596
+ ...customLoaders,
593
597
  },
594
598
  });
595
- return configFilePath ? cosmi.load(configFilePath) : cosmi.search(process.cwd());
599
+ const pathStats = await lstat(configFilePath);
600
+ return pathStats.isDirectory() ? cosmi.search(configFilePath) : cosmi.load(configFilePath);
596
601
  }
597
602
  async function loadContext(configFilePath) {
598
603
  const graphqlConfig = await findAndLoadGraphQLConfig(configFilePath);
@@ -601,7 +606,7 @@ async function loadContext(configFilePath) {
601
606
  graphqlConfig,
602
607
  });
603
608
  }
604
- const result = await loadCodegenConfig(configFilePath);
609
+ const result = await loadCodegenConfig({ configFilePath });
605
610
  if (!result) {
606
611
  if (configFilePath) {
607
612
  throw new pluginHelpers.DetailedError(`Config ${configFilePath} does not exist`, `
@@ -671,6 +676,10 @@ function buildOptions() {
671
676
  describe: 'Only print errors',
672
677
  type: 'boolean',
673
678
  },
679
+ profile: {
680
+ describe: 'Use profiler to measure performance',
681
+ type: 'boolean',
682
+ },
674
683
  p: {
675
684
  alias: 'project',
676
685
  describe: 'Name of a project in GraphQL Config',
@@ -712,6 +721,9 @@ function updateContextWithCliFlags(context, cliFlags) {
712
721
  if (cliFlags.project) {
713
722
  context.useProject(cliFlags.project);
714
723
  }
724
+ if (cliFlags.profile === true) {
725
+ context.useProfiler();
726
+ }
715
727
  context.updateConfig(config);
716
728
  }
717
729
  class CodegenContext {
@@ -721,6 +733,7 @@ class CodegenContext {
721
733
  this._graphqlConfig = graphqlConfig;
722
734
  this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath;
723
735
  this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd();
736
+ this.profiler = pluginHelpers.createNoopProfiler();
724
737
  }
725
738
  useProject(name) {
726
739
  this._project = name;
@@ -751,6 +764,13 @@ class CodegenContext {
751
764
  ...config,
752
765
  };
753
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
+ }
754
774
  getPluginContext() {
755
775
  return this._pluginContext;
756
776
  }
@@ -786,19 +806,6 @@ const makeDefaultLoader = (from) => {
786
806
  };
787
807
  };
788
808
  async function executeCodegen(input) {
789
- function wrapTask(task, source) {
790
- return async () => {
791
- try {
792
- await Promise.resolve().then(() => task());
793
- }
794
- catch (error) {
795
- if (source && !(error instanceof graphql.GraphQLError)) {
796
- error.source = source;
797
- }
798
- throw error;
799
- }
800
- };
801
- }
802
809
  const context = ensureContext(input);
803
810
  const config = context.getConfig();
804
811
  const pluginContext = context.getPluginContext();
@@ -834,6 +841,21 @@ async function executeCodegen(input) {
834
841
  let rootSchemas;
835
842
  let rootDocuments;
836
843
  const generates = {};
844
+ function wrapTask(task, source, taskName) {
845
+ return () => {
846
+ return context.profiler.run(async () => {
847
+ try {
848
+ await Promise.resolve().then(() => task());
849
+ }
850
+ catch (error) {
851
+ if (source && !(error instanceof graphql.GraphQLError)) {
852
+ error.source = source;
853
+ }
854
+ throw error;
855
+ }
856
+ }, taskName);
857
+ };
858
+ }
837
859
  async function normalize() {
838
860
  /* Load Require extensions */
839
861
  const requireExtensions = pluginHelpers.normalizeInstanceOrArray(config.require);
@@ -937,7 +959,7 @@ async function executeCodegen(input) {
937
959
  }
938
960
  outputSchemaAst = await context.loadSchema(schemaPointerMap);
939
961
  outputSchema = pluginHelpers.getCachedDocumentNodeFromSchema(outputSchemaAst);
940
- }, filename),
962
+ }, filename, `Load GraphQL schemas: ${filename}`),
941
963
  },
942
964
  {
943
965
  title: 'Load GraphQL documents',
@@ -948,7 +970,7 @@ async function executeCodegen(input) {
948
970
  if (documents.length > 0) {
949
971
  outputDocuments.push(...documents);
950
972
  }
951
- }, filename),
973
+ }, filename, `Load GraphQL documents: ${filename}`),
952
974
  },
953
975
  {
954
976
  title: 'Generate',
@@ -976,7 +998,7 @@ async function executeCodegen(input) {
976
998
  };
977
999
  let outputs = [];
978
1000
  if (hasPreset) {
979
- outputs = await preset.buildGeneratesSection({
1001
+ outputs = await context.profiler.run(async () => preset.buildGeneratesSection({
980
1002
  baseOutputDir: filename,
981
1003
  presetConfig: outputConfig.presetConfig || {},
982
1004
  plugins: normalizedPluginsArray,
@@ -986,7 +1008,8 @@ async function executeCodegen(input) {
986
1008
  config: mergedConfig,
987
1009
  pluginMap,
988
1010
  pluginContext,
989
- });
1011
+ profiler: context.profiler,
1012
+ }), `Build Generates Section: ${filename}`);
990
1013
  }
991
1014
  else {
992
1015
  outputs = [
@@ -999,6 +1022,7 @@ async function executeCodegen(input) {
999
1022
  config: mergedConfig,
1000
1023
  pluginMap,
1001
1024
  pluginContext,
1025
+ profiler: context.profiler,
1002
1026
  },
1003
1027
  ];
1004
1028
  }
@@ -1010,8 +1034,8 @@ async function executeCodegen(input) {
1010
1034
  hooks: outputConfig.hooks || {},
1011
1035
  });
1012
1036
  };
1013
- await Promise.all(outputs.map(process));
1014
- }, filename),
1037
+ await context.profiler.run(() => Promise.all(outputs.map(process)), `Codegen: ${filename}`);
1038
+ }, filename, `Generate: ${filename}`),
1015
1039
  },
1016
1040
  ], {
1017
1041
  // it stops when one of tasks failed
@@ -1178,7 +1202,7 @@ const hash = (content) => crypto.createHash('sha1').update(content).digest('base
1178
1202
  async function generate(input, saveToFile = true) {
1179
1203
  const context = ensureContext(input);
1180
1204
  const config = context.getConfig();
1181
- await lifecycleHooks(config.hooks).afterStart();
1205
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterStart(), 'Lifecycle: afterStart');
1182
1206
  let previouslyGeneratedFilenames = [];
1183
1207
  function removeStaleFiles(config, generationResult) {
1184
1208
  const filenames = generationResult.map(o => o.filename);
@@ -1207,8 +1231,8 @@ async function generate(input, saveToFile = true) {
1207
1231
  if (config.watch) {
1208
1232
  removeStaleFiles(config, generationResult);
1209
1233
  }
1210
- await lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename));
1211
- await Promise.all(generationResult.map(async (result) => {
1234
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: beforeAllFileWrite');
1235
+ await context.profiler.run(() => Promise.all(generationResult.map(async (result) => {
1212
1236
  const exists = fileExists(result.filename);
1213
1237
  if (!shouldOverwrite(config, result.filename) && exists) {
1214
1238
  return;
@@ -1220,7 +1244,7 @@ async function generate(input, saveToFile = true) {
1220
1244
  previousHash = hash(readSync(result.filename));
1221
1245
  }
1222
1246
  if (previousHash && currentHash === previousHash) {
1223
- debugLog(`Skipping file (${result.filename}) writing due to indentical hash...`);
1247
+ debugLog(`Skipping file (${result.filename}) writing due to identical hash...`);
1224
1248
  return;
1225
1249
  }
1226
1250
  if (content.length === 0) {
@@ -1237,17 +1261,20 @@ async function generate(input, saveToFile = true) {
1237
1261
  writeSync(absolutePath, result.content);
1238
1262
  await lifecycleHooks(result.hooks).afterOneFileWrite(result.filename);
1239
1263
  await lifecycleHooks(config.hooks).afterOneFileWrite(result.filename);
1240
- }));
1241
- await lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename));
1264
+ })), 'Write files');
1265
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: afterAllFileWrite');
1242
1266
  return generationResult;
1243
1267
  }
1244
1268
  // watch mode
1245
1269
  if (config.watch) {
1246
1270
  return createWatcher(context, writeOutput);
1247
1271
  }
1248
- const outputFiles = await executeCodegen(context);
1249
- await writeOutput(outputFiles);
1250
- lifecycleHooks(config.hooks).beforeDone();
1272
+ const outputFiles = await context.profiler.run(() => executeCodegen(context), 'executeCodegen');
1273
+ await context.profiler.run(() => writeOutput(outputFiles), 'writeOutput');
1274
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeDone(), 'Lifecycle: beforeDone');
1275
+ if (context.profilerOutput) {
1276
+ writeSync(path.join(context.cwd, context.profilerOutput), JSON.stringify(context.profiler.collect()));
1277
+ }
1251
1278
  return outputFiles;
1252
1279
  }
1253
1280
  function shouldOverwrite(config, outputPath) {
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,13 +9,39 @@ export declare type YamlCliFlags = {
9
9
  project: string;
10
10
  silent: boolean;
11
11
  errorsOnly: boolean;
12
+ profile: boolean;
12
13
  };
13
- export interface LoadedCodegenConfig {
14
+ export declare function generateSearchPlaces(moduleName: string): string[];
15
+ export interface LoadCodegenConfigOptions {
16
+ /**
17
+ * The path to the config file or directory contains the config file.
18
+ * @default process.cwd()
19
+ */
20
+ configFilePath?: string;
21
+ /**
22
+ * The name of the config file
23
+ * @default codegen
24
+ */
25
+ moduleName?: string;
26
+ /**
27
+ * Additional search paths for the config file you want to check
28
+ */
29
+ searchPlaces?: string[];
30
+ /**
31
+ * @default codegen
32
+ */
33
+ packageProp?: string;
34
+ /**
35
+ * Overrides or extends the loaders for specific file extensions
36
+ */
37
+ loaders?: Record<string, (filepath: string, content: string) => Promise<Types.Config> | Types.Config>;
38
+ }
39
+ export interface LoadCodegenConfigResult {
14
40
  filepath: string;
15
41
  config: Types.Config;
16
42
  isEmpty?: boolean;
17
43
  }
18
- export declare function loadCodegenConfig(configFilePath?: string): Promise<LoadedCodegenConfig>;
44
+ export declare function loadCodegenConfig({ configFilePath, moduleName, searchPlaces: additionalSearchPlaces, packageProp, loaders: customLoaders, }: LoadCodegenConfigOptions): Promise<LoadCodegenConfigResult>;
19
45
  export declare function loadContext(configFilePath?: string): Promise<CodegenContext> | never;
20
46
  export declare function buildOptions(): {
21
47
  c: {
@@ -49,6 +75,10 @@ export declare function buildOptions(): {
49
75
  describe: string;
50
76
  type: "boolean";
51
77
  };
78
+ profile: {
79
+ describe: string;
80
+ type: "boolean";
81
+ };
52
82
  p: {
53
83
  alias: string;
54
84
  describe: string;
@@ -66,6 +96,8 @@ export declare class CodegenContext {
66
96
  private _pluginContext;
67
97
  cwd: string;
68
98
  filepath: string;
99
+ profiler: Profiler;
100
+ profilerOutput?: string;
69
101
  constructor({ config, graphqlConfig, filepath, }: {
70
102
  config?: Types.Config;
71
103
  graphqlConfig?: GraphQLConfig;
@@ -74,6 +106,7 @@ export declare class CodegenContext {
74
106
  useProject(name?: string): void;
75
107
  getConfig<T>(extraConfig?: T): T & Types.Config;
76
108
  updateConfig(config: Partial<Types.Config>): void;
109
+ useProfiler(): void;
77
110
  getPluginContext(): {
78
111
  [key: string]: any;
79
112
  };
package/index.js CHANGED
@@ -465,6 +465,7 @@ async function loadDocuments(documentPointers, config) {
465
465
  return loadedFromToolkit;
466
466
  }
467
467
 
468
+ const { lstat } = fs.promises;
468
469
  function generateSearchPlaces(moduleName) {
469
470
  const extensions = ['json', 'yaml', 'yml', 'js', 'config.js'];
470
471
  // gives codegen.json...
@@ -497,20 +498,24 @@ function customLoader(ext) {
497
498
  }
498
499
  return loader;
499
500
  }
500
- function loadCodegenConfig(configFilePath) {
501
- const moduleName = 'codegen';
501
+ async function loadCodegenConfig({ configFilePath, moduleName, searchPlaces: additionalSearchPlaces, packageProp, loaders: customLoaders, }) {
502
+ configFilePath = configFilePath || process.cwd();
503
+ moduleName = moduleName || 'codegen';
504
+ packageProp = packageProp || moduleName;
502
505
  const cosmi = cosmiconfig.cosmiconfig(moduleName, {
503
- searchPlaces: generateSearchPlaces(moduleName),
504
- packageProp: moduleName,
506
+ searchPlaces: generateSearchPlaces(moduleName).concat(additionalSearchPlaces || []),
507
+ packageProp,
505
508
  loaders: {
506
509
  '.json': customLoader('json'),
507
510
  '.yaml': customLoader('yaml'),
508
511
  '.yml': customLoader('yaml'),
509
512
  '.js': customLoader('js'),
510
513
  noExt: customLoader('yaml'),
514
+ ...customLoaders,
511
515
  },
512
516
  });
513
- return configFilePath ? cosmi.load(configFilePath) : cosmi.search(process.cwd());
517
+ const pathStats = await lstat(configFilePath);
518
+ return pathStats.isDirectory() ? cosmi.search(configFilePath) : cosmi.load(configFilePath);
514
519
  }
515
520
  async function loadContext(configFilePath) {
516
521
  const graphqlConfig = await findAndLoadGraphQLConfig(configFilePath);
@@ -519,7 +524,7 @@ async function loadContext(configFilePath) {
519
524
  graphqlConfig,
520
525
  });
521
526
  }
522
- const result = await loadCodegenConfig(configFilePath);
527
+ const result = await loadCodegenConfig({ configFilePath });
523
528
  if (!result) {
524
529
  if (configFilePath) {
525
530
  throw new pluginHelpers.DetailedError(`Config ${configFilePath} does not exist`, `
@@ -589,6 +594,10 @@ function buildOptions() {
589
594
  describe: 'Only print errors',
590
595
  type: 'boolean',
591
596
  },
597
+ profile: {
598
+ describe: 'Use profiler to measure performance',
599
+ type: 'boolean',
600
+ },
592
601
  p: {
593
602
  alias: 'project',
594
603
  describe: 'Name of a project in GraphQL Config',
@@ -630,6 +639,9 @@ function updateContextWithCliFlags(context, cliFlags) {
630
639
  if (cliFlags.project) {
631
640
  context.useProject(cliFlags.project);
632
641
  }
642
+ if (cliFlags.profile === true) {
643
+ context.useProfiler();
644
+ }
633
645
  context.updateConfig(config);
634
646
  }
635
647
  class CodegenContext {
@@ -639,6 +651,7 @@ class CodegenContext {
639
651
  this._graphqlConfig = graphqlConfig;
640
652
  this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath;
641
653
  this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd();
654
+ this.profiler = pluginHelpers.createNoopProfiler();
642
655
  }
643
656
  useProject(name) {
644
657
  this._project = name;
@@ -669,6 +682,13 @@ class CodegenContext {
669
682
  ...config,
670
683
  };
671
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
+ }
672
692
  getPluginContext() {
673
693
  return this._pluginContext;
674
694
  }
@@ -704,19 +724,6 @@ const makeDefaultLoader = (from) => {
704
724
  };
705
725
  };
706
726
  async function executeCodegen(input) {
707
- function wrapTask(task, source) {
708
- return async () => {
709
- try {
710
- await Promise.resolve().then(() => task());
711
- }
712
- catch (error) {
713
- if (source && !(error instanceof graphql.GraphQLError)) {
714
- error.source = source;
715
- }
716
- throw error;
717
- }
718
- };
719
- }
720
727
  const context = ensureContext(input);
721
728
  const config = context.getConfig();
722
729
  const pluginContext = context.getPluginContext();
@@ -752,6 +759,21 @@ async function executeCodegen(input) {
752
759
  let rootSchemas;
753
760
  let rootDocuments;
754
761
  const generates = {};
762
+ function wrapTask(task, source, taskName) {
763
+ return () => {
764
+ return context.profiler.run(async () => {
765
+ try {
766
+ await Promise.resolve().then(() => task());
767
+ }
768
+ catch (error) {
769
+ if (source && !(error instanceof graphql.GraphQLError)) {
770
+ error.source = source;
771
+ }
772
+ throw error;
773
+ }
774
+ }, taskName);
775
+ };
776
+ }
755
777
  async function normalize() {
756
778
  /* Load Require extensions */
757
779
  const requireExtensions = pluginHelpers.normalizeInstanceOrArray(config.require);
@@ -855,7 +877,7 @@ async function executeCodegen(input) {
855
877
  }
856
878
  outputSchemaAst = await context.loadSchema(schemaPointerMap);
857
879
  outputSchema = pluginHelpers.getCachedDocumentNodeFromSchema(outputSchemaAst);
858
- }, filename),
880
+ }, filename, `Load GraphQL schemas: ${filename}`),
859
881
  },
860
882
  {
861
883
  title: 'Load GraphQL documents',
@@ -866,7 +888,7 @@ async function executeCodegen(input) {
866
888
  if (documents.length > 0) {
867
889
  outputDocuments.push(...documents);
868
890
  }
869
- }, filename),
891
+ }, filename, `Load GraphQL documents: ${filename}`),
870
892
  },
871
893
  {
872
894
  title: 'Generate',
@@ -894,7 +916,7 @@ async function executeCodegen(input) {
894
916
  };
895
917
  let outputs = [];
896
918
  if (hasPreset) {
897
- outputs = await preset.buildGeneratesSection({
919
+ outputs = await context.profiler.run(async () => preset.buildGeneratesSection({
898
920
  baseOutputDir: filename,
899
921
  presetConfig: outputConfig.presetConfig || {},
900
922
  plugins: normalizedPluginsArray,
@@ -904,7 +926,8 @@ async function executeCodegen(input) {
904
926
  config: mergedConfig,
905
927
  pluginMap,
906
928
  pluginContext,
907
- });
929
+ profiler: context.profiler,
930
+ }), `Build Generates Section: ${filename}`);
908
931
  }
909
932
  else {
910
933
  outputs = [
@@ -917,6 +940,7 @@ async function executeCodegen(input) {
917
940
  config: mergedConfig,
918
941
  pluginMap,
919
942
  pluginContext,
943
+ profiler: context.profiler,
920
944
  },
921
945
  ];
922
946
  }
@@ -928,8 +952,8 @@ async function executeCodegen(input) {
928
952
  hooks: outputConfig.hooks || {},
929
953
  });
930
954
  };
931
- await Promise.all(outputs.map(process));
932
- }, filename),
955
+ await context.profiler.run(() => Promise.all(outputs.map(process)), `Codegen: ${filename}`);
956
+ }, filename, `Generate: ${filename}`),
933
957
  },
934
958
  ], {
935
959
  // it stops when one of tasks failed
@@ -1179,7 +1203,7 @@ const hash = (content) => crypto.createHash('sha1').update(content).digest('base
1179
1203
  async function generate(input, saveToFile = true) {
1180
1204
  const context = ensureContext(input);
1181
1205
  const config = context.getConfig();
1182
- await lifecycleHooks(config.hooks).afterStart();
1206
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterStart(), 'Lifecycle: afterStart');
1183
1207
  let previouslyGeneratedFilenames = [];
1184
1208
  function removeStaleFiles(config, generationResult) {
1185
1209
  const filenames = generationResult.map(o => o.filename);
@@ -1208,8 +1232,8 @@ async function generate(input, saveToFile = true) {
1208
1232
  if (config.watch) {
1209
1233
  removeStaleFiles(config, generationResult);
1210
1234
  }
1211
- await lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename));
1212
- await Promise.all(generationResult.map(async (result) => {
1235
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: beforeAllFileWrite');
1236
+ await context.profiler.run(() => Promise.all(generationResult.map(async (result) => {
1213
1237
  const exists = fileExists(result.filename);
1214
1238
  if (!shouldOverwrite(config, result.filename) && exists) {
1215
1239
  return;
@@ -1221,7 +1245,7 @@ async function generate(input, saveToFile = true) {
1221
1245
  previousHash = hash(readSync(result.filename));
1222
1246
  }
1223
1247
  if (previousHash && currentHash === previousHash) {
1224
- debugLog(`Skipping file (${result.filename}) writing due to indentical hash...`);
1248
+ debugLog(`Skipping file (${result.filename}) writing due to identical hash...`);
1225
1249
  return;
1226
1250
  }
1227
1251
  if (content.length === 0) {
@@ -1238,17 +1262,20 @@ async function generate(input, saveToFile = true) {
1238
1262
  writeSync(absolutePath, result.content);
1239
1263
  await lifecycleHooks(result.hooks).afterOneFileWrite(result.filename);
1240
1264
  await lifecycleHooks(config.hooks).afterOneFileWrite(result.filename);
1241
- }));
1242
- await lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename));
1265
+ })), 'Write files');
1266
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: afterAllFileWrite');
1243
1267
  return generationResult;
1244
1268
  }
1245
1269
  // watch mode
1246
1270
  if (config.watch) {
1247
1271
  return createWatcher(context, writeOutput);
1248
1272
  }
1249
- const outputFiles = await executeCodegen(context);
1250
- await writeOutput(outputFiles);
1251
- lifecycleHooks(config.hooks).beforeDone();
1273
+ const outputFiles = await context.profiler.run(() => executeCodegen(context), 'executeCodegen');
1274
+ await context.profiler.run(() => writeOutput(outputFiles), 'writeOutput');
1275
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeDone(), 'Lifecycle: beforeDone');
1276
+ if (context.profilerOutput) {
1277
+ writeSync(path.join(context.cwd, context.profilerOutput), JSON.stringify(context.profiler.collect()));
1278
+ }
1252
1279
  return outputFiles;
1253
1280
  }
1254
1281
  function shouldOverwrite(config, outputPath) {
@@ -1781,6 +1808,7 @@ exports.ensureGraphQlPackage = ensureGraphQlPackage;
1781
1808
  exports.executeCodegen = executeCodegen;
1782
1809
  exports.findAndLoadGraphQLConfig = findAndLoadGraphQLConfig;
1783
1810
  exports.generate = generate;
1811
+ exports.generateSearchPlaces = generateSearchPlaces;
1784
1812
  exports.init = init;
1785
1813
  exports.loadCodegenConfig = loadCodegenConfig;
1786
1814
  exports.loadContext = loadContext;
package/index.mjs CHANGED
@@ -1,4 +1,4 @@
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
3
  import chalk from 'chalk';
4
4
  import logSymbols from 'log-symbols';
@@ -24,7 +24,7 @@ import { JsonFileLoader } from '@graphql-tools/json-file-loader';
24
24
  import { UrlLoader } from '@graphql-tools/url-loader';
25
25
  import yaml from 'yaml';
26
26
  import { createRequire } from 'module';
27
- import fs, { readFileSync, writeFileSync, statSync, unlink } from 'fs';
27
+ import fs, { promises, writeFileSync, readFileSync, statSync, unlink } from 'fs';
28
28
  import Listr from 'listr';
29
29
  import { exec } from 'child_process';
30
30
  import isGlob from 'is-glob';
@@ -438,6 +438,7 @@ async function loadDocuments(documentPointers, config) {
438
438
  return loadedFromToolkit;
439
439
  }
440
440
 
441
+ const { lstat } = promises;
441
442
  function generateSearchPlaces(moduleName) {
442
443
  const extensions = ['json', 'yaml', 'yml', 'js', 'config.js'];
443
444
  // gives codegen.json...
@@ -470,20 +471,24 @@ function customLoader(ext) {
470
471
  }
471
472
  return loader;
472
473
  }
473
- function loadCodegenConfig(configFilePath) {
474
- const moduleName = 'codegen';
474
+ async function loadCodegenConfig({ configFilePath, moduleName, searchPlaces: additionalSearchPlaces, packageProp, loaders: customLoaders, }) {
475
+ configFilePath = configFilePath || process.cwd();
476
+ moduleName = moduleName || 'codegen';
477
+ packageProp = packageProp || moduleName;
475
478
  const cosmi = cosmiconfig(moduleName, {
476
- searchPlaces: generateSearchPlaces(moduleName),
477
- packageProp: moduleName,
479
+ searchPlaces: generateSearchPlaces(moduleName).concat(additionalSearchPlaces || []),
480
+ packageProp,
478
481
  loaders: {
479
482
  '.json': customLoader('json'),
480
483
  '.yaml': customLoader('yaml'),
481
484
  '.yml': customLoader('yaml'),
482
485
  '.js': customLoader('js'),
483
486
  noExt: customLoader('yaml'),
487
+ ...customLoaders,
484
488
  },
485
489
  });
486
- return configFilePath ? cosmi.load(configFilePath) : cosmi.search(process.cwd());
490
+ const pathStats = await lstat(configFilePath);
491
+ return pathStats.isDirectory() ? cosmi.search(configFilePath) : cosmi.load(configFilePath);
487
492
  }
488
493
  async function loadContext(configFilePath) {
489
494
  const graphqlConfig = await findAndLoadGraphQLConfig(configFilePath);
@@ -492,7 +497,7 @@ async function loadContext(configFilePath) {
492
497
  graphqlConfig,
493
498
  });
494
499
  }
495
- const result = await loadCodegenConfig(configFilePath);
500
+ const result = await loadCodegenConfig({ configFilePath });
496
501
  if (!result) {
497
502
  if (configFilePath) {
498
503
  throw new DetailedError(`Config ${configFilePath} does not exist`, `
@@ -562,6 +567,10 @@ function buildOptions() {
562
567
  describe: 'Only print errors',
563
568
  type: 'boolean',
564
569
  },
570
+ profile: {
571
+ describe: 'Use profiler to measure performance',
572
+ type: 'boolean',
573
+ },
565
574
  p: {
566
575
  alias: 'project',
567
576
  describe: 'Name of a project in GraphQL Config',
@@ -603,6 +612,9 @@ function updateContextWithCliFlags(context, cliFlags) {
603
612
  if (cliFlags.project) {
604
613
  context.useProject(cliFlags.project);
605
614
  }
615
+ if (cliFlags.profile === true) {
616
+ context.useProfiler();
617
+ }
606
618
  context.updateConfig(config);
607
619
  }
608
620
  class CodegenContext {
@@ -612,6 +624,7 @@ class CodegenContext {
612
624
  this._graphqlConfig = graphqlConfig;
613
625
  this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath;
614
626
  this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd();
627
+ this.profiler = createNoopProfiler();
615
628
  }
616
629
  useProject(name) {
617
630
  this._project = name;
@@ -642,6 +655,13 @@ class CodegenContext {
642
655
  ...config,
643
656
  };
644
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
+ }
645
665
  getPluginContext() {
646
666
  return this._pluginContext;
647
667
  }
@@ -677,19 +697,6 @@ const makeDefaultLoader = (from) => {
677
697
  };
678
698
  };
679
699
  async function executeCodegen(input) {
680
- function wrapTask(task, source) {
681
- return async () => {
682
- try {
683
- await Promise.resolve().then(() => task());
684
- }
685
- catch (error) {
686
- if (source && !(error instanceof GraphQLError)) {
687
- error.source = source;
688
- }
689
- throw error;
690
- }
691
- };
692
- }
693
700
  const context = ensureContext(input);
694
701
  const config = context.getConfig();
695
702
  const pluginContext = context.getPluginContext();
@@ -725,6 +732,21 @@ async function executeCodegen(input) {
725
732
  let rootSchemas;
726
733
  let rootDocuments;
727
734
  const generates = {};
735
+ function wrapTask(task, source, taskName) {
736
+ return () => {
737
+ return context.profiler.run(async () => {
738
+ try {
739
+ await Promise.resolve().then(() => task());
740
+ }
741
+ catch (error) {
742
+ if (source && !(error instanceof GraphQLError)) {
743
+ error.source = source;
744
+ }
745
+ throw error;
746
+ }
747
+ }, taskName);
748
+ };
749
+ }
728
750
  async function normalize() {
729
751
  /* Load Require extensions */
730
752
  const requireExtensions = normalizeInstanceOrArray(config.require);
@@ -828,7 +850,7 @@ async function executeCodegen(input) {
828
850
  }
829
851
  outputSchemaAst = await context.loadSchema(schemaPointerMap);
830
852
  outputSchema = getCachedDocumentNodeFromSchema(outputSchemaAst);
831
- }, filename),
853
+ }, filename, `Load GraphQL schemas: ${filename}`),
832
854
  },
833
855
  {
834
856
  title: 'Load GraphQL documents',
@@ -839,7 +861,7 @@ async function executeCodegen(input) {
839
861
  if (documents.length > 0) {
840
862
  outputDocuments.push(...documents);
841
863
  }
842
- }, filename),
864
+ }, filename, `Load GraphQL documents: ${filename}`),
843
865
  },
844
866
  {
845
867
  title: 'Generate',
@@ -867,7 +889,7 @@ async function executeCodegen(input) {
867
889
  };
868
890
  let outputs = [];
869
891
  if (hasPreset) {
870
- outputs = await preset.buildGeneratesSection({
892
+ outputs = await context.profiler.run(async () => preset.buildGeneratesSection({
871
893
  baseOutputDir: filename,
872
894
  presetConfig: outputConfig.presetConfig || {},
873
895
  plugins: normalizedPluginsArray,
@@ -877,7 +899,8 @@ async function executeCodegen(input) {
877
899
  config: mergedConfig,
878
900
  pluginMap,
879
901
  pluginContext,
880
- });
902
+ profiler: context.profiler,
903
+ }), `Build Generates Section: ${filename}`);
881
904
  }
882
905
  else {
883
906
  outputs = [
@@ -890,6 +913,7 @@ async function executeCodegen(input) {
890
913
  config: mergedConfig,
891
914
  pluginMap,
892
915
  pluginContext,
916
+ profiler: context.profiler,
893
917
  },
894
918
  ];
895
919
  }
@@ -901,8 +925,8 @@ async function executeCodegen(input) {
901
925
  hooks: outputConfig.hooks || {},
902
926
  });
903
927
  };
904
- await Promise.all(outputs.map(process));
905
- }, filename),
928
+ await context.profiler.run(() => Promise.all(outputs.map(process)), `Codegen: ${filename}`);
929
+ }, filename, `Generate: ${filename}`),
906
930
  },
907
931
  ], {
908
932
  // it stops when one of tasks failed
@@ -1152,7 +1176,7 @@ const hash = (content) => createHash('sha1').update(content).digest('base64');
1152
1176
  async function generate(input, saveToFile = true) {
1153
1177
  const context = ensureContext(input);
1154
1178
  const config = context.getConfig();
1155
- await lifecycleHooks(config.hooks).afterStart();
1179
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterStart(), 'Lifecycle: afterStart');
1156
1180
  let previouslyGeneratedFilenames = [];
1157
1181
  function removeStaleFiles(config, generationResult) {
1158
1182
  const filenames = generationResult.map(o => o.filename);
@@ -1181,8 +1205,8 @@ async function generate(input, saveToFile = true) {
1181
1205
  if (config.watch) {
1182
1206
  removeStaleFiles(config, generationResult);
1183
1207
  }
1184
- await lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename));
1185
- await Promise.all(generationResult.map(async (result) => {
1208
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: beforeAllFileWrite');
1209
+ await context.profiler.run(() => Promise.all(generationResult.map(async (result) => {
1186
1210
  const exists = fileExists(result.filename);
1187
1211
  if (!shouldOverwrite(config, result.filename) && exists) {
1188
1212
  return;
@@ -1194,7 +1218,7 @@ async function generate(input, saveToFile = true) {
1194
1218
  previousHash = hash(readSync(result.filename));
1195
1219
  }
1196
1220
  if (previousHash && currentHash === previousHash) {
1197
- debugLog(`Skipping file (${result.filename}) writing due to indentical hash...`);
1221
+ debugLog(`Skipping file (${result.filename}) writing due to identical hash...`);
1198
1222
  return;
1199
1223
  }
1200
1224
  if (content.length === 0) {
@@ -1211,17 +1235,20 @@ async function generate(input, saveToFile = true) {
1211
1235
  writeSync(absolutePath, result.content);
1212
1236
  await lifecycleHooks(result.hooks).afterOneFileWrite(result.filename);
1213
1237
  await lifecycleHooks(config.hooks).afterOneFileWrite(result.filename);
1214
- }));
1215
- await lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename));
1238
+ })), 'Write files');
1239
+ await context.profiler.run(() => lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename)), 'Lifecycle: afterAllFileWrite');
1216
1240
  return generationResult;
1217
1241
  }
1218
1242
  // watch mode
1219
1243
  if (config.watch) {
1220
1244
  return createWatcher(context, writeOutput);
1221
1245
  }
1222
- const outputFiles = await executeCodegen(context);
1223
- await writeOutput(outputFiles);
1224
- lifecycleHooks(config.hooks).beforeDone();
1246
+ const outputFiles = await context.profiler.run(() => executeCodegen(context), 'executeCodegen');
1247
+ await context.profiler.run(() => writeOutput(outputFiles), 'writeOutput');
1248
+ await context.profiler.run(() => lifecycleHooks(config.hooks).beforeDone(), 'Lifecycle: beforeDone');
1249
+ if (context.profilerOutput) {
1250
+ writeSync(join(context.cwd, context.profilerOutput), JSON.stringify(context.profiler.collect()));
1251
+ }
1225
1252
  return outputFiles;
1226
1253
  }
1227
1254
  function shouldOverwrite(config, outputPath) {
@@ -1744,4 +1771,4 @@ async function ensureGraphQlPackage() {
1744
1771
  }
1745
1772
  }
1746
1773
 
1747
- export { CodegenContext, CodegenExtension, buildOptions, cliError, createContext, ensureContext, ensureGraphQlPackage, executeCodegen, findAndLoadGraphQLConfig, generate, init, loadCodegenConfig, loadContext, parseArgv, runCli, updateContextWithCliFlags };
1774
+ export { CodegenContext, CodegenExtension, buildOptions, cliError, createContext, ensureContext, ensureGraphQlPackage, executeCodegen, findAndLoadGraphQLConfig, generate, generateSearchPlaces, init, loadCodegenConfig, loadContext, parseArgv, runCli, updateContextWithCliFlags };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@graphql-codegen/cli",
3
- "version": "2.3.0-alpha-5ed8c1163.0",
3
+ "version": "2.4.0-alpha-23d229715.0",
4
4
  "peerDependencies": {
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"
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.2.0",
9
- "@graphql-codegen/plugin-helpers": "^2.2.0",
8
+ "@graphql-codegen/core": "2.4.0-alpha-23d229715.0",
9
+ "@graphql-codegen/plugin-helpers": "2.4.0-alpha-23d229715.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",
@@ -28,8 +28,8 @@
28
28
  "detect-indent": "^6.0.0",
29
29
  "glob": "^7.1.6",
30
30
  "globby": "^11.0.4",
31
- "graphql-config": "^4.0.1",
32
- "inquirer": "^7.3.3",
31
+ "graphql-config": "^4.1.0",
32
+ "inquirer": "^8.0.0",
33
33
  "is-glob": "^4.0.1",
34
34
  "json-to-pretty-yaml": "^1.2.2",
35
35
  "latest-version": "5.1.0",
@@ -78,6 +78,7 @@
78
78
  "definition": "index.d.ts"
79
79
  },
80
80
  "exports": {
81
+ "./package.json": "./package.json",
81
82
  ".": {
82
83
  "require": "./index.js",
83
84
  "import": "./index.mjs"