@oclif/core 3.0.0-beta.1 → 3.0.0-beta.3

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 (85) hide show
  1. package/README.md +9 -7
  2. package/lib/command.d.ts +2 -0
  3. package/lib/command.js +4 -4
  4. package/lib/config/config.d.ts +9 -12
  5. package/lib/config/config.js +90 -137
  6. package/lib/config/index.d.ts +2 -1
  7. package/lib/config/index.js +2 -1
  8. package/lib/config/plugin-loader.d.ts +30 -0
  9. package/lib/config/plugin-loader.js +129 -0
  10. package/lib/config/plugin.d.ts +5 -10
  11. package/lib/config/plugin.js +21 -17
  12. package/lib/config/ts-node.d.ts +3 -2
  13. package/lib/config/ts-node.js +83 -36
  14. package/lib/errors/config.js +5 -5
  15. package/lib/errors/errors/cli.d.ts +1 -0
  16. package/lib/errors/errors/cli.js +1 -0
  17. package/lib/errors/handle.d.ts +2 -2
  18. package/lib/errors/handle.js +4 -5
  19. package/lib/errors/index.d.ts +2 -1
  20. package/lib/errors/index.js +9 -2
  21. package/lib/errors/logger.js +3 -3
  22. package/lib/execute.d.ts +49 -0
  23. package/lib/execute.js +62 -0
  24. package/lib/flags.js +6 -4
  25. package/lib/help/index.js +3 -3
  26. package/lib/index.d.ts +9 -7
  27. package/lib/index.js +13 -19
  28. package/lib/interfaces/config.d.ts +26 -26
  29. package/lib/interfaces/parser.d.ts +14 -66
  30. package/lib/interfaces/pjson.d.ts +2 -0
  31. package/lib/interfaces/plugin.d.ts +8 -1
  32. package/lib/interfaces/ts-config.d.ts +9 -0
  33. package/lib/main.d.ts +1 -54
  34. package/lib/main.js +11 -73
  35. package/lib/module-loader.d.ts +1 -2
  36. package/lib/module-loader.js +9 -9
  37. package/lib/parser/errors.js +1 -1
  38. package/lib/parser/parse.js +1 -34
  39. package/lib/performance.d.ts +1 -1
  40. package/lib/performance.js +2 -3
  41. package/lib/screen.js +2 -2
  42. package/lib/settings.d.ts +2 -1
  43. package/lib/settings.js +2 -2
  44. package/lib/{cli-ux → ux}/action/base.js +2 -2
  45. package/lib/{cli-ux → ux}/action/spinner.js +1 -1
  46. package/lib/{cli-ux → ux}/config.d.ts +0 -1
  47. package/lib/{cli-ux → ux}/config.js +6 -10
  48. package/lib/{cli-ux → ux}/exit.d.ts +1 -1
  49. package/lib/{cli-ux → ux}/exit.js +1 -1
  50. package/lib/ux/flush.d.ts +1 -0
  51. package/lib/ux/flush.js +27 -0
  52. package/lib/{cli-ux → ux}/index.d.ts +8 -27
  53. package/lib/{cli-ux → ux}/index.js +21 -80
  54. package/lib/{cli-ux → ux}/prompt.js +2 -2
  55. package/lib/{cli-ux → ux}/styled/json.js +3 -3
  56. package/package.json +24 -19
  57. package/flush.d.ts +0 -3
  58. package/flush.js +0 -1
  59. package/handle.js +0 -1
  60. package/lib/cli-ux/action/pride-spinner.d.ts +0 -4
  61. package/lib/cli-ux/action/pride-spinner.js +0 -30
  62. /package/lib/{cli-ux → ux}/action/base.d.ts +0 -0
  63. /package/lib/{cli-ux → ux}/action/simple.d.ts +0 -0
  64. /package/lib/{cli-ux → ux}/action/simple.js +0 -0
  65. /package/lib/{cli-ux → ux}/action/spinner.d.ts +0 -0
  66. /package/lib/{cli-ux → ux}/action/spinners.d.ts +0 -0
  67. /package/lib/{cli-ux → ux}/action/spinners.js +0 -0
  68. /package/lib/{cli-ux → ux}/list.d.ts +0 -0
  69. /package/lib/{cli-ux → ux}/list.js +0 -0
  70. /package/lib/{cli-ux → ux}/prompt.d.ts +0 -0
  71. /package/lib/{cli-ux → ux}/stream.d.ts +0 -0
  72. /package/lib/{cli-ux → ux}/stream.js +0 -0
  73. /package/lib/{cli-ux → ux}/styled/index.d.ts +0 -0
  74. /package/lib/{cli-ux → ux}/styled/index.js +0 -0
  75. /package/lib/{cli-ux → ux}/styled/json.d.ts +0 -0
  76. /package/lib/{cli-ux → ux}/styled/object.d.ts +0 -0
  77. /package/lib/{cli-ux → ux}/styled/object.js +0 -0
  78. /package/lib/{cli-ux → ux}/styled/progress.d.ts +0 -0
  79. /package/lib/{cli-ux → ux}/styled/progress.js +0 -0
  80. /package/lib/{cli-ux → ux}/styled/table.d.ts +0 -0
  81. /package/lib/{cli-ux → ux}/styled/table.js +0 -0
  82. /package/lib/{cli-ux → ux}/styled/tree.d.ts +0 -0
  83. /package/lib/{cli-ux → ux}/styled/tree.js +0 -0
  84. /package/lib/{cli-ux → ux}/wait.d.ts +0 -0
  85. /package/lib/{cli-ux → ux}/wait.js +0 -0
@@ -0,0 +1,129 @@
1
+ "use strict";
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");
7
+ const performance_1 = require("../performance");
8
+ // eslint-disable-next-line new-cap
9
+ const debug = (0, util_1.Debug)();
10
+ class PluginLoader {
11
+ constructor(options) {
12
+ this.options = options;
13
+ this.plugins = new Map();
14
+ this.errors = [];
15
+ this.pluginsProvided = false;
16
+ if (options.plugins) {
17
+ this.pluginsProvided = true;
18
+ this.plugins = Array.isArray(options.plugins) ? new Map(options.plugins.map(p => [p.name, p])) : options.plugins;
19
+ }
20
+ }
21
+ async loadRoot() {
22
+ let rootPlugin;
23
+ if (this.pluginsProvided) {
24
+ const plugins = [...this.plugins.values()];
25
+ rootPlugin = plugins.find(p => p.root === this.options.root) ?? plugins[0];
26
+ }
27
+ else {
28
+ rootPlugin = new Plugin.Plugin({ root: this.options.root });
29
+ await rootPlugin.load();
30
+ }
31
+ this.plugins.set(rootPlugin.name, rootPlugin);
32
+ return rootPlugin;
33
+ }
34
+ async loadChildren(opts) {
35
+ if (!this.pluginsProvided || opts.force) {
36
+ await this.loadUserPlugins(opts);
37
+ await this.loadDevPlugins(opts);
38
+ await this.loadCorePlugins(opts);
39
+ }
40
+ return { plugins: this.plugins, errors: this.errors };
41
+ }
42
+ async loadCorePlugins(opts) {
43
+ if (opts.rootPlugin.pjson.oclif.plugins) {
44
+ await this.loadPlugins(opts.rootPlugin.root, 'core', opts.rootPlugin.pjson.oclif.plugins);
45
+ }
46
+ }
47
+ async loadDevPlugins(opts) {
48
+ if (opts.devPlugins !== false) {
49
+ // do not load oclif.devPlugins in production
50
+ if ((0, util_2.isProd)())
51
+ return;
52
+ try {
53
+ const devPlugins = opts.rootPlugin.pjson.oclif.devPlugins;
54
+ if (devPlugins)
55
+ await this.loadPlugins(opts.rootPlugin.root, 'dev', devPlugins);
56
+ }
57
+ catch (error) {
58
+ process.emitWarning(error);
59
+ }
60
+ }
61
+ }
62
+ async loadUserPlugins(opts) {
63
+ if (opts.userPlugins !== false) {
64
+ try {
65
+ const userPJSONPath = path.join(opts.dataDir, 'package.json');
66
+ debug('reading user plugins pjson %s', userPJSONPath);
67
+ const pjson = await (0, util_1.loadJSON)(userPJSONPath);
68
+ if (!pjson.oclif)
69
+ pjson.oclif = { schema: 1 };
70
+ if (!pjson.oclif.plugins)
71
+ pjson.oclif.plugins = [];
72
+ await this.loadPlugins(userPJSONPath, 'user', pjson.oclif.plugins.filter((p) => p.type === 'user'));
73
+ await this.loadPlugins(userPJSONPath, 'link', pjson.oclif.plugins.filter((p) => p.type === 'link'));
74
+ }
75
+ catch (error) {
76
+ if (error.code !== 'ENOENT')
77
+ process.emitWarning(error);
78
+ }
79
+ }
80
+ }
81
+ async loadPlugins(root, type, plugins, parent) {
82
+ if (!plugins || plugins.length === 0)
83
+ return;
84
+ const mark = performance_1.default.mark(`config.loadPlugins#${type}`);
85
+ debug('loading plugins', plugins);
86
+ await Promise.all((plugins || []).map(async (plugin) => {
87
+ try {
88
+ const name = typeof plugin === 'string' ? plugin : plugin.name;
89
+ const opts = {
90
+ name,
91
+ type,
92
+ root,
93
+ };
94
+ if (typeof plugin !== 'string') {
95
+ opts.tag = plugin.tag || opts.tag;
96
+ opts.root = plugin.root || opts.root;
97
+ }
98
+ if (this.plugins.has(name))
99
+ return;
100
+ const pluginMarker = performance_1.default.mark(`plugin.load#${name}`);
101
+ const instance = new Plugin.Plugin(opts);
102
+ await instance.load();
103
+ pluginMarker?.addDetails({
104
+ hasManifest: instance.hasManifest,
105
+ commandCount: instance.commands.length,
106
+ topicCount: instance.topics.length,
107
+ type: instance.type,
108
+ usesMain: Boolean(instance.pjson.main),
109
+ name: instance.name,
110
+ });
111
+ pluginMarker?.stop();
112
+ this.plugins.set(instance.name, instance);
113
+ if (parent) {
114
+ instance.parent = parent;
115
+ if (!parent.children)
116
+ parent.children = [];
117
+ parent.children.push(instance);
118
+ }
119
+ await this.loadPlugins(instance.root, type, instance.pjson.oclif.plugins || [], instance);
120
+ }
121
+ catch (error) {
122
+ this.errors.push(error);
123
+ }
124
+ }));
125
+ mark?.addDetails({ pluginCount: plugins.length });
126
+ mark?.stop();
127
+ }
128
+ }
129
+ exports.default = PluginLoader;
@@ -1,4 +1,3 @@
1
- import { CLIError } from '../errors';
2
1
  import { Plugin as IPlugin, PluginOptions } from '../interfaces/plugin';
3
2
  import { Manifest } from '../interfaces/manifest';
4
3
  import { PJSON } from '../interfaces/pjson';
@@ -11,6 +10,7 @@ export declare class Plugin implements IPlugin {
11
10
  version: string;
12
11
  pjson: PJSON.Plugin;
13
12
  type: string;
13
+ moduleType: 'module' | 'commonjs';
14
14
  root: string;
15
15
  alias: string;
16
16
  tag?: string;
@@ -25,16 +25,11 @@ export declare class Plugin implements IPlugin {
25
25
  children: Plugin[];
26
26
  hasManifest: boolean;
27
27
  private _commandsDir;
28
+ private flexibleTaxonomy;
28
29
  protected _debug: (..._: any) => void;
29
30
  protected warned: boolean;
30
31
  constructor(options: PluginOptions);
31
- /**
32
- * Loads a plugin
33
- * @param isWritingManifest - if true, exclude selected data from manifest
34
- * default is false to maintain backwards compatibility
35
- * @returns Promise<void>
36
- */
37
- load(isWritingManifest?: boolean): Promise<void>;
32
+ load(): Promise<void>;
38
33
  get topics(): Topic[];
39
34
  get commandsDir(): string | undefined;
40
35
  get commandIDs(): string[];
@@ -44,7 +39,7 @@ export declare class Plugin implements IPlugin {
44
39
  findCommand(id: string, opts?: {
45
40
  must: boolean;
46
41
  }): Promise<Command.Class | undefined>;
47
- protected _manifest(ignoreManifest: boolean, errorOnManifestCreate?: boolean, isWritingManifest?: boolean): Promise<Manifest>;
48
- protected warn(err: string | Error | CLIError, scope?: string): void;
42
+ private _manifest;
43
+ private warn;
49
44
  private addErrorScope;
50
45
  }
@@ -90,7 +90,6 @@ async function findRoot(name, root) {
90
90
  class Plugin {
91
91
  constructor(options) {
92
92
  this.options = options;
93
- // static loadedPlugins: {[name: string]: Plugin} = {}
94
93
  this._base = `${_pjson.name}@${_pjson.version}`;
95
94
  this.valid = false;
96
95
  this.alreadyLoaded = false;
@@ -100,26 +99,22 @@ class Plugin {
100
99
  this._debug = (0, util_2.Debug)();
101
100
  this.warned = false;
102
101
  }
103
- /**
104
- * Loads a plugin
105
- * @param isWritingManifest - if true, exclude selected data from manifest
106
- * default is false to maintain backwards compatibility
107
- * @returns Promise<void>
108
- */
109
- async load(isWritingManifest) {
102
+ async load() {
110
103
  this.type = this.options.type || 'core';
111
104
  this.tag = this.options.tag;
112
105
  const root = await findRoot(this.options.name, this.options.root);
113
106
  if (!root)
114
- throw new Error(`could not find package.json with ${(0, util_1.inspect)(this.options)}`);
107
+ throw new errors_1.CLIError(`could not find package.json with ${(0, util_1.inspect)(this.options)}`);
115
108
  this.root = root;
116
109
  this._debug('reading %s plugin %s', this.type, root);
117
110
  this.pjson = await (0, util_3.loadJSON)(path.join(root, 'package.json'));
111
+ this.flexibleTaxonomy = this.options?.flexibleTaxonomy || this.pjson.oclif?.flexibleTaxonomy || false;
112
+ this.moduleType = this.pjson.type === 'module' ? 'module' : 'commonjs';
118
113
  this.name = this.pjson.name;
119
114
  this.alias = this.options.name ?? this.pjson.name;
120
115
  const pjsonPath = path.join(root, 'package.json');
121
116
  if (!this.name)
122
- throw new Error(`no name in ${pjsonPath}`);
117
+ throw new errors_1.CLIError(`no name in ${pjsonPath}`);
123
118
  if (!(0, util_4.isProd)() && !this.pjson.files)
124
119
  this.warn(`files attribute must be specified in ${pjsonPath}`);
125
120
  // eslint-disable-next-line new-cap
@@ -132,7 +127,7 @@ class Plugin {
132
127
  this.pjson.oclif = this.pjson['cli-engine'] || {};
133
128
  }
134
129
  this.hooks = (0, util_3.mapValues)(this.pjson.oclif.hooks || {}, i => Array.isArray(i) ? i : [i]);
135
- this.manifest = await this._manifest(Boolean(this.options.ignoreManifest), Boolean(this.options.errorOnManifestCreate), isWritingManifest);
130
+ this.manifest = await this._manifest();
136
131
  this.commands = Object
137
132
  .entries(this.manifest.commands)
138
133
  .map(([id, c]) => ({
@@ -149,13 +144,13 @@ class Plugin {
149
144
  get commandsDir() {
150
145
  if (this._commandsDir)
151
146
  return this._commandsDir;
152
- this._commandsDir = (0, ts_node_1.tsPath)(this.root, this.pjson.oclif.commands, this.type);
147
+ this._commandsDir = (0, ts_node_1.tsPath)(this.root, this.pjson.oclif.commands, this);
153
148
  return this._commandsDir;
154
149
  }
155
150
  get commandIDs() {
156
151
  if (!this.commandsDir)
157
152
  return [];
158
- const marker = performance_1.Performance.mark(`plugin.commandIDs#${this.name}`, { plugin: this.name });
153
+ const marker = performance_1.default.mark(`plugin.commandIDs#${this.name}`, { plugin: this.name });
159
154
  this._debug(`loading IDs from ${this.commandsDir}`);
160
155
  const patterns = [
161
156
  '**/*.+(js|cjs|mjs|ts|tsx)',
@@ -175,7 +170,7 @@ class Plugin {
175
170
  return ids;
176
171
  }
177
172
  async findCommand(id, opts = {}) {
178
- const marker = performance_1.Performance.mark(`plugin.findCommand#${this.name}.${id}`, { id, plugin: this.name });
173
+ const marker = performance_1.default.mark(`plugin.findCommand#${this.name}.${id}`, { id, plugin: this.name });
179
174
  const fetch = async () => {
180
175
  if (!this.commandsDir)
181
176
  return;
@@ -211,7 +206,10 @@ class Plugin {
211
206
  marker?.stop();
212
207
  return cmd;
213
208
  }
214
- async _manifest(ignoreManifest, errorOnManifestCreate = false, isWritingManifest = false) {
209
+ async _manifest() {
210
+ const ignoreManifest = Boolean(this.options.ignoreManifest);
211
+ const errorOnManifestCreate = Boolean(this.options.errorOnManifestCreate);
212
+ const respectNoCacheDefault = Boolean(this.options.respectNoCacheDefault);
215
213
  const readManifest = async (dotfile = false) => {
216
214
  try {
217
215
  const p = path.join(this.root, `${dotfile ? '.' : ''}oclif.manifest.json`);
@@ -235,7 +233,7 @@ class Plugin {
235
233
  }
236
234
  }
237
235
  };
238
- const marker = performance_1.Performance.mark(`plugin.manifest#${this.name}`, { plugin: this.name });
236
+ const marker = performance_1.default.mark(`plugin.manifest#${this.name}`, { plugin: this.name });
239
237
  if (!ignoreManifest) {
240
238
  const manifest = await readManifest();
241
239
  if (manifest) {
@@ -248,7 +246,13 @@ class Plugin {
248
246
  version: this.version,
249
247
  commands: (await Promise.all(this.commandIDs.map(async (id) => {
250
248
  try {
251
- return [id, await (0, config_1.toCached)(await this.findCommand(id, { must: true }), this, isWritingManifest)];
249
+ const cached = await (0, config_1.toCached)(await this.findCommand(id, { must: true }), this, respectNoCacheDefault);
250
+ if (this.flexibleTaxonomy) {
251
+ const permutations = (0, util_2.getCommandIdPermutations)(id);
252
+ const aliasPermutations = cached.aliases.flatMap(a => (0, util_2.getCommandIdPermutations)(a));
253
+ return [id, { ...cached, permutations, aliasPermutations }];
254
+ }
255
+ return [id, cached];
252
256
  }
253
257
  catch (error) {
254
258
  const scope = 'toCached';
@@ -1,7 +1,8 @@
1
+ import { Plugin } from '../interfaces';
1
2
  /**
2
3
  * Convert a path from the compiled ./lib files to the ./src typescript source
3
4
  * this is for developing typescript plugins/CLIs
4
5
  * if there is a tsconfig and the original sources exist, it attempts to require ts-node
5
6
  */
6
- export declare function tsPath(root: string, orig: string, type?: string): string;
7
- export declare function tsPath(root: string, orig: string | undefined, type?: string): string | undefined;
7
+ export declare function tsPath(root: string, orig: string, plugin: Plugin): string;
8
+ export declare function tsPath(root: string, orig: string | undefined, plugin?: Plugin): string | undefined;
@@ -6,11 +6,15 @@ const path = require("path");
6
6
  const settings_1 = require("../settings");
7
7
  const util_1 = require("../util");
8
8
  const util_2 = require("./util");
9
+ const config_1 = require("./config");
10
+ const errors_1 = require("../errors");
9
11
  // eslint-disable-next-line new-cap
10
12
  const debug = (0, util_2.Debug)('ts-node');
11
- const TYPE_ROOTS = [`${__dirname}/../node_modules/@types`];
12
- const ROOT_DIRS = [];
13
+ const TS_CONFIGS = {};
14
+ const REGISTERED = new Set();
13
15
  function loadTSConfig(root) {
16
+ if (TS_CONFIGS[root])
17
+ return TS_CONFIGS[root];
14
18
  const tsconfigPath = path.join(root, 'tsconfig.json');
15
19
  let typescript;
16
20
  try {
@@ -18,7 +22,7 @@ function loadTSConfig(root) {
18
22
  }
19
23
  catch {
20
24
  try {
21
- typescript = require(root + '/node_modules/typescript');
25
+ typescript = require(path.join(root, 'node_modules', 'typescript'));
22
26
  }
23
27
  catch { }
24
28
  }
@@ -28,6 +32,7 @@ function loadTSConfig(root) {
28
32
  throw new Error(`Could not read and parse tsconfig.json at ${tsconfigPath}, or it ` +
29
33
  'did not contain a "compilerOptions" section.');
30
34
  }
35
+ TS_CONFIGS[root] = tsconfig;
31
36
  return tsconfig;
32
37
  }
33
38
  }
@@ -35,54 +40,96 @@ function registerTSNode(root) {
35
40
  const tsconfig = loadTSConfig(root);
36
41
  if (!tsconfig)
37
42
  return;
43
+ if (REGISTERED.has(root))
44
+ return tsconfig;
38
45
  debug('registering ts-node at', root);
39
46
  const tsNodePath = require.resolve('ts-node', { paths: [root, __dirname] });
47
+ debug('ts-node path:', tsNodePath);
40
48
  const tsNode = require(tsNodePath);
41
- TYPE_ROOTS.push(`${root}/node_modules/@types`);
49
+ const typeRoots = [
50
+ path.join(root, 'node_modules', '@types'),
51
+ ];
52
+ const rootDirs = [];
42
53
  if (tsconfig.compilerOptions.rootDirs) {
43
- ROOT_DIRS.push(...tsconfig.compilerOptions.rootDirs.map(r => path.join(root, r)));
54
+ for (const r of tsconfig.compilerOptions.rootDirs) {
55
+ rootDirs.push(path.join(root, r));
56
+ }
57
+ }
58
+ else if (tsconfig.compilerOptions.rootDir) {
59
+ rootDirs.push(path.join(root, tsconfig.compilerOptions.rootDir));
44
60
  }
45
61
  else {
46
- ROOT_DIRS.push(`${root}/src`);
62
+ rootDirs.push(path.join(root, 'src'));
47
63
  }
48
- const cwd = process.cwd();
49
- try {
50
- process.chdir(root);
51
- tsNode.register({
52
- skipProject: true,
53
- transpileOnly: true,
54
- compilerOptions: {
55
- esModuleInterop: tsconfig.compilerOptions.esModuleInterop,
56
- target: tsconfig.compilerOptions.target || 'es2017',
57
- experimentalDecorators: tsconfig.compilerOptions.experimentalDecorators || false,
58
- emitDecoratorMetadata: tsconfig.compilerOptions.emitDecoratorMetadata || false,
59
- module: 'commonjs',
60
- sourceMap: true,
61
- rootDirs: ROOT_DIRS,
62
- typeRoots: TYPE_ROOTS,
63
- jsx: 'react',
64
- },
65
- });
66
- return tsconfig;
64
+ const conf = {
65
+ compilerOptions: {
66
+ esModuleInterop: tsconfig.compilerOptions.esModuleInterop,
67
+ target: tsconfig.compilerOptions.target ?? 'es2019',
68
+ experimentalDecorators: tsconfig.compilerOptions.experimentalDecorators ?? false,
69
+ emitDecoratorMetadata: tsconfig.compilerOptions.emitDecoratorMetadata ?? false,
70
+ module: tsconfig.compilerOptions.module ?? 'commonjs',
71
+ sourceMap: tsconfig.compilerOptions.sourceMap ?? true,
72
+ rootDirs,
73
+ typeRoots,
74
+ },
75
+ skipProject: true,
76
+ transpileOnly: true,
77
+ esm: tsconfig['ts-node']?.esm ?? true,
78
+ scope: true,
79
+ scopeDir: root,
80
+ cwd: root,
81
+ experimentalSpecifierResolution: tsconfig['ts-node']?.experimentalSpecifierResolution ?? 'explicit',
82
+ };
83
+ if (tsconfig.compilerOptions.moduleResolution) {
84
+ // @ts-expect-error TSNode.RegisterOptions.compilerOptions is typed as a plain object
85
+ conf.compilerOptions.moduleResolution = tsconfig.compilerOptions.moduleResolution;
67
86
  }
68
- finally {
69
- process.chdir(cwd);
87
+ if (tsconfig.compilerOptions.jsx) {
88
+ // @ts-expect-error TSNode.RegisterOptions.compilerOptions is typed as a plain object
89
+ conf.compilerOptions.jsx = tsconfig.compilerOptions.jsx;
70
90
  }
91
+ tsNode.register(conf);
92
+ REGISTERED.add(root);
93
+ return tsconfig;
71
94
  }
72
- function tsPath(root, orig, type) {
95
+ // eslint-disable-next-line complexity
96
+ function tsPath(root, orig, plugin) {
73
97
  if (!orig)
74
98
  return orig;
75
99
  orig = orig.startsWith(root) ? orig : path.join(root, orig);
76
- const skipTSNode =
77
- // the CLI specifically turned it off
78
- (settings_1.settings.tsnodeEnabled === false) ||
79
- // the CLI didn't specify ts-node and it is production
80
- (settings_1.settings.tsnodeEnabled === undefined && (0, util_1.isProd)());
81
- // We always want to load the tsconfig for linked plugins.
82
- if (skipTSNode && type !== 'link')
100
+ // NOTE: The order of these checks matter!
101
+ if (settings_1.default.tsnodeEnabled === false) {
102
+ debug(`Skipping ts-node registration for ${root} because tsNodeEnabled is explicitly set to false`);
103
+ return orig;
104
+ }
105
+ // Skip ts-node registration if plugin is an ESM plugin executing from a CJS plugin
106
+ if (plugin?.moduleType === 'module' && config_1.Config.rootPlugin?.moduleType === 'commonjs') {
107
+ debug(`Skipping ts-node registration for ${root} because it's an ESM module but the root plugin is CommonJS`);
108
+ if (plugin.type === 'link')
109
+ (0, errors_1.memoizedWarn)(`${plugin.name} is a linked ESM module and cannot be auto-compiled from a CommonJS root plugin. Existing compiled source will be used instead.`);
83
110
  return orig;
111
+ }
112
+ // If plugin is an ESM plugin being executed from an ESM root plugin, check to see if ts-node/esm loader has been set
113
+ // either in the NODE_OPTIONS env var or from the exec args. If the ts-node/esm loader has NOT been loaded then we want
114
+ // to skip ts-node registration so that it falls back on the compiled source.
115
+ if (plugin?.moduleType === 'module') {
116
+ const tsNodeEsmLoaderInExecArgv = process.execArgv.includes('--loader') && process.execArgv.includes('ts-node/esm');
117
+ const tsNodeEsmLoaderInNodeOptions = process.env.NODE_OPTIONS?.includes('--loader=ts-node/esm') ?? false;
118
+ if (!tsNodeEsmLoaderInExecArgv && !tsNodeEsmLoaderInNodeOptions) {
119
+ debug(`Skipping ts-node registration for ${root} because it's an ESM module but the ts-node/esm loader hasn't been run`);
120
+ debug('try setting NODE_OPTIONS="--loader ts-node/esm" in your environment.');
121
+ if (plugin.type === 'link') {
122
+ (0, errors_1.memoizedWarn)(`${plugin.name} is a linked ESM module and cannot be auto-compiled without setting NODE_OPTIONS="--loader=ts-node/esm" in the environment. Existing compiled source will be used instead.`);
123
+ }
124
+ return orig;
125
+ }
126
+ }
127
+ if (settings_1.default.tsnodeEnabled === undefined && (0, util_1.isProd)() && plugin?.type !== 'link') {
128
+ debug(`Skipping ts-node registration for ${root} because NODE_ENV is NOT "test" or "development"`);
129
+ return orig;
130
+ }
84
131
  try {
85
- const tsconfig = type === 'link' ? registerTSNode(root) : loadTSConfig(root);
132
+ const tsconfig = registerTSNode(root);
86
133
  if (!tsconfig)
87
134
  return orig;
88
135
  const { rootDir, rootDirs, outDir } = tsconfig.compilerOptions;
@@ -15,24 +15,24 @@ function displayWarnings() {
15
15
  exports.config = {
16
16
  errorLogger: undefined,
17
17
  get debug() {
18
- return Boolean(settings_1.settings.debug);
18
+ return Boolean(settings_1.default.debug);
19
19
  },
20
20
  set debug(enabled) {
21
- settings_1.settings.debug = enabled;
21
+ settings_1.default.debug = enabled;
22
22
  if (enabled)
23
23
  displayWarnings();
24
24
  },
25
25
  get errlog() {
26
- return settings_1.settings.errlog;
26
+ return settings_1.default.errlog;
27
27
  },
28
28
  set errlog(errlog) {
29
29
  if (errlog) {
30
30
  this.errorLogger = new logger_1.Logger(errlog);
31
- settings_1.settings.errlog = errlog;
31
+ settings_1.default.errlog = errlog;
32
32
  }
33
33
  else {
34
34
  delete this.errorLogger;
35
- delete settings_1.settings.errlog;
35
+ delete settings_1.default.errlog;
36
36
  }
37
37
  },
38
38
  };
@@ -8,6 +8,7 @@ export declare function addOclifExitCode(error: Record<string, any>, options?: {
8
8
  export declare class CLIError extends Error implements OclifError {
9
9
  oclif: OclifError['oclif'];
10
10
  code?: string;
11
+ suggestions?: string[];
11
12
  constructor(error: string | Error, options?: {
12
13
  exit?: number | false;
13
14
  } & PrettyPrintableError);
@@ -24,6 +24,7 @@ class CLIError extends Error {
24
24
  this.oclif = {};
25
25
  addOclifExitCode(this, options);
26
26
  this.code = options.code;
27
+ this.suggestions = options.suggestions;
27
28
  }
28
29
  get stack() {
29
30
  return cs(super.stack, { pretty: true });
@@ -1,4 +1,4 @@
1
1
  import { OclifError, PrettyPrintableError } from '../interfaces';
2
- export declare const handle: (err: Error & Partial<PrettyPrintableError> & Partial<OclifError> & {
2
+ export default function handle(err: Error & Partial<PrettyPrintableError> & Partial<OclifError> & {
3
3
  skipOclifErrorHandling?: boolean;
4
- }) => void;
4
+ }): Promise<void>;
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handle = void 0;
4
3
  /* eslint-disable no-process-exit */
5
4
  /* eslint-disable unicorn/no-process-exit */
6
5
  const config_1 = require("./config");
@@ -8,7 +7,7 @@ const pretty_print_1 = require("./errors/pretty-print");
8
7
  const _1 = require(".");
9
8
  const clean = require("clean-stack");
10
9
  const cli_1 = require("./errors/cli");
11
- const handle = (err) => {
10
+ async function handle(err) {
12
11
  try {
13
12
  if (!err)
14
13
  err = new cli_1.CLIError('no error?');
@@ -25,7 +24,7 @@ const handle = (err) => {
25
24
  if (stack) {
26
25
  config_1.config.errorLogger.log(stack);
27
26
  }
28
- config_1.config.errorLogger.flush()
27
+ await config_1.config.errorLogger.flush()
29
28
  .then(() => process.exit(exitCode))
30
29
  .catch(console.error);
31
30
  }
@@ -37,5 +36,5 @@ const handle = (err) => {
37
36
  console.error(error.stack);
38
37
  process.exit(1);
39
38
  }
40
- };
41
- exports.handle = handle;
39
+ }
40
+ exports.default = handle;
@@ -1,4 +1,4 @@
1
- export { handle } from './handle';
1
+ export { default as handle } from './handle';
2
2
  export { ExitError } from './errors/exit';
3
3
  export { ModuleLoadError } from './errors/module-load';
4
4
  export { CLIError } from './errors/cli';
@@ -14,3 +14,4 @@ export declare function error(input: string | Error, options?: {
14
14
  exit?: number;
15
15
  } & PrettyPrintableError): never;
16
16
  export declare function warn(input: string | Error): void;
17
+ export declare function memoizedWarn(input: string | Error): void;
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.warn = exports.error = exports.exit = exports.config = exports.Logger = exports.CLIError = exports.ModuleLoadError = exports.ExitError = exports.handle = void 0;
3
+ exports.memoizedWarn = exports.warn = exports.error = exports.exit = exports.config = exports.Logger = exports.CLIError = exports.ModuleLoadError = exports.ExitError = exports.handle = void 0;
4
4
  var handle_1 = require("./handle");
5
- Object.defineProperty(exports, "handle", { enumerable: true, get: function () { return handle_1.handle; } });
5
+ Object.defineProperty(exports, "handle", { enumerable: true, get: function () { return handle_1.default; } });
6
6
  var exit_1 = require("./errors/exit");
7
7
  Object.defineProperty(exports, "ExitError", { enumerable: true, get: function () { return exit_1.ExitError; } });
8
8
  var module_load_1 = require("./errors/module-load");
@@ -60,3 +60,10 @@ function warn(input) {
60
60
  config_2.config.errorLogger.log(err?.stack ?? '');
61
61
  }
62
62
  exports.warn = warn;
63
+ const WARNINGS = new Set();
64
+ function memoizedWarn(input) {
65
+ if (!WARNINGS.has(input))
66
+ warn(input);
67
+ WARNINGS.add(input);
68
+ }
69
+ exports.memoizedWarn = memoizedWarn;
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Logger = void 0;
4
- const fs = require("fs-extra");
5
- const path = require("path");
4
+ const fs = require("fs/promises");
5
+ const path_1 = require("path");
6
6
  const stripAnsi = require("strip-ansi");
7
7
  const timestamp = () => new Date().toISOString();
8
8
  let timer;
@@ -35,7 +35,7 @@ class Logger {
35
35
  return;
36
36
  const mylines = this.buffer;
37
37
  this.buffer = [];
38
- await fs.mkdirp(path.dirname(this.file));
38
+ await fs.mkdir((0, path_1.dirname)(this.file), { recursive: true });
39
39
  await fs.appendFile(this.file, mylines.join('\n') + '\n');
40
40
  });
41
41
  await this.flushing;
@@ -0,0 +1,49 @@
1
+ import * as Interfaces from './interfaces';
2
+ /**
3
+ * Load and run oclif CLI
4
+ *
5
+ * @param options - options to load the CLI
6
+ * @returns Promise<void>
7
+ *
8
+ * @example For ESM dev.js
9
+ * ```
10
+ * #!/usr/bin/env node
11
+ * void (async () => {
12
+ * const oclif = await import('@oclif/core')
13
+ * await oclif.execute({development: true, dir: import.meta.url})
14
+ * })()
15
+ * ```
16
+ *
17
+ * @example For ESM run.js
18
+ * ```
19
+ * #!/usr/bin/env node
20
+ * void (async () => {
21
+ * const oclif = await import('@oclif/core')
22
+ * await oclif.execute({dir: import.meta.url})
23
+ * })()
24
+ * ```
25
+ *
26
+ * @example For CJS dev.js
27
+ * ```
28
+ * #!/usr/bin/env node
29
+ * void (async () => {
30
+ * const oclif = await import('@oclif/core')
31
+ * await oclif.execute({development: true, dir: __dirname})
32
+ * })()
33
+ * ```
34
+ *
35
+ * @example For CJS run.js
36
+ * ```
37
+ * #!/usr/bin/env node
38
+ * void (async () => {
39
+ * const oclif = await import('@oclif/core')
40
+ * await oclif.execute({dir: __dirname})
41
+ * })()
42
+ * ```
43
+ */
44
+ export default function execute(options: {
45
+ dir: string;
46
+ args?: string[];
47
+ loadOptions?: Interfaces.LoadOptions;
48
+ development?: boolean;
49
+ }): Promise<unknown>;