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

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 (55) hide show
  1. package/README.md +8 -6
  2. package/flush.js +1 -1
  3. package/handle.js +1 -1
  4. package/lib/cli-ux/action/base.js +2 -2
  5. package/lib/cli-ux/action/spinner.js +1 -1
  6. package/lib/cli-ux/config.d.ts +0 -1
  7. package/lib/cli-ux/config.js +6 -10
  8. package/lib/cli-ux/exit.d.ts +1 -1
  9. package/lib/cli-ux/exit.js +1 -1
  10. package/lib/cli-ux/flush.d.ts +1 -0
  11. package/lib/cli-ux/flush.js +28 -0
  12. package/lib/cli-ux/index.d.ts +1 -3
  13. package/lib/cli-ux/index.js +7 -31
  14. package/lib/cli-ux/prompt.js +2 -2
  15. package/lib/cli-ux/styled/json.js +1 -1
  16. package/lib/command.d.ts +2 -0
  17. package/lib/config/config.d.ts +9 -12
  18. package/lib/config/config.js +88 -135
  19. package/lib/config/index.d.ts +2 -1
  20. package/lib/config/index.js +2 -1
  21. package/lib/config/plugin-loader.d.ts +30 -0
  22. package/lib/config/plugin-loader.js +129 -0
  23. package/lib/config/plugin.d.ts +5 -10
  24. package/lib/config/plugin.js +21 -17
  25. package/lib/config/ts-node.d.ts +3 -2
  26. package/lib/config/ts-node.js +83 -36
  27. package/lib/errors/errors/cli.d.ts +1 -0
  28. package/lib/errors/errors/cli.js +1 -0
  29. package/lib/errors/handle.d.ts +2 -2
  30. package/lib/errors/handle.js +3 -3
  31. package/lib/errors/index.d.ts +1 -0
  32. package/lib/errors/index.js +8 -1
  33. package/lib/errors/logger.js +3 -3
  34. package/lib/execute.d.ts +49 -0
  35. package/lib/execute.js +62 -0
  36. package/lib/flags.js +6 -4
  37. package/lib/help/index.js +2 -2
  38. package/lib/index.d.ts +6 -4
  39. package/lib/index.js +9 -15
  40. package/lib/interfaces/config.d.ts +26 -26
  41. package/lib/interfaces/index.d.ts +14 -14
  42. package/lib/interfaces/parser.d.ts +14 -66
  43. package/lib/interfaces/pjson.d.ts +2 -0
  44. package/lib/interfaces/plugin.d.ts +8 -1
  45. package/lib/interfaces/ts-config.d.ts +9 -0
  46. package/lib/main.d.ts +1 -54
  47. package/lib/main.js +10 -72
  48. package/lib/module-loader.d.ts +1 -2
  49. package/lib/module-loader.js +9 -9
  50. package/lib/parser/parse.js +1 -34
  51. package/lib/performance.d.ts +1 -1
  52. package/lib/performance.js +1 -2
  53. package/package.json +14 -15
  54. package/lib/cli-ux/action/pride-spinner.d.ts +0 -4
  55. package/lib/cli-ux/action/pride-spinner.js +0 -30
@@ -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.settings.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.settings.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;
@@ -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 declare function handle(err: Error & Partial<PrettyPrintableError> & Partial<OclifError> & {
3
3
  skipOclifErrorHandling?: boolean;
4
- }) => void;
4
+ }): Promise<void>;
@@ -8,7 +8,7 @@ const pretty_print_1 = require("./errors/pretty-print");
8
8
  const _1 = require(".");
9
9
  const clean = require("clean-stack");
10
10
  const cli_1 = require("./errors/cli");
11
- const handle = (err) => {
11
+ async function handle(err) {
12
12
  try {
13
13
  if (!err)
14
14
  err = new cli_1.CLIError('no error?');
@@ -25,7 +25,7 @@ const handle = (err) => {
25
25
  if (stack) {
26
26
  config_1.config.errorLogger.log(stack);
27
27
  }
28
- config_1.config.errorLogger.flush()
28
+ await config_1.config.errorLogger.flush()
29
29
  .then(() => process.exit(exitCode))
30
30
  .catch(console.error);
31
31
  }
@@ -37,5 +37,5 @@ const handle = (err) => {
37
37
  console.error(error.stack);
38
38
  process.exit(1);
39
39
  }
40
- };
40
+ }
41
41
  exports.handle = handle;
@@ -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,6 +1,6 @@
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
5
  Object.defineProperty(exports, "handle", { enumerable: true, get: function () { return handle_1.handle; } });
6
6
  var exit_1 = require("./errors/exit");
@@ -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>;
package/lib/execute.js ADDED
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const settings_1 = require("./settings");
4
+ const flush_1 = require("./cli-ux/flush");
5
+ const handle_1 = require("./errors/handle");
6
+ const main_1 = require("./main");
7
+ /**
8
+ * Load and run oclif CLI
9
+ *
10
+ * @param options - options to load the CLI
11
+ * @returns Promise<void>
12
+ *
13
+ * @example For ESM dev.js
14
+ * ```
15
+ * #!/usr/bin/env node
16
+ * void (async () => {
17
+ * const oclif = await import('@oclif/core')
18
+ * await oclif.execute({development: true, dir: import.meta.url})
19
+ * })()
20
+ * ```
21
+ *
22
+ * @example For ESM run.js
23
+ * ```
24
+ * #!/usr/bin/env node
25
+ * void (async () => {
26
+ * const oclif = await import('@oclif/core')
27
+ * await oclif.execute({dir: import.meta.url})
28
+ * })()
29
+ * ```
30
+ *
31
+ * @example For CJS dev.js
32
+ * ```
33
+ * #!/usr/bin/env node
34
+ * void (async () => {
35
+ * const oclif = await import('@oclif/core')
36
+ * await oclif.execute({development: true, dir: __dirname})
37
+ * })()
38
+ * ```
39
+ *
40
+ * @example For CJS run.js
41
+ * ```
42
+ * #!/usr/bin/env node
43
+ * void (async () => {
44
+ * const oclif = await import('@oclif/core')
45
+ * await oclif.execute({dir: __dirname})
46
+ * })()
47
+ * ```
48
+ */
49
+ async function execute(options) {
50
+ if (options.development) {
51
+ // In dev mode -> use ts-node and dev plugins
52
+ process.env.NODE_ENV = 'development';
53
+ settings_1.settings.debug = true;
54
+ }
55
+ return (0, main_1.default)(options.args ?? process.argv.slice(2), options.loadOptions ?? options.dir)
56
+ .then(async (result) => {
57
+ (0, flush_1.flush)();
58
+ return result;
59
+ })
60
+ .catch(async (error) => (0, handle_1.handle)(error));
61
+ }
62
+ exports.default = execute;
package/lib/flags.js CHANGED
@@ -4,6 +4,7 @@ exports.help = exports.version = exports.string = exports.url = exports.file = e
4
4
  const url_1 = require("url");
5
5
  const help_1 = require("./help");
6
6
  const util_1 = require("./util");
7
+ const errors_1 = require("./errors");
7
8
  function custom(defaults) {
8
9
  return (options = {}) => {
9
10
  return {
@@ -29,12 +30,12 @@ exports.boolean = boolean;
29
30
  exports.integer = custom({
30
31
  parse: async (input, _, opts) => {
31
32
  if (!/^-?\d+$/.test(input))
32
- throw new Error(`Expected an integer but received: ${input}`);
33
+ throw new errors_1.CLIError(`Expected an integer but received: ${input}`);
33
34
  const num = Number.parseInt(input, 10);
34
35
  if (opts.min !== undefined && num < opts.min)
35
- throw new Error(`Expected an integer greater than or equal to ${opts.min} but received: ${input}`);
36
+ throw new errors_1.CLIError(`Expected an integer greater than or equal to ${opts.min} but received: ${input}`);
36
37
  if (opts.max !== undefined && num > opts.max)
37
- throw new Error(`Expected an integer less than or equal to ${opts.max} but received: ${input}`);
38
+ throw new errors_1.CLIError(`Expected an integer less than or equal to ${opts.max} but received: ${input}`);
38
39
  return num;
39
40
  },
40
41
  });
@@ -84,7 +85,8 @@ const help = (opts = {}) => {
84
85
  description: 'Show CLI help.',
85
86
  ...opts,
86
87
  parse: async (_, cmd) => {
87
- new help_1.Help(cmd.config).showHelp(cmd.id ? [cmd.id, ...cmd.argv] : cmd.argv);
88
+ const Help = await (0, help_1.loadHelpClass)(cmd.config);
89
+ await new Help(cmd.config, cmd.config.pjson.helpOptions).showHelp(cmd.id ? [cmd.id, ...cmd.argv] : cmd.argv);
88
90
  cmd.exit(0);
89
91
  },
90
92
  });
package/lib/help/index.js CHANGED
@@ -91,7 +91,7 @@ class Help extends HelpBase {
91
91
  const command = this.config.findCommand(subject);
92
92
  if (command) {
93
93
  if (command.hasDynamicHelp && command.pluginType !== 'jit') {
94
- const dynamicCommand = await (0, config_1.toCached)(await command.load(), undefined, false);
94
+ const dynamicCommand = await (0, config_1.toCached)(await command.load());
95
95
  await this.showCommandHelp(dynamicCommand);
96
96
  }
97
97
  else {
@@ -123,7 +123,7 @@ class Help extends HelpBase {
123
123
  const depth = name.split(':').length;
124
124
  const subTopics = this.sortedTopics.filter(t => t.name.startsWith(name + ':') && t.name.split(':').length === depth + 1);
125
125
  const subCommands = this.sortedCommands.filter(c => c.id.startsWith(name + ':') && c.id.split(':').length === depth + 1);
126
- const plugin = this.config.plugins.find(p => p.name === command.pluginName);
126
+ const plugin = this.config.plugins.get(command.pluginName);
127
127
  const state = this.config.pjson?.oclif?.state || plugin?.pjson?.oclif?.state || command.state;
128
128
  if (state) {
129
129
  this.log(state === 'deprecated' ?
package/lib/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { Command } from './command';
2
- import { run, execute } from './main';
2
+ import run from './main';
3
+ import execute from './execute';
4
+ import { handle } from './errors/handle';
3
5
  import { Config, Plugin, tsPath, toCached } from './config';
4
6
  import * as Interfaces from './interfaces';
5
7
  import * as Errors from './errors';
@@ -13,6 +15,6 @@ import { settings, Settings } from './settings';
13
15
  import { HelpSection, HelpSectionRenderer, HelpSectionKeyValueTable } from './help/formatter';
14
16
  import * as ux from './cli-ux';
15
17
  import { stderr, stdout } from './cli-ux/stream';
16
- import { Performance } from './performance';
17
- declare const flush: typeof ux.ux.flush;
18
- export { Args, Command, CommandHelp, Config, Errors, Flags, loadHelpClass, Help, HelpBase, HelpSection, HelpSectionRenderer, HelpSectionKeyValueTable, Hook, Interfaces, Parser, Plugin, Performance, run, toCached, tsPath, toStandardizedId, toConfiguredId, settings, Settings, flush, ux, execute, stderr, stdout, };
18
+ import Performance from './performance';
19
+ import { flush } from './cli-ux/flush';
20
+ export { Args, Command, CommandHelp, Config, Errors, execute, Flags, flush, handle, Help, HelpBase, HelpSection, HelpSectionKeyValueTable, HelpSectionRenderer, Hook, Interfaces, loadHelpClass, Parser, Performance, Plugin, run, settings, Settings, stderr, stdout, toCached, toConfiguredId, toStandardizedId, tsPath, ux, };
package/lib/index.js CHANGED
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.stdout = exports.stderr = exports.execute = exports.ux = exports.flush = exports.settings = exports.toConfiguredId = exports.toStandardizedId = exports.tsPath = exports.toCached = exports.run = exports.Performance = exports.Plugin = exports.Parser = exports.Interfaces = exports.HelpBase = exports.Help = exports.loadHelpClass = exports.Flags = exports.Errors = exports.Config = exports.CommandHelp = exports.Command = exports.Args = void 0;
4
- const semver = require("semver");
3
+ exports.ux = exports.tsPath = exports.toStandardizedId = exports.toConfiguredId = exports.toCached = exports.stdout = exports.stderr = exports.settings = exports.run = exports.Plugin = exports.Performance = exports.Parser = exports.loadHelpClass = exports.Interfaces = exports.HelpBase = exports.Help = exports.handle = exports.flush = exports.Flags = exports.execute = exports.Errors = exports.Config = exports.CommandHelp = exports.Command = exports.Args = void 0;
5
4
  const command_1 = require("./command");
6
5
  Object.defineProperty(exports, "Command", { enumerable: true, get: function () { return command_1.Command; } });
7
6
  const main_1 = require("./main");
8
- Object.defineProperty(exports, "run", { enumerable: true, get: function () { return main_1.run; } });
9
- Object.defineProperty(exports, "execute", { enumerable: true, get: function () { return main_1.execute; } });
7
+ exports.run = main_1.default;
8
+ const execute_1 = require("./execute");
9
+ exports.execute = execute_1.default;
10
+ const handle_1 = require("./errors/handle");
11
+ Object.defineProperty(exports, "handle", { enumerable: true, get: function () { return handle_1.handle; } });
10
12
  const config_1 = require("./config");
11
13
  Object.defineProperty(exports, "Config", { enumerable: true, get: function () { return config_1.Config; } });
12
14
  Object.defineProperty(exports, "Plugin", { enumerable: true, get: function () { return config_1.Plugin; } });
@@ -34,14 +36,13 @@ const settings_1 = require("./settings");
34
36
  Object.defineProperty(exports, "settings", { enumerable: true, get: function () { return settings_1.settings; } });
35
37
  const ux = require("./cli-ux");
36
38
  exports.ux = ux;
37
- const util_2 = require("./util");
38
39
  const stream_1 = require("./cli-ux/stream");
39
40
  Object.defineProperty(exports, "stderr", { enumerable: true, get: function () { return stream_1.stderr; } });
40
41
  Object.defineProperty(exports, "stdout", { enumerable: true, get: function () { return stream_1.stdout; } });
41
42
  const performance_1 = require("./performance");
42
- Object.defineProperty(exports, "Performance", { enumerable: true, get: function () { return performance_1.Performance; } });
43
- const flush = ux.flush;
44
- exports.flush = flush;
43
+ exports.Performance = performance_1.default;
44
+ const flush_1 = require("./cli-ux/flush");
45
+ Object.defineProperty(exports, "flush", { enumerable: true, get: function () { return flush_1.flush; } });
45
46
  function checkCWD() {
46
47
  try {
47
48
  process.cwd();
@@ -52,11 +53,4 @@ function checkCWD() {
52
53
  }
53
54
  }
54
55
  }
55
- function checkNodeVersion() {
56
- const pjson = (0, util_2.requireJson)(__dirname, '..', 'package.json');
57
- if (!semver.satisfies(process.versions.node, pjson.engines.node)) {
58
- stream_1.stderr.write(`WARNING\nWARNING Node version must be ${pjson.engines.node} to use this CLI\nWARNING Current node version: ${process.versions.node}\nWARNING\n`);
59
- }
60
- }
61
56
  checkCWD();
62
- checkNodeVersion();