@oclif/core 3.19.7 → 3.20.1-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cache.d.ts +8 -0
- package/lib/cache.js +23 -0
- package/lib/cli-ux/config.js +3 -2
- package/lib/command.js +2 -2
- package/lib/config/config.d.ts +1 -0
- package/lib/config/config.js +19 -7
- package/lib/config/index.d.ts +1 -1
- package/lib/config/index.js +2 -2
- package/lib/config/plugin.d.ts +7 -2
- package/lib/config/plugin.js +136 -36
- package/lib/config/{ts-node.js → ts-path.js} +67 -21
- package/lib/help/docopts.js +1 -1
- package/lib/help/index.js +9 -2
- package/lib/interfaces/config.d.ts +1 -0
- package/lib/interfaces/pjson.d.ts +88 -2
- package/lib/interfaces/plugin.d.ts +2 -2
- package/lib/main.js +7 -11
- package/lib/module-loader.js +2 -2
- package/lib/settings.d.ts +11 -8
- package/lib/symbols.d.ts +1 -0
- package/lib/symbols.js +4 -0
- package/lib/util/fs.d.ts +0 -1
- package/lib/util/fs.js +1 -6
- package/package.json +2 -4
- /package/lib/config/{ts-node.d.ts → ts-path.d.ts} +0 -0
package/lib/cache.d.ts
CHANGED
|
@@ -2,15 +2,23 @@ import { PJSON, Plugin } from './interfaces';
|
|
|
2
2
|
type CacheContents = {
|
|
3
3
|
rootPlugin: Plugin;
|
|
4
4
|
exitCodes: PJSON.Plugin['oclif']['exitCodes'];
|
|
5
|
+
'@oclif/core': OclifCoreInfo;
|
|
5
6
|
};
|
|
6
7
|
type ValueOf<T> = T[keyof T];
|
|
8
|
+
type OclifCoreInfo = {
|
|
9
|
+
name: string;
|
|
10
|
+
version: string;
|
|
11
|
+
};
|
|
7
12
|
/**
|
|
8
13
|
* A simple cache for storing values that need to be accessed globally.
|
|
9
14
|
*/
|
|
10
15
|
export default class Cache extends Map<keyof CacheContents, ValueOf<CacheContents>> {
|
|
11
16
|
static instance: Cache;
|
|
17
|
+
constructor();
|
|
12
18
|
static getInstance(): Cache;
|
|
19
|
+
get(key: '@oclif/core'): OclifCoreInfo;
|
|
13
20
|
get(key: 'rootPlugin'): Plugin | undefined;
|
|
14
21
|
get(key: 'exitCodes'): PJSON.Plugin['oclif']['exitCodes'] | undefined;
|
|
22
|
+
private getOclifCoreMeta;
|
|
15
23
|
}
|
|
16
24
|
export {};
|
package/lib/cache.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_fs_1 = require("node:fs");
|
|
4
|
+
const node_path_1 = require("node:path");
|
|
3
5
|
/**
|
|
4
6
|
* A simple cache for storing values that need to be accessed globally.
|
|
5
7
|
*/
|
|
6
8
|
class Cache extends Map {
|
|
7
9
|
static instance;
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
this.set('@oclif/core', this.getOclifCoreMeta());
|
|
13
|
+
}
|
|
8
14
|
static getInstance() {
|
|
9
15
|
if (!Cache.instance) {
|
|
10
16
|
Cache.instance = new Cache();
|
|
@@ -14,5 +20,22 @@ class Cache extends Map {
|
|
|
14
20
|
get(key) {
|
|
15
21
|
return super.get(key);
|
|
16
22
|
}
|
|
23
|
+
getOclifCoreMeta() {
|
|
24
|
+
try {
|
|
25
|
+
// eslint-disable-next-line node/no-extraneous-require
|
|
26
|
+
return { name: '@oclif/core', version: require('@oclif/core/package.json').version };
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
try {
|
|
30
|
+
return {
|
|
31
|
+
name: '@oclif/core',
|
|
32
|
+
version: JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, '..', 'package.json'), 'utf8')),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return { name: '@oclif/core', version: 'unknown' };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
17
40
|
}
|
|
18
41
|
exports.default = Cache;
|
package/lib/cli-ux/config.js
CHANGED
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.config = exports.Config = void 0;
|
|
7
|
-
const
|
|
7
|
+
const cache_1 = __importDefault(require("../cache"));
|
|
8
8
|
const simple_1 = __importDefault(require("./action/simple"));
|
|
9
9
|
const spinner_1 = __importDefault(require("./action/spinner"));
|
|
10
10
|
const g = global;
|
|
@@ -35,7 +35,8 @@ class Config {
|
|
|
35
35
|
}
|
|
36
36
|
exports.Config = Config;
|
|
37
37
|
function fetch() {
|
|
38
|
-
const
|
|
38
|
+
const core = cache_1.default.getInstance().get('@oclif/core');
|
|
39
|
+
const major = core?.version.split('.')[0] || 'unknown';
|
|
39
40
|
if (globals[major])
|
|
40
41
|
return globals[major];
|
|
41
42
|
globals[major] = new Config();
|
package/lib/command.js
CHANGED
|
@@ -30,16 +30,16 @@ exports.Command = void 0;
|
|
|
30
30
|
const chalk_1 = __importDefault(require("chalk"));
|
|
31
31
|
const node_url_1 = require("node:url");
|
|
32
32
|
const node_util_1 = require("node:util");
|
|
33
|
+
const cache_1 = __importDefault(require("./cache"));
|
|
33
34
|
const cli_ux_1 = require("./cli-ux");
|
|
34
35
|
const config_1 = require("./config");
|
|
35
36
|
const Errors = __importStar(require("./errors"));
|
|
36
37
|
const util_1 = require("./help/util");
|
|
37
38
|
const Parser = __importStar(require("./parser"));
|
|
38
39
|
const aggregate_flags_1 = require("./util/aggregate-flags");
|
|
39
|
-
const fs_1 = require("./util/fs");
|
|
40
40
|
const ids_1 = require("./util/ids");
|
|
41
41
|
const util_2 = require("./util/util");
|
|
42
|
-
const pjson = (
|
|
42
|
+
const pjson = cache_1.default.getInstance().get('@oclif/core');
|
|
43
43
|
/**
|
|
44
44
|
* swallows stdout epipe errors
|
|
45
45
|
* this occurs when stdout closes such as when piping to head
|
package/lib/config/config.d.ts
CHANGED
package/lib/config/config.js
CHANGED
|
@@ -44,11 +44,11 @@ const fs_1 = require("../util/fs");
|
|
|
44
44
|
const os_1 = require("../util/os");
|
|
45
45
|
const util_2 = require("../util/util");
|
|
46
46
|
const plugin_loader_1 = __importDefault(require("./plugin-loader"));
|
|
47
|
-
const
|
|
47
|
+
const ts_path_1 = require("./ts-path");
|
|
48
48
|
const util_3 = require("./util");
|
|
49
49
|
// eslint-disable-next-line new-cap
|
|
50
50
|
const debug = (0, util_3.Debug)();
|
|
51
|
-
const _pjson = (
|
|
51
|
+
const _pjson = cache_1.default.getInstance().get('@oclif/core');
|
|
52
52
|
const BASE = `${_pjson.name}@${_pjson.version}`;
|
|
53
53
|
function channelFromVersion(version) {
|
|
54
54
|
const m = version.match(/[^-]+(?:-([^.]+))?/);
|
|
@@ -98,6 +98,7 @@ class Config {
|
|
|
98
98
|
errlog;
|
|
99
99
|
flexibleTaxonomy;
|
|
100
100
|
home;
|
|
101
|
+
isSingleCommandCLI = false;
|
|
101
102
|
name;
|
|
102
103
|
npmRegistry;
|
|
103
104
|
nsisCustomization;
|
|
@@ -328,6 +329,10 @@ class Config {
|
|
|
328
329
|
...(s3.templates && s3.templates.vanilla),
|
|
329
330
|
},
|
|
330
331
|
};
|
|
332
|
+
this.isSingleCommandCLI = Boolean(this.pjson.oclif.default ||
|
|
333
|
+
(typeof this.pjson.oclif.commands !== 'string' &&
|
|
334
|
+
this.pjson.oclif.commands?.strategy === 'single' &&
|
|
335
|
+
this.pjson.oclif.commands?.target));
|
|
331
336
|
await this.loadPluginsAndCommands();
|
|
332
337
|
debug('config done');
|
|
333
338
|
marker?.addDetails({
|
|
@@ -482,14 +487,21 @@ class Config {
|
|
|
482
487
|
};
|
|
483
488
|
const hooks = p.hooks[event] || [];
|
|
484
489
|
for (const hook of hooks) {
|
|
485
|
-
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `config.runHook#${p.name}(${hook})`);
|
|
490
|
+
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `config.runHook#${p.name}(${hook.target})`);
|
|
486
491
|
try {
|
|
487
492
|
/* eslint-disable no-await-in-loop */
|
|
488
|
-
const { filePath, isESM, module } = await (0, module_loader_1.loadWithData)(p, await (0,
|
|
493
|
+
const { filePath, isESM, module } = await (0, module_loader_1.loadWithData)(p, await (0, ts_path_1.tsPath)(p.root, hook.target, p));
|
|
489
494
|
debug('start', isESM ? '(import)' : '(require)', filePath);
|
|
495
|
+
// If no hook is found using the identifier, then we should `search` for the hook but only if the hook identifier is 'default'
|
|
496
|
+
// A named identifier (e.g. MY_HOOK) that isn't found indicates that the hook isn't implemented in the plugin.
|
|
497
|
+
const hookFn = module[hook.identifier] ?? (hook.identifier === 'default' ? search(module) : undefined);
|
|
498
|
+
if (!hookFn) {
|
|
499
|
+
debug('No hook found for hook definition:', hook);
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
490
502
|
const result = timeout
|
|
491
|
-
? await withTimeout(timeout,
|
|
492
|
-
: await
|
|
503
|
+
? await withTimeout(timeout, hookFn.call(context, { ...opts, config: this, context }))
|
|
504
|
+
: await hookFn.call(context, { ...opts, config: this, context });
|
|
493
505
|
final.successes.push({ plugin: p, result });
|
|
494
506
|
if (p.name === '@oclif/plugin-legacy' && event === 'init') {
|
|
495
507
|
this.insertLegacyPlugins(result);
|
|
@@ -511,7 +523,7 @@ class Config {
|
|
|
511
523
|
}
|
|
512
524
|
marker?.addDetails({
|
|
513
525
|
event,
|
|
514
|
-
hook,
|
|
526
|
+
hook: hook.target,
|
|
515
527
|
plugin: p.name,
|
|
516
528
|
});
|
|
517
529
|
marker?.stop();
|
package/lib/config/index.d.ts
CHANGED
package/lib/config/index.js
CHANGED
|
@@ -5,5 +5,5 @@ var config_1 = require("./config");
|
|
|
5
5
|
Object.defineProperty(exports, "Config", { enumerable: true, get: function () { return config_1.Config; } });
|
|
6
6
|
var plugin_1 = require("./plugin");
|
|
7
7
|
Object.defineProperty(exports, "Plugin", { enumerable: true, get: function () { return plugin_1.Plugin; } });
|
|
8
|
-
var
|
|
9
|
-
Object.defineProperty(exports, "tsPath", { enumerable: true, get: function () { return
|
|
8
|
+
var ts_path_1 = require("./ts-path");
|
|
9
|
+
Object.defineProperty(exports, "tsPath", { enumerable: true, get: function () { return ts_path_1.tsPath; } });
|
package/lib/config/plugin.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from '../command';
|
|
2
2
|
import { Manifest } from '../interfaces/manifest';
|
|
3
|
-
import { PJSON } from '../interfaces/pjson';
|
|
3
|
+
import { HookOptions, PJSON } from '../interfaces/pjson';
|
|
4
4
|
import { Plugin as IPlugin, PluginOptions } from '../interfaces/plugin';
|
|
5
5
|
import { Topic } from '../interfaces/topic';
|
|
6
6
|
export declare class Plugin implements IPlugin {
|
|
@@ -13,7 +13,7 @@ export declare class Plugin implements IPlugin {
|
|
|
13
13
|
commandsDir: string | undefined;
|
|
14
14
|
hasManifest: boolean;
|
|
15
15
|
hooks: {
|
|
16
|
-
[
|
|
16
|
+
[key: string]: HookOptions[];
|
|
17
17
|
};
|
|
18
18
|
isRoot: boolean;
|
|
19
19
|
manifest: Manifest;
|
|
@@ -29,6 +29,8 @@ export declare class Plugin implements IPlugin {
|
|
|
29
29
|
protected warned: boolean;
|
|
30
30
|
_base: string;
|
|
31
31
|
protected _debug: (..._: any) => void;
|
|
32
|
+
private commandCache;
|
|
33
|
+
private commandDiscoveryOpts;
|
|
32
34
|
private flexibleTaxonomy;
|
|
33
35
|
constructor(options: PluginOptions);
|
|
34
36
|
get topics(): Topic[];
|
|
@@ -42,6 +44,9 @@ export declare class Plugin implements IPlugin {
|
|
|
42
44
|
private _manifest;
|
|
43
45
|
private addErrorScope;
|
|
44
46
|
private getCommandIDs;
|
|
47
|
+
private getCommandIdsFromPattern;
|
|
48
|
+
private getCommandIdsFromTarget;
|
|
45
49
|
private getCommandsDir;
|
|
50
|
+
private loadCommandsFromTarget;
|
|
46
51
|
private warn;
|
|
47
52
|
}
|
package/lib/config/plugin.js
CHANGED
|
@@ -7,16 +7,18 @@ exports.Plugin = void 0;
|
|
|
7
7
|
const globby_1 = __importDefault(require("globby"));
|
|
8
8
|
const node_path_1 = require("node:path");
|
|
9
9
|
const node_util_1 = require("node:util");
|
|
10
|
+
const cache_1 = __importDefault(require("../cache"));
|
|
10
11
|
const errors_1 = require("../errors");
|
|
11
12
|
const module_loader_1 = require("../module-loader");
|
|
12
13
|
const performance_1 = require("../performance");
|
|
14
|
+
const symbols_1 = require("../symbols");
|
|
13
15
|
const cache_command_1 = require("../util/cache-command");
|
|
14
16
|
const find_root_1 = require("../util/find-root");
|
|
15
17
|
const fs_1 = require("../util/fs");
|
|
16
18
|
const util_1 = require("../util/util");
|
|
17
|
-
const
|
|
19
|
+
const ts_path_1 = require("./ts-path");
|
|
18
20
|
const util_2 = require("./util");
|
|
19
|
-
const _pjson = (
|
|
21
|
+
const _pjson = cache_1.default.getInstance().get('@oclif/core');
|
|
20
22
|
function topicsToArray(input, base) {
|
|
21
23
|
if (!input)
|
|
22
24
|
return [];
|
|
@@ -30,13 +32,17 @@ function topicsToArray(input, base) {
|
|
|
30
32
|
});
|
|
31
33
|
}
|
|
32
34
|
const cachedCommandCanBeUsed = (manifest, id) => Boolean(manifest?.commands[id] && 'isESM' in manifest.commands[id] && 'relativePath' in manifest.commands[id]);
|
|
33
|
-
const
|
|
35
|
+
const searchForCommandClass = (cmd) => {
|
|
34
36
|
if (typeof cmd.run === 'function')
|
|
35
37
|
return cmd;
|
|
36
38
|
if (cmd.default && cmd.default.run)
|
|
37
39
|
return cmd.default;
|
|
38
40
|
return Object.values(cmd).find((cmd) => typeof cmd.run === 'function');
|
|
39
41
|
};
|
|
42
|
+
const ensureCommandClass = (cmd) => {
|
|
43
|
+
if (cmd && typeof cmd.run === 'function')
|
|
44
|
+
return cmd;
|
|
45
|
+
};
|
|
40
46
|
const GLOB_PATTERNS = [
|
|
41
47
|
'**/*.+(js|cjs|mjs|ts|tsx|mts|cts)',
|
|
42
48
|
'!**/*.+(d.ts|test.ts|test.js|spec.ts|spec.js|d.mts|d.cts)?(x)',
|
|
@@ -47,9 +53,34 @@ function processCommandIds(files) {
|
|
|
47
53
|
const topics = p.dir.split('/');
|
|
48
54
|
const command = p.name !== 'index' && p.name;
|
|
49
55
|
const id = [...topics, command].filter(Boolean).join(':');
|
|
50
|
-
return id === '' ?
|
|
56
|
+
return id === '' ? symbols_1.SINGLE_COMMAND_CLI_SYMBOL : id;
|
|
51
57
|
});
|
|
52
58
|
}
|
|
59
|
+
function determineCommandDiscoveryOptions(commandDiscovery, defaultCmdId) {
|
|
60
|
+
if (!commandDiscovery)
|
|
61
|
+
return;
|
|
62
|
+
if (typeof commandDiscovery === 'string' && defaultCmdId) {
|
|
63
|
+
return { strategy: 'single', target: commandDiscovery };
|
|
64
|
+
}
|
|
65
|
+
if (typeof commandDiscovery === 'string') {
|
|
66
|
+
return { globPatterns: GLOB_PATTERNS, strategy: 'pattern', target: commandDiscovery };
|
|
67
|
+
}
|
|
68
|
+
if (!commandDiscovery.target)
|
|
69
|
+
throw new errors_1.CLIError('`oclif.commandDiscovery.target` is required.');
|
|
70
|
+
if (!commandDiscovery.strategy)
|
|
71
|
+
throw new errors_1.CLIError('`oclif.commandDiscovery.strategy` is required.');
|
|
72
|
+
if (commandDiscovery.strategy === 'explicit' && !commandDiscovery.identifier) {
|
|
73
|
+
commandDiscovery.identifier = 'default';
|
|
74
|
+
}
|
|
75
|
+
return commandDiscovery;
|
|
76
|
+
}
|
|
77
|
+
function determineHookOptions(hook) {
|
|
78
|
+
if (typeof hook === 'string')
|
|
79
|
+
return { identifier: 'default', target: hook };
|
|
80
|
+
if (!hook.identifier)
|
|
81
|
+
return { ...hook, identifier: 'default' };
|
|
82
|
+
return hook;
|
|
83
|
+
}
|
|
53
84
|
class Plugin {
|
|
54
85
|
options;
|
|
55
86
|
alias;
|
|
@@ -76,6 +107,8 @@ class Plugin {
|
|
|
76
107
|
_base = `${_pjson.name}@${_pjson.version}`;
|
|
77
108
|
// eslint-disable-next-line new-cap
|
|
78
109
|
_debug = (0, util_2.Debug)();
|
|
110
|
+
commandCache;
|
|
111
|
+
commandDiscoveryOpts;
|
|
79
112
|
flexibleTaxonomy;
|
|
80
113
|
constructor(options) {
|
|
81
114
|
this.options = options;
|
|
@@ -89,32 +122,43 @@ class Plugin {
|
|
|
89
122
|
plugin: this.name,
|
|
90
123
|
});
|
|
91
124
|
const fetch = async () => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
125
|
+
if (this.commandDiscoveryOpts?.strategy === 'pattern') {
|
|
126
|
+
const commandsDir = await this.getCommandsDir();
|
|
127
|
+
if (!commandsDir)
|
|
128
|
+
return;
|
|
129
|
+
let module;
|
|
130
|
+
let isESM;
|
|
131
|
+
let filePath;
|
|
132
|
+
try {
|
|
133
|
+
;
|
|
134
|
+
({ filePath, isESM, module } = cachedCommandCanBeUsed(this.manifest, id)
|
|
135
|
+
? await (0, module_loader_1.loadWithDataFromManifest)(this.manifest.commands[id], this.root)
|
|
136
|
+
: await (0, module_loader_1.loadWithData)(this, (0, node_path_1.join)(commandsDir ?? this.pjson.oclif.commands, ...id.split(':'))));
|
|
137
|
+
this._debug(isESM ? '(import)' : '(require)', filePath);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
if (!opts.must && error.code === 'MODULE_NOT_FOUND')
|
|
141
|
+
return;
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
const cmd = searchForCommandClass(module);
|
|
145
|
+
if (!cmd)
|
|
146
|
+
return;
|
|
147
|
+
cmd.id = id;
|
|
148
|
+
cmd.plugin = this;
|
|
149
|
+
cmd.isESM = isESM;
|
|
150
|
+
cmd.relativePath = (0, node_path_1.relative)(this.root, filePath || '').split(node_path_1.sep);
|
|
151
|
+
return cmd;
|
|
104
152
|
}
|
|
105
|
-
|
|
106
|
-
|
|
153
|
+
if (this.commandDiscoveryOpts?.strategy === 'single' || this.commandDiscoveryOpts?.strategy === 'explicit') {
|
|
154
|
+
const commandCache = await this.loadCommandsFromTarget();
|
|
155
|
+
const cmd = ensureCommandClass(commandCache?.[id]);
|
|
156
|
+
if (!cmd)
|
|
107
157
|
return;
|
|
108
|
-
|
|
158
|
+
cmd.id = id;
|
|
159
|
+
cmd.plugin = this;
|
|
160
|
+
return cmd;
|
|
109
161
|
}
|
|
110
|
-
const cmd = search(module);
|
|
111
|
-
if (!cmd)
|
|
112
|
-
return;
|
|
113
|
-
cmd.id = id;
|
|
114
|
-
cmd.plugin = this;
|
|
115
|
-
cmd.isESM = isESM;
|
|
116
|
-
cmd.relativePath = (0, node_path_1.relative)(this.root, filePath || '').split(node_path_1.sep);
|
|
117
|
-
return cmd;
|
|
118
162
|
};
|
|
119
163
|
const cmd = await fetch();
|
|
120
164
|
if (!cmd && opts.must)
|
|
@@ -153,7 +197,12 @@ class Plugin {
|
|
|
153
197
|
else {
|
|
154
198
|
this.pjson.oclif = this.pjson['cli-engine'] || {};
|
|
155
199
|
}
|
|
156
|
-
this.hooks = Object.fromEntries(Object.entries(this.pjson.oclif.hooks ?? {}).map(([k, v]) => [
|
|
200
|
+
this.hooks = Object.fromEntries(Object.entries(this.pjson.oclif.hooks ?? {}).map(([k, v]) => [
|
|
201
|
+
k,
|
|
202
|
+
(0, util_1.castArray)(v).map((v) => determineHookOptions(v)),
|
|
203
|
+
]));
|
|
204
|
+
this.commandDiscoveryOpts = determineCommandDiscoveryOptions(this.pjson.oclif?.commands, this.pjson.oclif?.default);
|
|
205
|
+
this._debug('command discovery options', this.commandDiscoveryOpts);
|
|
157
206
|
this.manifest = await this._manifest();
|
|
158
207
|
this.commands = Object.entries(this.manifest.commands)
|
|
159
208
|
.map(([id, c]) => ({
|
|
@@ -205,7 +254,13 @@ class Plugin {
|
|
|
205
254
|
const manifest = {
|
|
206
255
|
commands: (await Promise.all(this.commandIDs.map(async (id) => {
|
|
207
256
|
try {
|
|
208
|
-
const
|
|
257
|
+
const found = await this.findCommand(id, { must: true });
|
|
258
|
+
const cached = await (0, cache_command_1.cacheCommand)(found, this, respectNoCacheDefault);
|
|
259
|
+
// Ensure that id is set to the id being processed
|
|
260
|
+
// This is necessary because the id is set by findCommand but if there
|
|
261
|
+
// are multiple instances of a Command, then the id will be set to the
|
|
262
|
+
// last one found.
|
|
263
|
+
cached.id = id;
|
|
209
264
|
if (this.flexibleTaxonomy) {
|
|
210
265
|
const permutations = (0, util_2.getCommandIdPermutations)(id);
|
|
211
266
|
const aliasPermutations = cached.aliases.flatMap((a) => (0, util_2.getCommandIdPermutations)(a));
|
|
@@ -246,25 +301,70 @@ class Plugin {
|
|
|
246
301
|
return err;
|
|
247
302
|
}
|
|
248
303
|
async getCommandIDs() {
|
|
249
|
-
const commandsDir = await this.getCommandsDir();
|
|
250
|
-
if (!commandsDir)
|
|
251
|
-
return [];
|
|
252
304
|
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `plugin.getCommandIDs#${this.name}`, { plugin: this.name });
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
305
|
+
let ids;
|
|
306
|
+
switch (this.commandDiscoveryOpts?.strategy) {
|
|
307
|
+
case 'explicit': {
|
|
308
|
+
ids = (await this.getCommandIdsFromTarget()) ?? [];
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
case 'pattern': {
|
|
312
|
+
ids = await this.getCommandIdsFromPattern();
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
case 'single': {
|
|
316
|
+
ids = (await this.getCommandIdsFromTarget()) ?? [];
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
default: {
|
|
320
|
+
ids = [];
|
|
321
|
+
}
|
|
322
|
+
}
|
|
256
323
|
this._debug('found commands', ids);
|
|
257
324
|
marker?.addDetails({ count: ids.length });
|
|
258
325
|
marker?.stop();
|
|
259
326
|
return ids;
|
|
260
327
|
}
|
|
328
|
+
async getCommandIdsFromPattern() {
|
|
329
|
+
const commandsDir = await this.getCommandsDir();
|
|
330
|
+
if (!commandsDir)
|
|
331
|
+
return [];
|
|
332
|
+
this._debug(`loading IDs from ${commandsDir}`);
|
|
333
|
+
const files = await (0, globby_1.default)(this.commandDiscoveryOpts?.globPatterns ?? GLOB_PATTERNS, { cwd: commandsDir });
|
|
334
|
+
return processCommandIds(files);
|
|
335
|
+
}
|
|
336
|
+
async getCommandIdsFromTarget() {
|
|
337
|
+
const commandsFromExport = await this.loadCommandsFromTarget();
|
|
338
|
+
if (commandsFromExport) {
|
|
339
|
+
return Object.entries((await this.loadCommandsFromTarget()) ?? [])
|
|
340
|
+
.filter(([, cmd]) => ensureCommandClass(cmd))
|
|
341
|
+
.map(([id]) => id);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
261
344
|
async getCommandsDir() {
|
|
262
345
|
if (this.commandsDir)
|
|
263
346
|
return this.commandsDir;
|
|
264
|
-
this.commandsDir = await (0,
|
|
347
|
+
this.commandsDir = await (0, ts_path_1.tsPath)(this.root, this.commandDiscoveryOpts?.target, this);
|
|
265
348
|
return this.commandsDir;
|
|
266
349
|
}
|
|
350
|
+
async loadCommandsFromTarget() {
|
|
351
|
+
if (this.commandCache)
|
|
352
|
+
return this.commandCache;
|
|
353
|
+
if (this.commandDiscoveryOpts?.strategy === 'explicit' && this.commandDiscoveryOpts.target) {
|
|
354
|
+
const filePath = await (0, ts_path_1.tsPath)(this.root, this.commandDiscoveryOpts.target, this);
|
|
355
|
+
const module = await (0, module_loader_1.load)(this, filePath);
|
|
356
|
+
this.commandCache = module[this.commandDiscoveryOpts?.identifier ?? 'default'] ?? {};
|
|
357
|
+
return this.commandCache;
|
|
358
|
+
}
|
|
359
|
+
if (this.commandDiscoveryOpts?.strategy === 'single' && this.commandDiscoveryOpts.target) {
|
|
360
|
+
const filePath = await (0, ts_path_1.tsPath)(this.root, this.commandDiscoveryOpts?.target ?? this.root, this);
|
|
361
|
+
const module = await (0, module_loader_1.load)(this, filePath);
|
|
362
|
+
this.commandCache = { [symbols_1.SINGLE_COMMAND_CLI_SYMBOL]: searchForCommandClass(module) };
|
|
363
|
+
return this.commandCache;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
267
366
|
warn(err, scope) {
|
|
367
|
+
console.trace();
|
|
268
368
|
if (this.warned)
|
|
269
369
|
return;
|
|
270
370
|
if (typeof err === 'string')
|
|
@@ -13,9 +13,50 @@ const read_tsconfig_1 = require("../util/read-tsconfig");
|
|
|
13
13
|
const util_1 = require("../util/util");
|
|
14
14
|
const util_2 = require("./util");
|
|
15
15
|
// eslint-disable-next-line new-cap
|
|
16
|
-
const debug = (0, util_2.Debug)('ts-
|
|
16
|
+
const debug = (0, util_2.Debug)('ts-path');
|
|
17
17
|
exports.TS_CONFIGS = {};
|
|
18
18
|
const REGISTERED = new Set();
|
|
19
|
+
function determineRuntime() {
|
|
20
|
+
/**
|
|
21
|
+
* Examples:
|
|
22
|
+
* #!/usr/bin/env bun
|
|
23
|
+
* bun bin/run.js
|
|
24
|
+
* bun bin/dev.js
|
|
25
|
+
*/
|
|
26
|
+
if (process.execPath.split(node_path_1.sep).includes('bun'))
|
|
27
|
+
return 'bun';
|
|
28
|
+
/**
|
|
29
|
+
* Examples:
|
|
30
|
+
* #!/usr/bin/env node
|
|
31
|
+
* #!/usr/bin/env node --loader ts-node/esm --experimental-specifier-resolution=node --no-warnings
|
|
32
|
+
* node bin/run.js
|
|
33
|
+
* node bin/dev.js
|
|
34
|
+
*/
|
|
35
|
+
if (process.execArgv.length === 0)
|
|
36
|
+
return 'node';
|
|
37
|
+
/**
|
|
38
|
+
* Examples:
|
|
39
|
+
* #!/usr/bin/env ts-node
|
|
40
|
+
* #!/usr/bin/env node_modules/.bin/ts-node
|
|
41
|
+
* ts-node bin/run.js
|
|
42
|
+
* ts-node bin/dev.js
|
|
43
|
+
*/
|
|
44
|
+
if (process.execArgv[0] === '--require' && process.execArgv[1].split(node_path_1.sep).includes('ts-node'))
|
|
45
|
+
return 'ts-node';
|
|
46
|
+
if (process.execArgv[0].split(node_path_1.sep).includes('ts-node'))
|
|
47
|
+
return 'ts-node';
|
|
48
|
+
/**
|
|
49
|
+
* Examples:
|
|
50
|
+
* #!/usr/bin/env tsx
|
|
51
|
+
* #!/usr/bin/env node_modules/.bin/tsx
|
|
52
|
+
* tsx bin/run.js
|
|
53
|
+
* tsx bin/dev.js
|
|
54
|
+
*/
|
|
55
|
+
if (process.execArgv[0] === '--require' && process.execArgv[1].split(node_path_1.sep).includes('tsx'))
|
|
56
|
+
return 'tsx';
|
|
57
|
+
return 'node';
|
|
58
|
+
}
|
|
59
|
+
const RUN_TIME = determineRuntime();
|
|
19
60
|
function isErrno(error) {
|
|
20
61
|
return 'code' in error && error.code === 'ENOENT';
|
|
21
62
|
}
|
|
@@ -23,22 +64,23 @@ async function loadTSConfig(root) {
|
|
|
23
64
|
try {
|
|
24
65
|
if (exports.TS_CONFIGS[root])
|
|
25
66
|
return exports.TS_CONFIGS[root];
|
|
26
|
-
|
|
67
|
+
const tsconfig = await (0, read_tsconfig_1.readTSConfig)(root);
|
|
68
|
+
if (!tsconfig)
|
|
69
|
+
return;
|
|
70
|
+
debug('tsconfig: %O', tsconfig);
|
|
71
|
+
exports.TS_CONFIGS[root] = tsconfig;
|
|
27
72
|
return exports.TS_CONFIGS[root];
|
|
28
73
|
}
|
|
29
74
|
catch (error) {
|
|
30
75
|
if (isErrno(error))
|
|
31
76
|
return;
|
|
32
|
-
debug(`Could not parse tsconfig.json. Skipping
|
|
77
|
+
debug(`Could not parse tsconfig.json. Skipping typescript path lookup for ${root}.`);
|
|
33
78
|
(0, errors_1.memoizedWarn)(`Could not parse tsconfig.json for ${root}. Falling back to compiled source.`);
|
|
34
79
|
}
|
|
35
80
|
}
|
|
36
|
-
async function registerTSNode(root) {
|
|
37
|
-
const tsconfig = await loadTSConfig(root);
|
|
38
|
-
if (!tsconfig)
|
|
39
|
-
return;
|
|
81
|
+
async function registerTSNode(root, tsconfig) {
|
|
40
82
|
if (REGISTERED.has(root))
|
|
41
|
-
return
|
|
83
|
+
return;
|
|
42
84
|
debug('registering ts-node at', root);
|
|
43
85
|
const tsNodePath = require.resolve('ts-node', { paths: [root, __dirname] });
|
|
44
86
|
debug('ts-node path:', tsNodePath);
|
|
@@ -87,11 +129,9 @@ async function registerTSNode(root) {
|
|
|
87
129
|
skipProject: true,
|
|
88
130
|
transpileOnly: true,
|
|
89
131
|
};
|
|
132
|
+
debug('ts-node options: %O', conf);
|
|
90
133
|
tsNode.register(conf);
|
|
91
134
|
REGISTERED.add(root);
|
|
92
|
-
debug('tsconfig: %O', tsconfig);
|
|
93
|
-
debug('ts-node options: %O', conf);
|
|
94
|
-
return tsconfig;
|
|
95
135
|
}
|
|
96
136
|
/**
|
|
97
137
|
* Skip ts-node registration for ESM plugins in production.
|
|
@@ -121,17 +161,22 @@ function cannotUseTsNode(root, plugin, isProduction) {
|
|
|
121
161
|
if (plugin?.moduleType !== 'module' || isProduction)
|
|
122
162
|
return false;
|
|
123
163
|
const nodeMajor = Number.parseInt(process.version.replace('v', '').split('.')[0], 10);
|
|
124
|
-
|
|
125
|
-
return tsNodeExecIsUsed && nodeMajor >= 20;
|
|
164
|
+
return RUN_TIME === 'ts-node' && nodeMajor >= 20;
|
|
126
165
|
}
|
|
127
166
|
/**
|
|
128
167
|
* Determine the path to the source file from the compiled ./lib files
|
|
129
168
|
*/
|
|
130
169
|
async function determinePath(root, orig) {
|
|
131
|
-
const tsconfig = await
|
|
170
|
+
const tsconfig = await loadTSConfig(root);
|
|
132
171
|
if (!tsconfig)
|
|
133
172
|
return orig;
|
|
134
|
-
debug(`
|
|
173
|
+
debug(`Determining path for ${orig}`);
|
|
174
|
+
if (RUN_TIME === 'tsx' || RUN_TIME === 'bun') {
|
|
175
|
+
debug(`Skipping ts-node registration for ${root} because the runtime is: ${RUN_TIME}`);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
await registerTSNode(root, tsconfig);
|
|
179
|
+
}
|
|
135
180
|
const { baseUrl, outDir, rootDir, rootDirs } = tsconfig.compilerOptions;
|
|
136
181
|
const rootDirPath = rootDir ?? (rootDirs ?? [])[0] ?? baseUrl;
|
|
137
182
|
if (!rootDirPath) {
|
|
@@ -171,24 +216,25 @@ async function tsPath(root, orig, plugin) {
|
|
|
171
216
|
return orig;
|
|
172
217
|
orig = orig.startsWith(root) ? orig : (0, node_path_1.join)(root, orig);
|
|
173
218
|
// NOTE: The order of these checks matter!
|
|
174
|
-
|
|
175
|
-
|
|
219
|
+
const enableAutoTranspile = settings_1.settings.enableAutoTranspile ?? settings_1.settings.tsnodeEnabled;
|
|
220
|
+
if (enableAutoTranspile === false) {
|
|
221
|
+
debug(`Skipping typescript path lookup for ${root} because enableAutoTranspile is explicitly set to false`);
|
|
176
222
|
return orig;
|
|
177
223
|
}
|
|
178
224
|
const isProduction = (0, util_1.isProd)();
|
|
179
225
|
// Do not skip ts-node registration if the plugin is linked
|
|
180
|
-
if (
|
|
181
|
-
debug(`Skipping
|
|
226
|
+
if (enableAutoTranspile === undefined && isProduction && plugin?.type !== 'link') {
|
|
227
|
+
debug(`Skipping typescript path lookup for ${root} because NODE_ENV is NOT "test" or "development"`);
|
|
182
228
|
return orig;
|
|
183
229
|
}
|
|
184
230
|
if (cannotTranspileEsm(rootPlugin, plugin, isProduction)) {
|
|
185
|
-
debug(`Skipping
|
|
231
|
+
debug(`Skipping typescript path lookup for ${root} because it's an ESM module (NODE_ENV: ${process.env.NODE_ENV}, root plugin module type: ${rootPlugin?.moduleType})`);
|
|
186
232
|
if (plugin?.type === 'link')
|
|
187
233
|
(0, errors_1.memoizedWarn)(`${plugin?.name} is a linked ESM module and cannot be auto-transpiled. Existing compiled source will be used instead.`);
|
|
188
234
|
return orig;
|
|
189
235
|
}
|
|
190
236
|
if (cannotUseTsNode(root, plugin, isProduction)) {
|
|
191
|
-
debug(`Skipping
|
|
237
|
+
debug(`Skipping typescript path lookup for ${root} because ts-node is run in node version ${process.version}"`);
|
|
192
238
|
(0, errors_1.memoizedWarn)(`ts-node executable cannot transpile ESM in Node 20. Existing compiled source will be used instead. See https://github.com/oclif/core/issues/817.`);
|
|
193
239
|
return orig;
|
|
194
240
|
}
|
package/lib/help/docopts.js
CHANGED
|
@@ -77,7 +77,7 @@ class DocOpts {
|
|
|
77
77
|
return new DocOpts(cmd).toString();
|
|
78
78
|
}
|
|
79
79
|
toString() {
|
|
80
|
-
const opts =
|
|
80
|
+
const opts = ['<%= command.id %>'];
|
|
81
81
|
if (this.cmd.args) {
|
|
82
82
|
const a = Object.values((0, ensure_arg_object_1.ensureArgObject)(this.cmd.args)).map((arg) => arg.required ? arg.name.toUpperCase() : `[${arg.name.toUpperCase()}]`) || [];
|
|
83
83
|
opts.push(...a);
|
package/lib/help/index.js
CHANGED
|
@@ -10,6 +10,7 @@ const theme_1 = require("../cli-ux/theme");
|
|
|
10
10
|
const write_1 = __importDefault(require("../cli-ux/write"));
|
|
11
11
|
const errors_1 = require("../errors");
|
|
12
12
|
const module_loader_1 = require("../module-loader");
|
|
13
|
+
const symbols_1 = require("../symbols");
|
|
13
14
|
const cache_default_value_1 = require("../util/cache-default-value");
|
|
14
15
|
const ids_1 = require("../util/ids");
|
|
15
16
|
const util_1 = require("../util/util");
|
|
@@ -189,8 +190,8 @@ class Help extends HelpBase {
|
|
|
189
190
|
argv = (0, util_2.standardizeIDFromArgv)(argv, this.config);
|
|
190
191
|
const subject = getHelpSubject(argv, this.config);
|
|
191
192
|
if (!subject) {
|
|
192
|
-
if (this.config.
|
|
193
|
-
const rootCmd = this.config.findCommand(
|
|
193
|
+
if (this.config.isSingleCommandCLI) {
|
|
194
|
+
const rootCmd = this.config.findCommand(symbols_1.SINGLE_COMMAND_CLI_SYMBOL);
|
|
194
195
|
if (rootCmd) {
|
|
195
196
|
await this.showCommandHelp(rootCmd);
|
|
196
197
|
return;
|
|
@@ -201,6 +202,12 @@ class Help extends HelpBase {
|
|
|
201
202
|
}
|
|
202
203
|
const command = this.config.findCommand(subject);
|
|
203
204
|
if (command) {
|
|
205
|
+
if (command.id === symbols_1.SINGLE_COMMAND_CLI_SYMBOL) {
|
|
206
|
+
// If the command is the root command of a single command CLI,
|
|
207
|
+
// then set the command id to an empty string to prevent the
|
|
208
|
+
// the SINGLE_COMMAND_CLI_SYMBOL from being displayed in the help output.
|
|
209
|
+
command.id = '';
|
|
210
|
+
}
|
|
204
211
|
if (command.hasDynamicHelp && command.pluginType !== 'jit') {
|
|
205
212
|
const loaded = await command.load();
|
|
206
213
|
for (const [name, flag] of Object.entries(loaded.flags ?? {})) {
|
|
@@ -16,6 +16,86 @@ export interface PJSON {
|
|
|
16
16
|
};
|
|
17
17
|
version: string;
|
|
18
18
|
}
|
|
19
|
+
export type CommandDiscovery = {
|
|
20
|
+
/**
|
|
21
|
+
* The strategy to use for loading commands.
|
|
22
|
+
*
|
|
23
|
+
* - `pattern` will use glob patterns to find command files in the specified `target`.
|
|
24
|
+
* - `explicit` will use `import` (or `require` for CJS) to load the commands from the
|
|
25
|
+
* specified `target`.
|
|
26
|
+
* - `single` will use the `target` which should export a command class. This is for CLIs that
|
|
27
|
+
* only have a single command.
|
|
28
|
+
*
|
|
29
|
+
* In both cases, the `oclif.manifest.json` file will be used to find the commands if it exists.
|
|
30
|
+
*/
|
|
31
|
+
strategy: 'pattern' | 'explicit' | 'single';
|
|
32
|
+
/**
|
|
33
|
+
* If the `strategy` is `pattern`, this is the **directory** to use to find command files.
|
|
34
|
+
*
|
|
35
|
+
* If the `strategy` is `explicit`, this is the **file** that exports the commands.
|
|
36
|
+
* - This export must be an object with keys that are the command names and values that are the command classes.
|
|
37
|
+
* - Unless `identifier` is specified, the default export will be used.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // in src/commands.ts
|
|
42
|
+
* import {Command} from '@oclif/core'
|
|
43
|
+
* import Hello from './commands/hello/index.js'
|
|
44
|
+
* import HelloWorld from './commands/hello/world.js'
|
|
45
|
+
*
|
|
46
|
+
* export default {
|
|
47
|
+
* hello: Hello,
|
|
48
|
+
* 'hello:world': HelloWorld,
|
|
49
|
+
* } satisfies Record<string, Command.Class>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
target: string;
|
|
53
|
+
/**
|
|
54
|
+
* The glob patterns to use to find command files when no `oclif.manifest.json` is present.
|
|
55
|
+
* This is only used when `strategy` is `pattern`.
|
|
56
|
+
*/
|
|
57
|
+
globPatterns?: string[];
|
|
58
|
+
/**
|
|
59
|
+
* The name of the export to used when loading the command object from the `target` file. Only
|
|
60
|
+
* used when `strategy` is `explicit`. Defaults to `default`.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* // in src/commands.ts
|
|
65
|
+
* import {Command} from '@oclif/core'
|
|
66
|
+
* import Hello from './commands/hello/index.js'
|
|
67
|
+
* import HelloWorld from './commands/hello/world.js'
|
|
68
|
+
*
|
|
69
|
+
* export const MY_COMMANDS = {
|
|
70
|
+
* hello: Hello,
|
|
71
|
+
* 'hello:world': HelloWorld,
|
|
72
|
+
* } satisfies Record<string, Command.Class>
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* In the package.json:
|
|
76
|
+
* ```json
|
|
77
|
+
* {
|
|
78
|
+
* "oclif": {
|
|
79
|
+
* "commands": {
|
|
80
|
+
* "strategy": "explicit",
|
|
81
|
+
* "target": "./dist/index.js",
|
|
82
|
+
* "identifier": "MY_COMMANDS"
|
|
83
|
+
* }
|
|
84
|
+
* }
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
identifier?: string;
|
|
88
|
+
};
|
|
89
|
+
export type HookOptions = {
|
|
90
|
+
/**
|
|
91
|
+
* The file path containing hook.
|
|
92
|
+
*/
|
|
93
|
+
target: string;
|
|
94
|
+
/**
|
|
95
|
+
* The name of the export to use when loading the hook function from the `target` file. Defaults to `default`.
|
|
96
|
+
*/
|
|
97
|
+
identifier: string;
|
|
98
|
+
};
|
|
19
99
|
export declare namespace PJSON {
|
|
20
100
|
interface Plugin extends PJSON {
|
|
21
101
|
name: string;
|
|
@@ -25,7 +105,13 @@ export declare namespace PJSON {
|
|
|
25
105
|
aliases?: {
|
|
26
106
|
[name: string]: null | string;
|
|
27
107
|
};
|
|
28
|
-
commands?: string;
|
|
108
|
+
commands?: string | CommandDiscovery;
|
|
109
|
+
/**
|
|
110
|
+
* Default command id when no command is found. This is used to support single command CLIs.
|
|
111
|
+
* Only supported value is "."
|
|
112
|
+
*
|
|
113
|
+
* @deprecated Use `commands.strategy: 'single'` instead.
|
|
114
|
+
*/
|
|
29
115
|
default?: string;
|
|
30
116
|
description?: string;
|
|
31
117
|
devPlugins?: string[];
|
|
@@ -42,7 +128,7 @@ export declare namespace PJSON {
|
|
|
42
128
|
helpClass?: string;
|
|
43
129
|
helpOptions?: HelpOptions;
|
|
44
130
|
hooks?: {
|
|
45
|
-
[name: string]: string | string[];
|
|
131
|
+
[name: string]: string | string[] | HookOptions | HookOptions[];
|
|
46
132
|
};
|
|
47
133
|
jitPlugins?: Record<string, string>;
|
|
48
134
|
macos?: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from '../command';
|
|
2
|
-
import { PJSON } from './pjson';
|
|
2
|
+
import { HookOptions, PJSON } from './pjson';
|
|
3
3
|
import { Topic } from './topic';
|
|
4
4
|
export interface PluginOptions {
|
|
5
5
|
children?: Plugin[];
|
|
@@ -44,7 +44,7 @@ export interface Plugin {
|
|
|
44
44
|
}): Promise<Command.Class> | undefined;
|
|
45
45
|
readonly hasManifest: boolean;
|
|
46
46
|
hooks: {
|
|
47
|
-
[
|
|
47
|
+
[key: string]: HookOptions[];
|
|
48
48
|
};
|
|
49
49
|
/**
|
|
50
50
|
* True if the plugin is the root plugin.
|
package/lib/main.js
CHANGED
|
@@ -6,9 +6,10 @@ const cli_ux_1 = require("./cli-ux");
|
|
|
6
6
|
const config_1 = require("./config");
|
|
7
7
|
const help_1 = require("./help");
|
|
8
8
|
const performance_1 = require("./performance");
|
|
9
|
+
const symbols_1 = require("./symbols");
|
|
9
10
|
const debug = require('debug')('oclif:main');
|
|
10
11
|
const helpAddition = (argv, config) => {
|
|
11
|
-
if (argv.length === 0 && !config.
|
|
12
|
+
if (argv.length === 0 && !config.isSingleCommandCLI)
|
|
12
13
|
return true;
|
|
13
14
|
const mergedHelpFlags = (0, help_1.getHelpFlagAdditions)(config);
|
|
14
15
|
for (const arg of argv) {
|
|
@@ -52,7 +53,11 @@ async function run(argv, options) {
|
|
|
52
53
|
options = (0, node_url_1.fileURLToPath)(options);
|
|
53
54
|
}
|
|
54
55
|
const config = await config_1.Config.load(options ?? require.main?.filename ?? __dirname);
|
|
55
|
-
|
|
56
|
+
// If this is a single command CLI, then insert the SINGLE_COMMAND_CLI_SYMBOL into the argv array to serve as the command id.
|
|
57
|
+
if (config.isSingleCommandCLI) {
|
|
58
|
+
argv = [symbols_1.SINGLE_COMMAND_CLI_SYMBOL, ...argv];
|
|
59
|
+
}
|
|
60
|
+
const [id, ...argvSlice] = (0, help_1.normalizeArgv)(config, argv);
|
|
56
61
|
// run init hook
|
|
57
62
|
await config.runHook('init', { argv: argvSlice, id });
|
|
58
63
|
// display version if applicable
|
|
@@ -76,17 +81,8 @@ async function run(argv, options) {
|
|
|
76
81
|
await collectPerf();
|
|
77
82
|
return;
|
|
78
83
|
}
|
|
79
|
-
if (config.pjson.oclif.default) {
|
|
80
|
-
id = config.pjson.oclif.default;
|
|
81
|
-
argvSlice = argv;
|
|
82
|
-
}
|
|
83
84
|
}
|
|
84
85
|
initMarker?.stop();
|
|
85
|
-
// If the the default command is '.' (signifying that the CLI is a single command CLI) and '.' is provided
|
|
86
|
-
// as an argument, we need to add back the '.' to argv since it was stripped out earlier as part of the
|
|
87
|
-
// command id.
|
|
88
|
-
if (config.pjson.oclif.default === '.' && id === '.' && argv[0] === '.')
|
|
89
|
-
argvSlice = ['.', ...argvSlice];
|
|
90
86
|
try {
|
|
91
87
|
return await config.runCommand(id, argvSlice, cmd);
|
|
92
88
|
}
|
package/lib/module-loader.js
CHANGED
|
@@ -4,7 +4,7 @@ exports.isPathModule = exports.loadWithDataFromManifest = exports.loadWithData =
|
|
|
4
4
|
const node_fs_1 = require("node:fs");
|
|
5
5
|
const node_path_1 = require("node:path");
|
|
6
6
|
const node_url_1 = require("node:url");
|
|
7
|
-
const
|
|
7
|
+
const ts_path_1 = require("./config/ts-path");
|
|
8
8
|
const errors_1 = require("./errors");
|
|
9
9
|
const fs_1 = require("./util/fs");
|
|
10
10
|
const getPackageType = require('get-package-type');
|
|
@@ -164,7 +164,7 @@ async function resolvePath(config, modulePath) {
|
|
|
164
164
|
}
|
|
165
165
|
catch {
|
|
166
166
|
filePath =
|
|
167
|
-
(isPlugin(config) ? await (0,
|
|
167
|
+
(isPlugin(config) ? await (0, ts_path_1.tsPath)(config.root, modulePath, config) : await (0, ts_path_1.tsPath)(config.root, modulePath)) ??
|
|
168
168
|
modulePath;
|
|
169
169
|
let fileExists = false;
|
|
170
170
|
let isDirectory = false;
|
package/lib/settings.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export type Settings = {
|
|
|
9
9
|
/**
|
|
10
10
|
* Show additional debug output without DEBUG. Mainly shows stackstraces.
|
|
11
11
|
*
|
|
12
|
-
* Useful to set in the ./bin/dev script.
|
|
12
|
+
* Useful to set in the ./bin/dev.js script.
|
|
13
13
|
* oclif.settings.debug = true;
|
|
14
14
|
*/
|
|
15
15
|
debug?: boolean;
|
|
@@ -25,15 +25,18 @@ export type Settings = {
|
|
|
25
25
|
*/
|
|
26
26
|
performanceEnabled?: boolean;
|
|
27
27
|
/**
|
|
28
|
-
* Try to use ts-node to load typescript source files instead of
|
|
29
|
-
*
|
|
28
|
+
* Try to use ts-node to load typescript source files instead of javascript files.
|
|
29
|
+
* Defaults to true in development and test environments (e.g. using bin/dev.js or
|
|
30
|
+
* NODE_ENV=development or NODE_ENV=test).
|
|
30
31
|
*
|
|
31
|
-
*
|
|
32
|
-
* require('ts-node').register();
|
|
33
|
-
*
|
|
34
|
-
* Environment Variable:
|
|
35
|
-
* NODE_ENV=development
|
|
32
|
+
* @deprecated use enableAutoTranspile instead.
|
|
36
33
|
*/
|
|
37
34
|
tsnodeEnabled?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Enable automatic transpilation of TypeScript files to JavaScript.
|
|
37
|
+
*
|
|
38
|
+
* Defaults to true in development and test environments (e.g. using bin/dev.js or NODE_ENV=development or NODE_ENV=test).
|
|
39
|
+
*/
|
|
40
|
+
enableAutoTranspile?: boolean;
|
|
38
41
|
};
|
|
39
42
|
export declare const settings: Settings;
|
package/lib/symbols.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SINGLE_COMMAND_CLI_SYMBOL: string;
|
package/lib/symbols.js
ADDED
package/lib/util/fs.d.ts
CHANGED
package/lib/util/fs.js
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.existsSync = exports.safeReadJson = exports.readJsonSync = exports.readJson = exports.fileExists = exports.dirExists =
|
|
3
|
+
exports.existsSync = exports.safeReadJson = exports.readJsonSync = exports.readJson = exports.fileExists = exports.dirExists = void 0;
|
|
4
4
|
const node_fs_1 = require("node:fs");
|
|
5
5
|
const promises_1 = require("node:fs/promises");
|
|
6
|
-
const node_path_1 = require("node:path");
|
|
7
|
-
function requireJson(...pathParts) {
|
|
8
|
-
return JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(...pathParts), 'utf8'));
|
|
9
|
-
}
|
|
10
|
-
exports.requireJson = requireJson;
|
|
11
6
|
/**
|
|
12
7
|
* Parser for Args.directory and Flags.directory. Checks that the provided path
|
|
13
8
|
* exists and is a directory.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oclif/core",
|
|
3
3
|
"description": "base library for oclif CLIs",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.20.1-dev.0",
|
|
5
5
|
"author": "Salesforce",
|
|
6
6
|
"bugs": "https://github.com/oclif/core/issues",
|
|
7
7
|
"dependencies": {
|
|
@@ -114,7 +114,6 @@
|
|
|
114
114
|
"access": "public"
|
|
115
115
|
},
|
|
116
116
|
"scripts": {
|
|
117
|
-
"build:dev": "shx rm -rf lib && tsc --sourceMap",
|
|
118
117
|
"build": "shx rm -rf lib && tsc",
|
|
119
118
|
"commitlint": "commitlint",
|
|
120
119
|
"compile": "tsc",
|
|
@@ -127,9 +126,8 @@
|
|
|
127
126
|
"test:circular-deps": "madge lib/ -c",
|
|
128
127
|
"test:debug": "nyc mocha --debug-brk --inspect \"test/**/*.test.ts\"",
|
|
129
128
|
"test:integration": "mocha --forbid-only \"test/**/*.integration.ts\" --parallel --timeout 1200000",
|
|
130
|
-
"test:
|
|
129
|
+
"test:interoperability": "cross-env DEBUG=integration:* ts-node test/integration/interop.ts",
|
|
131
130
|
"test:perf": "ts-node test/perf/parser.perf.ts",
|
|
132
|
-
"test:dev": "nyc mocha \"test/**/*.test.ts\"",
|
|
133
131
|
"test": "nyc mocha --forbid-only \"test/**/*.test.ts\""
|
|
134
132
|
},
|
|
135
133
|
"types": "lib/index.d.ts"
|
|
File without changes
|