first commit
This commit is contained in:
136
node_modules/@oclif/core/lib/config/config.d.ts
generated
vendored
Normal file
136
node_modules/@oclif/core/lib/config/config.d.ts
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
import { Command } from '../command';
|
||||
import { Hook, Hooks, OclifConfiguration, PJSON, S3Templates, Topic, UserPJSON } from '../interfaces';
|
||||
import { ArchTypes, Config as IConfig, LoadOptions, PlatformTypes, VersionDetails } from '../interfaces/config';
|
||||
import { Plugin as IPlugin, Options } from '../interfaces/plugin';
|
||||
import { Theme } from '../interfaces/theme';
|
||||
export declare class Config implements IConfig {
|
||||
options: Options;
|
||||
arch: ArchTypes;
|
||||
bin: string;
|
||||
binAliases?: string[] | undefined;
|
||||
binPath?: string | undefined;
|
||||
cacheDir: string;
|
||||
channel: string;
|
||||
configDir: string;
|
||||
dataDir: string;
|
||||
dirname: string;
|
||||
flexibleTaxonomy: boolean;
|
||||
home: string;
|
||||
isSingleCommandCLI: boolean;
|
||||
name: string;
|
||||
npmRegistry?: string | undefined;
|
||||
nsisCustomization?: string | undefined;
|
||||
pjson: PJSON;
|
||||
platform: PlatformTypes;
|
||||
plugins: Map<string, IPlugin>;
|
||||
root: string;
|
||||
shell: string;
|
||||
theme?: Theme | undefined;
|
||||
topicSeparator: ' ' | ':';
|
||||
updateConfig: NonNullable<OclifConfiguration['update']>;
|
||||
userAgent: string;
|
||||
userPJSON?: UserPJSON | undefined;
|
||||
valid: boolean;
|
||||
version: string;
|
||||
protected warned: boolean;
|
||||
windows: boolean;
|
||||
private _base;
|
||||
private _commandIDs;
|
||||
private _commands;
|
||||
private _topics;
|
||||
private commandPermutations;
|
||||
private pluginLoader;
|
||||
private rootPlugin;
|
||||
private topicPermutations;
|
||||
constructor(options: Options);
|
||||
static load(opts?: LoadOptions): Promise<Config>;
|
||||
get commandIDs(): string[];
|
||||
get commands(): Command.Loadable[];
|
||||
protected get isProd(): boolean;
|
||||
static get rootPlugin(): IPlugin | undefined;
|
||||
get topics(): Topic[];
|
||||
get versionDetails(): VersionDetails;
|
||||
protected _shell(): string;
|
||||
protected dir(category: 'cache' | 'config' | 'data'): string;
|
||||
findCommand(id: string, opts: {
|
||||
must: true;
|
||||
}): Command.Loadable;
|
||||
findCommand(id: string, opts?: {
|
||||
must: boolean;
|
||||
}): Command.Loadable | undefined;
|
||||
/**
|
||||
* Find all command ids that include the provided command id.
|
||||
*
|
||||
* For example, if the command ids are:
|
||||
* - foo:bar:baz
|
||||
* - one:two:three
|
||||
*
|
||||
* `bar` would return `foo:bar:baz`
|
||||
*
|
||||
* @param partialCmdId string
|
||||
* @param argv string[] process.argv containing the flags and arguments provided by the user
|
||||
* @returns string[]
|
||||
*/
|
||||
findMatches(partialCmdId: string, argv: string[]): Command.Loadable[];
|
||||
findTopic(id: string, opts: {
|
||||
must: true;
|
||||
}): Topic;
|
||||
findTopic(id: string, opts?: {
|
||||
must: boolean;
|
||||
}): Topic | undefined;
|
||||
/**
|
||||
* Returns an array of all command ids. If flexible taxonomy is enabled then all permutations will be appended to the array.
|
||||
* @returns string[]
|
||||
*/
|
||||
getAllCommandIDs(): string[];
|
||||
/**
|
||||
* Returns an array of all commands. If flexible taxonomy is enabled then all permutations will be appended to the array.
|
||||
* @returns Command.Loadable[]
|
||||
*/
|
||||
getAllCommands(): Command.Loadable[];
|
||||
getPluginsList(): IPlugin[];
|
||||
load(): Promise<void>;
|
||||
loadPluginsAndCommands(opts?: {
|
||||
force: boolean;
|
||||
}): Promise<void>;
|
||||
loadTheme(): Promise<Theme | undefined>;
|
||||
protected macosCacheDir(): string | undefined;
|
||||
runCommand<T = unknown>(id: string, argv?: string[], cachedCommand?: Command.Loadable | null): Promise<T>;
|
||||
runHook<T extends keyof Hooks, P extends Hooks = Hooks>(event: T, opts: P[T]['options'], timeout?: number, captureErrors?: boolean): Promise<Hook.Result<P[T]['return']>>;
|
||||
s3Key(type: keyof S3Templates, ext?: '.tar.gz' | '.tar.xz' | IConfig.s3Key.Options, options?: IConfig.s3Key.Options): string;
|
||||
s3Url(key: string): string;
|
||||
scopedEnvVar(k: string): string | undefined;
|
||||
/**
|
||||
* this DOES NOT account for bin aliases, use scopedEnvVarKeys instead which will account for bin aliases
|
||||
* @param k {string}, the unscoped key you want to get the value for
|
||||
* @returns {string} returns the env var key
|
||||
*/
|
||||
scopedEnvVarKey(k: string): string;
|
||||
/**
|
||||
* gets the scoped env var keys for a given key, including bin aliases
|
||||
* @param k {string}, the env key e.g. 'debug'
|
||||
* @returns {string[]} e.g. ['SF_DEBUG', 'SFDX_DEBUG']
|
||||
*/
|
||||
scopedEnvVarKeys(k: string): string[];
|
||||
scopedEnvVarTrue(k: string): boolean;
|
||||
protected windowsHome(): string | undefined;
|
||||
protected windowsHomedriveHome(): string | undefined;
|
||||
protected windowsUserprofileHome(): string | undefined;
|
||||
private buildS3Config;
|
||||
private getCmdLookupId;
|
||||
private getTopicLookupId;
|
||||
/**
|
||||
* Insert legacy plugins
|
||||
*
|
||||
* Replace invalid CLI plugins (cli-engine plugins, mostly Heroku) loaded via `this.loadPlugins`
|
||||
* with oclif-compatible ones returned by @oclif/plugin-legacy init hook.
|
||||
*
|
||||
* @param plugins array of oclif-compatible plugins
|
||||
*/
|
||||
private insertLegacyPlugins;
|
||||
private isJitPluginCommand;
|
||||
private loadCommands;
|
||||
private loadTopics;
|
||||
private maybeAdjustDebugSetting;
|
||||
private warn;
|
||||
}
|
||||
816
node_modules/@oclif/core/lib/config/config.js
generated
vendored
Normal file
816
node_modules/@oclif/core/lib/config/config.js
generated
vendored
Normal file
@@ -0,0 +1,816 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Config = void 0;
|
||||
const ejs = __importStar(require("ejs"));
|
||||
const is_wsl_1 = __importDefault(require("is-wsl"));
|
||||
const node_os_1 = require("node:os");
|
||||
const node_path_1 = require("node:path");
|
||||
const node_url_1 = require("node:url");
|
||||
const cache_1 = __importDefault(require("../cache"));
|
||||
const errors_1 = require("../errors");
|
||||
const util_1 = require("../help/util");
|
||||
const logger_1 = require("../logger");
|
||||
const module_loader_1 = require("../module-loader");
|
||||
const performance_1 = require("../performance");
|
||||
const settings_1 = require("../settings");
|
||||
const determine_priority_1 = require("../util/determine-priority");
|
||||
const fs_1 = require("../util/fs");
|
||||
const ids_1 = require("../util/ids");
|
||||
const os_1 = require("../util/os");
|
||||
const util_2 = require("../util/util");
|
||||
const ux_1 = require("../ux");
|
||||
const theme_1 = require("../ux/theme");
|
||||
const plugin_loader_1 = __importDefault(require("./plugin-loader"));
|
||||
const ts_path_1 = require("./ts-path");
|
||||
const util_3 = require("./util");
|
||||
const debug = (0, util_3.makeDebug)();
|
||||
const _pjson = cache_1.default.getInstance().get('@oclif/core');
|
||||
const BASE = `${_pjson.name}@${_pjson.version}`;
|
||||
const ROOT_ONLY_HOOKS = new Set(['preparse']);
|
||||
function displayWarnings() {
|
||||
if (process.listenerCount('warning') > 1)
|
||||
return;
|
||||
process.on('warning', (warning) => {
|
||||
console.error(warning.stack);
|
||||
if (warning.detail)
|
||||
console.error(warning.detail);
|
||||
});
|
||||
}
|
||||
function channelFromVersion(version) {
|
||||
const m = version.match(/[^-]+(?:-([^.]+))?/);
|
||||
return (m && m[1]) || 'stable';
|
||||
}
|
||||
function isConfig(o) {
|
||||
return o && Boolean(o._base);
|
||||
}
|
||||
class Permutations extends Map {
|
||||
validPermutations = new Map();
|
||||
add(permutation, commandId) {
|
||||
this.validPermutations.set(permutation, commandId);
|
||||
for (const id of (0, util_3.collectUsableIds)([permutation])) {
|
||||
if (this.has(id)) {
|
||||
this.set(id, this.get(id).add(commandId));
|
||||
}
|
||||
else {
|
||||
this.set(id, new Set([commandId]));
|
||||
}
|
||||
}
|
||||
}
|
||||
get(key) {
|
||||
return super.get(key) ?? new Set();
|
||||
}
|
||||
getAllValid() {
|
||||
return [...this.validPermutations.keys()];
|
||||
}
|
||||
getValid(key) {
|
||||
return this.validPermutations.get(key);
|
||||
}
|
||||
hasValid(key) {
|
||||
return this.validPermutations.has(key);
|
||||
}
|
||||
}
|
||||
class Config {
|
||||
options;
|
||||
arch;
|
||||
bin;
|
||||
binAliases;
|
||||
binPath;
|
||||
cacheDir;
|
||||
channel;
|
||||
configDir;
|
||||
dataDir;
|
||||
dirname;
|
||||
flexibleTaxonomy;
|
||||
home;
|
||||
isSingleCommandCLI = false;
|
||||
name;
|
||||
npmRegistry;
|
||||
nsisCustomization;
|
||||
pjson;
|
||||
platform;
|
||||
plugins = new Map();
|
||||
root;
|
||||
shell;
|
||||
theme;
|
||||
topicSeparator = ':';
|
||||
updateConfig;
|
||||
userAgent;
|
||||
userPJSON;
|
||||
valid;
|
||||
version;
|
||||
warned = false;
|
||||
windows;
|
||||
_base = BASE;
|
||||
_commandIDs;
|
||||
_commands = new Map();
|
||||
_topics = new Map();
|
||||
commandPermutations = new Permutations();
|
||||
pluginLoader;
|
||||
rootPlugin;
|
||||
topicPermutations = new Permutations();
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
static async load(opts = module.filename || __dirname) {
|
||||
(0, logger_1.setLogger)(opts);
|
||||
// Handle the case when a file URL string is passed in such as 'import.meta.url'; covert to file path.
|
||||
if (typeof opts === 'string' && opts.startsWith('file://')) {
|
||||
opts = (0, node_url_1.fileURLToPath)(opts);
|
||||
}
|
||||
if (typeof opts === 'string')
|
||||
opts = { root: opts };
|
||||
if (isConfig(opts)) {
|
||||
/**
|
||||
* Reload the Config based on the version required by the command.
|
||||
* This is needed because the command is given the Config instantiated
|
||||
* by the root plugin, which may be a different version than the one
|
||||
* required by the command.
|
||||
*
|
||||
* Doing this ensures that the command can freely use any method on Config that
|
||||
* exists in the version of Config required by the command but may not exist on the
|
||||
* root's instance of Config.
|
||||
*/
|
||||
if (BASE !== opts._base) {
|
||||
debug(`reloading config from ${opts._base} to ${BASE}`);
|
||||
const config = new Config({ ...opts.options, plugins: opts.plugins });
|
||||
await config.load();
|
||||
return config;
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
const config = new Config(opts);
|
||||
await config.load();
|
||||
return config;
|
||||
}
|
||||
get commandIDs() {
|
||||
if (this._commandIDs)
|
||||
return this._commandIDs;
|
||||
this._commandIDs = this.commands.map((c) => c.id);
|
||||
return this._commandIDs;
|
||||
}
|
||||
get commands() {
|
||||
return [...this._commands.values()];
|
||||
}
|
||||
get isProd() {
|
||||
return (0, util_2.isProd)();
|
||||
}
|
||||
static get rootPlugin() {
|
||||
return this.rootPlugin;
|
||||
}
|
||||
get topics() {
|
||||
return [...this._topics.values()];
|
||||
}
|
||||
get versionDetails() {
|
||||
const [cliVersion, architecture, nodeVersion] = this.userAgent.split(' ');
|
||||
return {
|
||||
architecture,
|
||||
cliVersion,
|
||||
nodeVersion,
|
||||
osVersion: `${(0, node_os_1.type)()} ${(0, node_os_1.release)()}`,
|
||||
pluginVersions: Object.fromEntries([...this.plugins.values()].map((p) => [p.name, { root: p.root, type: p.type, version: p.version }])),
|
||||
rootPath: this.root,
|
||||
shell: this.shell,
|
||||
};
|
||||
}
|
||||
_shell() {
|
||||
let shellPath;
|
||||
const { COMSPEC } = process.env;
|
||||
const SHELL = process.env.SHELL ?? (0, node_os_1.userInfo)().shell?.split(node_path_1.sep)?.pop();
|
||||
if (SHELL) {
|
||||
shellPath = SHELL.split('/');
|
||||
}
|
||||
else if (this.windows && process.title.toLowerCase().includes('powershell')) {
|
||||
shellPath = ['powershell'];
|
||||
}
|
||||
else if (this.windows && process.title.toLowerCase().includes('command prompt')) {
|
||||
shellPath = ['cmd.exe'];
|
||||
}
|
||||
else if (this.windows && COMSPEC) {
|
||||
shellPath = COMSPEC.split(/\\|\//);
|
||||
}
|
||||
else {
|
||||
shellPath = ['unknown'];
|
||||
}
|
||||
return shellPath.at(-1) ?? 'unknown';
|
||||
}
|
||||
dir(category) {
|
||||
const base = process.env[`XDG_${category.toUpperCase()}_HOME`] ||
|
||||
(this.windows && process.env.LOCALAPPDATA) ||
|
||||
(0, node_path_1.join)(this.home, category === 'data' ? '.local/share' : '.' + category);
|
||||
return (0, node_path_1.join)(base, this.dirname);
|
||||
}
|
||||
findCommand(id, opts = {}) {
|
||||
const lookupId = this.getCmdLookupId(id);
|
||||
const command = this._commands.get(lookupId);
|
||||
if (opts.must && !command)
|
||||
(0, errors_1.error)(`command ${lookupId} not found`);
|
||||
return command;
|
||||
}
|
||||
/**
|
||||
* Find all command ids that include the provided command id.
|
||||
*
|
||||
* For example, if the command ids are:
|
||||
* - foo:bar:baz
|
||||
* - one:two:three
|
||||
*
|
||||
* `bar` would return `foo:bar:baz`
|
||||
*
|
||||
* @param partialCmdId string
|
||||
* @param argv string[] process.argv containing the flags and arguments provided by the user
|
||||
* @returns string[]
|
||||
*/
|
||||
findMatches(partialCmdId, argv) {
|
||||
const flags = argv
|
||||
.filter((arg) => !(0, util_1.getHelpFlagAdditions)(this).includes(arg) && arg.startsWith('-'))
|
||||
.map((a) => a.replaceAll('-', ''));
|
||||
const possibleMatches = [...this.commandPermutations.get(partialCmdId)].map((k) => this._commands.get(k));
|
||||
const matches = possibleMatches.filter((command) => {
|
||||
const cmdFlags = Object.entries(command.flags).flatMap(([flag, def]) => def.char ? [def.char, flag] : [flag]);
|
||||
// A command is a match if the provided flags belong to the full command
|
||||
return flags.every((f) => cmdFlags.includes(f));
|
||||
});
|
||||
return matches;
|
||||
}
|
||||
findTopic(name, opts = {}) {
|
||||
const lookupId = this.getTopicLookupId(name);
|
||||
const topic = this._topics.get(lookupId);
|
||||
if (topic)
|
||||
return topic;
|
||||
if (opts.must)
|
||||
throw new Error(`topic ${name} not found`);
|
||||
}
|
||||
/**
|
||||
* Returns an array of all command ids. If flexible taxonomy is enabled then all permutations will be appended to the array.
|
||||
* @returns string[]
|
||||
*/
|
||||
getAllCommandIDs() {
|
||||
return this.getAllCommands().map((c) => c.id);
|
||||
}
|
||||
/**
|
||||
* Returns an array of all commands. If flexible taxonomy is enabled then all permutations will be appended to the array.
|
||||
* @returns Command.Loadable[]
|
||||
*/
|
||||
getAllCommands() {
|
||||
const commands = [...this._commands.values()];
|
||||
const validPermutations = [...this.commandPermutations.getAllValid()];
|
||||
for (const permutation of validPermutations) {
|
||||
if (!this._commands.has(permutation)) {
|
||||
const cmd = this._commands.get(this.getCmdLookupId(permutation));
|
||||
commands.push({ ...cmd, id: permutation });
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
getPluginsList() {
|
||||
return [...this.plugins.values()];
|
||||
}
|
||||
// eslint-disable-next-line complexity
|
||||
async load() {
|
||||
settings_1.settings.performanceEnabled =
|
||||
(settings_1.settings.performanceEnabled === undefined ? this.options.enablePerf : settings_1.settings.performanceEnabled) ?? false;
|
||||
if (settings_1.settings.debug)
|
||||
displayWarnings();
|
||||
(0, logger_1.setLogger)(this.options);
|
||||
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, 'config.load');
|
||||
this.pluginLoader = new plugin_loader_1.default({ plugins: this.options.plugins, root: this.options.root });
|
||||
this.rootPlugin = await this.pluginLoader.loadRoot({ pjson: this.options.pjson });
|
||||
// Cache the root plugin so that we can reference it later when determining if
|
||||
// we should skip ts-node registration for an ESM plugin.
|
||||
const cache = cache_1.default.getInstance();
|
||||
cache.set('rootPlugin', this.rootPlugin);
|
||||
cache.set('exitCodes', this.rootPlugin.pjson.oclif.exitCodes ?? {});
|
||||
this.root = this.rootPlugin.root;
|
||||
this.pjson = this.rootPlugin.pjson;
|
||||
this.plugins.set(this.rootPlugin.name, this.rootPlugin);
|
||||
this.root = this.rootPlugin.root;
|
||||
this.pjson = this.rootPlugin.pjson;
|
||||
this.name = this.pjson.name;
|
||||
this.version = this.options.version || this.pjson.version || '0.0.0';
|
||||
this.channel = this.options.channel || channelFromVersion(this.version);
|
||||
this.valid = this.rootPlugin.valid;
|
||||
this.arch = (0, node_os_1.arch)() === 'ia32' ? 'x86' : (0, node_os_1.arch)();
|
||||
this.platform = is_wsl_1.default ? 'wsl' : (0, os_1.getPlatform)();
|
||||
this.windows = this.platform === 'win32';
|
||||
this.bin = this.pjson.oclif.bin || this.name;
|
||||
this.binAliases = this.pjson.oclif.binAliases;
|
||||
this.nsisCustomization = this.pjson.oclif.nsisCustomization;
|
||||
this.dirname = this.pjson.oclif.dirname || this.name;
|
||||
this.flexibleTaxonomy = this.pjson.oclif.flexibleTaxonomy || false;
|
||||
// currently, only colons or spaces are valid separators
|
||||
if (this.pjson.oclif.topicSeparator && [' ', ':'].includes(this.pjson.oclif.topicSeparator))
|
||||
this.topicSeparator = this.pjson.oclif.topicSeparator;
|
||||
if (this.platform === 'win32')
|
||||
this.dirname = this.dirname.replace('/', '\\');
|
||||
this.userAgent = `${this.name}/${this.version} ${this.platform}-${this.arch} node-${process.version}`;
|
||||
this.shell = this._shell();
|
||||
this.home = process.env.HOME || (this.windows && this.windowsHome()) || (0, os_1.getHomeDir)() || (0, node_os_1.tmpdir)();
|
||||
this.cacheDir = this.scopedEnvVar('CACHE_DIR') || this.macosCacheDir() || this.dir('cache');
|
||||
this.configDir = this.scopedEnvVar('CONFIG_DIR') || this.dir('config');
|
||||
this.dataDir = this.scopedEnvVar('DATA_DIR') || this.dir('data');
|
||||
this.binPath = this.scopedEnvVar('BINPATH');
|
||||
this.npmRegistry = this.scopedEnvVar('NPM_REGISTRY') || this.pjson.oclif.npmRegistry;
|
||||
this.theme = await this.loadTheme();
|
||||
this.updateConfig = {
|
||||
...this.pjson.oclif.update,
|
||||
node: this.pjson.oclif.update?.node ?? {},
|
||||
s3: this.buildS3Config(),
|
||||
};
|
||||
this.isSingleCommandCLI = Boolean(typeof this.pjson.oclif.commands !== 'string' &&
|
||||
this.pjson.oclif.commands?.strategy === 'single' &&
|
||||
this.pjson.oclif.commands?.target);
|
||||
this.maybeAdjustDebugSetting();
|
||||
await this.loadPluginsAndCommands();
|
||||
debug('config done');
|
||||
marker?.addDetails({
|
||||
commandPermutations: this.commands.length,
|
||||
commands: [...this.plugins.values()].reduce((acc, p) => acc + p.commands.length, 0),
|
||||
plugins: this.plugins.size,
|
||||
topics: this.topics.length,
|
||||
});
|
||||
marker?.stop();
|
||||
}
|
||||
async loadPluginsAndCommands(opts) {
|
||||
const pluginsMarker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, 'config.loadAllPlugins');
|
||||
const { errors, plugins } = await this.pluginLoader.loadChildren({
|
||||
dataDir: this.dataDir,
|
||||
devPlugins: this.options.devPlugins,
|
||||
force: opts?.force ?? false,
|
||||
pluginAdditions: this.options.pluginAdditions,
|
||||
rootPlugin: this.rootPlugin,
|
||||
userPlugins: this.options.userPlugins,
|
||||
});
|
||||
this.plugins = plugins;
|
||||
pluginsMarker?.stop();
|
||||
const commandsMarker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, 'config.loadAllCommands');
|
||||
for (const plugin of this.plugins.values()) {
|
||||
this.loadCommands(plugin);
|
||||
this.loadTopics(plugin);
|
||||
}
|
||||
commandsMarker?.stop();
|
||||
for (const error of errors) {
|
||||
this.warn(error);
|
||||
}
|
||||
}
|
||||
async loadTheme() {
|
||||
if (this.scopedEnvVarTrue('DISABLE_THEME'))
|
||||
return;
|
||||
const userThemeFile = (0, node_path_1.resolve)(this.configDir, 'theme.json');
|
||||
const getDefaultTheme = async () => {
|
||||
if (!this.pjson.oclif.theme)
|
||||
return;
|
||||
if (typeof this.pjson.oclif.theme === 'string') {
|
||||
return (0, fs_1.safeReadJson)((0, node_path_1.resolve)(this.root, this.pjson.oclif.theme));
|
||||
}
|
||||
return this.pjson.oclif.theme;
|
||||
};
|
||||
const [defaultTheme, userTheme] = await Promise.all([
|
||||
getDefaultTheme(),
|
||||
(0, fs_1.safeReadJson)(userThemeFile),
|
||||
]);
|
||||
// Merge the default theme with the user theme, giving the user theme precedence.
|
||||
const merged = { ...defaultTheme, ...userTheme };
|
||||
return Object.keys(merged).length > 0 ? (0, theme_1.parseTheme)(merged) : undefined;
|
||||
}
|
||||
macosCacheDir() {
|
||||
return (this.platform === 'darwin' && (0, node_path_1.join)(this.home, 'Library', 'Caches', this.dirname)) || undefined;
|
||||
}
|
||||
async runCommand(id, argv = [], cachedCommand = null) {
|
||||
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `config.runCommand#${id}`);
|
||||
debug('runCommand %s %o', id, argv);
|
||||
let c = cachedCommand ?? this.findCommand(id);
|
||||
if (!c) {
|
||||
const matches = this.flexibleTaxonomy ? this.findMatches(id, argv) : [];
|
||||
const hookResult = this.flexibleTaxonomy && matches.length > 0
|
||||
? await this.runHook('command_incomplete', { argv, id, matches })
|
||||
: await this.runHook('command_not_found', { argv, id });
|
||||
if (hookResult.successes[0])
|
||||
return hookResult.successes[0].result;
|
||||
if (hookResult.failures[0])
|
||||
throw hookResult.failures[0].error;
|
||||
throw new errors_1.CLIError(`command ${id} not found`);
|
||||
}
|
||||
if (this.isJitPluginCommand(c)) {
|
||||
const pluginName = c.pluginName;
|
||||
const pluginVersion = this.pjson.oclif.jitPlugins[pluginName];
|
||||
const jitResult = await this.runHook('jit_plugin_not_installed', {
|
||||
argv,
|
||||
command: c,
|
||||
id,
|
||||
pluginName,
|
||||
pluginVersion,
|
||||
});
|
||||
if (jitResult.failures[0])
|
||||
throw jitResult.failures[0].error;
|
||||
if (jitResult.successes[0]) {
|
||||
await this.loadPluginsAndCommands({ force: true });
|
||||
c = this.findCommand(id) ?? c;
|
||||
}
|
||||
else {
|
||||
// this means that no jit_plugin_not_installed hook exists, so we should run the default behavior
|
||||
const result = await this.runHook('command_not_found', { argv, id });
|
||||
if (result.successes[0])
|
||||
return result.successes[0].result;
|
||||
if (result.failures[0])
|
||||
throw result.failures[0].error;
|
||||
throw new errors_1.CLIError(`command ${id} not found`);
|
||||
}
|
||||
}
|
||||
const command = await c.load();
|
||||
await this.runHook('prerun', { argv, Command: command });
|
||||
const result = (await command.run(argv, this));
|
||||
// If plugins:uninstall was run, we need to remove all the uninstalled plugins
|
||||
// from this.plugins so that the postrun hook doesn't attempt to run any
|
||||
// hooks that might have existed in the uninstalled plugins.
|
||||
if (c.id === 'plugins:uninstall') {
|
||||
for (const arg of argv)
|
||||
this.plugins.delete(arg);
|
||||
}
|
||||
await this.runHook('postrun', { argv, Command: command, result });
|
||||
marker?.addDetails({ command: id, plugin: c.pluginName });
|
||||
marker?.stop();
|
||||
return result;
|
||||
}
|
||||
async runHook(event, opts, timeout, captureErrors) {
|
||||
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `config.runHook#${event}`);
|
||||
debug('start %s hook', event);
|
||||
const search = (m) => {
|
||||
if (typeof m === 'function')
|
||||
return m;
|
||||
if (m.default && typeof m.default === 'function')
|
||||
return m.default;
|
||||
return Object.values(m).find((m) => typeof m === 'function');
|
||||
};
|
||||
const withTimeout = async (ms, promise) => {
|
||||
let id;
|
||||
const timeout = new Promise((_, reject) => {
|
||||
id = setTimeout(() => {
|
||||
reject(new Error(`Timed out after ${ms} ms.`));
|
||||
}, ms).unref();
|
||||
});
|
||||
return Promise.race([promise, timeout]).then((result) => {
|
||||
clearTimeout(id);
|
||||
return result;
|
||||
});
|
||||
};
|
||||
const final = {
|
||||
failures: [],
|
||||
successes: [],
|
||||
};
|
||||
const plugins = ROOT_ONLY_HOOKS.has(event) ? [this.rootPlugin] : [...this.plugins.values()];
|
||||
const promises = plugins.map(async (p) => {
|
||||
const debug = (0, logger_1.makeDebug)([p.name, 'hooks', event].join(':'));
|
||||
const context = {
|
||||
config: this,
|
||||
debug,
|
||||
error(message, options = {}) {
|
||||
(0, errors_1.error)(message, options);
|
||||
},
|
||||
exit(code = 0) {
|
||||
(0, errors_1.exit)(code);
|
||||
},
|
||||
log(message, ...args) {
|
||||
ux_1.ux.stdout(message, ...args);
|
||||
},
|
||||
warn(message) {
|
||||
(0, errors_1.warn)(message);
|
||||
},
|
||||
};
|
||||
const hooks = p.hooks[event] || [];
|
||||
for (const hook of hooks) {
|
||||
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `config.runHook#${p.name}(${hook.target})`);
|
||||
try {
|
||||
/* eslint-disable no-await-in-loop */
|
||||
const { filePath, isESM, module } = await (0, module_loader_1.loadWithData)(p, await (0, ts_path_1.tsPath)(p.root, hook.target, p));
|
||||
debug('start', isESM ? '(import)' : '(require)', filePath);
|
||||
// If no hook is found using the identifier, then we should `search` for the hook but only if the hook identifier is 'default'
|
||||
// A named identifier (e.g. MY_HOOK) that isn't found indicates that the hook isn't implemented in the plugin.
|
||||
const hookFn = module[hook.identifier] ?? (hook.identifier === 'default' ? search(module) : undefined);
|
||||
if (!hookFn) {
|
||||
debug('No hook found for hook definition:', hook);
|
||||
continue;
|
||||
}
|
||||
const result = timeout
|
||||
? await withTimeout(timeout, hookFn.call(context, { ...opts, config: this, context }))
|
||||
: await hookFn.call(context, { ...opts, config: this, context });
|
||||
final.successes.push({ plugin: p, result });
|
||||
if (p.name === '@oclif/plugin-legacy' && event === 'init') {
|
||||
this.insertLegacyPlugins(result);
|
||||
}
|
||||
debug('done');
|
||||
}
|
||||
catch (error) {
|
||||
final.failures.push({ error: error, plugin: p });
|
||||
debug(error);
|
||||
// Do not throw the error if
|
||||
// captureErrors is set to true
|
||||
// error.oclif.exit is undefined or 0
|
||||
// error.code is MODULE_NOT_FOUND
|
||||
if (!captureErrors &&
|
||||
error.oclif?.exit !== undefined &&
|
||||
error.oclif?.exit !== 0 &&
|
||||
error.code !== 'MODULE_NOT_FOUND')
|
||||
throw error;
|
||||
}
|
||||
marker?.addDetails({
|
||||
event,
|
||||
hook: hook.target,
|
||||
plugin: p.name,
|
||||
});
|
||||
marker?.stop();
|
||||
}
|
||||
});
|
||||
await Promise.all(promises);
|
||||
debug('%s hook done', event);
|
||||
marker?.stop();
|
||||
return final;
|
||||
}
|
||||
s3Key(type, ext, options = {}) {
|
||||
if (typeof ext === 'object')
|
||||
options = ext;
|
||||
else if (ext)
|
||||
options.ext = ext;
|
||||
const template = this.updateConfig.s3?.templates?.[options.platform ? 'target' : 'vanilla'][type] ?? '';
|
||||
return ejs.render(template, { ...this, ...options });
|
||||
}
|
||||
s3Url(key) {
|
||||
const { host } = this.updateConfig.s3 ?? { host: undefined };
|
||||
if (!host)
|
||||
throw new Error('no s3 host is set');
|
||||
const url = new node_url_1.URL(host);
|
||||
url.pathname = (0, node_path_1.join)(url.pathname, key);
|
||||
return url.toString();
|
||||
}
|
||||
scopedEnvVar(k) {
|
||||
return process.env[this.scopedEnvVarKeys(k).find((k) => process.env[k])];
|
||||
}
|
||||
/**
|
||||
* this DOES NOT account for bin aliases, use scopedEnvVarKeys instead which will account for bin aliases
|
||||
* @param k {string}, the unscoped key you want to get the value for
|
||||
* @returns {string} returns the env var key
|
||||
*/
|
||||
scopedEnvVarKey(k) {
|
||||
return [this.bin, k]
|
||||
.map((p) => p.replaceAll('@', '').replaceAll(/[/-]/g, '_'))
|
||||
.join('_')
|
||||
.toUpperCase();
|
||||
}
|
||||
/**
|
||||
* gets the scoped env var keys for a given key, including bin aliases
|
||||
* @param k {string}, the env key e.g. 'debug'
|
||||
* @returns {string[]} e.g. ['SF_DEBUG', 'SFDX_DEBUG']
|
||||
*/
|
||||
scopedEnvVarKeys(k) {
|
||||
return [this.bin, ...(this.binAliases ?? [])]
|
||||
.filter(Boolean)
|
||||
.map((alias) => [alias.replaceAll('@', '').replaceAll(/[/-]/g, '_'), k].join('_').toUpperCase());
|
||||
}
|
||||
scopedEnvVarTrue(k) {
|
||||
const v = this.scopedEnvVar(k);
|
||||
return v === '1' || v === 'true';
|
||||
}
|
||||
windowsHome() {
|
||||
return this.windowsHomedriveHome() || this.windowsUserprofileHome();
|
||||
}
|
||||
windowsHomedriveHome() {
|
||||
return process.env.HOMEDRIVE && process.env.HOMEPATH && (0, node_path_1.join)(process.env.HOMEDRIVE, process.env.HOMEPATH);
|
||||
}
|
||||
windowsUserprofileHome() {
|
||||
return process.env.USERPROFILE;
|
||||
}
|
||||
buildS3Config() {
|
||||
const s3 = this.pjson.oclif.update?.s3;
|
||||
const bucket = this.scopedEnvVar('S3_BUCKET') ?? s3?.bucket;
|
||||
const host = s3?.host ?? (bucket && `https://${bucket}.s3.amazonaws.com`);
|
||||
const templates = {
|
||||
...s3?.templates,
|
||||
target: {
|
||||
baseDir: '<%- bin %>',
|
||||
manifest: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %><%- platform %>-<%- arch %>",
|
||||
unversioned: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %><%- bin %>-<%- platform %>-<%- arch %><%- ext %>",
|
||||
versioned: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %><%- bin %>-v<%- version %>/<%- bin %>-v<%- version %>-<%- platform %>-<%- arch %><%- ext %>",
|
||||
...(s3?.templates && s3?.templates.target),
|
||||
},
|
||||
vanilla: {
|
||||
baseDir: '<%- bin %>',
|
||||
manifest: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %>version",
|
||||
unversioned: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %><%- bin %><%- ext %>",
|
||||
versioned: "<%- channel === 'stable' ? '' : 'channels/' + channel + '/' %><%- bin %>-v<%- version %>/<%- bin %>-v<%- version %><%- ext %>",
|
||||
...(s3?.templates && s3?.templates.vanilla),
|
||||
},
|
||||
};
|
||||
return {
|
||||
bucket,
|
||||
host,
|
||||
templates,
|
||||
};
|
||||
}
|
||||
getCmdLookupId(id) {
|
||||
if (this._commands.has(id))
|
||||
return id;
|
||||
if (this.commandPermutations.hasValid(id))
|
||||
return this.commandPermutations.getValid(id);
|
||||
return id;
|
||||
}
|
||||
getTopicLookupId(id) {
|
||||
if (this._topics.has(id))
|
||||
return id;
|
||||
if (this.topicPermutations.hasValid(id))
|
||||
return this.topicPermutations.getValid(id);
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* Insert legacy plugins
|
||||
*
|
||||
* Replace invalid CLI plugins (cli-engine plugins, mostly Heroku) loaded via `this.loadPlugins`
|
||||
* with oclif-compatible ones returned by @oclif/plugin-legacy init hook.
|
||||
*
|
||||
* @param plugins array of oclif-compatible plugins
|
||||
*/
|
||||
insertLegacyPlugins(plugins) {
|
||||
for (const plugin of plugins) {
|
||||
this.plugins.set(plugin.name, plugin);
|
||||
// Delete all commands from the legacy plugin so that we can re-add them.
|
||||
// This is necessary because determinePriority will pick the initial
|
||||
// command that was added, which won't have been converted by PluginLegacy yet.
|
||||
for (const cmd of plugin.commands ?? []) {
|
||||
this._commands.delete(cmd.id);
|
||||
for (const alias of [...(cmd.aliases ?? []), ...(cmd.hiddenAliases ?? [])]) {
|
||||
this._commands.delete(alias);
|
||||
}
|
||||
}
|
||||
this.loadCommands(plugin);
|
||||
}
|
||||
}
|
||||
isJitPluginCommand(c) {
|
||||
// Return true if the command's plugin is listed under oclif.jitPlugins AND if the plugin hasn't been loaded to this.plugins
|
||||
return (Object.keys(this.pjson.oclif.jitPlugins ?? {}).includes(c.pluginName ?? '') &&
|
||||
Boolean(c?.pluginName && !this.plugins.has(c.pluginName)));
|
||||
}
|
||||
loadCommands(plugin) {
|
||||
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `config.loadCommands#${plugin.name}`, { plugin: plugin.name });
|
||||
for (const command of plugin.commands) {
|
||||
// set canonical command id
|
||||
if (this._commands.has(command.id)) {
|
||||
const prioritizedCommand = (0, determine_priority_1.determinePriority)(this.pjson.oclif.plugins ?? [], [
|
||||
this._commands.get(command.id),
|
||||
command,
|
||||
]);
|
||||
this._commands.set(prioritizedCommand.id, prioritizedCommand);
|
||||
}
|
||||
else {
|
||||
this._commands.set(command.id, command);
|
||||
}
|
||||
// v3 moved command id permutations to the manifest, but some plugins may not have
|
||||
// the new manifest yet. For those, we need to calculate the permutations here.
|
||||
const permutations = this.flexibleTaxonomy && command.permutations === undefined
|
||||
? (0, util_3.getCommandIdPermutations)(command.id)
|
||||
: (command.permutations ?? [command.id]);
|
||||
// set every permutation
|
||||
for (const permutation of permutations) {
|
||||
this.commandPermutations.add(permutation, command.id);
|
||||
}
|
||||
const handleAlias = (alias, hidden = false) => {
|
||||
const aliasWithDefaultTopicSeparator = (0, ids_1.toStandardizedId)(alias, this);
|
||||
if (this._commands.has(aliasWithDefaultTopicSeparator)) {
|
||||
const prioritizedCommand = (0, determine_priority_1.determinePriority)(this.pjson.oclif.plugins ?? [], [
|
||||
this._commands.get(aliasWithDefaultTopicSeparator),
|
||||
command,
|
||||
]);
|
||||
this._commands.set(aliasWithDefaultTopicSeparator, {
|
||||
...prioritizedCommand,
|
||||
id: aliasWithDefaultTopicSeparator,
|
||||
});
|
||||
}
|
||||
else {
|
||||
this._commands.set(aliasWithDefaultTopicSeparator, { ...command, hidden, id: aliasWithDefaultTopicSeparator });
|
||||
}
|
||||
// set every permutation of the aliases
|
||||
// v3 moved command alias permutations to the manifest, but some plugins may not have
|
||||
// the new manifest yet. For those, we need to calculate the permutations here.
|
||||
const aliasPermutations = this.flexibleTaxonomy && command.aliasPermutations === undefined
|
||||
? (0, util_3.getCommandIdPermutations)(aliasWithDefaultTopicSeparator)
|
||||
: (command.permutations ?? [aliasWithDefaultTopicSeparator]);
|
||||
// set every permutation
|
||||
for (const permutation of aliasPermutations) {
|
||||
this.commandPermutations.add(permutation, command.id);
|
||||
}
|
||||
};
|
||||
// set command aliases
|
||||
for (const alias of command.aliases ?? []) {
|
||||
handleAlias(alias);
|
||||
}
|
||||
// set hidden command aliases
|
||||
for (const alias of command.hiddenAliases ?? []) {
|
||||
handleAlias(alias, true);
|
||||
}
|
||||
}
|
||||
marker?.addDetails({ commandCount: plugin.commands.length });
|
||||
marker?.stop();
|
||||
}
|
||||
loadTopics(plugin) {
|
||||
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `config.loadTopics#${plugin.name}`, { plugin: plugin.name });
|
||||
for (const topic of (0, util_2.compact)(plugin.topics)) {
|
||||
const existing = this._topics.get(topic.name);
|
||||
if (existing) {
|
||||
existing.description = topic.description || existing.description;
|
||||
existing.hidden = existing.hidden || topic.hidden;
|
||||
}
|
||||
else {
|
||||
this._topics.set(topic.name, topic);
|
||||
}
|
||||
const permutations = this.flexibleTaxonomy ? (0, util_3.getCommandIdPermutations)(topic.name) : [topic.name];
|
||||
for (const permutation of permutations) {
|
||||
this.topicPermutations.add(permutation, topic.name);
|
||||
}
|
||||
}
|
||||
// Add missing topics for displaying help when partial commands are entered.
|
||||
for (const c of plugin.commands.filter((c) => !c.hidden)) {
|
||||
const parts = c.id.split(':');
|
||||
while (parts.length > 0) {
|
||||
const name = parts.join(':');
|
||||
if (name && !this._topics.has(name)) {
|
||||
this._topics.set(name, { description: c.summary || c.description, name });
|
||||
}
|
||||
parts.pop();
|
||||
}
|
||||
}
|
||||
marker?.stop();
|
||||
}
|
||||
maybeAdjustDebugSetting() {
|
||||
if (this.scopedEnvVarTrue('DEBUG')) {
|
||||
settings_1.settings.debug = true;
|
||||
displayWarnings();
|
||||
}
|
||||
}
|
||||
warn(err, scope) {
|
||||
if (this.warned)
|
||||
return;
|
||||
if (typeof err === 'string') {
|
||||
process.emitWarning(err);
|
||||
return;
|
||||
}
|
||||
if (err instanceof Error) {
|
||||
const modifiedErr = err;
|
||||
modifiedErr.name = `${err.name} Plugin: ${this.name}`;
|
||||
modifiedErr.detail = (0, util_2.compact)([
|
||||
err.detail,
|
||||
`module: ${this._base}`,
|
||||
scope && `task: ${scope}`,
|
||||
`plugin: ${this.name}`,
|
||||
`root: ${this.root}`,
|
||||
'See more details with DEBUG=*',
|
||||
]).join('\n');
|
||||
process.emitWarning(err);
|
||||
return;
|
||||
}
|
||||
// err is an object
|
||||
process.emitWarning('Config.warn expected either a string or Error, but instead received an object');
|
||||
err.name = `${err.name} Plugin: ${this.name}`;
|
||||
err.detail = (0, util_2.compact)([
|
||||
err.detail,
|
||||
`module: ${this._base}`,
|
||||
scope && `task: ${scope}`,
|
||||
`plugin: ${this.name}`,
|
||||
`root: ${this.root}`,
|
||||
'See more details with DEBUG=*',
|
||||
]).join('\n');
|
||||
process.emitWarning(JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
exports.Config = Config;
|
||||
3
node_modules/@oclif/core/lib/config/index.d.ts
generated
vendored
Normal file
3
node_modules/@oclif/core/lib/config/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export { Config } from './config';
|
||||
export { Plugin } from './plugin';
|
||||
export { tsPath } from './ts-path';
|
||||
9
node_modules/@oclif/core/lib/config/index.js
generated
vendored
Normal file
9
node_modules/@oclif/core/lib/config/index.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.tsPath = exports.Plugin = exports.Config = void 0;
|
||||
var config_1 = require("./config");
|
||||
Object.defineProperty(exports, "Config", { enumerable: true, get: function () { return config_1.Config; } });
|
||||
var plugin_1 = require("./plugin");
|
||||
Object.defineProperty(exports, "Plugin", { enumerable: true, get: function () { return plugin_1.Plugin; } });
|
||||
var ts_path_1 = require("./ts-path");
|
||||
Object.defineProperty(exports, "tsPath", { enumerable: true, get: function () { return ts_path_1.tsPath; } });
|
||||
38
node_modules/@oclif/core/lib/config/plugin-loader.d.ts
generated
vendored
Normal file
38
node_modules/@oclif/core/lib/config/plugin-loader.d.ts
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
import { PJSON } from '../interfaces';
|
||||
import { Plugin as IPlugin } from '../interfaces/plugin';
|
||||
type PluginLoaderOptions = {
|
||||
plugins?: IPlugin[] | PluginsMap | undefined;
|
||||
root: string;
|
||||
};
|
||||
type LoadOpts = {
|
||||
dataDir: string;
|
||||
devPlugins?: boolean | undefined;
|
||||
force?: boolean | undefined;
|
||||
rootPlugin: IPlugin;
|
||||
userPlugins?: boolean | undefined;
|
||||
pluginAdditions?: {
|
||||
core?: string[];
|
||||
dev?: string[];
|
||||
path?: string;
|
||||
} | undefined;
|
||||
};
|
||||
type PluginsMap = Map<string, IPlugin>;
|
||||
export default class PluginLoader {
|
||||
options: PluginLoaderOptions;
|
||||
errors: (Error | string)[];
|
||||
plugins: PluginsMap;
|
||||
private pluginsProvided;
|
||||
constructor(options: PluginLoaderOptions);
|
||||
loadChildren(opts: LoadOpts): Promise<{
|
||||
errors: (Error | string)[];
|
||||
plugins: PluginsMap;
|
||||
}>;
|
||||
loadRoot({ pjson }: {
|
||||
pjson?: PJSON | undefined;
|
||||
}): Promise<IPlugin>;
|
||||
private loadCorePlugins;
|
||||
private loadDevPlugins;
|
||||
private loadPlugins;
|
||||
private loadUserPlugins;
|
||||
}
|
||||
export {};
|
||||
188
node_modules/@oclif/core/lib/config/plugin-loader.js
generated
vendored
Normal file
188
node_modules/@oclif/core/lib/config/plugin-loader.js
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const minimatch_1 = require("minimatch");
|
||||
const node_path_1 = require("node:path");
|
||||
const performance_1 = require("../performance");
|
||||
const fs_1 = require("../util/fs");
|
||||
const util_1 = require("../util/util");
|
||||
const plugin_1 = require("./plugin");
|
||||
const util_2 = require("./util");
|
||||
const debug = (0, util_2.makeDebug)();
|
||||
function findMatchingDependencies(dependencies, patterns) {
|
||||
return Object.keys(dependencies).filter((p) => patterns.some((w) => (0, minimatch_1.minimatch)(p, w)));
|
||||
}
|
||||
class PluginLoader {
|
||||
options;
|
||||
errors = [];
|
||||
plugins = new Map();
|
||||
pluginsProvided = false;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
if (options.plugins) {
|
||||
this.pluginsProvided = true;
|
||||
this.plugins = Array.isArray(options.plugins) ? new Map(options.plugins.map((p) => [p.name, p])) : options.plugins;
|
||||
}
|
||||
}
|
||||
async loadChildren(opts) {
|
||||
if (!this.pluginsProvided || opts.force) {
|
||||
await this.loadUserPlugins(opts);
|
||||
await this.loadDevPlugins(opts);
|
||||
await this.loadCorePlugins(opts);
|
||||
}
|
||||
return { errors: this.errors, plugins: this.plugins };
|
||||
}
|
||||
async loadRoot({ pjson }) {
|
||||
let rootPlugin;
|
||||
if (this.pluginsProvided) {
|
||||
const plugins = [...this.plugins.values()];
|
||||
rootPlugin = plugins.find((p) => p.root === this.options.root) ?? plugins[0];
|
||||
}
|
||||
else {
|
||||
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, 'plugin.load#root');
|
||||
rootPlugin = new plugin_1.Plugin({ isRoot: true, pjson, root: this.options.root });
|
||||
await rootPlugin.load();
|
||||
marker?.addDetails({
|
||||
commandCount: rootPlugin.commands.length,
|
||||
hasManifest: rootPlugin.hasManifest ?? false,
|
||||
name: rootPlugin.name,
|
||||
topicCount: rootPlugin.topics.length,
|
||||
type: rootPlugin.type,
|
||||
usesMain: Boolean(rootPlugin.pjson.main),
|
||||
});
|
||||
marker?.stop();
|
||||
}
|
||||
this.plugins.set(rootPlugin.name, rootPlugin);
|
||||
return rootPlugin;
|
||||
}
|
||||
async loadCorePlugins(opts) {
|
||||
const { plugins: corePlugins } = opts.rootPlugin.pjson.oclif;
|
||||
if (corePlugins) {
|
||||
const plugins = findMatchingDependencies(opts.rootPlugin.pjson.dependencies ?? {}, corePlugins);
|
||||
await this.loadPlugins(opts.rootPlugin.root, 'core', plugins);
|
||||
}
|
||||
const { core: pluginAdditionsCore, path } = opts.pluginAdditions ?? { core: [] };
|
||||
if (pluginAdditionsCore) {
|
||||
if (path) {
|
||||
// If path is provided, load plugins from the path
|
||||
const pjson = await (0, fs_1.readJson)((0, node_path_1.join)(path, 'package.json'));
|
||||
const plugins = findMatchingDependencies(pjson.dependencies ?? {}, pluginAdditionsCore);
|
||||
await this.loadPlugins(path, 'core', plugins);
|
||||
}
|
||||
else {
|
||||
const plugins = findMatchingDependencies(opts.rootPlugin.pjson.dependencies ?? {}, pluginAdditionsCore);
|
||||
await this.loadPlugins(opts.rootPlugin.root, 'core', plugins);
|
||||
}
|
||||
}
|
||||
}
|
||||
async loadDevPlugins(opts) {
|
||||
if (opts.devPlugins !== false) {
|
||||
// do not load oclif.devPlugins in production
|
||||
if ((0, util_1.isProd)())
|
||||
return;
|
||||
try {
|
||||
const { devPlugins } = opts.rootPlugin.pjson.oclif;
|
||||
if (devPlugins) {
|
||||
const allDeps = { ...opts.rootPlugin.pjson.dependencies, ...opts.rootPlugin.pjson.devDependencies };
|
||||
const plugins = findMatchingDependencies(allDeps ?? {}, devPlugins);
|
||||
await this.loadPlugins(opts.rootPlugin.root, 'dev', plugins);
|
||||
}
|
||||
const { dev: pluginAdditionsDev, path } = opts.pluginAdditions ?? { core: [] };
|
||||
if (pluginAdditionsDev) {
|
||||
if (path) {
|
||||
// If path is provided, load plugins from the path
|
||||
const pjson = await (0, fs_1.readJson)((0, node_path_1.join)(path, 'package.json'));
|
||||
const allDeps = { ...pjson.dependencies, ...pjson.devDependencies };
|
||||
const plugins = findMatchingDependencies(allDeps ?? {}, pluginAdditionsDev);
|
||||
await this.loadPlugins(path, 'dev', plugins);
|
||||
}
|
||||
else {
|
||||
const allDeps = { ...opts.rootPlugin.pjson.dependencies, ...opts.rootPlugin.pjson.devDependencies };
|
||||
const plugins = findMatchingDependencies(allDeps ?? {}, pluginAdditionsDev);
|
||||
await this.loadPlugins(opts.rootPlugin.root, 'dev', plugins);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
process.emitWarning(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
async loadPlugins(root, type, plugins, parent) {
|
||||
if (!plugins || plugins.length === 0)
|
||||
return;
|
||||
const mark = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `config.loadPlugins#${type}`);
|
||||
debug('loading plugins', plugins);
|
||||
await Promise.all((plugins || []).map(async (plugin) => {
|
||||
try {
|
||||
const name = typeof plugin === 'string' ? plugin : plugin.name;
|
||||
const opts = {
|
||||
name,
|
||||
root,
|
||||
type,
|
||||
};
|
||||
if (typeof plugin !== 'string') {
|
||||
opts.tag = plugin.tag || opts.tag;
|
||||
opts.root = plugin.root || opts.root;
|
||||
opts.url = plugin.url;
|
||||
}
|
||||
if (parent) {
|
||||
opts.parent = parent;
|
||||
}
|
||||
if (this.plugins.has(name))
|
||||
return;
|
||||
const pluginMarker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `plugin.load#${name}`);
|
||||
const instance = new plugin_1.Plugin(opts);
|
||||
await instance.load();
|
||||
pluginMarker?.addDetails({
|
||||
commandCount: instance.commands.length,
|
||||
hasManifest: instance.hasManifest,
|
||||
name: instance.name,
|
||||
topicCount: instance.topics.length,
|
||||
type: instance.type,
|
||||
usesMain: Boolean(instance.pjson.main),
|
||||
});
|
||||
pluginMarker?.stop();
|
||||
this.plugins.set(instance.name, instance);
|
||||
if (parent) {
|
||||
instance.parent = parent;
|
||||
if (!parent.children)
|
||||
parent.children = [];
|
||||
parent.children.push(instance);
|
||||
}
|
||||
if (instance.pjson.oclif.plugins) {
|
||||
const allDeps = type === 'dev'
|
||||
? { ...instance.pjson.dependencies, ...instance.pjson.devDependencies }
|
||||
: instance.pjson.dependencies;
|
||||
const plugins = findMatchingDependencies(allDeps ?? {}, instance.pjson.oclif.plugins);
|
||||
await this.loadPlugins(instance.root, type, plugins, instance);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
this.errors.push(error);
|
||||
}
|
||||
}));
|
||||
mark?.addDetails({ pluginCount: plugins.length });
|
||||
mark?.stop();
|
||||
}
|
||||
async loadUserPlugins(opts) {
|
||||
if (opts.userPlugins !== false) {
|
||||
try {
|
||||
const userPJSONPath = (0, node_path_1.join)(opts.dataDir, 'package.json');
|
||||
debug('reading user plugins pjson %s', userPJSONPath);
|
||||
// ignore cache because the file might have changed within the same process (e.g. during a JIT plugin install)
|
||||
const pjson = await (0, fs_1.readJson)(userPJSONPath, false);
|
||||
if (!pjson.oclif)
|
||||
pjson.oclif = { schema: 1 };
|
||||
if (!pjson.oclif.plugins)
|
||||
pjson.oclif.plugins = [];
|
||||
await this.loadPlugins(userPJSONPath, 'user', pjson.oclif.plugins.filter((p) => p.type === 'user'));
|
||||
await this.loadPlugins(userPJSONPath, 'link', pjson.oclif.plugins.filter((p) => p.type === 'link'));
|
||||
}
|
||||
catch (error) {
|
||||
if (error.code !== 'ENOENT')
|
||||
process.emitWarning(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = PluginLoader;
|
||||
51
node_modules/@oclif/core/lib/config/plugin.d.ts
generated
vendored
Normal file
51
node_modules/@oclif/core/lib/config/plugin.d.ts
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Command } from '../command';
|
||||
import { Manifest } from '../interfaces/manifest';
|
||||
import { HookOptions, PJSON } from '../interfaces/pjson';
|
||||
import { Plugin as IPlugin, PluginOptions } from '../interfaces/plugin';
|
||||
import { Topic } from '../interfaces/topic';
|
||||
export declare class Plugin implements IPlugin {
|
||||
options: PluginOptions;
|
||||
_base: string;
|
||||
protected _debug: (..._: any) => void;
|
||||
alias: string;
|
||||
alreadyLoaded: boolean;
|
||||
children: Plugin[];
|
||||
commandIDs: string[];
|
||||
commands: Command.Loadable[];
|
||||
commandsDir: string | undefined;
|
||||
hasManifest: boolean;
|
||||
hooks: {
|
||||
[key: string]: HookOptions[];
|
||||
};
|
||||
isRoot: boolean;
|
||||
manifest: Manifest;
|
||||
moduleType: 'commonjs' | 'module';
|
||||
name: string;
|
||||
parent?: Plugin | undefined;
|
||||
pjson: PJSON;
|
||||
root: string;
|
||||
tag?: string | undefined;
|
||||
type: string;
|
||||
valid: boolean;
|
||||
version: string;
|
||||
private commandCache;
|
||||
private commandDiscoveryOpts;
|
||||
private flexibleTaxonomy;
|
||||
constructor(options: PluginOptions);
|
||||
get topics(): Topic[];
|
||||
findCommand(id: string, opts: {
|
||||
must: true;
|
||||
}): Promise<Command.Class>;
|
||||
findCommand(id: string, opts?: {
|
||||
must: boolean;
|
||||
}): Promise<Command.Class | undefined>;
|
||||
load(): Promise<void>;
|
||||
private _manifest;
|
||||
private addErrorScope;
|
||||
private getCommandIDs;
|
||||
private getCommandIdsFromPattern;
|
||||
private getCommandIdsFromTarget;
|
||||
private getCommandsDir;
|
||||
private loadCommandsFromTarget;
|
||||
private warn;
|
||||
}
|
||||
374
node_modules/@oclif/core/lib/config/plugin.js
generated
vendored
Normal file
374
node_modules/@oclif/core/lib/config/plugin.js
generated
vendored
Normal file
@@ -0,0 +1,374 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Plugin = void 0;
|
||||
const node_path_1 = require("node:path");
|
||||
const node_util_1 = require("node:util");
|
||||
const tinyglobby_1 = require("tinyglobby");
|
||||
const cache_1 = __importDefault(require("../cache"));
|
||||
const errors_1 = require("../errors");
|
||||
const module_loader_1 = require("../module-loader");
|
||||
const performance_1 = require("../performance");
|
||||
const symbols_1 = require("../symbols");
|
||||
const cache_command_1 = require("../util/cache-command");
|
||||
const find_root_1 = require("../util/find-root");
|
||||
const fs_1 = require("../util/fs");
|
||||
const read_pjson_1 = require("../util/read-pjson");
|
||||
const util_1 = require("../util/util");
|
||||
const ts_path_1 = require("./ts-path");
|
||||
const util_2 = require("./util");
|
||||
const _pjson = cache_1.default.getInstance().get('@oclif/core');
|
||||
function topicsToArray(input, base) {
|
||||
if (!input)
|
||||
return [];
|
||||
base = base ? `${base}:` : '';
|
||||
if (Array.isArray(input)) {
|
||||
return [...input, input.flatMap((t) => topicsToArray(t.subtopics, `${base}${t.name}`))];
|
||||
}
|
||||
return Object.keys(input).flatMap((k) => {
|
||||
input[k].name = k;
|
||||
return [{ ...input[k], name: `${base}${k}` }, ...topicsToArray(input[k].subtopics, `${base}${input[k].name}`)];
|
||||
});
|
||||
}
|
||||
const cachedCommandCanBeUsed = (manifest, id) => Boolean(manifest?.commands[id] && 'isESM' in manifest.commands[id] && 'relativePath' in manifest.commands[id]);
|
||||
const searchForCommandClass = (cmd) => {
|
||||
if (typeof cmd.run === 'function')
|
||||
return cmd;
|
||||
if (cmd.default && cmd.default.run)
|
||||
return cmd.default;
|
||||
return Object.values(cmd).find((cmd) => typeof cmd.run === 'function');
|
||||
};
|
||||
const ensureCommandClass = (cmd) => {
|
||||
if (cmd && typeof cmd.run === 'function')
|
||||
return cmd;
|
||||
};
|
||||
const GLOB_PATTERNS = [
|
||||
'**/*.+(js|cjs|mjs|ts|tsx|mts|cts)',
|
||||
'!**/*.+(d.ts|test.ts|test.js|spec.ts|spec.js|d.mts|d.cts)?(x)',
|
||||
];
|
||||
function processCommandIds(files) {
|
||||
return files.map((file) => {
|
||||
const p = (0, node_path_1.parse)(file);
|
||||
const topics = p.dir.split('/');
|
||||
const command = p.name !== 'index' && p.name;
|
||||
const id = [...topics, command].filter(Boolean).join(':');
|
||||
return id === '' ? symbols_1.SINGLE_COMMAND_CLI_SYMBOL : id;
|
||||
});
|
||||
}
|
||||
function determineCommandDiscoveryOptions(commandDiscovery) {
|
||||
if (!commandDiscovery)
|
||||
return;
|
||||
if (typeof commandDiscovery === 'string') {
|
||||
return { globPatterns: GLOB_PATTERNS, strategy: 'pattern', target: commandDiscovery };
|
||||
}
|
||||
if (!commandDiscovery.target)
|
||||
throw new errors_1.CLIError('`oclif.commandDiscovery.target` is required.');
|
||||
if (!commandDiscovery.strategy)
|
||||
throw new errors_1.CLIError('`oclif.commandDiscovery.strategy` is required.');
|
||||
if (commandDiscovery.strategy === 'explicit' && !commandDiscovery.identifier) {
|
||||
commandDiscovery.identifier = 'default';
|
||||
}
|
||||
return commandDiscovery;
|
||||
}
|
||||
function determineHookOptions(hook) {
|
||||
if (typeof hook === 'string')
|
||||
return { identifier: 'default', target: hook };
|
||||
if (!hook.identifier)
|
||||
return { ...hook, identifier: 'default' };
|
||||
return hook;
|
||||
}
|
||||
class Plugin {
|
||||
options;
|
||||
_base = `${_pjson.name}@${_pjson.version}`;
|
||||
_debug = (0, util_2.makeDebug)();
|
||||
alias;
|
||||
alreadyLoaded = false;
|
||||
children = [];
|
||||
commandIDs = [];
|
||||
// This will be initialized in the _manifest() method, which gets called in the load() method.
|
||||
commands;
|
||||
commandsDir;
|
||||
hasManifest = false;
|
||||
hooks;
|
||||
isRoot = false;
|
||||
manifest;
|
||||
moduleType;
|
||||
name;
|
||||
parent;
|
||||
pjson;
|
||||
root;
|
||||
tag;
|
||||
type;
|
||||
valid = false;
|
||||
version;
|
||||
commandCache;
|
||||
commandDiscoveryOpts;
|
||||
flexibleTaxonomy;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
get topics() {
|
||||
return topicsToArray(this.pjson.oclif.topics || {});
|
||||
}
|
||||
async findCommand(id, opts = {}) {
|
||||
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `plugin.findCommand#${this.name}.${id}`, {
|
||||
id,
|
||||
plugin: this.name,
|
||||
});
|
||||
const fetch = async () => {
|
||||
if (this.commandDiscoveryOpts?.strategy === 'pattern') {
|
||||
const commandsDir = await this.getCommandsDir();
|
||||
if (!commandsDir)
|
||||
return;
|
||||
let module;
|
||||
let isESM;
|
||||
let filePath;
|
||||
try {
|
||||
;
|
||||
({ filePath, isESM, module } = cachedCommandCanBeUsed(this.manifest, id)
|
||||
? await (0, module_loader_1.loadWithDataFromManifest)(this.manifest.commands[id], this.root)
|
||||
: await (0, module_loader_1.loadWithData)(this, (0, node_path_1.join)(commandsDir ?? this.pjson.oclif.commands, ...id.split(':'))));
|
||||
this._debug(isESM ? '(import)' : '(require)', filePath);
|
||||
}
|
||||
catch (error) {
|
||||
if (!opts.must && error.code === 'MODULE_NOT_FOUND')
|
||||
return;
|
||||
throw error;
|
||||
}
|
||||
const cmd = searchForCommandClass(module);
|
||||
if (!cmd)
|
||||
return;
|
||||
cmd.id = id;
|
||||
cmd.plugin = this;
|
||||
cmd.isESM = isESM;
|
||||
cmd.relativePath = (0, node_path_1.relative)(this.root, filePath || '').split(node_path_1.sep);
|
||||
return cmd;
|
||||
}
|
||||
if (this.commandDiscoveryOpts?.strategy === 'single' || this.commandDiscoveryOpts?.strategy === 'explicit') {
|
||||
const commandCache = await this.loadCommandsFromTarget();
|
||||
const cmd = ensureCommandClass(commandCache?.[id]);
|
||||
if (!cmd)
|
||||
return;
|
||||
cmd.id = id;
|
||||
cmd.plugin = this;
|
||||
return cmd;
|
||||
}
|
||||
};
|
||||
const cmd = await fetch();
|
||||
if (!cmd && opts.must)
|
||||
(0, errors_1.error)(`command ${id} not found`);
|
||||
marker?.stop();
|
||||
return cmd;
|
||||
}
|
||||
// eslint-disable-next-line complexity
|
||||
async load() {
|
||||
this.type = this.options.type ?? 'core';
|
||||
this.tag = this.options.tag;
|
||||
this.isRoot = this.options.isRoot ?? false;
|
||||
if (this.options.parent)
|
||||
this.parent = this.options.parent;
|
||||
// Linked plugins already have a root so there's no need to search for it.
|
||||
// However there could be child plugins nested inside the linked plugin, in which
|
||||
// case we still need to search for the child plugin's root.
|
||||
const root = this.options.pjson && this.options.isRoot
|
||||
? this.options.root
|
||||
: this.type === 'link' && !this.parent
|
||||
? this.options.root
|
||||
: await (0, find_root_1.findRoot)(this.options.name, this.options.root);
|
||||
if (!root)
|
||||
throw new errors_1.CLIError(`could not find package.json with ${(0, node_util_1.inspect)(this.options)}`);
|
||||
this.root = root;
|
||||
this._debug(`loading ${this.type} plugin from ${root}`);
|
||||
this.pjson = this.options.pjson ?? (await (0, read_pjson_1.readPjson)(root));
|
||||
this.flexibleTaxonomy = this.options?.flexibleTaxonomy || this.pjson.oclif?.flexibleTaxonomy || false;
|
||||
this.moduleType = this.pjson.type === 'module' ? 'module' : 'commonjs';
|
||||
this.name = this.pjson.name;
|
||||
this.alias = this.options.name ?? this.pjson.name;
|
||||
if (!this.name)
|
||||
throw new errors_1.CLIError(`no name in package.json (${root})`);
|
||||
this._debug = (0, util_2.makeDebug)(this.name);
|
||||
this.version = this.pjson.version;
|
||||
if (this.pjson.oclif) {
|
||||
this.valid = true;
|
||||
}
|
||||
else {
|
||||
this.pjson.oclif = this.pjson['cli-engine'] || {};
|
||||
}
|
||||
this.hooks = Object.fromEntries(Object.entries(this.pjson.oclif.hooks ?? {}).map(([k, v]) => [
|
||||
k,
|
||||
(0, util_1.castArray)(v).map((v) => determineHookOptions(v)),
|
||||
]));
|
||||
this.commandDiscoveryOpts = determineCommandDiscoveryOptions(this.pjson.oclif?.commands);
|
||||
this._debug('command discovery options', this.commandDiscoveryOpts);
|
||||
this.manifest = await this._manifest();
|
||||
this.commands = Object.entries(this.manifest.commands)
|
||||
.map(([id, c]) => ({
|
||||
...c,
|
||||
load: async () => this.findCommand(id, { must: true }),
|
||||
pluginAlias: this.alias,
|
||||
pluginType: c.pluginType === 'jit' ? 'jit' : this.type,
|
||||
}))
|
||||
.sort((a, b) => a.id.localeCompare(b.id));
|
||||
}
|
||||
async _manifest() {
|
||||
const ignoreManifest = Boolean(this.options.ignoreManifest);
|
||||
const errorOnManifestCreate = Boolean(this.options.errorOnManifestCreate);
|
||||
const respectNoCacheDefault = Boolean(this.options.respectNoCacheDefault);
|
||||
const readManifest = async (dotfile = false) => {
|
||||
try {
|
||||
const p = (0, node_path_1.join)(this.root, `${dotfile ? '.' : ''}oclif.manifest.json`);
|
||||
const manifest = await (0, fs_1.readJson)(p);
|
||||
if (!process.env.OCLIF_NEXT_VERSION && manifest.version.split('-')[0] !== this.version.split('-')[0]) {
|
||||
process.emitWarning(`Mismatched version in ${this.name} plugin manifest. Expected: ${this.version} Received: ${manifest.version}\nThis usually means you have an oclif.manifest.json file that should be deleted in development. This file should be automatically generated when publishing.`);
|
||||
}
|
||||
else {
|
||||
this._debug('using manifest from', p);
|
||||
this.hasManifest = true;
|
||||
return manifest;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
if (!dotfile)
|
||||
return readManifest(true);
|
||||
}
|
||||
else {
|
||||
this.warn(error, 'readManifest');
|
||||
}
|
||||
}
|
||||
};
|
||||
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `plugin.manifest#${this.name}`, { plugin: this.name });
|
||||
if (!ignoreManifest) {
|
||||
const manifest = await readManifest();
|
||||
if (manifest) {
|
||||
marker?.addDetails({ commandCount: Object.keys(manifest.commands).length, fromCache: true });
|
||||
marker?.stop();
|
||||
this.commandIDs = Object.keys(manifest.commands);
|
||||
return manifest;
|
||||
}
|
||||
}
|
||||
this.commandIDs = await this.getCommandIDs();
|
||||
const manifest = {
|
||||
commands: (await Promise.all(this.commandIDs.map(async (id) => {
|
||||
try {
|
||||
const found = await this.findCommand(id, { must: true });
|
||||
const cached = await (0, cache_command_1.cacheCommand)(found, this, respectNoCacheDefault);
|
||||
// Ensure that id is set to the id being processed
|
||||
// This is necessary because the id is set by findCommand but if there
|
||||
// are multiple instances of a Command, then the id will be set to the
|
||||
// last one found.
|
||||
cached.id = id;
|
||||
if (this.flexibleTaxonomy) {
|
||||
const permutations = (0, util_2.getCommandIdPermutations)(id);
|
||||
const aliasPermutations = cached.aliases.flatMap((a) => (0, util_2.getCommandIdPermutations)(a));
|
||||
return [id, { ...cached, aliasPermutations, permutations }];
|
||||
}
|
||||
return [id, cached];
|
||||
}
|
||||
catch (error) {
|
||||
const scope = `findCommand (${id})`;
|
||||
if (Boolean(errorOnManifestCreate) === false)
|
||||
this.warn(error, scope);
|
||||
else
|
||||
throw this.addErrorScope(error, scope);
|
||||
}
|
||||
})))
|
||||
// eslint-disable-next-line unicorn/prefer-native-coercion-functions
|
||||
.filter((f) => Boolean(f))
|
||||
.reduce((commands, [id, c]) => {
|
||||
commands[id] = c;
|
||||
return commands;
|
||||
}, {}),
|
||||
version: this.version,
|
||||
};
|
||||
marker?.addDetails({ commandCount: Object.keys(manifest.commands).length, fromCache: false });
|
||||
marker?.stop();
|
||||
return manifest;
|
||||
}
|
||||
addErrorScope(err, scope) {
|
||||
err.name = err.name ?? (0, node_util_1.inspect)(err).trim();
|
||||
err.detail = (0, util_1.compact)([
|
||||
err.detail,
|
||||
`module: ${this._base}`,
|
||||
scope && `task: ${scope}`,
|
||||
`plugin: ${this.name}`,
|
||||
`root: ${this.root}`,
|
||||
...(err.code ? [`code: ${err.code}`] : []),
|
||||
...(err.message ? [`message: ${err.message}`] : []),
|
||||
'See more details with DEBUG=*',
|
||||
]).join('\n');
|
||||
return err;
|
||||
}
|
||||
async getCommandIDs() {
|
||||
const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `plugin.getCommandIDs#${this.name}`, { plugin: this.name });
|
||||
let ids;
|
||||
switch (this.commandDiscoveryOpts?.strategy) {
|
||||
case 'explicit': {
|
||||
ids = (await this.getCommandIdsFromTarget()) ?? [];
|
||||
break;
|
||||
}
|
||||
case 'pattern': {
|
||||
ids = await this.getCommandIdsFromPattern();
|
||||
break;
|
||||
}
|
||||
case 'single': {
|
||||
ids = (await this.getCommandIdsFromTarget()) ?? [];
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ids = [];
|
||||
}
|
||||
}
|
||||
this._debug('found commands', ids);
|
||||
marker?.addDetails({ count: ids.length });
|
||||
marker?.stop();
|
||||
return ids;
|
||||
}
|
||||
async getCommandIdsFromPattern() {
|
||||
const commandsDir = await this.getCommandsDir();
|
||||
if (!commandsDir)
|
||||
return [];
|
||||
this._debug(`loading IDs from ${commandsDir}`);
|
||||
const files = await (0, tinyglobby_1.glob)(this.commandDiscoveryOpts?.globPatterns ?? GLOB_PATTERNS, { cwd: commandsDir });
|
||||
return processCommandIds(files);
|
||||
}
|
||||
async getCommandIdsFromTarget() {
|
||||
const commandsFromExport = await this.loadCommandsFromTarget();
|
||||
if (commandsFromExport) {
|
||||
return Object.entries((await this.loadCommandsFromTarget()) ?? [])
|
||||
.filter(([, cmd]) => ensureCommandClass(cmd))
|
||||
.map(([id]) => id);
|
||||
}
|
||||
}
|
||||
async getCommandsDir() {
|
||||
if (this.commandsDir)
|
||||
return this.commandsDir;
|
||||
this.commandsDir = await (0, ts_path_1.tsPath)(this.root, this.commandDiscoveryOpts?.target, this);
|
||||
return this.commandsDir;
|
||||
}
|
||||
async loadCommandsFromTarget() {
|
||||
if (this.commandCache)
|
||||
return this.commandCache;
|
||||
if (this.commandDiscoveryOpts?.strategy === 'explicit' && this.commandDiscoveryOpts.target) {
|
||||
const filePath = await (0, ts_path_1.tsPath)(this.root, this.commandDiscoveryOpts.target, this);
|
||||
const module = await (0, module_loader_1.load)(this, filePath);
|
||||
this.commandCache = module[this.commandDiscoveryOpts?.identifier ?? 'default'] ?? {};
|
||||
return this.commandCache;
|
||||
}
|
||||
if (this.commandDiscoveryOpts?.strategy === 'single' && this.commandDiscoveryOpts.target) {
|
||||
const filePath = await (0, ts_path_1.tsPath)(this.root, this.commandDiscoveryOpts?.target ?? this.root, this);
|
||||
const module = await (0, module_loader_1.load)(this, filePath);
|
||||
this.commandCache = { [symbols_1.SINGLE_COMMAND_CLI_SYMBOL]: searchForCommandClass(module) };
|
||||
return this.commandCache;
|
||||
}
|
||||
}
|
||||
warn(err, scope) {
|
||||
if (typeof err === 'string')
|
||||
err = new Error(err);
|
||||
const warning = this.addErrorScope(err, scope);
|
||||
process.emitWarning(warning.name, warning);
|
||||
}
|
||||
}
|
||||
exports.Plugin = Plugin;
|
||||
9
node_modules/@oclif/core/lib/config/ts-path.d.ts
generated
vendored
Normal file
9
node_modules/@oclif/core/lib/config/ts-path.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Plugin, TSConfig } from '../interfaces';
|
||||
export declare const TS_CONFIGS: Record<string, TSConfig | undefined>;
|
||||
/**
|
||||
* Convert a path from the compiled ./lib files to the ./src typescript source
|
||||
* this is for developing typescript plugins/CLIs
|
||||
* if there is a tsconfig and the original sources exist, it attempts to require ts-node
|
||||
*/
|
||||
export declare function tsPath(root: string, orig: string, plugin: Plugin): Promise<string>;
|
||||
export declare function tsPath(root: string, orig: string | undefined, plugin?: Plugin | undefined): Promise<string | undefined>;
|
||||
293
node_modules/@oclif/core/lib/config/ts-path.js
generated
vendored
Normal file
293
node_modules/@oclif/core/lib/config/ts-path.js
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TS_CONFIGS = void 0;
|
||||
exports.tsPath = tsPath;
|
||||
const promises_1 = require("node:fs/promises");
|
||||
const node_path_1 = require("node:path");
|
||||
const node_url_1 = require("node:url");
|
||||
const cache_1 = __importDefault(require("../cache"));
|
||||
const warn_1 = require("../errors/warn");
|
||||
const settings_1 = require("../settings");
|
||||
const fs_1 = require("../util/fs");
|
||||
const read_tsconfig_1 = require("../util/read-tsconfig");
|
||||
const util_1 = require("../util/util");
|
||||
const util_2 = require("./util");
|
||||
const debug = (0, util_2.makeDebug)('ts-path');
|
||||
exports.TS_CONFIGS = {};
|
||||
const REGISTERED = new Set();
|
||||
function determineRuntime() {
|
||||
/**
|
||||
* Examples:
|
||||
* #!/usr/bin/env bun
|
||||
* bun bin/run.js
|
||||
* bun bin/dev.js
|
||||
*/
|
||||
if (process.execPath.split(node_path_1.sep).includes('bun'))
|
||||
return 'bun';
|
||||
/**
|
||||
* Examples:
|
||||
* #!/usr/bin/env node
|
||||
* #!/usr/bin/env node --loader ts-node/esm --experimental-specifier-resolution=node --no-warnings
|
||||
* node bin/run.js
|
||||
* node bin/dev.js
|
||||
*/
|
||||
if (process.execArgv.length === 0)
|
||||
return 'node';
|
||||
/**
|
||||
* Examples:
|
||||
* #!/usr/bin/env ts-node
|
||||
* #!/usr/bin/env node_modules/.bin/ts-node
|
||||
* ts-node bin/run.js
|
||||
* ts-node bin/dev.js
|
||||
*/
|
||||
if (process.execArgv[0] === '--require' && process.execArgv[1].split(node_path_1.sep).includes('ts-node'))
|
||||
return 'ts-node';
|
||||
if (process.execArgv[0].split(node_path_1.sep).includes('ts-node'))
|
||||
return 'ts-node';
|
||||
/**
|
||||
* Examples:
|
||||
* #!/usr/bin/env tsx
|
||||
* #!/usr/bin/env node_modules/.bin/tsx
|
||||
* tsx bin/run.js
|
||||
* tsx bin/dev.js
|
||||
*/
|
||||
if (process.execArgv[0] === '--require' && process.execArgv[1].split(node_path_1.sep).includes('tsx'))
|
||||
return 'tsx';
|
||||
return 'node';
|
||||
}
|
||||
const RUN_TIME = determineRuntime();
|
||||
function isErrno(error) {
|
||||
return 'code' in error && error.code === 'ENOENT';
|
||||
}
|
||||
async function loadTSConfig(root) {
|
||||
try {
|
||||
if (exports.TS_CONFIGS[root])
|
||||
return exports.TS_CONFIGS[root];
|
||||
const tsconfig = await (0, read_tsconfig_1.readTSConfig)(root);
|
||||
if (!tsconfig)
|
||||
return;
|
||||
debug('tsconfig: %O', tsconfig);
|
||||
exports.TS_CONFIGS[root] = tsconfig;
|
||||
return exports.TS_CONFIGS[root];
|
||||
}
|
||||
catch (error) {
|
||||
if (isErrno(error))
|
||||
return;
|
||||
debug(`Could not parse tsconfig.json. Skipping typescript path lookup for ${root}.`);
|
||||
(0, warn_1.memoizedWarn)(`Could not parse tsconfig.json for ${root}. Falling back to compiled source.`);
|
||||
}
|
||||
}
|
||||
async function registerTsx(root, moduleType) {
|
||||
if (REGISTERED.has(root))
|
||||
return;
|
||||
try {
|
||||
const apiPath = moduleType === 'module' ? 'tsx/esm/api' : 'tsx/cjs/api';
|
||||
const tsxPath = require.resolve(apiPath, { paths: [root] });
|
||||
if (!tsxPath)
|
||||
return;
|
||||
debug('registering tsx at', root);
|
||||
debug('tsx path:', tsxPath);
|
||||
const { href } = (0, node_url_1.pathToFileURL)(tsxPath);
|
||||
debug('tsx href:', href);
|
||||
const { register } = await import(href);
|
||||
debug('Successfully imported tsx');
|
||||
register();
|
||||
REGISTERED.add(root);
|
||||
}
|
||||
catch (error) {
|
||||
debug(`Could not find tsx. Skipping tsx registration for ${root}.`);
|
||||
debug(error);
|
||||
}
|
||||
}
|
||||
async function registerTSNode(root, tsconfig) {
|
||||
if (REGISTERED.has(root))
|
||||
return;
|
||||
debug('registering ts-node at', root);
|
||||
const tsNodePath = require.resolve('ts-node', { paths: [root, __dirname] });
|
||||
debug('ts-node path:', tsNodePath);
|
||||
let tsNode;
|
||||
try {
|
||||
tsNode = require(tsNodePath);
|
||||
debug('Successfully required ts-node');
|
||||
}
|
||||
catch (error) {
|
||||
debug(`Could not find ts-node at ${tsNodePath}. Skipping ts-node registration for ${root}.`);
|
||||
debug(error);
|
||||
(0, warn_1.memoizedWarn)(`Could not find ts-node at ${tsNodePath}. Please ensure that ts-node is a devDependency. Falling back to compiled source.`);
|
||||
return;
|
||||
}
|
||||
const typeRoots = [(0, node_path_1.join)(root, 'node_modules', '@types')];
|
||||
const rootDirs = [];
|
||||
if (tsconfig.compilerOptions.rootDirs) {
|
||||
for (const r of tsconfig.compilerOptions.rootDirs) {
|
||||
rootDirs.push((0, node_path_1.join)(root, r));
|
||||
}
|
||||
}
|
||||
else if (tsconfig.compilerOptions.rootDir) {
|
||||
rootDirs.push((0, node_path_1.join)(root, tsconfig.compilerOptions.rootDir));
|
||||
}
|
||||
else if (tsconfig.compilerOptions.baseUrl) {
|
||||
rootDirs.push((0, node_path_1.join)(root, tsconfig.compilerOptions.baseUrl));
|
||||
}
|
||||
else {
|
||||
rootDirs.push((0, node_path_1.join)(root, 'src'));
|
||||
}
|
||||
// Because we need to provide a modified `rootDirs` to ts-node, we need to
|
||||
// remove `baseUrl` and `rootDir` from `compilerOptions` so that they
|
||||
// don't conflict.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { baseUrl, rootDir, ...rest } = tsconfig.compilerOptions;
|
||||
const conf = {
|
||||
compilerOptions: {
|
||||
...rest,
|
||||
rootDirs,
|
||||
typeRoots,
|
||||
},
|
||||
...tsconfig['ts-node'],
|
||||
cwd: root,
|
||||
esm: tsconfig['ts-node']?.esm ?? true,
|
||||
experimentalSpecifierResolution: tsconfig['ts-node']?.experimentalSpecifierResolution ?? 'explicit',
|
||||
scope: true,
|
||||
scopeDir: root,
|
||||
skipProject: true,
|
||||
transpileOnly: true,
|
||||
};
|
||||
debug('ts-node options: %O', conf);
|
||||
tsNode.register(conf);
|
||||
REGISTERED.add(root);
|
||||
}
|
||||
/**
|
||||
* Skip ts-node registration for ESM plugins in production.
|
||||
* The node/ts-node ecosystem is not mature enough to support auto-transpiling ESM modules at this time.
|
||||
* See the following:
|
||||
* - https://github.com/TypeStrong/ts-node/issues/1791#issuecomment-1149754228
|
||||
* - https://github.com/nodejs/node/issues/49432
|
||||
* - https://github.com/nodejs/node/pull/49407
|
||||
* - https://github.com/nodejs/node/issues/34049
|
||||
*
|
||||
* We still register tsx/ts-node for ESM plugins when NODE_ENV is "test" or "development" and root plugin is also ESM
|
||||
* since that allows plugins to be auto-transpiled when developing locally using `bin/dev.js`.
|
||||
*/
|
||||
function cannotTranspileEsm(rootPlugin, plugin, isProduction) {
|
||||
return ((isProduction || rootPlugin?.moduleType === 'commonjs') &&
|
||||
plugin?.moduleType === 'module' &&
|
||||
!plugin?.pjson.devDependencies?.tsx);
|
||||
}
|
||||
/**
|
||||
* If the dev script is run with ts-node for an ESM plugin, skip ts-node registration
|
||||
* and fall back on compiled source since ts-node executable cannot transpile ESM in Node 20+
|
||||
*
|
||||
* See the following:
|
||||
* https://nodejs.org/en/blog/announcements/v20-release-announce#custom-esm-loader-hooks-nearing-stable
|
||||
* https://github.com/oclif/core/issues/817
|
||||
* https://github.com/TypeStrong/ts-node/issues/1997
|
||||
*/
|
||||
function cannotUseTsNode(root, plugin, isProduction) {
|
||||
if (plugin?.moduleType !== 'module' || isProduction)
|
||||
return false;
|
||||
const nodeMajor = Number.parseInt(process.version.replace('v', '').split('.')[0], 10);
|
||||
return RUN_TIME === 'ts-node' && nodeMajor >= 20;
|
||||
}
|
||||
/**
|
||||
* Determine the path to the source file from the compiled ./lib files
|
||||
*/
|
||||
async function determinePath(root, orig, plugin) {
|
||||
const tsconfig = await loadTSConfig(root);
|
||||
if (!tsconfig)
|
||||
return orig;
|
||||
debug(`Determining path for ${orig}`);
|
||||
if (RUN_TIME === 'bun') {
|
||||
debug(`Skipping ts-node registration for ${root} because the runtime is: ${RUN_TIME}`);
|
||||
}
|
||||
else {
|
||||
// attempt to register tsx first. If it fails to register, we will fall back to ts-node
|
||||
await registerTsx(root, plugin?.moduleType);
|
||||
// if tsx registration succeeded, then this will exit early since the path will be in REGISTERED already
|
||||
await registerTSNode(root, tsconfig);
|
||||
}
|
||||
const { baseUrl, outDir, rootDir, rootDirs } = tsconfig.compilerOptions;
|
||||
const rootDirPath = rootDir ?? (rootDirs ?? [])[0] ?? baseUrl;
|
||||
if (!rootDirPath) {
|
||||
debug(`no rootDir, rootDirs, or baseUrl specified in tsconfig.json. Returning default path ${orig}`);
|
||||
return orig;
|
||||
}
|
||||
if (!outDir) {
|
||||
debug(`no outDir specified in tsconfig.json. Returning default path ${orig}`);
|
||||
return orig;
|
||||
}
|
||||
// rewrite path from ./lib/foo to ./src/foo
|
||||
const lib = (0, node_path_1.join)(root, outDir); // ./lib
|
||||
const src = (0, node_path_1.join)(root, rootDirPath); // ./src
|
||||
const relative = (0, node_path_1.relative)(lib, orig); // ./commands
|
||||
// For hooks, it might point to a js file, not a module. Something like "./hooks/myhook.js" which doesn't need the js.
|
||||
const out = (0, node_path_1.join)(src, relative).replace(/\.js$/, ''); // ./src/commands
|
||||
// this can be a directory of commands or point to a hook file
|
||||
// if it's a directory, we check if the path exists. If so, return the path to the directory.
|
||||
// For hooks, it might point to a module, not a file. Something like "./hooks/myhook"
|
||||
// That file doesn't exist, and the real file is "./hooks/myhook.ts"
|
||||
// In that case we attempt to resolve to the filename. If it fails it will revert back to the lib path
|
||||
debug(`lib dir: ${lib}`);
|
||||
debug(`src dir: ${src}`);
|
||||
debug(`src directory to find: ${out}`);
|
||||
if ((0, fs_1.existsSync)(out)) {
|
||||
debug(`Found source directory for ${orig} at ${out}`);
|
||||
return out;
|
||||
}
|
||||
const sourceFiles = await Promise.all([
|
||||
(0, promises_1.access)(`${out}.ts`)
|
||||
.then(() => `${out}.ts`)
|
||||
.catch(() => false),
|
||||
(0, promises_1.access)(`${out}.tsx`)
|
||||
.then(() => `${out}.tsx`)
|
||||
.catch(() => false),
|
||||
]);
|
||||
if (sourceFiles.some(Boolean)) {
|
||||
debug(`Found source file for ${orig} at ${out}`);
|
||||
return out;
|
||||
}
|
||||
debug(`No source file found. Returning default path ${orig}`);
|
||||
if (!(0, util_1.isProd)())
|
||||
(0, warn_1.memoizedWarn)(`Could not find source for ${orig} based on tsconfig. Defaulting to compiled source.`);
|
||||
return orig;
|
||||
}
|
||||
async function tsPath(root, orig, plugin) {
|
||||
const rootPlugin = plugin?.options.isRoot ? plugin : cache_1.default.getInstance().get('rootPlugin');
|
||||
if (!orig)
|
||||
return orig;
|
||||
orig = orig.startsWith(root) ? orig : (0, node_path_1.join)(root, orig);
|
||||
// NOTE: The order of these checks matter!
|
||||
const enableAutoTranspile = settings_1.settings.enableAutoTranspile ?? settings_1.settings.tsnodeEnabled;
|
||||
if (enableAutoTranspile === false) {
|
||||
debug(`Skipping typescript path lookup for ${root} because enableAutoTranspile is explicitly set to false`);
|
||||
return orig;
|
||||
}
|
||||
const isProduction = (0, util_1.isProd)();
|
||||
// Do not skip ts-node registration if the plugin is linked
|
||||
if (enableAutoTranspile === undefined && isProduction && plugin?.type !== 'link') {
|
||||
debug(`Skipping typescript path lookup for ${root} because NODE_ENV is NOT "test" or "development"`);
|
||||
return orig;
|
||||
}
|
||||
if (cannotTranspileEsm(rootPlugin, plugin, isProduction)) {
|
||||
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})`);
|
||||
const warningIsDisabled = process.env.OCLIF_DISABLE_LINKED_ESM_WARNING && (0, util_1.isTruthy)(process.env.OCLIF_DISABLE_LINKED_ESM_WARNING);
|
||||
// Only warn if the plugin is linked AND the warning is not disabled
|
||||
if (plugin?.type === 'link' && !warningIsDisabled)
|
||||
(0, warn_1.memoizedWarn)(`${plugin?.name} is a linked ESM module and cannot be auto-transpiled. Existing compiled source will be used instead.`);
|
||||
return orig;
|
||||
}
|
||||
if (cannotUseTsNode(root, plugin, isProduction)) {
|
||||
debug(`Skipping typescript path lookup for ${root} because ts-node is run in node version ${process.version}"`);
|
||||
(0, warn_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.`);
|
||||
return orig;
|
||||
}
|
||||
try {
|
||||
return await determinePath(root, orig, plugin);
|
||||
}
|
||||
catch (error) {
|
||||
debug(error);
|
||||
return orig;
|
||||
}
|
||||
}
|
||||
23
node_modules/@oclif/core/lib/config/util.d.ts
generated
vendored
Normal file
23
node_modules/@oclif/core/lib/config/util.d.ts
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
export declare function makeDebug(...scope: string[]): (..._: any) => void;
|
||||
export declare function getPermutations(arr: string[]): Array<string[]>;
|
||||
export declare function getCommandIdPermutations(commandId: string): string[];
|
||||
/**
|
||||
* Return an array of ids that represent all the usable combinations that a user could enter.
|
||||
*
|
||||
* For example, if the command ids are:
|
||||
* - foo:bar:baz
|
||||
* - one:two:three
|
||||
* Then the usable ids would be:
|
||||
* - foo
|
||||
* - foo:bar
|
||||
* - foo:bar:baz
|
||||
* - one
|
||||
* - one:two
|
||||
* - one:two:three
|
||||
*
|
||||
* This allows us to determine which parts of the argv array belong to the command id whenever the topicSeparator is a space.
|
||||
*
|
||||
* @param commandIds string[]
|
||||
* @returns string[]
|
||||
*/
|
||||
export declare const collectUsableIds: (commandIds: string[]) => Set<string>;
|
||||
54
node_modules/@oclif/core/lib/config/util.js
generated
vendored
Normal file
54
node_modules/@oclif/core/lib/config/util.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.collectUsableIds = void 0;
|
||||
exports.makeDebug = makeDebug;
|
||||
exports.getPermutations = getPermutations;
|
||||
exports.getCommandIdPermutations = getCommandIdPermutations;
|
||||
const logger_1 = require("../logger");
|
||||
function makeDebug(...scope) {
|
||||
return (formatter, ...args) => (0, logger_1.getLogger)(['config', ...scope].join(':')).debug(formatter, ...args);
|
||||
}
|
||||
// Adapted from https://github.com/angus-c/just/blob/master/packages/array-permutations/index.js
|
||||
function getPermutations(arr) {
|
||||
if (arr.length === 0)
|
||||
return [];
|
||||
if (arr.length === 1)
|
||||
return [arr];
|
||||
const output = [];
|
||||
const partialPermutations = getPermutations(arr.slice(1));
|
||||
const first = arr[0];
|
||||
for (let i = 0, len = partialPermutations.length; i < len; i++) {
|
||||
const partial = partialPermutations[i];
|
||||
for (let j = 0, len2 = partial.length; j <= len2; j++) {
|
||||
const start = partial.slice(0, j);
|
||||
const end = partial.slice(j);
|
||||
const merged = [...start, first, ...end];
|
||||
output.push(merged);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
function getCommandIdPermutations(commandId) {
|
||||
return getPermutations(commandId.split(':')).flatMap((c) => c.join(':'));
|
||||
}
|
||||
/**
|
||||
* Return an array of ids that represent all the usable combinations that a user could enter.
|
||||
*
|
||||
* For example, if the command ids are:
|
||||
* - foo:bar:baz
|
||||
* - one:two:three
|
||||
* Then the usable ids would be:
|
||||
* - foo
|
||||
* - foo:bar
|
||||
* - foo:bar:baz
|
||||
* - one
|
||||
* - one:two
|
||||
* - one:two:three
|
||||
*
|
||||
* This allows us to determine which parts of the argv array belong to the command id whenever the topicSeparator is a space.
|
||||
*
|
||||
* @param commandIds string[]
|
||||
* @returns string[]
|
||||
*/
|
||||
const collectUsableIds = (commandIds) => new Set(commandIds.flatMap((id) => id.split(':').map((_, i, a) => a.slice(0, i + 1).join(':'))));
|
||||
exports.collectUsableIds = collectUsableIds;
|
||||
Reference in New Issue
Block a user