UNPKG

func-contract-analyzer

Version:

FunC Smart Contract Static Analyzer - Storage, Call Graph, Function References, Global Variables, and Constant Analysis

1,379 lines (1,367 loc) 386 kB
#!/usr/bin/env bun // @bun var __create = Object.create; var __getProtoOf = Object.getPrototypeOf; var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __toESM = (mod, isNodeMode, target) => { target = mod != null ? __create(__getProtoOf(mod)) : {}; const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target; for (let key of __getOwnPropNames(mod)) if (!__hasOwnProp.call(to, key)) __defProp(to, key, { get: () => mod[key], enumerable: true }); return to; }; var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports); var __require = import.meta.require; // node_modules/commander/lib/error.js var require_error = __commonJS((exports) => { class CommanderError extends Error { constructor(exitCode, code, message) { super(message); Error.captureStackTrace(this, this.constructor); this.name = this.constructor.name; this.code = code; this.exitCode = exitCode; this.nestedError = undefined; } } class InvalidArgumentError extends CommanderError { constructor(message) { super(1, "commander.invalidArgument", message); Error.captureStackTrace(this, this.constructor); this.name = this.constructor.name; } } exports.CommanderError = CommanderError; exports.InvalidArgumentError = InvalidArgumentError; }); // node_modules/commander/lib/argument.js var require_argument = __commonJS((exports) => { var { InvalidArgumentError } = require_error(); class Argument { constructor(name, description) { this.description = description || ""; this.variadic = false; this.parseArg = undefined; this.defaultValue = undefined; this.defaultValueDescription = undefined; this.argChoices = undefined; switch (name[0]) { case "<": this.required = true; this._name = name.slice(1, -1); break; case "[": this.required = false; this._name = name.slice(1, -1); break; default: this.required = true; this._name = name; break; } if (this._name.length > 3 && this._name.slice(-3) === "...") { this.variadic = true; this._name = this._name.slice(0, -3); } } name() { return this._name; } _concatValue(value, previous) { if (previous === this.defaultValue || !Array.isArray(previous)) { return [value]; } return previous.concat(value); } default(value, description) { this.defaultValue = value; this.defaultValueDescription = description; return this; } argParser(fn) { this.parseArg = fn; return this; } choices(values) { this.argChoices = values.slice(); this.parseArg = (arg, previous) => { if (!this.argChoices.includes(arg)) { throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`); } if (this.variadic) { return this._concatValue(arg, previous); } return arg; }; return this; } argRequired() { this.required = true; return this; } argOptional() { this.required = false; return this; } } function humanReadableArgName(arg) { const nameOutput = arg.name() + (arg.variadic === true ? "..." : ""); return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]"; } exports.Argument = Argument; exports.humanReadableArgName = humanReadableArgName; }); // node_modules/commander/lib/help.js var require_help = __commonJS((exports) => { var { humanReadableArgName } = require_argument(); class Help { constructor() { this.helpWidth = undefined; this.minWidthToWrap = 40; this.sortSubcommands = false; this.sortOptions = false; this.showGlobalOptions = false; } prepareContext(contextOptions) { this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80; } visibleCommands(cmd) { const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden); const helpCommand = cmd._getHelpCommand(); if (helpCommand && !helpCommand._hidden) { visibleCommands.push(helpCommand); } if (this.sortSubcommands) { visibleCommands.sort((a, b) => { return a.name().localeCompare(b.name()); }); } return visibleCommands; } compareOptions(a, b) { const getSortKey = (option) => { return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, ""); }; return getSortKey(a).localeCompare(getSortKey(b)); } visibleOptions(cmd) { const visibleOptions = cmd.options.filter((option) => !option.hidden); const helpOption = cmd._getHelpOption(); if (helpOption && !helpOption.hidden) { const removeShort = helpOption.short && cmd._findOption(helpOption.short); const removeLong = helpOption.long && cmd._findOption(helpOption.long); if (!removeShort && !removeLong) { visibleOptions.push(helpOption); } else if (helpOption.long && !removeLong) { visibleOptions.push(cmd.createOption(helpOption.long, helpOption.description)); } else if (helpOption.short && !removeShort) { visibleOptions.push(cmd.createOption(helpOption.short, helpOption.description)); } } if (this.sortOptions) { visibleOptions.sort(this.compareOptions); } return visibleOptions; } visibleGlobalOptions(cmd) { if (!this.showGlobalOptions) return []; const globalOptions = []; for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) { const visibleOptions = ancestorCmd.options.filter((option) => !option.hidden); globalOptions.push(...visibleOptions); } if (this.sortOptions) { globalOptions.sort(this.compareOptions); } return globalOptions; } visibleArguments(cmd) { if (cmd._argsDescription) { cmd.registeredArguments.forEach((argument) => { argument.description = argument.description || cmd._argsDescription[argument.name()] || ""; }); } if (cmd.registeredArguments.find((argument) => argument.description)) { return cmd.registeredArguments; } return []; } subcommandTerm(cmd) { const args2 = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" "); return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + (args2 ? " " + args2 : ""); } optionTerm(option) { return option.flags; } argumentTerm(argument) { return argument.name(); } longestSubcommandTermLength(cmd, helper) { return helper.visibleCommands(cmd).reduce((max, command) => { return Math.max(max, this.displayWidth(helper.styleSubcommandTerm(helper.subcommandTerm(command)))); }, 0); } longestOptionTermLength(cmd, helper) { return helper.visibleOptions(cmd).reduce((max, option) => { return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option)))); }, 0); } longestGlobalOptionTermLength(cmd, helper) { return helper.visibleGlobalOptions(cmd).reduce((max, option) => { return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option)))); }, 0); } longestArgumentTermLength(cmd, helper) { return helper.visibleArguments(cmd).reduce((max, argument) => { return Math.max(max, this.displayWidth(helper.styleArgumentTerm(helper.argumentTerm(argument)))); }, 0); } commandUsage(cmd) { let cmdName = cmd._name; if (cmd._aliases[0]) { cmdName = cmdName + "|" + cmd._aliases[0]; } let ancestorCmdNames = ""; for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) { ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames; } return ancestorCmdNames + cmdName + " " + cmd.usage(); } commandDescription(cmd) { return cmd.description(); } subcommandDescription(cmd) { return cmd.summary() || cmd.description(); } optionDescription(option) { const extraInfo = []; if (option.argChoices) { extraInfo.push(`choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`); } if (option.defaultValue !== undefined) { const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean"; if (showDefault) { extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`); } } if (option.presetArg !== undefined && option.optional) { extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`); } if (option.envVar !== undefined) { extraInfo.push(`env: ${option.envVar}`); } if (extraInfo.length > 0) { const extraDescription = `(${extraInfo.join(", ")})`; if (option.description) { return `${option.description} ${extraDescription}`; } return extraDescription; } return option.description; } argumentDescription(argument) { const extraInfo = []; if (argument.argChoices) { extraInfo.push(`choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`); } if (argument.defaultValue !== undefined) { extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`); } if (extraInfo.length > 0) { const extraDescription = `(${extraInfo.join(", ")})`; if (argument.description) { return `${argument.description} ${extraDescription}`; } return extraDescription; } return argument.description; } formatItemList(heading, items, helper) { if (items.length === 0) return []; return [helper.styleTitle(heading), ...items, ""]; } groupItems(unsortedItems, visibleItems, getGroup) { const result = new Map; unsortedItems.forEach((item) => { const group = getGroup(item); if (!result.has(group)) result.set(group, []); }); visibleItems.forEach((item) => { const group = getGroup(item); if (!result.has(group)) { result.set(group, []); } result.get(group).push(item); }); return result; } formatHelp(cmd, helper) { const termWidth = helper.padWidth(cmd, helper); const helpWidth = helper.helpWidth ?? 80; function callFormatItem(term, description) { return helper.formatItem(term, termWidth, description, helper); } let output = [ `${helper.styleTitle("Usage:")} ${helper.styleUsage(helper.commandUsage(cmd))}`, "" ]; const commandDescription = helper.commandDescription(cmd); if (commandDescription.length > 0) { output = output.concat([ helper.boxWrap(helper.styleCommandDescription(commandDescription), helpWidth), "" ]); } const argumentList = helper.visibleArguments(cmd).map((argument) => { return callFormatItem(helper.styleArgumentTerm(helper.argumentTerm(argument)), helper.styleArgumentDescription(helper.argumentDescription(argument))); }); output = output.concat(this.formatItemList("Arguments:", argumentList, helper)); const optionGroups = this.groupItems(cmd.options, helper.visibleOptions(cmd), (option) => option.helpGroupHeading ?? "Options:"); optionGroups.forEach((options, group) => { const optionList = options.map((option) => { return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option))); }); output = output.concat(this.formatItemList(group, optionList, helper)); }); if (helper.showGlobalOptions) { const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => { return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option))); }); output = output.concat(this.formatItemList("Global Options:", globalOptionList, helper)); } const commandGroups = this.groupItems(cmd.commands, helper.visibleCommands(cmd), (sub) => sub.helpGroup() || "Commands:"); commandGroups.forEach((commands, group) => { const commandList = commands.map((sub) => { return callFormatItem(helper.styleSubcommandTerm(helper.subcommandTerm(sub)), helper.styleSubcommandDescription(helper.subcommandDescription(sub))); }); output = output.concat(this.formatItemList(group, commandList, helper)); }); return output.join(` `); } displayWidth(str) { return stripColor(str).length; } styleTitle(str) { return str; } styleUsage(str) { return str.split(" ").map((word) => { if (word === "[options]") return this.styleOptionText(word); if (word === "[command]") return this.styleSubcommandText(word); if (word[0] === "[" || word[0] === "<") return this.styleArgumentText(word); return this.styleCommandText(word); }).join(" "); } styleCommandDescription(str) { return this.styleDescriptionText(str); } styleOptionDescription(str) { return this.styleDescriptionText(str); } styleSubcommandDescription(str) { return this.styleDescriptionText(str); } styleArgumentDescription(str) { return this.styleDescriptionText(str); } styleDescriptionText(str) { return str; } styleOptionTerm(str) { return this.styleOptionText(str); } styleSubcommandTerm(str) { return str.split(" ").map((word) => { if (word === "[options]") return this.styleOptionText(word); if (word[0] === "[" || word[0] === "<") return this.styleArgumentText(word); return this.styleSubcommandText(word); }).join(" "); } styleArgumentTerm(str) { return this.styleArgumentText(str); } styleOptionText(str) { return str; } styleArgumentText(str) { return str; } styleSubcommandText(str) { return str; } styleCommandText(str) { return str; } padWidth(cmd, helper) { return Math.max(helper.longestOptionTermLength(cmd, helper), helper.longestGlobalOptionTermLength(cmd, helper), helper.longestSubcommandTermLength(cmd, helper), helper.longestArgumentTermLength(cmd, helper)); } preformatted(str) { return /\n[^\S\r\n]/.test(str); } formatItem(term, termWidth, description, helper) { const itemIndent = 2; const itemIndentStr = " ".repeat(itemIndent); if (!description) return itemIndentStr + term; const paddedTerm = term.padEnd(termWidth + term.length - helper.displayWidth(term)); const spacerWidth = 2; const helpWidth = this.helpWidth ?? 80; const remainingWidth = helpWidth - termWidth - spacerWidth - itemIndent; let formattedDescription; if (remainingWidth < this.minWidthToWrap || helper.preformatted(description)) { formattedDescription = description; } else { const wrappedDescription = helper.boxWrap(description, remainingWidth); formattedDescription = wrappedDescription.replace(/\n/g, ` ` + " ".repeat(termWidth + spacerWidth)); } return itemIndentStr + paddedTerm + " ".repeat(spacerWidth) + formattedDescription.replace(/\n/g, ` ${itemIndentStr}`); } boxWrap(str, width) { if (width < this.minWidthToWrap) return str; const rawLines = str.split(/\r\n|\n/); const chunkPattern = /[\s]*[^\s]+/g; const wrappedLines = []; rawLines.forEach((line) => { const chunks = line.match(chunkPattern); if (chunks === null) { wrappedLines.push(""); return; } let sumChunks = [chunks.shift()]; let sumWidth = this.displayWidth(sumChunks[0]); chunks.forEach((chunk) => { const visibleWidth = this.displayWidth(chunk); if (sumWidth + visibleWidth <= width) { sumChunks.push(chunk); sumWidth += visibleWidth; return; } wrappedLines.push(sumChunks.join("")); const nextChunk = chunk.trimStart(); sumChunks = [nextChunk]; sumWidth = this.displayWidth(nextChunk); }); wrappedLines.push(sumChunks.join("")); }); return wrappedLines.join(` `); } } function stripColor(str) { const sgrPattern = /\x1b\[\d*(;\d*)*m/g; return str.replace(sgrPattern, ""); } exports.Help = Help; exports.stripColor = stripColor; }); // node_modules/commander/lib/option.js var require_option = __commonJS((exports) => { var { InvalidArgumentError } = require_error(); class Option { constructor(flags2, description) { this.flags = flags2; this.description = description || ""; this.required = flags2.includes("<"); this.optional = flags2.includes("["); this.variadic = /\w\.\.\.[>\]]$/.test(flags2); this.mandatory = false; const optionFlags = splitOptionFlags(flags2); this.short = optionFlags.shortFlag; this.long = optionFlags.longFlag; this.negate = false; if (this.long) { this.negate = this.long.startsWith("--no-"); } this.defaultValue = undefined; this.defaultValueDescription = undefined; this.presetArg = undefined; this.envVar = undefined; this.parseArg = undefined; this.hidden = false; this.argChoices = undefined; this.conflictsWith = []; this.implied = undefined; this.helpGroupHeading = undefined; } default(value, description) { this.defaultValue = value; this.defaultValueDescription = description; return this; } preset(arg) { this.presetArg = arg; return this; } conflicts(names) { this.conflictsWith = this.conflictsWith.concat(names); return this; } implies(impliedOptionValues) { let newImplied = impliedOptionValues; if (typeof impliedOptionValues === "string") { newImplied = { [impliedOptionValues]: true }; } this.implied = Object.assign(this.implied || {}, newImplied); return this; } env(name) { this.envVar = name; return this; } argParser(fn) { this.parseArg = fn; return this; } makeOptionMandatory(mandatory = true) { this.mandatory = !!mandatory; return this; } hideHelp(hide = true) { this.hidden = !!hide; return this; } _concatValue(value, previous) { if (previous === this.defaultValue || !Array.isArray(previous)) { return [value]; } return previous.concat(value); } choices(values) { this.argChoices = values.slice(); this.parseArg = (arg, previous) => { if (!this.argChoices.includes(arg)) { throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`); } if (this.variadic) { return this._concatValue(arg, previous); } return arg; }; return this; } name() { if (this.long) { return this.long.replace(/^--/, ""); } return this.short.replace(/^-/, ""); } attributeName() { if (this.negate) { return camelcase(this.name().replace(/^no-/, "")); } return camelcase(this.name()); } helpGroup(heading) { this.helpGroupHeading = heading; return this; } is(arg) { return this.short === arg || this.long === arg; } isBoolean() { return !this.required && !this.optional && !this.negate; } } class DualOptions { constructor(options) { this.positiveOptions = new Map; this.negativeOptions = new Map; this.dualOptions = new Set; options.forEach((option) => { if (option.negate) { this.negativeOptions.set(option.attributeName(), option); } else { this.positiveOptions.set(option.attributeName(), option); } }); this.negativeOptions.forEach((value, key) => { if (this.positiveOptions.has(key)) { this.dualOptions.add(key); } }); } valueFromOption(value, option) { const optionKey = option.attributeName(); if (!this.dualOptions.has(optionKey)) return true; const preset = this.negativeOptions.get(optionKey).presetArg; const negativeValue = preset !== undefined ? preset : false; return option.negate === (negativeValue === value); } } function camelcase(str) { return str.split("-").reduce((str2, word) => { return str2 + word[0].toUpperCase() + word.slice(1); }); } function splitOptionFlags(flags2) { let shortFlag; let longFlag; const shortFlagExp = /^-[^-]$/; const longFlagExp = /^--[^-]/; const flagParts = flags2.split(/[ |,]+/).concat("guard"); if (shortFlagExp.test(flagParts[0])) shortFlag = flagParts.shift(); if (longFlagExp.test(flagParts[0])) longFlag = flagParts.shift(); if (!shortFlag && shortFlagExp.test(flagParts[0])) shortFlag = flagParts.shift(); if (!shortFlag && longFlagExp.test(flagParts[0])) { shortFlag = longFlag; longFlag = flagParts.shift(); } if (flagParts[0].startsWith("-")) { const unsupportedFlag = flagParts[0]; const baseError = `option creation failed due to '${unsupportedFlag}' in option flags '${flags2}'`; if (/^-[^-][^-]/.test(unsupportedFlag)) throw new Error(`${baseError} - a short flag is a single dash and a single character - either use a single dash and a single character (for a short flag) - or use a double dash for a long option (and can have two, like '--ws, --workspace')`); if (shortFlagExp.test(unsupportedFlag)) throw new Error(`${baseError} - too many short flags`); if (longFlagExp.test(unsupportedFlag)) throw new Error(`${baseError} - too many long flags`); throw new Error(`${baseError} - unrecognised flag format`); } if (shortFlag === undefined && longFlag === undefined) throw new Error(`option creation failed due to no flags found in '${flags2}'.`); return { shortFlag, longFlag }; } exports.Option = Option; exports.DualOptions = DualOptions; }); // node_modules/commander/lib/suggestSimilar.js var require_suggestSimilar = __commonJS((exports) => { var maxDistance = 3; function editDistance(a, b) { if (Math.abs(a.length - b.length) > maxDistance) return Math.max(a.length, b.length); const d = []; for (let i = 0;i <= a.length; i++) { d[i] = [i]; } for (let j = 0;j <= b.length; j++) { d[0][j] = j; } for (let j = 1;j <= b.length; j++) { for (let i = 1;i <= a.length; i++) { let cost = 1; if (a[i - 1] === b[j - 1]) { cost = 0; } else { cost = 1; } d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost); if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) { d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1); } } } return d[a.length][b.length]; } function suggestSimilar(word, candidates) { if (!candidates || candidates.length === 0) return ""; candidates = Array.from(new Set(candidates)); const searchingOptions = word.startsWith("--"); if (searchingOptions) { word = word.slice(2); candidates = candidates.map((candidate) => candidate.slice(2)); } let similar = []; let bestDistance = maxDistance; const minSimilarity = 0.4; candidates.forEach((candidate) => { if (candidate.length <= 1) return; const distance = editDistance(word, candidate); const length = Math.max(word.length, candidate.length); const similarity = (length - distance) / length; if (similarity > minSimilarity) { if (distance < bestDistance) { bestDistance = distance; similar = [candidate]; } else if (distance === bestDistance) { similar.push(candidate); } } }); similar.sort((a, b) => a.localeCompare(b)); if (searchingOptions) { similar = similar.map((candidate) => `--${candidate}`); } if (similar.length > 1) { return ` (Did you mean one of ${similar.join(", ")}?)`; } if (similar.length === 1) { return ` (Did you mean ${similar[0]}?)`; } return ""; } exports.suggestSimilar = suggestSimilar; }); // node_modules/commander/lib/command.js var require_command = __commonJS((exports) => { var EventEmitter = __require("events").EventEmitter; var childProcess = __require("child_process"); var path = __require("path"); var fs2 = __require("fs"); var process2 = __require("process"); var { Argument, humanReadableArgName } = require_argument(); var { CommanderError } = require_error(); var { Help, stripColor } = require_help(); var { Option, DualOptions } = require_option(); var { suggestSimilar } = require_suggestSimilar(); class Command extends EventEmitter { constructor(name) { super(); this.commands = []; this.options = []; this.parent = null; this._allowUnknownOption = false; this._allowExcessArguments = false; this.registeredArguments = []; this._args = this.registeredArguments; this.args = []; this.rawArgs = []; this.processedArgs = []; this._scriptPath = null; this._name = name || ""; this._optionValues = {}; this._optionValueSources = {}; this._storeOptionsAsProperties = false; this._actionHandler = null; this._executableHandler = false; this._executableFile = null; this._executableDir = null; this._defaultCommandName = null; this._exitCallback = null; this._aliases = []; this._combineFlagAndOptionalValue = true; this._description = ""; this._summary = ""; this._argsDescription = undefined; this._enablePositionalOptions = false; this._passThroughOptions = false; this._lifeCycleHooks = {}; this._showHelpAfterError = false; this._showSuggestionAfterError = true; this._savedState = null; this._outputConfiguration = { writeOut: (str) => process2.stdout.write(str), writeErr: (str) => process2.stderr.write(str), outputError: (str, write) => write(str), getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : undefined, getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : undefined, getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()), getErrHasColors: () => useColor() ?? (process2.stderr.isTTY && process2.stderr.hasColors?.()), stripColor: (str) => stripColor(str) }; this._hidden = false; this._helpOption = undefined; this._addImplicitHelpCommand = undefined; this._helpCommand = undefined; this._helpConfiguration = {}; this._helpGroupHeading = undefined; this._defaultCommandGroup = undefined; this._defaultOptionGroup = undefined; } copyInheritedSettings(sourceCommand) { this._outputConfiguration = sourceCommand._outputConfiguration; this._helpOption = sourceCommand._helpOption; this._helpCommand = sourceCommand._helpCommand; this._helpConfiguration = sourceCommand._helpConfiguration; this._exitCallback = sourceCommand._exitCallback; this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties; this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue; this._allowExcessArguments = sourceCommand._allowExcessArguments; this._enablePositionalOptions = sourceCommand._enablePositionalOptions; this._showHelpAfterError = sourceCommand._showHelpAfterError; this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError; return this; } _getCommandAndAncestors() { const result = []; for (let command = this;command; command = command.parent) { result.push(command); } return result; } command(nameAndArgs, actionOptsOrExecDesc, execOpts) { let desc = actionOptsOrExecDesc; let opts = execOpts; if (typeof desc === "object" && desc !== null) { opts = desc; desc = null; } opts = opts || {}; const [, name, args2] = nameAndArgs.match(/([^ ]+) *(.*)/); const cmd = this.createCommand(name); if (desc) { cmd.description(desc); cmd._executableHandler = true; } if (opts.isDefault) this._defaultCommandName = cmd._name; cmd._hidden = !!(opts.noHelp || opts.hidden); cmd._executableFile = opts.executableFile || null; if (args2) cmd.arguments(args2); this._registerCommand(cmd); cmd.parent = this; cmd.copyInheritedSettings(this); if (desc) return this; return cmd; } createCommand(name) { return new Command(name); } createHelp() { return Object.assign(new Help, this.configureHelp()); } configureHelp(configuration) { if (configuration === undefined) return this._helpConfiguration; this._helpConfiguration = configuration; return this; } configureOutput(configuration) { if (configuration === undefined) return this._outputConfiguration; this._outputConfiguration = Object.assign({}, this._outputConfiguration, configuration); return this; } showHelpAfterError(displayHelp = true) { if (typeof displayHelp !== "string") displayHelp = !!displayHelp; this._showHelpAfterError = displayHelp; return this; } showSuggestionAfterError(displaySuggestion = true) { this._showSuggestionAfterError = !!displaySuggestion; return this; } addCommand(cmd, opts) { if (!cmd._name) { throw new Error(`Command passed to .addCommand() must have a name - specify the name in Command constructor or using .name()`); } opts = opts || {}; if (opts.isDefault) this._defaultCommandName = cmd._name; if (opts.noHelp || opts.hidden) cmd._hidden = true; this._registerCommand(cmd); cmd.parent = this; cmd._checkForBrokenPassThrough(); return this; } createArgument(name, description) { return new Argument(name, description); } argument(name, description, parseArg, defaultValue) { const argument = this.createArgument(name, description); if (typeof parseArg === "function") { argument.default(defaultValue).argParser(parseArg); } else { argument.default(parseArg); } this.addArgument(argument); return this; } arguments(names) { names.trim().split(/ +/).forEach((detail) => { this.argument(detail); }); return this; } addArgument(argument) { const previousArgument = this.registeredArguments.slice(-1)[0]; if (previousArgument && previousArgument.variadic) { throw new Error(`only the last argument can be variadic '${previousArgument.name()}'`); } if (argument.required && argument.defaultValue !== undefined && argument.parseArg === undefined) { throw new Error(`a default value for a required argument is never used: '${argument.name()}'`); } this.registeredArguments.push(argument); return this; } helpCommand(enableOrNameAndArgs, description) { if (typeof enableOrNameAndArgs === "boolean") { this._addImplicitHelpCommand = enableOrNameAndArgs; if (enableOrNameAndArgs && this._defaultCommandGroup) { this._initCommandGroup(this._getHelpCommand()); } return this; } const nameAndArgs = enableOrNameAndArgs ?? "help [command]"; const [, helpName, helpArgs] = nameAndArgs.match(/([^ ]+) *(.*)/); const helpDescription = description ?? "display help for command"; const helpCommand = this.createCommand(helpName); helpCommand.helpOption(false); if (helpArgs) helpCommand.arguments(helpArgs); if (helpDescription) helpCommand.description(helpDescription); this._addImplicitHelpCommand = true; this._helpCommand = helpCommand; if (enableOrNameAndArgs || description) this._initCommandGroup(helpCommand); return this; } addHelpCommand(helpCommand, deprecatedDescription) { if (typeof helpCommand !== "object") { this.helpCommand(helpCommand, deprecatedDescription); return this; } this._addImplicitHelpCommand = true; this._helpCommand = helpCommand; this._initCommandGroup(helpCommand); return this; } _getHelpCommand() { const hasImplicitHelpCommand = this._addImplicitHelpCommand ?? (this.commands.length && !this._actionHandler && !this._findCommand("help")); if (hasImplicitHelpCommand) { if (this._helpCommand === undefined) { this.helpCommand(undefined, undefined); } return this._helpCommand; } return null; } hook(event, listener) { const allowedValues = ["preSubcommand", "preAction", "postAction"]; if (!allowedValues.includes(event)) { throw new Error(`Unexpected value for event passed to hook : '${event}'. Expecting one of '${allowedValues.join("', '")}'`); } if (this._lifeCycleHooks[event]) { this._lifeCycleHooks[event].push(listener); } else { this._lifeCycleHooks[event] = [listener]; } return this; } exitOverride(fn) { if (fn) { this._exitCallback = fn; } else { this._exitCallback = (err2) => { if (err2.code !== "commander.executeSubCommandAsync") { throw err2; } else {} }; } return this; } _exit(exitCode, code, message) { if (this._exitCallback) { this._exitCallback(new CommanderError(exitCode, code, message)); } process2.exit(exitCode); } action(fn) { const listener = (args2) => { const expectedArgsCount = this.registeredArguments.length; const actionArgs = args2.slice(0, expectedArgsCount); if (this._storeOptionsAsProperties) { actionArgs[expectedArgsCount] = this; } else { actionArgs[expectedArgsCount] = this.opts(); } actionArgs.push(this); return fn.apply(this, actionArgs); }; this._actionHandler = listener; return this; } createOption(flags2, description) { return new Option(flags2, description); } _callParseArg(target, value, previous, invalidArgumentMessage) { try { return target.parseArg(value, previous); } catch (err2) { if (err2.code === "commander.invalidArgument") { const message = `${invalidArgumentMessage} ${err2.message}`; this.error(message, { exitCode: err2.exitCode, code: err2.code }); } throw err2; } } _registerOption(option) { const matchingOption = option.short && this._findOption(option.short) || option.long && this._findOption(option.long); if (matchingOption) { const matchingFlag = option.long && this._findOption(option.long) ? option.long : option.short; throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}' - already used by option '${matchingOption.flags}'`); } this._initOptionGroup(option); this.options.push(option); } _registerCommand(command) { const knownBy = (cmd) => { return [cmd.name()].concat(cmd.aliases()); }; const alreadyUsed = knownBy(command).find((name) => this._findCommand(name)); if (alreadyUsed) { const existingCmd = knownBy(this._findCommand(alreadyUsed)).join("|"); const newCmd = knownBy(command).join("|"); throw new Error(`cannot add command '${newCmd}' as already have command '${existingCmd}'`); } this._initCommandGroup(command); this.commands.push(command); } addOption(option) { this._registerOption(option); const oname = option.name(); const name = option.attributeName(); if (option.negate) { const positiveLongFlag = option.long.replace(/^--no-/, "--"); if (!this._findOption(positiveLongFlag)) { this.setOptionValueWithSource(name, option.defaultValue === undefined ? true : option.defaultValue, "default"); } } else if (option.defaultValue !== undefined) { this.setOptionValueWithSource(name, option.defaultValue, "default"); } const handleOptionValue = (val, invalidValueMessage, valueSource) => { if (val == null && option.presetArg !== undefined) { val = option.presetArg; } const oldValue = this.getOptionValue(name); if (val !== null && option.parseArg) { val = this._callParseArg(option, val, oldValue, invalidValueMessage); } else if (val !== null && option.variadic) { val = option._concatValue(val, oldValue); } if (val == null) { if (option.negate) { val = false; } else if (option.isBoolean() || option.optional) { val = true; } else { val = ""; } } this.setOptionValueWithSource(name, val, valueSource); }; this.on("option:" + oname, (val) => { const invalidValueMessage = `error: option '${option.flags}' argument '${val}' is invalid.`; handleOptionValue(val, invalidValueMessage, "cli"); }); if (option.envVar) { this.on("optionEnv:" + oname, (val) => { const invalidValueMessage = `error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`; handleOptionValue(val, invalidValueMessage, "env"); }); } return this; } _optionEx(config, flags2, description, fn, defaultValue) { if (typeof flags2 === "object" && flags2 instanceof Option) { throw new Error("To add an Option object use addOption() instead of option() or requiredOption()"); } const option = this.createOption(flags2, description); option.makeOptionMandatory(!!config.mandatory); if (typeof fn === "function") { option.default(defaultValue).argParser(fn); } else if (fn instanceof RegExp) { const regex = fn; fn = (val, def) => { const m = regex.exec(val); return m ? m[0] : def; }; option.default(defaultValue).argParser(fn); } else { option.default(fn); } return this.addOption(option); } option(flags2, description, parseArg, defaultValue) { return this._optionEx({}, flags2, description, parseArg, defaultValue); } requiredOption(flags2, description, parseArg, defaultValue) { return this._optionEx({ mandatory: true }, flags2, description, parseArg, defaultValue); } combineFlagAndOptionalValue(combine = true) { this._combineFlagAndOptionalValue = !!combine; return this; } allowUnknownOption(allowUnknown = true) { this._allowUnknownOption = !!allowUnknown; return this; } allowExcessArguments(allowExcess = true) { this._allowExcessArguments = !!allowExcess; return this; } enablePositionalOptions(positional = true) { this._enablePositionalOptions = !!positional; return this; } passThroughOptions(passThrough = true) { this._passThroughOptions = !!passThrough; this._checkForBrokenPassThrough(); return this; } _checkForBrokenPassThrough() { if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) { throw new Error(`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`); } } storeOptionsAsProperties(storeAsProperties = true) { if (this.options.length) { throw new Error("call .storeOptionsAsProperties() before adding options"); } if (Object.keys(this._optionValues).length) { throw new Error("call .storeOptionsAsProperties() before setting option values"); } this._storeOptionsAsProperties = !!storeAsProperties; return this; } getOptionValue(key) { if (this._storeOptionsAsProperties) { return this[key]; } return this._optionValues[key]; } setOptionValue(key, value) { return this.setOptionValueWithSource(key, value, undefined); } setOptionValueWithSource(key, value, source) { if (this._storeOptionsAsProperties) { this[key] = value; } else { this._optionValues[key] = value; } this._optionValueSources[key] = source; return this; } getOptionValueSource(key) { return this._optionValueSources[key]; } getOptionValueSourceWithGlobals(key) { let source; this._getCommandAndAncestors().forEach((cmd) => { if (cmd.getOptionValueSource(key) !== undefined) { source = cmd.getOptionValueSource(key); } }); return source; } _prepareUserArgs(argv, parseOptions) { if (argv !== undefined && !Array.isArray(argv)) { throw new Error("first parameter to parse must be array or undefined"); } parseOptions = parseOptions || {}; if (argv === undefined && parseOptions.from === undefined) { if (process2.versions?.electron) { parseOptions.from = "electron"; } const execArgv = process2.execArgv ?? []; if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) { parseOptions.from = "eval"; } } if (argv === undefined) { argv = process2.argv; } this.rawArgs = argv.slice(); let userArgs; switch (parseOptions.from) { case undefined: case "node": this._scriptPath = argv[1]; userArgs = argv.slice(2); break; case "electron": if (process2.defaultApp) { this._scriptPath = argv[1]; userArgs = argv.slice(2); } else { userArgs = argv.slice(1); } break; case "user": userArgs = argv.slice(0); break; case "eval": userArgs = argv.slice(1); break; default: throw new Error(`unexpected parse option { from: '${parseOptions.from}' }`); } if (!this._name && this._scriptPath) this.nameFromFilename(this._scriptPath); this._name = this._name || "program"; return userArgs; } parse(argv, parseOptions) { this._prepareForParse(); const userArgs = this._prepareUserArgs(argv, parseOptions); this._parseCommand([], userArgs); return this; } async parseAsync(argv, parseOptions) { this._prepareForParse(); const userArgs = this._prepareUserArgs(argv, parseOptions); await this._parseCommand([], userArgs); return this; } _prepareForParse() { if (this._savedState === null) { this.saveStateBeforeParse(); } else { this.restoreStateBeforeParse(); } } saveStateBeforeParse() { this._savedState = { _name: this._name, _optionValues: { ...this._optionValues }, _optionValueSources: { ...this._optionValueSources } }; } restoreStateBeforeParse() { if (this._storeOptionsAsProperties) throw new Error(`Can not call parse again when storeOptionsAsProperties is true. - either make a new Command for each call to parse, or stop storing options as properties`); this._name = this._savedState._name; this._scriptPath = null; this.rawArgs = []; this._optionValues = { ...this._savedState._optionValues }; this._optionValueSources = { ...this._savedState._optionValueSources }; this.args = []; this.processedArgs = []; } _checkForMissingExecutable(executableFile, executableDir, subcommandName) { if (fs2.existsSync(executableFile)) return; const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory"; const executableMissing = `'${executableFile}' does not exist - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead - if the default executable name is not suitable, use the executableFile option to supply a custom name or path - ${executableDirMessage}`; throw new Error(executableMissing); } _executeSubCommand(subcommand, args2) { args2 = args2.slice(); let launchWithNode = false; const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"]; function findFile(baseDir, baseName) { const localBin = path.resolve(baseDir, baseName); if (fs2.existsSync(localBin)) return localBin; if (sourceExt.includes(path.extname(baseName))) return; const foundExt = sourceExt.find((ext) => fs2.existsSync(`${localBin}${ext}`)); if (foundExt) return `${localBin}${foundExt}`; return; } this._checkForMissingMandatoryOptions(); this._checkForConflictingOptions(); let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`; let executableDir = this._executableDir || ""; if (this._scriptPath) { let resolvedScriptPath; try { resolvedScriptPath = fs2.realpathSync(this._scriptPath); } catch { resolvedScriptPath = this._scriptPath; } executableDir = path.resolve(path.dirname(resolvedScriptPath), executableDir); } if (executableDir) { let localFile = findFile(executableDir, executableFile); if (!localFile && !subcommand._executableFile && this._scriptPath) { const legacyName = path.basename(this._scriptPath, path.extname(this._scriptPath)); if (legacyName !== this._name) { localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`); } } executableFile = localFile || executableFile; } launchWithNode = sourceExt.includes(path.extname(executableFile)); let proc; if (process2.platform !== "win32") { if (launchWithNode) { args2.unshift(executableFile); args2 = incrementNodeInspectorPort(process2.execArgv).concat(args2); proc = childProcess.spawn(process2.argv[0], args2, { stdio: "inherit" }); } else { proc = childProcess.spawn(executableFile, args2, { stdio: "inherit" }); } } else { this._checkForMissingExecutable(executableFile, executableDir, subcommand._name); args2.unshift(executableFile); args2 = incrementNodeInspectorPort(process2.execArgv).concat(args2); proc = childProcess.spawn(process2.execPath, args2, { stdio: "inherit" }); } if (!proc.killed) { const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"]; signals.forEach((signal) => { process2.on(signal, () => { if (proc.killed === false && proc.exitCode === null) { proc.kill(signal); } }); }); } const exitCallback = this._exitCallback; proc.on("close", (code) => { code = code ?? 1; if (!exitCallback) { process2.exit(code); } else { exitCallback(new CommanderError(code, "commander.executeSubCommandAsync", "(close)")); } }); proc.on("error", (err2) => { if (err2.code === "ENOENT") { this._checkForMissingExecutable(executableFile, executableDir, subcommand._name); } else if (err2.code === "EACCES") { throw new Error(`'${executableFile}' not executable`); } if (!exitCallback) { process2.exit(1); } else { const wrappedError = new CommanderError(1, "commander.executeSubCommandAsync", "(error)"); wrappedError.nestedError = err2; exitCallback(wrappedError); } }); this.runningCommand = proc; } _dispatchSubcommand(commandName, operands, unknown) { const subCommand = this._findCommand(commandName); if (!subCommand) this.help({ error: true }); subCommand._prepareForParse(); let promiseChain; promiseChain = this._chainOrCallSubCommandHook(promise