first commit
This commit is contained in:
52
node_modules/@oclif/core/lib/parser/errors.d.ts
generated
vendored
Normal file
52
node_modules/@oclif/core/lib/parser/errors.d.ts
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
import { CLIError } from '../errors';
|
||||
import { Arg, ArgInput, CLIParseErrorOptions, OptionFlag } from '../interfaces/parser';
|
||||
export { CLIError } from '../errors';
|
||||
export type Validation = {
|
||||
name: string;
|
||||
reason?: string | undefined;
|
||||
status: 'failed' | 'success';
|
||||
validationFn: string;
|
||||
};
|
||||
export declare class CLIParseError extends CLIError {
|
||||
parse: CLIParseErrorOptions['parse'];
|
||||
showHelp: boolean;
|
||||
constructor(options: CLIParseErrorOptions & {
|
||||
message: string;
|
||||
});
|
||||
}
|
||||
export declare class InvalidArgsSpecError extends CLIParseError {
|
||||
args: ArgInput;
|
||||
constructor({ args, exit, parse }: CLIParseErrorOptions & {
|
||||
args: ArgInput;
|
||||
});
|
||||
}
|
||||
export declare class RequiredArgsError extends CLIParseError {
|
||||
args: Arg<any>[];
|
||||
constructor({ args, exit, flagsWithMultiple, parse, }: CLIParseErrorOptions & {
|
||||
args: Arg<any>[];
|
||||
flagsWithMultiple?: string[];
|
||||
});
|
||||
}
|
||||
export declare class UnexpectedArgsError extends CLIParseError {
|
||||
args: unknown[];
|
||||
constructor({ args, exit, parse }: CLIParseErrorOptions & {
|
||||
args: unknown[];
|
||||
});
|
||||
}
|
||||
export declare class NonExistentFlagsError extends CLIParseError {
|
||||
flags: string[];
|
||||
constructor({ exit, flags, parse }: CLIParseErrorOptions & {
|
||||
flags: string[];
|
||||
});
|
||||
}
|
||||
export declare class FlagInvalidOptionError extends CLIParseError {
|
||||
constructor(flag: OptionFlag<any>, input: string);
|
||||
}
|
||||
export declare class ArgInvalidOptionError extends CLIParseError {
|
||||
constructor(arg: Arg<any>, input: string);
|
||||
}
|
||||
export declare class FailedFlagValidationError extends CLIParseError {
|
||||
constructor({ exit, failed, parse }: CLIParseErrorOptions & {
|
||||
failed: Validation[];
|
||||
});
|
||||
}
|
||||
104
node_modules/@oclif/core/lib/parser/errors.js
generated
vendored
Normal file
104
node_modules/@oclif/core/lib/parser/errors.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.FailedFlagValidationError = exports.ArgInvalidOptionError = exports.FlagInvalidOptionError = exports.NonExistentFlagsError = exports.UnexpectedArgsError = exports.RequiredArgsError = exports.InvalidArgsSpecError = exports.CLIParseError = exports.CLIError = void 0;
|
||||
const cache_1 = __importDefault(require("../cache"));
|
||||
const errors_1 = require("../errors");
|
||||
const util_1 = require("../util/util");
|
||||
const list_1 = __importDefault(require("../ux/list"));
|
||||
const theme_1 = require("../ux/theme");
|
||||
var errors_2 = require("../errors");
|
||||
Object.defineProperty(exports, "CLIError", { enumerable: true, get: function () { return errors_2.CLIError; } });
|
||||
class CLIParseError extends errors_1.CLIError {
|
||||
parse;
|
||||
showHelp = false;
|
||||
constructor(options) {
|
||||
options.message += '\nSee more help with --help';
|
||||
super(options.message, { exit: options.exit });
|
||||
this.parse = options.parse;
|
||||
}
|
||||
}
|
||||
exports.CLIParseError = CLIParseError;
|
||||
class InvalidArgsSpecError extends CLIParseError {
|
||||
args;
|
||||
constructor({ args, exit, parse }) {
|
||||
let message = 'Invalid argument spec';
|
||||
const namedArgs = Object.values(args).filter((a) => a.name);
|
||||
if (namedArgs.length > 0) {
|
||||
const list = (0, list_1.default)(namedArgs.map((a) => [`${a.name} (${a.required ? 'required' : 'optional'})`, a.description]));
|
||||
message += `:\n${list}`;
|
||||
}
|
||||
super({ exit: cache_1.default.getInstance().get('exitCodes')?.invalidArgsSpec ?? exit, message, parse });
|
||||
this.args = args;
|
||||
}
|
||||
}
|
||||
exports.InvalidArgsSpecError = InvalidArgsSpecError;
|
||||
class RequiredArgsError extends CLIParseError {
|
||||
args;
|
||||
constructor({ args, exit, flagsWithMultiple, parse, }) {
|
||||
let message = `Missing ${args.length} required arg${args.length === 1 ? '' : 's'}`;
|
||||
const namedArgs = args.filter((a) => a.name);
|
||||
if (namedArgs.length > 0) {
|
||||
const list = (0, list_1.default)(namedArgs.map((a) => {
|
||||
const description = a.options ? `(${a.options.join('|')}) ${a.description}` : a.description;
|
||||
return [a.name, description];
|
||||
}));
|
||||
message += `:\n${list}`;
|
||||
}
|
||||
if (flagsWithMultiple?.length) {
|
||||
const flags = flagsWithMultiple.map((f) => `--${f}`).join(', ');
|
||||
message += `\n\nNote: ${flags} allow${flagsWithMultiple.length === 1 ? 's' : ''} multiple values. Because of this you need to provide all arguments before providing ${flagsWithMultiple.length === 1 ? 'that flag' : 'those flags'}.`;
|
||||
message += '\nAlternatively, you can use "--" to signify the end of the flags and the beginning of arguments.';
|
||||
}
|
||||
super({ exit: cache_1.default.getInstance().get('exitCodes')?.requiredArgs ?? exit, message, parse });
|
||||
this.args = args;
|
||||
this.showHelp = true;
|
||||
}
|
||||
}
|
||||
exports.RequiredArgsError = RequiredArgsError;
|
||||
class UnexpectedArgsError extends CLIParseError {
|
||||
args;
|
||||
constructor({ args, exit, parse }) {
|
||||
const message = `Unexpected argument${args.length === 1 ? '' : 's'}: ${args.join(', ')}`;
|
||||
super({ exit: cache_1.default.getInstance().get('exitCodes')?.unexpectedArgs ?? exit, message, parse });
|
||||
this.args = args;
|
||||
this.showHelp = true;
|
||||
}
|
||||
}
|
||||
exports.UnexpectedArgsError = UnexpectedArgsError;
|
||||
class NonExistentFlagsError extends CLIParseError {
|
||||
flags;
|
||||
constructor({ exit, flags, parse }) {
|
||||
const message = `Nonexistent flag${flags.length === 1 ? '' : 's'}: ${flags.join(', ')}`;
|
||||
super({ exit: cache_1.default.getInstance().get('exitCodes')?.nonExistentFlag ?? exit, message, parse });
|
||||
this.flags = flags;
|
||||
this.showHelp = true;
|
||||
}
|
||||
}
|
||||
exports.NonExistentFlagsError = NonExistentFlagsError;
|
||||
class FlagInvalidOptionError extends CLIParseError {
|
||||
constructor(flag, input) {
|
||||
const message = `Expected --${flag.name}=${input} to be one of: ${flag.options.join(', ')}`;
|
||||
super({ message, parse: {} });
|
||||
}
|
||||
}
|
||||
exports.FlagInvalidOptionError = FlagInvalidOptionError;
|
||||
class ArgInvalidOptionError extends CLIParseError {
|
||||
constructor(arg, input) {
|
||||
const message = `Expected ${input} to be one of: ${arg.options.join(', ')}`;
|
||||
super({ message, parse: {} });
|
||||
}
|
||||
}
|
||||
exports.ArgInvalidOptionError = ArgInvalidOptionError;
|
||||
class FailedFlagValidationError extends CLIParseError {
|
||||
constructor({ exit, failed, parse }) {
|
||||
const reasons = failed.map((r) => r.reason);
|
||||
const deduped = (0, util_1.uniq)(reasons);
|
||||
const errString = deduped.length === 1 ? 'error' : 'errors';
|
||||
const message = `The following ${errString} occurred:\n ${(0, theme_1.colorize)('dim', deduped.join('\n '))}`;
|
||||
super({ exit: cache_1.default.getInstance().get('exitCodes')?.failedFlagValidation ?? exit, message, parse });
|
||||
}
|
||||
}
|
||||
exports.FailedFlagValidationError = FailedFlagValidationError;
|
||||
3
node_modules/@oclif/core/lib/parser/help.d.ts
generated
vendored
Normal file
3
node_modules/@oclif/core/lib/parser/help.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { Flag, FlagUsageOptions } from '../interfaces/parser';
|
||||
export declare function flagUsage(flag: Flag<any>, options?: FlagUsageOptions): [string, string | undefined];
|
||||
export declare function flagUsages(flags: Flag<any>[], options?: FlagUsageOptions): [string, string | undefined][];
|
||||
29
node_modules/@oclif/core/lib/parser/help.js
generated
vendored
Normal file
29
node_modules/@oclif/core/lib/parser/help.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.flagUsage = flagUsage;
|
||||
exports.flagUsages = flagUsages;
|
||||
const util_1 = require("../util/util");
|
||||
const ux_1 = require("../ux");
|
||||
function flagUsage(flag, options = {}) {
|
||||
const label = [];
|
||||
if (flag.helpLabel) {
|
||||
label.push(flag.helpLabel);
|
||||
}
|
||||
else {
|
||||
if (flag.char)
|
||||
label.push(`-${flag.char}`);
|
||||
if (flag.name)
|
||||
label.push(` --${flag.name}`);
|
||||
}
|
||||
const usage = flag.type === 'option' ? ` ${flag.name.toUpperCase()}` : '';
|
||||
let description = flag.summary || flag.description || '';
|
||||
if (options.displayRequired && flag.required)
|
||||
description = `(required) ${description}`;
|
||||
description = description ? (0, ux_1.colorize)('dim', description) : undefined;
|
||||
return [` ${label.join(',').trim()}${usage}`, description];
|
||||
}
|
||||
function flagUsages(flags, options = {}) {
|
||||
if (flags.length === 0)
|
||||
return [];
|
||||
return (0, util_1.sortBy)(flags, (f) => [f.char ? -1 : 1, f.char, f.name]).map((f) => flagUsage(f, options));
|
||||
}
|
||||
5
node_modules/@oclif/core/lib/parser/index.d.ts
generated
vendored
Normal file
5
node_modules/@oclif/core/lib/parser/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { Input, OutputArgs, OutputFlags, ParserOutput } from '../interfaces/parser';
|
||||
export type { ArgInput, FlagInput, Input, OutputArgs, OutputFlags, ParserOutput } from '../interfaces/parser';
|
||||
export { flagUsages } from './help';
|
||||
export { validate } from './validate';
|
||||
export declare function parse<TFlags extends OutputFlags<any>, BFlags extends OutputFlags<any>, TArgs extends OutputArgs<any>>(argv: string[], options: Input<TFlags, BFlags, TArgs>): Promise<ParserOutput<TFlags, BFlags, TArgs>>;
|
||||
24
node_modules/@oclif/core/lib/parser/index.js
generated
vendored
Normal file
24
node_modules/@oclif/core/lib/parser/index.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.validate = exports.flagUsages = void 0;
|
||||
exports.parse = parse;
|
||||
const parse_1 = require("./parse");
|
||||
const validate_1 = require("./validate");
|
||||
var help_1 = require("./help");
|
||||
Object.defineProperty(exports, "flagUsages", { enumerable: true, get: function () { return help_1.flagUsages; } });
|
||||
var validate_2 = require("./validate");
|
||||
Object.defineProperty(exports, "validate", { enumerable: true, get: function () { return validate_2.validate; } });
|
||||
async function parse(argv, options) {
|
||||
const input = {
|
||||
'--': options['--'],
|
||||
args: (options.args ?? {}),
|
||||
argv,
|
||||
context: options.context,
|
||||
flags: (options.flags ?? {}),
|
||||
strict: options.strict !== false,
|
||||
};
|
||||
const parser = new parse_1.Parser(input);
|
||||
const output = await parser.parse();
|
||||
await (0, validate_1.validate)({ input, output });
|
||||
return output;
|
||||
}
|
||||
37
node_modules/@oclif/core/lib/parser/parse.d.ts
generated
vendored
Normal file
37
node_modules/@oclif/core/lib/parser/parse.d.ts
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
import { OutputArgs, OutputFlags, ParserInput, ParserOutput } from '../interfaces/parser';
|
||||
declare global {
|
||||
/**
|
||||
* Cache the stdin so that it can be read multiple times.
|
||||
*
|
||||
* This fixes a bug where the stdin would be read multiple times (because Parser.parse() was called more than once)
|
||||
* but only the first read would be successful - all other reads would return null.
|
||||
*
|
||||
* Storing in global is necessary because we want the cache to be shared across all versions of @oclif/core in
|
||||
* in the dependency tree. Storing in a variable would only share the cache within the same version of @oclif/core.
|
||||
*/
|
||||
var oclif: {
|
||||
stdinCache?: string;
|
||||
};
|
||||
}
|
||||
export declare const readStdin: () => Promise<null | string>;
|
||||
export declare class Parser<T extends ParserInput, TFlags extends OutputFlags<T['flags']>, BFlags extends OutputFlags<T['flags']>, TArgs extends OutputArgs<T['args']>> {
|
||||
private readonly input;
|
||||
private readonly argv;
|
||||
private readonly booleanFlags;
|
||||
private readonly context;
|
||||
private currentFlag?;
|
||||
private readonly flagAliases;
|
||||
private readonly raw;
|
||||
constructor(input: T);
|
||||
private get _argTokens();
|
||||
parse(): Promise<ParserOutput<TFlags, BFlags, TArgs>>;
|
||||
private _args;
|
||||
private _debugInput;
|
||||
private _debugOutput;
|
||||
private _flags;
|
||||
private _setNames;
|
||||
private findFlag;
|
||||
private findLongFlag;
|
||||
private findShortFlag;
|
||||
private mapAndValidateFlags;
|
||||
}
|
||||
495
node_modules/@oclif/core/lib/parser/parse.js
generated
vendored
Normal file
495
node_modules/@oclif/core/lib/parser/parse.js
generated
vendored
Normal file
@@ -0,0 +1,495 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Parser = exports.readStdin = void 0;
|
||||
/* eslint-disable no-await-in-loop */
|
||||
const node_os_1 = require("node:os");
|
||||
const node_readline_1 = require("node:readline");
|
||||
const cache_1 = __importDefault(require("../cache"));
|
||||
const logger_1 = require("../logger");
|
||||
const util_1 = require("../util/util");
|
||||
const errors_1 = require("./errors");
|
||||
let debug;
|
||||
try {
|
||||
debug =
|
||||
process.env.CLI_FLAGS_DEBUG === '1'
|
||||
? (0, logger_1.makeDebug)('parser')
|
||||
: () => {
|
||||
// noop
|
||||
};
|
||||
}
|
||||
catch {
|
||||
debug = () => {
|
||||
// noop
|
||||
};
|
||||
}
|
||||
const readStdin = async () => {
|
||||
const { stdin, stdout } = process;
|
||||
// process.stdin.isTTY is true whenever it's running in a terminal.
|
||||
// process.stdin.isTTY is undefined when it's running in a pipe, e.g. echo 'foo' | my-cli command
|
||||
// process.stdin.isTTY is undefined when it's running in a spawned process, even if there's no pipe.
|
||||
// This means that reading from stdin could hang indefinitely while waiting for a non-existent pipe.
|
||||
// Because of this, we have to set a timeout to prevent the process from hanging.
|
||||
if (stdin.isTTY)
|
||||
return null;
|
||||
if (globalThis.oclif?.stdinCache) {
|
||||
debug('resolved stdin from global cache', globalThis.oclif.stdinCache);
|
||||
return globalThis.oclif.stdinCache;
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
const lines = [];
|
||||
const ac = new AbortController();
|
||||
const { signal } = ac;
|
||||
const timeout = setTimeout(() => ac.abort(), 10);
|
||||
const rl = (0, node_readline_1.createInterface)({
|
||||
input: stdin,
|
||||
output: stdout,
|
||||
terminal: false,
|
||||
});
|
||||
rl.on('line', (line) => {
|
||||
lines.push(line);
|
||||
});
|
||||
rl.once('close', () => {
|
||||
const result = lines.join(node_os_1.EOL);
|
||||
clearTimeout(timeout);
|
||||
debug('resolved from stdin', result);
|
||||
globalThis.oclif = { ...globalThis.oclif, stdinCache: result };
|
||||
resolve(result);
|
||||
});
|
||||
signal.addEventListener('abort', () => {
|
||||
debug('stdin aborted');
|
||||
clearTimeout(timeout);
|
||||
rl.close();
|
||||
resolve(null);
|
||||
}, { once: true });
|
||||
});
|
||||
};
|
||||
exports.readStdin = readStdin;
|
||||
function isNegativeNumber(input) {
|
||||
return /^-\d/g.test(input);
|
||||
}
|
||||
const validateOptions = (flag, input) => {
|
||||
if (flag.options && !flag.options.includes(input))
|
||||
throw new errors_1.FlagInvalidOptionError(flag, input);
|
||||
return input;
|
||||
};
|
||||
const NEGATION = '--no-';
|
||||
class Parser {
|
||||
input;
|
||||
argv;
|
||||
booleanFlags;
|
||||
context;
|
||||
currentFlag;
|
||||
flagAliases;
|
||||
raw = [];
|
||||
constructor(input) {
|
||||
this.input = input;
|
||||
this.context = input.context ?? {};
|
||||
this.argv = [...input.argv];
|
||||
this._setNames();
|
||||
this.booleanFlags = (0, util_1.pickBy)(input.flags, (f) => f.type === 'boolean');
|
||||
this.flagAliases = Object.fromEntries(Object.values(input.flags).flatMap((flag) => [...(flag.aliases ?? []), ...(flag.charAliases ?? [])].map((a) => [a, flag])));
|
||||
}
|
||||
get _argTokens() {
|
||||
return this.raw.filter((o) => o.type === 'arg');
|
||||
}
|
||||
async parse() {
|
||||
this._debugInput();
|
||||
// eslint-disable-next-line complexity
|
||||
const parseFlag = async (arg) => {
|
||||
const { isLong, name } = this.findFlag(arg);
|
||||
if (!name) {
|
||||
const i = arg.indexOf('=');
|
||||
if (i !== -1) {
|
||||
const sliced = arg.slice(i + 1);
|
||||
this.argv.unshift(sliced);
|
||||
const equalsParsed = await parseFlag(arg.slice(0, i));
|
||||
if (!equalsParsed) {
|
||||
this.argv.shift();
|
||||
}
|
||||
return equalsParsed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const flag = this.input.flags[name];
|
||||
if (flag.type === 'option') {
|
||||
if (!flag.multiple && this.raw.some((o) => o.type === 'flag' && o.flag === name)) {
|
||||
throw new errors_1.CLIError(`Flag --${name} can only be specified once`);
|
||||
}
|
||||
this.currentFlag = flag;
|
||||
let input = isLong || arg.length < 3 ? this.argv.shift() : arg.slice(arg[2] === '=' ? 3 : 2);
|
||||
if (flag.allowStdin === 'only' && input !== '-' && input !== undefined && !this.findFlag(input).name) {
|
||||
throw new errors_1.CLIError(`Flag --${name} can only be read from stdin. The value must be "-" or not provided at all.`);
|
||||
}
|
||||
if ((flag.allowStdin && input === '-') || flag.allowStdin === 'only') {
|
||||
const stdin = await (0, exports.readStdin)();
|
||||
if (stdin) {
|
||||
input = stdin.trim();
|
||||
}
|
||||
}
|
||||
// if the value ends up being one of the command's flags, the user didn't provide an input
|
||||
if (typeof input !== 'string' || this.findFlag(input).name) {
|
||||
if (flag.options) {
|
||||
throw new errors_1.CLIError(`Flag --${name} expects one of these values: ${flag.options.join(', ')}`);
|
||||
}
|
||||
throw new errors_1.CLIError(`Flag --${name} expects a value`);
|
||||
}
|
||||
this.raw.push({ flag: flag.name, input, type: 'flag' });
|
||||
}
|
||||
else {
|
||||
this.raw.push({ flag: flag.name, input: arg, type: 'flag' });
|
||||
// push the rest of the short characters back on the stack
|
||||
if (!isLong && arg.length > 2) {
|
||||
this.argv.unshift(`-${arg.slice(2)}`);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
let parsingFlags = true;
|
||||
const nonExistentFlags = [];
|
||||
let dashdash = false;
|
||||
const originalArgv = [...this.argv];
|
||||
while (this.argv.length > 0) {
|
||||
const input = this.argv.shift();
|
||||
if (parsingFlags && input.startsWith('-') && input !== '-') {
|
||||
// attempt to parse as arg
|
||||
if (this.input['--'] !== false && input === '--') {
|
||||
parsingFlags = false;
|
||||
continue;
|
||||
}
|
||||
if (await parseFlag(input)) {
|
||||
continue;
|
||||
}
|
||||
if (input === '--') {
|
||||
dashdash = true;
|
||||
continue;
|
||||
}
|
||||
if (this.input['--'] !== false && !isNegativeNumber(input)) {
|
||||
// At this point we have a value that begins with '-' or '--'
|
||||
// but doesn't match up to a flag definition. So we assume that
|
||||
// this is a misspelled flag or a non-existent flag,
|
||||
// e.g. --hekp instead of --help
|
||||
nonExistentFlags.push(input);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (parsingFlags && this.currentFlag && this.currentFlag.multiple && !this.currentFlag.multipleNonGreedy) {
|
||||
this.raw.push({ flag: this.currentFlag.name, input, type: 'flag' });
|
||||
continue;
|
||||
}
|
||||
// not a flag, parse as arg
|
||||
const arg = Object.keys(this.input.args)[this._argTokens.length];
|
||||
this.raw.push({ arg, input, type: 'arg' });
|
||||
}
|
||||
const [{ args, argv }, { flags, metadata }] = await Promise.all([this._args(), this._flags()]);
|
||||
this._debugOutput(argv, args, flags);
|
||||
const unsortedArgv = (dashdash ? [...argv, ...nonExistentFlags, '--'] : [...argv, ...nonExistentFlags]);
|
||||
return {
|
||||
args: args,
|
||||
argv: unsortedArgv.sort((a, b) => originalArgv.indexOf(a) - originalArgv.indexOf(b)),
|
||||
flags,
|
||||
metadata,
|
||||
nonExistentFlags,
|
||||
raw: this.raw,
|
||||
};
|
||||
}
|
||||
async _args() {
|
||||
const argv = [];
|
||||
const args = {};
|
||||
const tokens = this._argTokens;
|
||||
let stdinRead = false;
|
||||
const ctx = this.context;
|
||||
for (const [name, arg] of Object.entries(this.input.args)) {
|
||||
const token = tokens.find((t) => t.arg === name);
|
||||
ctx.token = token;
|
||||
if (token) {
|
||||
if (arg.options && !arg.options.includes(token.input)) {
|
||||
throw new errors_1.ArgInvalidOptionError(arg, token.input);
|
||||
}
|
||||
const parsed = await arg.parse(token.input, ctx, arg);
|
||||
argv.push(parsed);
|
||||
args[token.arg] = parsed;
|
||||
}
|
||||
else if (!arg.ignoreStdin && !stdinRead) {
|
||||
let stdin = await (0, exports.readStdin)();
|
||||
if (stdin) {
|
||||
stdin = stdin.trim();
|
||||
const parsed = await arg.parse(stdin, ctx, arg);
|
||||
argv.push(parsed);
|
||||
args[name] = parsed;
|
||||
}
|
||||
stdinRead = true;
|
||||
}
|
||||
if (!args[name] && (arg.default || arg.default === false)) {
|
||||
if (typeof arg.default === 'function') {
|
||||
const f = await arg.default();
|
||||
argv.push(f);
|
||||
args[name] = f;
|
||||
}
|
||||
else {
|
||||
argv.push(arg.default);
|
||||
args[name] = arg.default;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const token of tokens) {
|
||||
if (args[token.arg] !== undefined)
|
||||
continue;
|
||||
argv.push(token.input);
|
||||
}
|
||||
return { args, argv };
|
||||
}
|
||||
_debugInput() {
|
||||
debug('input: %s', this.argv.join(' '));
|
||||
const args = Object.keys(this.input.args);
|
||||
if (args.length > 0) {
|
||||
debug('available args: %s', args.join(' '));
|
||||
}
|
||||
if (Object.keys(this.input.flags).length === 0)
|
||||
return;
|
||||
debug('available flags: %s', Object.keys(this.input.flags)
|
||||
.map((f) => `--${f}`)
|
||||
.join(' '));
|
||||
}
|
||||
_debugOutput(args, flags, argv) {
|
||||
if (argv.length > 0) {
|
||||
debug('argv: %o', argv);
|
||||
}
|
||||
if (Object.keys(args).length > 0) {
|
||||
debug('args: %o', args);
|
||||
}
|
||||
if (Object.keys(flags).length > 0) {
|
||||
debug('flags: %o', flags);
|
||||
}
|
||||
}
|
||||
async _flags() {
|
||||
const parseFlagOrThrowError = async (input, flag, context, token) => {
|
||||
if (!flag.parse)
|
||||
return input;
|
||||
const ctx = {
|
||||
...context,
|
||||
error: context?.error,
|
||||
exit: context?.exit,
|
||||
jsonEnabled: context?.jsonEnabled,
|
||||
log: context?.log,
|
||||
logToStderr: context?.logToStderr,
|
||||
token,
|
||||
warn: context?.warn,
|
||||
};
|
||||
try {
|
||||
if (flag.type === 'boolean') {
|
||||
return await flag.parse(input, ctx, flag);
|
||||
}
|
||||
return await flag.parse(input, ctx, flag);
|
||||
}
|
||||
catch (error) {
|
||||
error.message = `Parsing --${flag.name} \n\t${error.message}\nSee more help with --help`;
|
||||
if (cache_1.default.getInstance().get('exitCodes')?.failedFlagParsing)
|
||||
error.oclif = { exit: cache_1.default.getInstance().get('exitCodes')?.failedFlagParsing };
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
/* Could add a valueFunction (if there is a value/env/default) and could metadata.
|
||||
* Value function can be resolved later.
|
||||
*/
|
||||
const addValueFunction = (fws) => {
|
||||
const tokenLength = fws.tokens?.length;
|
||||
// user provided some input
|
||||
if (tokenLength) {
|
||||
// boolean
|
||||
if (fws.inputFlag.flag.type === 'boolean' && (0, util_1.last)(fws.tokens)?.input) {
|
||||
const doesNotContainNegation = (i) => {
|
||||
const possibleNegations = [i.inputFlag.name, ...(i.inputFlag.flag.aliases ?? [])].map((n) => `${NEGATION}${n}`);
|
||||
const input = (0, util_1.last)(i.tokens)?.input;
|
||||
if (!input)
|
||||
return true;
|
||||
return !possibleNegations.includes(input);
|
||||
};
|
||||
return {
|
||||
...fws,
|
||||
valueFunction: async (i) => parseFlagOrThrowError(doesNotContainNegation(i), i.inputFlag.flag, this.context, (0, util_1.last)(i.tokens)),
|
||||
};
|
||||
}
|
||||
// multiple with custom delimiter
|
||||
if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.delimiter && fws.inputFlag.flag.multiple) {
|
||||
// regex that will identify unescaped delimiters
|
||||
const makeDelimiter = (delimiter) => new RegExp(`(?<!\\\\)${delimiter}`);
|
||||
return {
|
||||
...fws,
|
||||
valueFunction: async (i) => (await Promise.all((i.tokens ?? [])
|
||||
.flatMap((token) => token.input.split(makeDelimiter(i.inputFlag.flag.delimiter ?? ',')))
|
||||
// trim, and remove surrounding doubleQuotes (which would hav been needed if the elements contain spaces)
|
||||
.map((v) => v
|
||||
.trim()
|
||||
// remove escaped characters from delimiter
|
||||
// example: --opt="a\,b,c" -> ["a,b", "c"]
|
||||
.replaceAll(new RegExp(`\\\\${i.inputFlag.flag.delimiter}`, 'g'), i.inputFlag.flag.delimiter ?? ',')
|
||||
.replace(/^"(.*)"$/, '$1')
|
||||
.replace(/^'(.*)'$/, '$1'))
|
||||
.map(async (v) => parseFlagOrThrowError(v, i.inputFlag.flag, this.context, {
|
||||
...(0, util_1.last)(i.tokens),
|
||||
input: v,
|
||||
})))).map((v) => validateOptions(i.inputFlag.flag, v)),
|
||||
};
|
||||
}
|
||||
// multiple in the oclif-core style
|
||||
if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.multiple) {
|
||||
return {
|
||||
...fws,
|
||||
valueFunction: async (i) => Promise.all((fws.tokens ?? []).map((token) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, token.input), i.inputFlag.flag, this.context, token))),
|
||||
};
|
||||
}
|
||||
// simple option flag
|
||||
if (fws.inputFlag.flag.type === 'option') {
|
||||
return {
|
||||
...fws,
|
||||
valueFunction: async (i) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, (0, util_1.last)(fws.tokens)?.input), i.inputFlag.flag, this.context, (0, util_1.last)(fws.tokens)),
|
||||
};
|
||||
}
|
||||
}
|
||||
// no input: env flags
|
||||
if (fws.inputFlag.flag.env && process.env[fws.inputFlag.flag.env]) {
|
||||
const valueFromEnv = process.env[fws.inputFlag.flag.env];
|
||||
if (fws.inputFlag.flag.type === 'option' && valueFromEnv) {
|
||||
return {
|
||||
...fws,
|
||||
valueFunction: async (i) => parseFlagOrThrowError(validateOptions(i.inputFlag.flag, valueFromEnv), i.inputFlag.flag, this.context),
|
||||
};
|
||||
}
|
||||
if (fws.inputFlag.flag.type === 'boolean') {
|
||||
return {
|
||||
...fws,
|
||||
valueFunction: async (i) => (0, util_1.isTruthy)(process.env[i.inputFlag.flag.env] ?? 'false'),
|
||||
};
|
||||
}
|
||||
}
|
||||
// no input, but flag has default value
|
||||
// eslint-disable-next-line no-constant-binary-expression, valid-typeof
|
||||
if (typeof fws.inputFlag.flag.default !== undefined) {
|
||||
return {
|
||||
...fws,
|
||||
metadata: { setFromDefault: true },
|
||||
valueFunction: typeof fws.inputFlag.flag.default === 'function'
|
||||
? (i, allFlags = {}) => fws.inputFlag.flag.default({ flags: allFlags, options: i.inputFlag.flag })
|
||||
: async () => fws.inputFlag.flag.default,
|
||||
};
|
||||
}
|
||||
// base case (no value function)
|
||||
return fws;
|
||||
};
|
||||
const addHelpFunction = (fws) => {
|
||||
if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.defaultHelp) {
|
||||
return {
|
||||
...fws,
|
||||
helpFunction: typeof fws.inputFlag.flag.defaultHelp === 'function'
|
||||
? (i, flags, ...context) =>
|
||||
// @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
|
||||
i.inputFlag.flag.defaultHelp({ flags, options: i.inputFlag }, ...context)
|
||||
: // @ts-expect-error flag type isn't specific enough to know defaultHelp will definitely be there
|
||||
(i) => i.inputFlag.flag.defaultHelp,
|
||||
};
|
||||
}
|
||||
return fws;
|
||||
};
|
||||
const addDefaultHelp = async (fwsArray) => {
|
||||
const valueReferenceForHelp = fwsArrayToObject(flagsWithAllValues.filter((fws) => !fws.metadata?.setFromDefault));
|
||||
return Promise.all(fwsArray.map(async (fws) => {
|
||||
try {
|
||||
if (fws.helpFunction) {
|
||||
return {
|
||||
...fws,
|
||||
metadata: {
|
||||
...fws.metadata,
|
||||
defaultHelp: await fws.helpFunction?.(fws, valueReferenceForHelp, this.context),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// no-op
|
||||
}
|
||||
return fws;
|
||||
}));
|
||||
};
|
||||
const fwsArrayToObject = (fwsArray) => Object.fromEntries(fwsArray.filter((fws) => fws.value !== undefined).map((fws) => [fws.inputFlag.name, fws.value]));
|
||||
const flagTokenMap = this.mapAndValidateFlags();
|
||||
const flagsWithValues = await Promise.all(Object.entries(this.input.flags)
|
||||
// we check them if they have a token, or might have env, default, or defaultHelp. Also include booleans so they get their default value
|
||||
.filter(([name, flag]) => flag.type === 'boolean' ||
|
||||
flag.env ||
|
||||
flag.default !== undefined ||
|
||||
'defaultHelp' in flag ||
|
||||
flagTokenMap.has(name))
|
||||
// match each possible flag to its token, if there is one
|
||||
.map(([name, flag]) => ({ inputFlag: { flag, name }, tokens: flagTokenMap.get(name) }))
|
||||
.map((fws) => addValueFunction(fws))
|
||||
.filter((fws) => fws.valueFunction !== undefined)
|
||||
.map((fws) => addHelpFunction(fws))
|
||||
// we can't apply the default values until all the other flags are resolved because `flag.default` can reference other flags
|
||||
.map(async (fws) => (fws.metadata?.setFromDefault ? fws : { ...fws, value: await fws.valueFunction?.(fws) })));
|
||||
const valueReference = fwsArrayToObject(flagsWithValues.filter((fws) => !fws.metadata?.setFromDefault));
|
||||
const flagsWithAllValues = await Promise.all(flagsWithValues.map(async (fws) => fws.metadata?.setFromDefault ? { ...fws, value: await fws.valueFunction?.(fws, valueReference) } : fws));
|
||||
const finalFlags = flagsWithAllValues.some((fws) => typeof fws.helpFunction === 'function')
|
||||
? await addDefaultHelp(flagsWithAllValues)
|
||||
: flagsWithAllValues;
|
||||
return {
|
||||
flags: fwsArrayToObject(finalFlags),
|
||||
metadata: {
|
||||
flags: Object.fromEntries(finalFlags.filter((fws) => fws.metadata).map((fws) => [fws.inputFlag.name, fws.metadata])),
|
||||
},
|
||||
};
|
||||
}
|
||||
_setNames() {
|
||||
for (const k of Object.keys(this.input.flags)) {
|
||||
this.input.flags[k].name = k;
|
||||
}
|
||||
for (const k of Object.keys(this.input.args)) {
|
||||
this.input.args[k].name = k;
|
||||
}
|
||||
}
|
||||
findFlag(arg) {
|
||||
const isLong = arg.startsWith('--');
|
||||
const short = isLong ? false : arg.startsWith('-');
|
||||
const name = isLong ? this.findLongFlag(arg) : short ? this.findShortFlag(arg) : undefined;
|
||||
return { isLong, name };
|
||||
}
|
||||
findLongFlag(arg) {
|
||||
const name = arg.slice(2);
|
||||
if (this.input.flags[name]) {
|
||||
return name;
|
||||
}
|
||||
if (this.flagAliases[name]) {
|
||||
return this.flagAliases[name].name;
|
||||
}
|
||||
if (arg.startsWith(NEGATION)) {
|
||||
const flag = this.booleanFlags[arg.slice(NEGATION.length)];
|
||||
if (flag && flag.allowNo)
|
||||
return flag.name;
|
||||
const flagAlias = this.flagAliases[arg.slice(NEGATION.length)];
|
||||
if (flagAlias && flagAlias.type === 'boolean' && flagAlias.allowNo) {
|
||||
return flagAlias.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
findShortFlag([_, char]) {
|
||||
if (this.flagAliases[char]) {
|
||||
return this.flagAliases[char].name;
|
||||
}
|
||||
return Object.keys(this.input.flags).find((k) => this.input.flags[k].char === char && char !== undefined && this.input.flags[k].char !== undefined);
|
||||
}
|
||||
mapAndValidateFlags() {
|
||||
const flagTokenMap = new Map();
|
||||
for (const token of this.raw.filter((o) => o.type === 'flag')) {
|
||||
// fail fast if there are any invalid flags
|
||||
if (!(token.flag in this.input.flags)) {
|
||||
throw new errors_1.CLIError(`Unexpected flag ${token.flag}`);
|
||||
}
|
||||
const existing = flagTokenMap.get(token.flag) ?? [];
|
||||
flagTokenMap.set(token.flag, [...existing, token]);
|
||||
}
|
||||
return flagTokenMap;
|
||||
}
|
||||
}
|
||||
exports.Parser = Parser;
|
||||
5
node_modules/@oclif/core/lib/parser/validate.d.ts
generated
vendored
Normal file
5
node_modules/@oclif/core/lib/parser/validate.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import { ParserInput, ParserOutput } from '../interfaces/parser';
|
||||
export declare function validate(parse: {
|
||||
input: ParserInput;
|
||||
output: ParserOutput;
|
||||
}): Promise<void>;
|
||||
236
node_modules/@oclif/core/lib/parser/validate.js
generated
vendored
Normal file
236
node_modules/@oclif/core/lib/parser/validate.js
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.validate = validate;
|
||||
const util_1 = require("../util/util");
|
||||
const errors_1 = require("./errors");
|
||||
async function validate(parse) {
|
||||
let cachedResolvedFlags;
|
||||
function validateArgs() {
|
||||
if (parse.output.nonExistentFlags?.length > 0) {
|
||||
throw new errors_1.NonExistentFlagsError({
|
||||
flags: parse.output.nonExistentFlags,
|
||||
parse,
|
||||
});
|
||||
}
|
||||
const maxArgs = Object.keys(parse.input.args).length;
|
||||
if (parse.input.strict && parse.output.argv.length > maxArgs) {
|
||||
const extras = parse.output.argv.slice(maxArgs);
|
||||
throw new errors_1.UnexpectedArgsError({
|
||||
args: extras,
|
||||
parse,
|
||||
});
|
||||
}
|
||||
const missingRequiredArgs = [];
|
||||
let hasOptional = false;
|
||||
for (const [name, arg] of Object.entries(parse.input.args)) {
|
||||
if (!arg.required) {
|
||||
hasOptional = true;
|
||||
}
|
||||
else if (hasOptional) {
|
||||
// (required arg) check whether an optional has occurred before
|
||||
// optionals should follow required, not before
|
||||
throw new errors_1.InvalidArgsSpecError({
|
||||
args: parse.input.args,
|
||||
parse,
|
||||
});
|
||||
}
|
||||
// Only add if it's required and undefined. Allow falsy values like empty strings and 0.
|
||||
if (arg.required && parse.output.args[name] === undefined) {
|
||||
missingRequiredArgs.push(arg);
|
||||
}
|
||||
}
|
||||
if (missingRequiredArgs.length > 0) {
|
||||
const flagsWithMultiple = Object.entries(parse.input.flags)
|
||||
.filter(([_, flagDef]) => flagDef.type === 'option' && Boolean(flagDef.multiple))
|
||||
.map(([name]) => name);
|
||||
throw new errors_1.RequiredArgsError({
|
||||
args: missingRequiredArgs,
|
||||
flagsWithMultiple,
|
||||
parse,
|
||||
});
|
||||
}
|
||||
}
|
||||
async function validateFlags() {
|
||||
const promises = Object.entries(parse.input.flags).flatMap(([name, flag]) => {
|
||||
if (parse.output.flags[name] !== undefined) {
|
||||
return [
|
||||
...(flag.relationships ? validateRelationships(name, flag) : []),
|
||||
...(flag.dependsOn ? [validateDependsOn(name, flag.dependsOn)] : []),
|
||||
...(flag.exclusive ? [validateExclusive(name, flag.exclusive)] : []),
|
||||
...(flag.combinable ? [validateCombinable(name, flag.combinable)] : []),
|
||||
...(flag.exactlyOne ? [validateExactlyOne(name, flag.exactlyOne)] : []),
|
||||
];
|
||||
}
|
||||
if (flag.required) {
|
||||
return [{ name, reason: `Missing required flag ${name}`, status: 'failed', validationFn: 'required' }];
|
||||
}
|
||||
if (flag.exactlyOne && flag.exactlyOne.length > 0) {
|
||||
return [validateExactlyOneAcrossFlags(flag)];
|
||||
}
|
||||
if (flag.atLeastOne && flag.atLeastOne.length > 0) {
|
||||
return [validateAtLeastOneAcrossFlags(flag)];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
const results = await Promise.all(promises);
|
||||
const failed = results.filter((r) => r.status === 'failed');
|
||||
if (failed.length > 0)
|
||||
throw new errors_1.FailedFlagValidationError({
|
||||
failed,
|
||||
parse,
|
||||
});
|
||||
}
|
||||
async function resolveFlags(flags) {
|
||||
if (cachedResolvedFlags)
|
||||
return cachedResolvedFlags;
|
||||
const promises = flags.map(async (flag) => {
|
||||
if (typeof flag === 'string') {
|
||||
return [flag, parse.output.flags[flag]];
|
||||
}
|
||||
const result = await flag.when(parse.output.flags);
|
||||
return result ? [flag.name, parse.output.flags[flag.name]] : null;
|
||||
});
|
||||
const resolved = await Promise.all(promises);
|
||||
cachedResolvedFlags = Object.fromEntries(resolved.filter((r) => r !== null));
|
||||
return cachedResolvedFlags;
|
||||
}
|
||||
const getPresentFlags = (flags) => Object.keys(flags).filter((key) => key !== undefined);
|
||||
function validateExactlyOneAcrossFlags(flag) {
|
||||
const base = { name: flag.name, validationFn: 'validateExactlyOneAcrossFlags' };
|
||||
const intersection = Object.entries(parse.input.flags)
|
||||
.map((entry) => entry[0]) // array of flag names
|
||||
.filter((flagName) => parse.output.flags[flagName] !== undefined) // with values
|
||||
.filter((flagName) => flag.exactlyOne && flag.exactlyOne.includes(flagName)); // and in the exactlyOne list
|
||||
if (intersection.length === 0) {
|
||||
// the command's exactlyOne may or may not include itself, so we'll use Set to add + de-dupe
|
||||
const deduped = (0, util_1.uniq)(flag.exactlyOne?.map((flag) => `--${flag}`) ?? []).join(', ');
|
||||
const reason = `Exactly one of the following must be provided: ${deduped}`;
|
||||
return { ...base, reason, status: 'failed' };
|
||||
}
|
||||
return { ...base, status: 'success' };
|
||||
}
|
||||
function validateAtLeastOneAcrossFlags(flag) {
|
||||
const base = { name: flag.name, validationFn: 'validateAtLeastOneAcrossFlags' };
|
||||
const intersection = Object.entries(parse.input.flags)
|
||||
.map((entry) => entry[0]) // array of flag names
|
||||
.filter((flagName) => parse.output.flags[flagName] !== undefined) // with values
|
||||
.filter((flagName) => flag.atLeastOne && flag.atLeastOne.includes(flagName)); // and in the atLeastOne list
|
||||
if (intersection.length === 0) {
|
||||
// the command's atLeastOne may or may not include itself, so we'll use Set to add + de-dupe
|
||||
const deduped = (0, util_1.uniq)(flag.atLeastOne?.map((flag) => `--${flag}`) ?? []).join(', ');
|
||||
const reason = `At least one of the following must be provided: ${deduped}`;
|
||||
return { ...base, reason, status: 'failed' };
|
||||
}
|
||||
return { ...base, status: 'success' };
|
||||
}
|
||||
async function validateExclusive(name, flags) {
|
||||
const base = { name, validationFn: 'validateExclusive' };
|
||||
const resolved = await resolveFlags(flags);
|
||||
const keys = getPresentFlags(resolved);
|
||||
for (const flag of keys) {
|
||||
// do not enforce exclusivity for flags that were defaulted
|
||||
if (parse.output.metadata.flags && parse.output.metadata.flags[flag]?.setFromDefault)
|
||||
continue;
|
||||
if (parse.output.metadata.flags && parse.output.metadata.flags[name]?.setFromDefault)
|
||||
continue;
|
||||
if (parse.output.flags[flag] !== undefined) {
|
||||
const flagValue = parse.output.metadata.flags?.[flag]?.defaultHelp ?? parse.output.flags[flag];
|
||||
return {
|
||||
...base,
|
||||
reason: `--${flag}=${flagValue} cannot also be provided when using --${name}`,
|
||||
status: 'failed',
|
||||
};
|
||||
}
|
||||
}
|
||||
return { ...base, status: 'success' };
|
||||
}
|
||||
async function validateCombinable(name, flags) {
|
||||
const base = { name, validationFn: 'validateCombinable' };
|
||||
const combinableFlags = new Set(flags.map((flag) => (typeof flag === 'string' ? flag : flag.name)));
|
||||
const resolved = await resolveFlags(flags);
|
||||
for (const flag of Object.keys(parse.output.flags)) {
|
||||
// do not enforce exclusivity for flags that were defaulted
|
||||
if (parse.output.metadata.flags && parse.output.metadata.flags[flag]?.setFromDefault)
|
||||
continue;
|
||||
if (parse.output.metadata.flags && parse.output.metadata.flags[name]?.setFromDefault)
|
||||
continue;
|
||||
if (flag !== name && parse.output.flags[flag] !== undefined && !combinableFlags.has(flag)) {
|
||||
const formattedFlags = Object.keys(resolved)
|
||||
.map((f) => `--${f}`)
|
||||
.join(', ');
|
||||
return {
|
||||
...base,
|
||||
reason: `Only the following can be provided when using --${name}: ${formattedFlags}`,
|
||||
status: 'failed',
|
||||
};
|
||||
}
|
||||
}
|
||||
return { ...base, status: 'success' };
|
||||
}
|
||||
async function validateExactlyOne(name, flags) {
|
||||
const base = { name, validationFn: 'validateExactlyOne' };
|
||||
const resolved = await resolveFlags(flags);
|
||||
const keys = getPresentFlags(resolved);
|
||||
for (const flag of keys) {
|
||||
if (flag !== name && parse.output.flags[flag] !== undefined) {
|
||||
return { ...base, reason: `--${flag} cannot also be provided when using --${name}`, status: 'failed' };
|
||||
}
|
||||
}
|
||||
return { ...base, status: 'success' };
|
||||
}
|
||||
async function validateDependsOn(name, flags) {
|
||||
const base = { name, validationFn: 'validateDependsOn' };
|
||||
const resolved = await resolveFlags(flags);
|
||||
const foundAll = Object.values(resolved).every((val) => val !== undefined);
|
||||
if (!foundAll) {
|
||||
const formattedFlags = Object.keys(resolved)
|
||||
.map((f) => `--${f}`)
|
||||
.join(', ');
|
||||
return {
|
||||
...base,
|
||||
reason: `All of the following must be provided when using --${name}: ${formattedFlags}`,
|
||||
status: 'failed',
|
||||
};
|
||||
}
|
||||
return { ...base, status: 'success' };
|
||||
}
|
||||
async function validateSome(name, flags) {
|
||||
const base = { name, validationFn: 'validateSome' };
|
||||
const resolved = await resolveFlags(flags);
|
||||
const foundAtLeastOne = Object.values(resolved).some(Boolean);
|
||||
if (!foundAtLeastOne) {
|
||||
const formattedFlags = Object.keys(resolved)
|
||||
.map((f) => `--${f}`)
|
||||
.join(', ');
|
||||
return {
|
||||
...base,
|
||||
reason: `One of the following must be provided when using --${name}: ${formattedFlags}`,
|
||||
status: 'failed',
|
||||
};
|
||||
}
|
||||
return { ...base, status: 'success' };
|
||||
}
|
||||
function validateRelationships(name, flag) {
|
||||
return (flag.relationships ?? []).map((relationship) => {
|
||||
switch (relationship.type) {
|
||||
case 'all': {
|
||||
return validateDependsOn(name, relationship.flags);
|
||||
}
|
||||
case 'none': {
|
||||
return validateExclusive(name, relationship.flags);
|
||||
}
|
||||
case 'only': {
|
||||
return validateCombinable(name, relationship.flags);
|
||||
}
|
||||
case 'some': {
|
||||
return validateSome(name, relationship.flags);
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Unknown relationship type: ${relationship.type}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
validateArgs();
|
||||
return validateFlags();
|
||||
}
|
||||
Reference in New Issue
Block a user