@oclif/core 3.0.0-beta.12 → 3.0.0-beta.14

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 (76) hide show
  1. package/README.md +3 -1
  2. package/lib/args.d.ts +1 -1
  3. package/lib/args.js +13 -15
  4. package/lib/cli-ux/action/base.d.ts +1 -1
  5. package/lib/cli-ux/action/base.js +20 -15
  6. package/lib/cli-ux/action/simple.js +10 -8
  7. package/lib/cli-ux/action/spinner.js +11 -10
  8. package/lib/cli-ux/config.js +8 -7
  9. package/lib/cli-ux/flush.js +2 -3
  10. package/lib/cli-ux/index.d.ts +10 -28
  11. package/lib/cli-ux/index.js +26 -45
  12. package/lib/cli-ux/list.js +1 -1
  13. package/lib/cli-ux/prompt.js +24 -19
  14. package/lib/cli-ux/styled/index.d.ts +5 -6
  15. package/lib/cli-ux/styled/index.js +11 -11
  16. package/lib/cli-ux/styled/json.js +3 -2
  17. package/lib/cli-ux/styled/object.js +6 -8
  18. package/lib/cli-ux/styled/table.js +36 -45
  19. package/lib/cli-ux/wait.js +3 -5
  20. package/lib/command.d.ts +7 -5
  21. package/lib/command.js +35 -28
  22. package/lib/config/config.d.ts +2 -2
  23. package/lib/config/config.js +57 -43
  24. package/lib/config/plugin-loader.js +25 -11
  25. package/lib/config/plugin.d.ts +1 -1
  26. package/lib/config/plugin.js +66 -56
  27. package/lib/config/ts-node.d.ts +2 -1
  28. package/lib/config/ts-node.js +42 -46
  29. package/lib/config/util.d.ts +1 -5
  30. package/lib/config/util.js +5 -46
  31. package/lib/errors/config.js +1 -1
  32. package/lib/errors/errors/cli.d.ts +1 -1
  33. package/lib/errors/errors/cli.js +14 -13
  34. package/lib/errors/errors/exit.d.ts +0 -3
  35. package/lib/errors/errors/module-load.d.ts +0 -3
  36. package/lib/errors/errors/pretty-print.js +9 -8
  37. package/lib/errors/handle.d.ts +12 -2
  38. package/lib/errors/handle.js +23 -14
  39. package/lib/errors/index.d.ts +2 -2
  40. package/lib/errors/index.js +20 -19
  41. package/lib/errors/logger.js +4 -4
  42. package/lib/execute.d.ts +5 -5
  43. package/lib/execute.js +6 -5
  44. package/lib/flags.d.ts +102 -31
  45. package/lib/flags.js +75 -42
  46. package/lib/help/command.d.ts +2 -0
  47. package/lib/help/command.js +32 -32
  48. package/lib/help/docopts.js +2 -9
  49. package/lib/help/formatter.d.ts +1 -1
  50. package/lib/help/formatter.js +17 -17
  51. package/lib/help/index.d.ts +2 -2
  52. package/lib/help/index.js +22 -21
  53. package/lib/help/root.js +2 -2
  54. package/lib/help/util.d.ts +1 -1
  55. package/lib/help/util.js +9 -9
  56. package/lib/index.d.ts +19 -20
  57. package/lib/index.js +38 -42
  58. package/lib/interfaces/config.d.ts +5 -4
  59. package/lib/interfaces/errors.d.ts +1 -1
  60. package/lib/interfaces/parser.d.ts +168 -45
  61. package/lib/interfaces/plugin.d.ts +1 -0
  62. package/lib/main.d.ts +1 -1
  63. package/lib/main.js +16 -16
  64. package/lib/module-loader.d.ts +67 -77
  65. package/lib/module-loader.js +179 -149
  66. package/lib/parser/errors.d.ts +2 -2
  67. package/lib/parser/errors.js +4 -3
  68. package/lib/parser/help.js +3 -2
  69. package/lib/parser/parse.d.ts +3 -0
  70. package/lib/parser/parse.js +56 -52
  71. package/lib/parser/validate.js +9 -5
  72. package/lib/performance.d.ts +6 -2
  73. package/lib/performance.js +23 -12
  74. package/lib/util.d.ts +25 -1
  75. package/lib/util.js +93 -29
  76. package/package.json +10 -15
@@ -1,20 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toCached = exports.Config = void 0;
4
- const node_url_1 = require("node:url");
5
- const node_util_1 = require("node:util");
6
- const node_os_1 = require("node:os");
7
- const node_path_1 = require("node:path");
8
- const ejs = require("ejs");
4
+ const tslib_1 = require("tslib");
5
+ const ejs = tslib_1.__importStar(require("ejs"));
9
6
  const errors_1 = require("../errors");
10
7
  const util_1 = require("./util");
8
+ const node_url_1 = require("node:url");
9
+ const node_os_1 = require("node:os");
11
10
  const util_2 = require("../util");
12
- const module_loader_1 = require("../module-loader");
13
- const help_1 = require("../help");
14
- const stream_1 = require("../cli-ux/stream");
11
+ const node_path_1 = require("node:path");
15
12
  const performance_1 = require("../performance");
13
+ const plugin_loader_1 = tslib_1.__importDefault(require("./plugin-loader"));
14
+ const node_util_1 = require("node:util");
15
+ const help_1 = require("../help");
16
+ const module_loader_1 = require("../module-loader");
16
17
  const settings_1 = require("../settings");
17
- const plugin_loader_1 = require("./plugin-loader");
18
+ const stream_1 = require("../cli-ux/stream");
18
19
  // eslint-disable-next-line new-cap
19
20
  const debug = (0, util_1.Debug)();
20
21
  const _pjson = (0, util_2.requireJson)(__dirname, '..', '..', 'package.json');
@@ -105,6 +106,7 @@ class Config {
105
106
  // eslint-disable-next-line complexity
106
107
  async load() {
107
108
  settings_1.settings.performanceEnabled = (settings_1.settings.performanceEnabled === undefined ? this.options.enablePerf : settings_1.settings.performanceEnabled) ?? false;
109
+ const marker = performance_1.Performance.mark('config.load');
108
110
  this.pluginLoader = new plugin_loader_1.default({ root: this.options.root, plugins: this.options.plugins });
109
111
  Config._rootPlugin = await this.pluginLoader.loadRoot();
110
112
  this.root = Config._rootPlugin.root;
@@ -117,7 +119,7 @@ class Config {
117
119
  this.channel = this.options.channel || channelFromVersion(this.version);
118
120
  this.valid = Config._rootPlugin.valid;
119
121
  this.arch = ((0, node_os_1.arch)() === 'ia32' ? 'x86' : (0, node_os_1.arch)());
120
- this.platform = WSL ? 'wsl' : (0, node_os_1.platform)();
122
+ this.platform = WSL ? 'wsl' : (0, util_2.getPlatform)();
121
123
  this.windows = this.platform === 'win32';
122
124
  this.bin = this.pjson.oclif.bin || this.name;
123
125
  this.binAliases = this.pjson.oclif.binAliases;
@@ -132,7 +134,7 @@ class Config {
132
134
  this.userAgent = `${this.name}/${this.version} ${this.platform}-${this.arch} node-${process.version}`;
133
135
  this.shell = this._shell();
134
136
  this.debug = this._debug();
135
- this.home = process.env.HOME || (this.windows && this.windowsHome()) || (0, node_os_1.homedir)() || (0, node_os_1.tmpdir)();
137
+ this.home = process.env.HOME || (this.windows && this.windowsHome()) || (0, util_2.getHomeDir)() || (0, node_os_1.tmpdir)();
136
138
  this.cacheDir = this.scopedEnvVar('CACHE_DIR') || this.macosCacheDir() || this.dir('cache');
137
139
  this.configDir = this.scopedEnvVar('CONFIG_DIR') || this.dir('config');
138
140
  this.dataDir = this.scopedEnvVar('DATA_DIR') || this.dir('data');
@@ -163,7 +165,6 @@ class Config {
163
165
  ...s3.templates && s3.templates.vanilla,
164
166
  },
165
167
  };
166
- const marker = performance_1.default.mark('config.load');
167
168
  await this.loadPluginsAndCommands();
168
169
  debug('config done');
169
170
  marker?.addDetails({
@@ -175,7 +176,7 @@ class Config {
175
176
  marker?.stop();
176
177
  }
177
178
  async loadPluginsAndCommands(opts) {
178
- const marker = performance_1.default.mark('config.loadPluginsAndCommands');
179
+ const pluginsMarker = performance_1.Performance.mark('config.loadAllPlugins');
179
180
  const { plugins, errors } = await this.pluginLoader.loadChildren({
180
181
  devPlugins: this.options.devPlugins,
181
182
  userPlugins: this.options.userPlugins,
@@ -184,17 +185,19 @@ class Config {
184
185
  force: opts?.force ?? false,
185
186
  });
186
187
  this.plugins = plugins;
188
+ pluginsMarker?.stop();
189
+ const commandsMarker = performance_1.Performance.mark('config.loadAllCommands');
187
190
  for (const plugin of this.plugins.values()) {
188
191
  this.loadCommands(plugin);
189
192
  this.loadTopics(plugin);
190
193
  }
194
+ commandsMarker?.stop();
191
195
  for (const error of errors) {
192
196
  this.warn(error);
193
197
  }
194
- marker?.stop();
195
198
  }
196
199
  async runHook(event, opts, timeout, captureErrors) {
197
- const marker = performance_1.default.mark(`config.runHook#${event}`);
200
+ const marker = performance_1.Performance.mark(`config.runHook#${event}`);
198
201
  debug('start %s hook', event);
199
202
  const search = (m) => {
200
203
  if (typeof m === 'function')
@@ -239,14 +242,14 @@ class Config {
239
242
  };
240
243
  const hooks = p.hooks[event] || [];
241
244
  for (const hook of hooks) {
242
- const marker = performance_1.default.mark(`config.runHook#${p.name}(${hook})`);
245
+ const marker = performance_1.Performance.mark(`config.runHook#${p.name}(${hook})`);
243
246
  try {
244
247
  /* eslint-disable no-await-in-loop */
245
- const { isESM, module, filePath } = await module_loader_1.default.loadWithData(p, hook);
248
+ const { isESM, module, filePath } = await (0, module_loader_1.loadWithData)(p, (0, node_path_1.join)(p.root, hook));
246
249
  debug('start', isESM ? '(import)' : '(require)', filePath);
247
- const result = timeout ?
248
- await withTimeout(timeout, search(module).call(context, { ...opts, config: this })) :
249
- await search(module).call(context, { ...opts, config: this });
250
+ const result = timeout
251
+ ? await withTimeout(timeout, search(module).call(context, { ...opts, config: this }))
252
+ : await search(module).call(context, { ...opts, config: this });
250
253
  final.successes.push({ plugin: p, result });
251
254
  if (p.name === '@oclif/plugin-legacy' && event === 'init') {
252
255
  this.insertLegacyPlugins(result);
@@ -273,14 +276,14 @@ class Config {
273
276
  return final;
274
277
  }
275
278
  async runCommand(id, argv = [], cachedCommand = null) {
276
- const marker = performance_1.default.mark(`config.runCommand#${id}`);
279
+ const marker = performance_1.Performance.mark(`config.runCommand#${id}`);
277
280
  debug('runCommand %s %o', id, argv);
278
281
  let c = cachedCommand ?? this.findCommand(id);
279
282
  if (!c) {
280
283
  const matches = this.flexibleTaxonomy ? this.findMatches(id, argv) : [];
281
- const hookResult = this.flexibleTaxonomy && matches.length > 0 ?
282
- await this.runHook('command_incomplete', { id, argv, matches }) :
283
- await this.runHook('command_not_found', { id, argv });
284
+ const hookResult = this.flexibleTaxonomy && matches.length > 0
285
+ ? await this.runHook('command_incomplete', { id, argv, matches })
286
+ : await this.runHook('command_not_found', { id, argv });
284
287
  if (hookResult.successes[0])
285
288
  return hookResult.successes[0].result;
286
289
  if (hookResult.failures[0])
@@ -335,7 +338,7 @@ class Config {
335
338
  */
336
339
  scopedEnvVarKey(k) {
337
340
  return [this.bin, k]
338
- .map(p => p.replace(/@/g, '').replace(/[/-]/g, '_'))
341
+ .map(p => p.replaceAll('@', '').replaceAll(/[/-]/g, '_'))
339
342
  .join('_')
340
343
  .toUpperCase();
341
344
  }
@@ -345,7 +348,7 @@ class Config {
345
348
  * @returns {string[]} e.g. ['SF_DEBUG', 'SFDX_DEBUG']
346
349
  */
347
350
  scopedEnvVarKeys(k) {
348
- return [this.bin, ...this.binAliases ?? []].filter(alias => Boolean(alias)).map(alias => [alias.replace(/@/g, '').replace(/[/-]/g, '_'), k].join('_').toUpperCase());
351
+ return [this.bin, ...this.binAliases ?? []].filter(Boolean).map(alias => [alias.replaceAll('@', '').replaceAll(/[/-]/g, '_'), k].join('_').toUpperCase());
349
352
  }
350
353
  findCommand(id, opts = {}) {
351
354
  const lookupId = this.getCmdLookupId(id);
@@ -376,12 +379,10 @@ class Config {
376
379
  * @returns string[]
377
380
  */
378
381
  findMatches(partialCmdId, argv) {
379
- const flags = argv.filter(arg => !(0, help_1.getHelpFlagAdditions)(this).includes(arg) && arg.startsWith('-')).map(a => a.replace(/-/g, ''));
382
+ const flags = argv.filter(arg => !(0, help_1.getHelpFlagAdditions)(this).includes(arg) && arg.startsWith('-')).map(a => a.replaceAll('-', ''));
380
383
  const possibleMatches = [...this.commandPermutations.get(partialCmdId)].map(k => this._commands.get(k));
381
384
  const matches = possibleMatches.filter(command => {
382
- const cmdFlags = Object.entries(command.flags).flatMap(([flag, def]) => {
383
- return def.char ? [def.char, flag] : [flag];
384
- });
385
+ const cmdFlags = Object.entries(command.flags).flatMap(([flag, def]) => def.char ? [def.char, flag] : [flag]);
385
386
  // A command is a match if the provided flags belong to the full command
386
387
  return flags.every(f => cmdFlags.includes(f));
387
388
  });
@@ -442,7 +443,7 @@ class Config {
442
443
  return ejs.render(template, { ...this, ...options });
443
444
  }
444
445
  s3Url(key) {
445
- const host = this.pjson.oclif.update.s3.host;
446
+ const { host } = this.pjson.oclif.update.s3;
446
447
  if (!host)
447
448
  throw new Error('no s3 host is set');
448
449
  const url = new node_url_1.URL(host);
@@ -453,9 +454,9 @@ class Config {
453
454
  return [...this.plugins.values()];
454
455
  }
455
456
  dir(category) {
456
- const base = process.env[`XDG_${category.toUpperCase()}_HOME`] ||
457
- (this.windows && process.env.LOCALAPPDATA) ||
458
- (0, node_path_1.join)(this.home, category === 'data' ? '.local/share' : '.' + category);
457
+ const base = process.env[`XDG_${category.toUpperCase()}_HOME`]
458
+ || (this.windows && process.env.LOCALAPPDATA)
459
+ || (0, node_path_1.join)(this.home, category === 'data' ? '.local/share' : '.' + category);
459
460
  return (0, node_path_1.join)(base, this.dirname);
460
461
  }
461
462
  windowsHome() {
@@ -472,7 +473,7 @@ class Config {
472
473
  }
473
474
  _shell() {
474
475
  let shellPath;
475
- const COMSPEC = process.env.COMSPEC;
476
+ const { COMSPEC } = process.env;
476
477
  const SHELL = process.env.SHELL ?? (0, node_os_1.userInfo)().shell?.split(node_path_1.sep)?.pop();
477
478
  if (SHELL) {
478
479
  shellPath = SHELL.split('/');
@@ -483,7 +484,7 @@ class Config {
483
484
  else {
484
485
  shellPath = ['unknown'];
485
486
  }
486
- return shellPath[shellPath.length - 1];
487
+ return shellPath.at(-1) ?? 'unknown';
487
488
  }
488
489
  _debug() {
489
490
  if (this.scopedEnvVarTrue('DEBUG'))
@@ -506,7 +507,7 @@ class Config {
506
507
  if (err instanceof Error) {
507
508
  const modifiedErr = err;
508
509
  modifiedErr.name = `${err.name} Plugin: ${this.name}`;
509
- modifiedErr.detail = (0, util_1.compact)([
510
+ modifiedErr.detail = (0, util_2.compact)([
510
511
  err.detail,
511
512
  `module: ${this._base}`,
512
513
  scope && `task: ${scope}`,
@@ -520,7 +521,7 @@ class Config {
520
521
  // err is an object
521
522
  process.emitWarning('Config.warn expected either a string or Error, but instead received an object');
522
523
  err.name = `${err.name} Plugin: ${this.name}`;
523
- err.detail = (0, util_1.compact)([
524
+ err.detail = (0, util_2.compact)([
524
525
  err.detail,
525
526
  `module: ${this._base}`,
526
527
  scope && `task: ${scope}`,
@@ -552,7 +553,7 @@ class Config {
552
553
  return id;
553
554
  }
554
555
  loadCommands(plugin) {
555
- const marker = performance_1.default.mark(`config.loadCommands#${plugin.name}`, { plugin: plugin.name });
556
+ const marker = performance_1.Performance.mark(`config.loadCommands#${plugin.name}`, { plugin: plugin.name });
556
557
  for (const command of plugin.commands) {
557
558
  // set canonical command id
558
559
  if (this._commands.has(command.id)) {
@@ -562,8 +563,13 @@ class Config {
562
563
  else {
563
564
  this._commands.set(command.id, command);
564
565
  }
566
+ // v3 moved command id permutations to the manifest, but some plugins may not have
567
+ // the new manifest yet. For those, we need to calculate the permutations here.
568
+ const permutations = this.flexibleTaxonomy && command.permutations === undefined
569
+ ? (0, util_1.getCommandIdPermutations)(command.id)
570
+ : command.permutations ?? [command.id];
565
571
  // set every permutation
566
- for (const permutation of command.permutations ?? [command.id]) {
572
+ for (const permutation of permutations) {
567
573
  this.commandPermutations.add(permutation, command.id);
568
574
  }
569
575
  // set command aliases
@@ -576,7 +582,13 @@ class Config {
576
582
  this._commands.set(alias, { ...command, id: alias });
577
583
  }
578
584
  // set every permutation of the aliases
579
- for (const permutation of command.aliasPermutations ?? [alias]) {
585
+ // v3 moved command alias permutations to the manifest, but some plugins may not have
586
+ // the new manifest yet. For those, we need to calculate the permutations here.
587
+ const aliasPermutations = this.flexibleTaxonomy && command.aliasPermutations === undefined
588
+ ? (0, util_1.getCommandIdPermutations)(alias)
589
+ : command.permutations ?? [alias];
590
+ // set every permutation
591
+ for (const permutation of aliasPermutations) {
580
592
  this.commandPermutations.add(permutation, command.id);
581
593
  }
582
594
  }
@@ -585,8 +597,8 @@ class Config {
585
597
  marker?.stop();
586
598
  }
587
599
  loadTopics(plugin) {
588
- const marker = performance_1.default.mark(`config.loadTopics#${plugin.name}`, { plugin: plugin.name });
589
- for (const topic of (0, util_1.compact)(plugin.topics)) {
600
+ const marker = performance_1.Performance.mark(`config.loadTopics#${plugin.name}`, { plugin: plugin.name });
601
+ for (const topic of (0, util_2.compact)(plugin.topics)) {
590
602
  const existing = this._topics.get(topic.name);
591
603
  if (existing) {
592
604
  existing.description = topic.description || existing.description;
@@ -750,6 +762,7 @@ async function toCached(c, plugin, respectNoCacheDefault = false) {
750
762
  deprecated: flag.deprecated,
751
763
  deprecateAliases: c.deprecateAliases,
752
764
  aliases: flag.aliases,
765
+ charAliases: flag.charAliases,
753
766
  delimiter: flag.delimiter,
754
767
  noCacheDefault: flag.noCacheDefault,
755
768
  };
@@ -775,6 +788,7 @@ async function toCached(c, plugin, respectNoCacheDefault = false) {
775
788
  deprecated: flag.deprecated,
776
789
  deprecateAliases: c.deprecateAliases,
777
790
  aliases: flag.aliases,
791
+ charAliases: flag.charAliases,
778
792
  delimiter: flag.delimiter,
779
793
  noCacheDefault: flag.noCacheDefault,
780
794
  };
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const path = require("path");
4
- const Plugin = require("./plugin");
5
- const util_1 = require("./util");
6
- const util_2 = require("../util");
3
+ const tslib_1 = require("tslib");
4
+ const Plugin = tslib_1.__importStar(require("./plugin"));
5
+ const util_1 = require("../util");
6
+ const util_2 = require("./util");
7
7
  const performance_1 = require("../performance");
8
+ const node_path_1 = require("node:path");
8
9
  // eslint-disable-next-line new-cap
9
- const debug = (0, util_1.Debug)();
10
+ const debug = (0, util_2.Debug)();
10
11
  class PluginLoader {
11
12
  constructor(options) {
12
13
  this.options = options;
@@ -25,8 +26,18 @@ class PluginLoader {
25
26
  rootPlugin = plugins.find(p => p.root === this.options.root) ?? plugins[0];
26
27
  }
27
28
  else {
29
+ const marker = performance_1.Performance.mark('plugin.load#root');
28
30
  rootPlugin = new Plugin.Plugin({ root: this.options.root });
29
31
  await rootPlugin.load();
32
+ marker?.addDetails({
33
+ hasManifest: rootPlugin.hasManifest ?? false,
34
+ commandCount: rootPlugin.commands.length,
35
+ topicCount: rootPlugin.topics.length,
36
+ type: rootPlugin.type,
37
+ usesMain: Boolean(rootPlugin.pjson.main),
38
+ name: rootPlugin.name,
39
+ });
40
+ marker?.stop();
30
41
  }
31
42
  this.plugins.set(rootPlugin.name, rootPlugin);
32
43
  return rootPlugin;
@@ -47,10 +58,10 @@ class PluginLoader {
47
58
  async loadDevPlugins(opts) {
48
59
  if (opts.devPlugins !== false) {
49
60
  // do not load oclif.devPlugins in production
50
- if ((0, util_2.isProd)())
61
+ if ((0, util_1.isProd)())
51
62
  return;
52
63
  try {
53
- const devPlugins = opts.rootPlugin.pjson.oclif.devPlugins;
64
+ const { devPlugins } = opts.rootPlugin.pjson.oclif;
54
65
  if (devPlugins)
55
66
  await this.loadPlugins(opts.rootPlugin.root, 'dev', devPlugins);
56
67
  }
@@ -62,9 +73,9 @@ class PluginLoader {
62
73
  async loadUserPlugins(opts) {
63
74
  if (opts.userPlugins !== false) {
64
75
  try {
65
- const userPJSONPath = path.join(opts.dataDir, 'package.json');
76
+ const userPJSONPath = (0, node_path_1.join)(opts.dataDir, 'package.json');
66
77
  debug('reading user plugins pjson %s', userPJSONPath);
67
- const pjson = await (0, util_1.loadJSON)(userPJSONPath);
78
+ const pjson = await (0, util_1.readJson)(userPJSONPath);
68
79
  if (!pjson.oclif)
69
80
  pjson.oclif = { schema: 1 };
70
81
  if (!pjson.oclif.plugins)
@@ -81,7 +92,7 @@ class PluginLoader {
81
92
  async loadPlugins(root, type, plugins, parent) {
82
93
  if (!plugins || plugins.length === 0)
83
94
  return;
84
- const mark = performance_1.default.mark(`config.loadPlugins#${type}`);
95
+ const mark = performance_1.Performance.mark(`config.loadPlugins#${type}`);
85
96
  debug('loading plugins', plugins);
86
97
  await Promise.all((plugins || []).map(async (plugin) => {
87
98
  try {
@@ -95,9 +106,12 @@ class PluginLoader {
95
106
  opts.tag = plugin.tag || opts.tag;
96
107
  opts.root = plugin.root || opts.root;
97
108
  }
109
+ if (parent) {
110
+ opts.parent = parent;
111
+ }
98
112
  if (this.plugins.has(name))
99
113
  return;
100
- const pluginMarker = performance_1.default.mark(`plugin.load#${name}`);
114
+ const pluginMarker = performance_1.Performance.mark(`plugin.load#${name}`);
101
115
  const instance = new Plugin.Plugin(opts);
102
116
  await instance.load();
103
117
  pluginMarker?.addDetails({
@@ -1,8 +1,8 @@
1
1
  import { Plugin as IPlugin, PluginOptions } from '../interfaces/plugin';
2
+ import { Command } from '../command';
2
3
  import { Manifest } from '../interfaces/manifest';
3
4
  import { PJSON } from '../interfaces/pjson';
4
5
  import { Topic } from '../interfaces/topic';
5
- import { Command } from '../command';
6
6
  export declare class Plugin implements IPlugin {
7
7
  options: PluginOptions;
8
8
  _base: string;
@@ -2,43 +2,42 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Plugin = void 0;
4
4
  const errors_1 = require("../errors");
5
- const globby = require("globby");
6
- const path = require("path");
7
- const util_1 = require("util");
8
- const config_1 = require("./config");
9
- const util_2 = require("./util");
10
- const ts_node_1 = require("./ts-node");
11
- const util_3 = require("./util");
12
- const util_4 = require("../util");
5
+ const util_1 = require("./util");
6
+ const util_2 = require("../util");
7
+ const node_path_1 = require("node:path");
13
8
  const module_loader_1 = require("../module-loader");
14
9
  const performance_1 = require("../performance");
15
- const _pjson = (0, util_4.requireJson)(__dirname, '..', '..', 'package.json');
10
+ const node_util_1 = require("node:util");
11
+ const globby_1 = require("globby");
12
+ const config_1 = require("./config");
13
+ const ts_node_1 = require("./ts-node");
14
+ const _pjson = (0, util_2.requireJson)(__dirname, '..', '..', 'package.json');
16
15
  function topicsToArray(input, base) {
17
16
  if (!input)
18
17
  return [];
19
18
  base = base ? `${base}:` : '';
20
19
  if (Array.isArray(input)) {
21
- return [...input, ...(0, util_3.flatMap)(input, t => topicsToArray(t.subtopics, `${base}${t.name}`))];
20
+ return [...input, ...(0, util_1.flatMap)(input, t => topicsToArray(t.subtopics, `${base}${t.name}`))];
22
21
  }
23
- return (0, util_3.flatMap)(Object.keys(input), k => {
22
+ return (0, util_1.flatMap)(Object.keys(input), k => {
24
23
  input[k].name = k;
25
24
  return [{ ...input[k], name: `${base}${k}` }, ...topicsToArray(input[k].subtopics, `${base}${input[k].name}`)];
26
25
  });
27
26
  }
28
27
  // essentially just "cd .."
29
28
  function* up(from) {
30
- while (path.dirname(from) !== from) {
29
+ while ((0, node_path_1.dirname)(from) !== from) {
31
30
  yield from;
32
- from = path.dirname(from);
31
+ from = (0, node_path_1.dirname)(from);
33
32
  }
34
33
  yield from;
35
34
  }
36
35
  async function findSourcesRoot(root) {
37
36
  for (const next of up(root)) {
38
- const cur = path.join(next, 'package.json');
37
+ const cur = (0, node_path_1.join)(next, 'package.json');
39
38
  // eslint-disable-next-line no-await-in-loop
40
- if (await (0, util_3.exists)(cur))
41
- return path.dirname(cur);
39
+ if (await (0, util_2.exists)(cur))
40
+ return (0, node_path_1.dirname)(cur);
42
41
  }
43
42
  }
44
43
  /**
@@ -56,23 +55,23 @@ async function findRootLegacy(name, root) {
56
55
  for (const next of up(root)) {
57
56
  let cur;
58
57
  if (name) {
59
- cur = path.join(next, 'node_modules', name, 'package.json');
58
+ cur = (0, node_path_1.join)(next, 'node_modules', name, 'package.json');
60
59
  // eslint-disable-next-line no-await-in-loop
61
- if (await (0, util_3.exists)(cur))
62
- return path.dirname(cur);
60
+ if (await (0, util_2.exists)(cur))
61
+ return (0, node_path_1.dirname)(cur);
63
62
  try {
64
63
  // eslint-disable-next-line no-await-in-loop
65
- const pkg = await (0, util_3.loadJSON)(path.join(next, 'package.json'));
64
+ const pkg = await (0, util_2.readJson)((0, node_path_1.join)(next, 'package.json'));
66
65
  if (pkg.name === name)
67
66
  return next;
68
67
  }
69
68
  catch { }
70
69
  }
71
70
  else {
72
- cur = path.join(next, 'package.json');
71
+ cur = (0, node_path_1.join)(next, 'package.json');
73
72
  // eslint-disable-next-line no-await-in-loop
74
- if (await (0, util_3.exists)(cur))
75
- return path.dirname(cur);
73
+ if (await (0, util_2.exists)(cur))
74
+ return (0, node_path_1.dirname)(cur);
76
75
  }
77
76
  }
78
77
  }
@@ -80,13 +79,21 @@ async function findRoot(name, root) {
80
79
  if (name) {
81
80
  let pkgPath;
82
81
  try {
83
- pkgPath = (0, util_3.resolvePackage)(name, { paths: [root] });
82
+ pkgPath = (0, util_1.resolvePackage)(name, { paths: [root] });
84
83
  }
85
84
  catch { }
86
- return pkgPath ? findSourcesRoot(path.dirname(pkgPath)) : findRootLegacy(name, root);
85
+ return pkgPath ? findSourcesRoot((0, node_path_1.dirname)(pkgPath)) : findRootLegacy(name, root);
87
86
  }
88
87
  return findSourcesRoot(root);
89
88
  }
89
+ const cachedCommandCanBeUsed = (manifest, id) => Boolean(manifest?.commands[id] && ('isESM' in manifest.commands[id] && 'relativePath' in manifest.commands[id]));
90
+ const search = (cmd) => {
91
+ if (typeof cmd.run === 'function')
92
+ return cmd;
93
+ if (cmd.default && cmd.default.run)
94
+ return cmd.default;
95
+ return Object.values(cmd).find((cmd) => typeof cmd.run === 'function');
96
+ };
90
97
  class Plugin {
91
98
  constructor(options) {
92
99
  this.options = options;
@@ -96,29 +103,34 @@ class Plugin {
96
103
  this.children = [];
97
104
  this.hasManifest = false;
98
105
  // eslint-disable-next-line new-cap
99
- this._debug = (0, util_2.Debug)();
106
+ this._debug = (0, util_1.Debug)();
100
107
  this.warned = false;
101
108
  }
102
109
  async load() {
103
110
  this.type = this.options.type || 'core';
104
111
  this.tag = this.options.tag;
105
- const root = await findRoot(this.options.name, this.options.root);
112
+ if (this.options.parent)
113
+ this.parent = this.options.parent;
114
+ // Linked plugins already have a root so there's no need to search for it.
115
+ // However there could be child plugins nested inside the linked plugin, in which
116
+ // case we still need to search for the child plugin's root.
117
+ const root = this.type === 'link' && !this.parent ? this.options.root : await findRoot(this.options.name, this.options.root);
106
118
  if (!root)
107
- throw new errors_1.CLIError(`could not find package.json with ${(0, util_1.inspect)(this.options)}`);
119
+ throw new errors_1.CLIError(`could not find package.json with ${(0, node_util_1.inspect)(this.options)}`);
108
120
  this.root = root;
109
121
  this._debug('reading %s plugin %s', this.type, root);
110
- this.pjson = await (0, util_3.loadJSON)(path.join(root, 'package.json'));
122
+ this.pjson = await (0, util_2.readJson)((0, node_path_1.join)(root, 'package.json'));
111
123
  this.flexibleTaxonomy = this.options?.flexibleTaxonomy || this.pjson.oclif?.flexibleTaxonomy || false;
112
124
  this.moduleType = this.pjson.type === 'module' ? 'module' : 'commonjs';
113
125
  this.name = this.pjson.name;
114
126
  this.alias = this.options.name ?? this.pjson.name;
115
- const pjsonPath = path.join(root, 'package.json');
127
+ const pjsonPath = (0, node_path_1.join)(root, 'package.json');
116
128
  if (!this.name)
117
129
  throw new errors_1.CLIError(`no name in ${pjsonPath}`);
118
- if (!(0, util_4.isProd)() && !this.pjson.files)
130
+ if (!(0, util_2.isProd)() && !this.pjson.files)
119
131
  this.warn(`files attribute must be specified in ${pjsonPath}`);
120
132
  // eslint-disable-next-line new-cap
121
- this._debug = (0, util_2.Debug)(this.name);
133
+ this._debug = (0, util_1.Debug)(this.name);
122
134
  this.version = this.pjson.version;
123
135
  if (this.pjson.oclif) {
124
136
  this.valid = true;
@@ -126,7 +138,7 @@ class Plugin {
126
138
  else {
127
139
  this.pjson.oclif = this.pjson['cli-engine'] || {};
128
140
  }
129
- this.hooks = (0, util_3.mapValues)(this.pjson.oclif.hooks || {}, i => Array.isArray(i) ? i : [i]);
141
+ this.hooks = (0, util_1.mapValues)(this.pjson.oclif.hooks || {}, i => Array.isArray(i) ? i : [i]);
130
142
  this.manifest = await this._manifest();
131
143
  this.commands = Object
132
144
  .entries(this.manifest.commands)
@@ -150,18 +162,18 @@ class Plugin {
150
162
  get commandIDs() {
151
163
  if (!this.commandsDir)
152
164
  return [];
153
- const marker = performance_1.default.mark(`plugin.commandIDs#${this.name}`, { plugin: this.name });
165
+ const marker = performance_1.Performance.mark(`plugin.commandIDs#${this.name}`, { plugin: this.name });
154
166
  this._debug(`loading IDs from ${this.commandsDir}`);
155
167
  const patterns = [
156
168
  '**/*.+(js|cjs|mjs|ts|tsx)',
157
169
  '!**/*.+(d.ts|test.ts|test.js|spec.ts|spec.js)?(x)',
158
170
  ];
159
- const ids = globby.sync(patterns, { cwd: this.commandsDir })
171
+ const ids = (0, globby_1.sync)(patterns, { cwd: this.commandsDir })
160
172
  .map(file => {
161
- const p = path.parse(file);
173
+ const p = (0, node_path_1.parse)(file);
162
174
  const topics = p.dir.split('/');
163
175
  const command = p.name !== 'index' && p.name;
164
- const id = [...topics, command].filter(f => f).join(':');
176
+ const id = [...topics, command].filter(Boolean).join(':');
165
177
  return id === '' ? '.' : id;
166
178
  });
167
179
  this._debug('found commands', ids);
@@ -170,34 +182,31 @@ class Plugin {
170
182
  return ids;
171
183
  }
172
184
  async findCommand(id, opts = {}) {
173
- const marker = performance_1.default.mark(`plugin.findCommand#${this.name}.${id}`, { id, plugin: this.name });
185
+ const marker = performance_1.Performance.mark(`plugin.findCommand#${this.name}.${id}`, { id, plugin: this.name });
174
186
  const fetch = async () => {
175
187
  if (!this.commandsDir)
176
188
  return;
177
- const search = (cmd) => {
178
- if (typeof cmd.run === 'function')
179
- return cmd;
180
- if (cmd.default && cmd.default.run)
181
- return cmd.default;
182
- return Object.values(cmd).find((cmd) => typeof cmd.run === 'function');
183
- };
184
- let m;
189
+ let module;
190
+ let isESM;
191
+ let filePath;
185
192
  try {
186
- const p = path.join(this.commandsDir ?? this.pjson.oclif.commands, ...id.split(':'));
187
- const { isESM, module, filePath } = await module_loader_1.default.loadWithData(this, p);
193
+ ({ isESM, module, filePath } = cachedCommandCanBeUsed(this.manifest, id)
194
+ ? await (0, module_loader_1.loadWithDataFromManifest)(this.manifest.commands[id], this.root)
195
+ : await (0, module_loader_1.loadWithData)(this, (0, node_path_1.join)(this.commandsDir ?? this.pjson.oclif.commands, ...id.split(':'))));
188
196
  this._debug(isESM ? '(import)' : '(require)', filePath);
189
- m = module;
190
197
  }
191
198
  catch (error) {
192
199
  if (!opts.must && error.code === 'MODULE_NOT_FOUND')
193
200
  return;
194
201
  throw error;
195
202
  }
196
- const cmd = search(m);
203
+ const cmd = search(module);
197
204
  if (!cmd)
198
205
  return;
199
206
  cmd.id = id;
200
207
  cmd.plugin = this;
208
+ cmd.isESM = isESM;
209
+ cmd.relativePath = (0, node_path_1.relative)(this.root, filePath || '').split(node_path_1.sep);
201
210
  return cmd;
202
211
  };
203
212
  const cmd = await fetch();
@@ -212,8 +221,8 @@ class Plugin {
212
221
  const respectNoCacheDefault = Boolean(this.options.respectNoCacheDefault);
213
222
  const readManifest = async (dotfile = false) => {
214
223
  try {
215
- const p = path.join(this.root, `${dotfile ? '.' : ''}oclif.manifest.json`);
216
- const manifest = await (0, util_3.loadJSON)(p);
224
+ const p = (0, node_path_1.join)(this.root, `${dotfile ? '.' : ''}oclif.manifest.json`);
225
+ const manifest = await (0, util_2.readJson)(p);
217
226
  if (!process.env.OCLIF_NEXT_VERSION && manifest.version.split('-')[0] !== this.version.split('-')[0]) {
218
227
  process.emitWarning(`Mismatched version in ${this.name} plugin manifest. Expected: ${this.version} Received: ${manifest.version}\nThis usually means you have an oclif.manifest.json file that should be deleted in development. This file should be automatically generated when publishing.`);
219
228
  }
@@ -233,7 +242,7 @@ class Plugin {
233
242
  }
234
243
  }
235
244
  };
236
- const marker = performance_1.default.mark(`plugin.manifest#${this.name}`, { plugin: this.name });
245
+ const marker = performance_1.Performance.mark(`plugin.manifest#${this.name}`, { plugin: this.name });
237
246
  if (!ignoreManifest) {
238
247
  const manifest = await readManifest();
239
248
  if (manifest) {
@@ -248,8 +257,8 @@ class Plugin {
248
257
  try {
249
258
  const cached = await (0, config_1.toCached)(await this.findCommand(id, { must: true }), this, respectNoCacheDefault);
250
259
  if (this.flexibleTaxonomy) {
251
- const permutations = (0, util_2.getCommandIdPermutations)(id);
252
- const aliasPermutations = cached.aliases.flatMap(a => (0, util_2.getCommandIdPermutations)(a));
260
+ const permutations = (0, util_1.getCommandIdPermutations)(id);
261
+ const aliasPermutations = cached.aliases.flatMap(a => (0, util_1.getCommandIdPermutations)(a));
253
262
  return [id, { ...cached, permutations, aliasPermutations }];
254
263
  }
255
264
  return [id, cached];
@@ -262,6 +271,7 @@ class Plugin {
262
271
  throw this.addErrorScope(error, scope);
263
272
  }
264
273
  })))
274
+ // eslint-disable-next-line unicorn/no-await-expression-member, unicorn/prefer-native-coercion-functions
265
275
  .filter((f) => Boolean(f))
266
276
  .reduce((commands, [id, c]) => {
267
277
  commands[id] = c;
@@ -281,7 +291,7 @@ class Plugin {
281
291
  }
282
292
  addErrorScope(err, scope) {
283
293
  err.name = `${err.name} Plugin: ${this.name}`;
284
- err.detail = (0, util_3.compact)([err.detail, `module: ${this._base}`, scope && `task: ${scope}`, `plugin: ${this.name}`, `root: ${this.root}`, 'See more details with DEBUG=*']).join('\n');
294
+ err.detail = (0, util_2.compact)([err.detail, `module: ${this._base}`, scope && `task: ${scope}`, `plugin: ${this.name}`, `root: ${this.root}`, 'See more details with DEBUG=*']).join('\n');
285
295
  return err;
286
296
  }
287
297
  }