@clo4/cli 2.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +957 -42
- package/dist/index.d.ts +69 -16
- package/dist/index.js +1101 -680
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts +89 -30
- package/dist/testing.js +1289 -243
- package/dist/testing.js.map +1 -1
- package/package.json +17 -2
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","names":[],"sources":["../src/util.ts","../src/testing.ts"],"sourcesContent":["import type { NonEmptyArray } from \"./types.js\";\n\nexport function isArray<T>(o: T | readonly T[]): o is readonly T[] {\n return Array.isArray(o);\n}\n\n/** Convert the value, if any, to an array with 0 or more elements */\nexport function makeArray<T>(thing: T | readonly T[] | undefined): T[] {\n if (thing === undefined) return [];\n if (isArray(thing)) {\n return thing.slice();\n }\n return [thing];\n}\n\n/**\n * Like {@link makeArray}, but without copying when the input is already an\n * array. Only safe when the caller treats the result as read-only — use it on\n * the hot path to avoid slicing read-only spec metadata.\n */\nexport function asArray<T>(thing: T | readonly T[] | undefined): readonly T[] {\n if (thing === undefined) return [];\n if (isArray(thing)) return thing;\n return [thing];\n}\n\n/** Convert the value to an array with at least one element */\nexport function makeArray1<T>(thing: T | NonEmptyArray<T>): [T, ...T[]] {\n if (isArray(thing)) {\n // We know that this array has at least one element in it\n return thing.slice() as [T, ...T[]];\n }\n return [thing];\n}\n\n/** Set many keys in a Map to the same value */\nexport function setEach<K, V>(map: Map<K, V>, keys: K | readonly K[], value: V): void {\n if (isArray(keys)) {\n for (const key of keys) {\n map.set(key, value);\n }\n } else {\n map.set(keys, value);\n }\n}\n\nexport function assert(expr: unknown, msg = \"\"): asserts expr {\n if (!expr) {\n throw new Error(msg);\n }\n}\n\n// Output {{{\n\ninterface WriteSyncFs {\n writeSync(fd: number, buffer: Uint8Array, offset: number, length: number): number;\n}\n\ninterface NodeProcess {\n getBuiltinModule?(id: \"node:fs\"): WriteSyncFs;\n stdout?: { write(data: Uint8Array): unknown };\n stderr?: { write(data: Uint8Array): unknown };\n}\n\nconst nodeProcess = (globalThis as { process?: NodeProcess }).process;\n\n/**\n * Write text to stdout (1) or stderr (2) with a synchronous `write` on the file\n * descriptor.\n *\n * The first `console.log` in a Node process builds the stdout stream, which\n * costs 1-3 ms. That's more than parsing takes, so all of this library's output\n * goes through here instead. Without `node:fs` it falls back to `console`.\n */\nfunction writeFd(fd: 1 | 2, text: string): void {\n const fs = nodeProcess?.getBuiltinModule?.(\"node:fs\");\n if (!fs) {\n (fd === 1 ? console.log : console.error)(text.endsWith(\"\\n\") ? text.slice(0, -1) : text);\n return;\n }\n const bytes = new TextEncoder().encode(text);\n let offset = 0;\n try {\n while (offset < bytes.length) {\n offset += fs.writeSync(fd, bytes, offset, bytes.length - offset);\n }\n } catch (error) {\n const code = (error as { code?: string }).code;\n // A non-blocking pipe that's full: let Node's stream queue the rest.\n if (code === \"EAGAIN\") {\n (fd === 1 ? nodeProcess?.stdout : nodeProcess?.stderr)?.write(bytes.subarray(offset));\n }\n // Anything else, like EPIPE from `cli --help | head -1`, is dropped, the\n // same as `console` does.\n }\n}\n\n/**\n * Where this library's output goes. Tests replace `write` to capture output.\n *\n * @internal\n */\nexport const output: { write: (fd: 1 | 2, text: string) => void } = { write: writeFd };\n\n/** Print a message to stdout, trimming trailing whitespace. */\nexport function print(text: string): void {\n output.write(1, `${text.trimEnd()}\\n`);\n}\n\n/** Print an error message to stderr with the shared `Error:` prefix. */\nexport function printActionError(message: string): void {\n output.write(2, `Error: ${message}\\n`);\n}\n\n// }}}\n\n/**\n * Returns the minimum number of arguments that satisfies the args.\n *\n * Accepts the raw spec value (a single arg, an array, or `undefined`) so the\n * hot path doesn't have to copy it into an array first.\n */\nexport function getMinArgs(\n args: { isOptional?: boolean } | readonly { isOptional?: boolean }[] | undefined,\n): number {\n if (args === undefined) return 0;\n if (!isArray(args)) return args.isOptional ? 0 : 1;\n let count = 0;\n for (let i = 0; i < args.length; i++) {\n if (args[i].isOptional) {\n break;\n }\n count++;\n }\n return count;\n}\n\n/** Returns the maximum number of arguments that satisfies the args. */\nexport function getMaxArgs(\n args: { isVariadic?: boolean } | readonly { isVariadic?: boolean }[] | undefined,\n): number {\n if (args === undefined) return 0;\n if (!isArray(args)) return args.isVariadic ? Infinity : 1;\n // Loop over the array backwards because variadic arguments are\n // more likely to be at the end of the array. They don't _need_\n // to be, but it's more idiomatic.\n for (let i = 0; i < args.length; i++) {\n if (args[args.length - 1 - i].isVariadic) {\n return Infinity;\n }\n }\n // None of the arguments are variadic, max is the number of args\n return args.length;\n}\n","/**\n * Supplementary module to make testing your CLI easier.\n *\n * @module\n */\n\nimport type { Arg, Option, SingleOrArray, Subcommand } from \"./types.js\";\nimport { assert, isArray, makeArray } from \"./util.js\";\nimport { getMaxArgs, getMinArgs } from \"./parse.js\";\n\nconst repr = JSON.stringify;\n\n// TODO: one decorators are stable (ts 4.9?), use decorators this file\n\n/**\n * Run a function once for each `args` property in the spec (recursive)\n *\n * This will convert single args to an array with one item.\n */\nfunction forEachArgArray(\n spec: Subcommand,\n fn: (args: Arg[], path: Subcommand[]) => void,\n path: Subcommand[] = [],\n): void {\n path = path.concat(spec);\n fn(makeArray(spec.args), path);\n for (const option of makeArray(spec.options)) {\n fn(makeArray(option.args), path);\n }\n for (const subcommand of makeArray(spec.subcommands)) {\n forEachArgArray(subcommand, fn, path);\n }\n}\n\n/** Run a function once for each `options` property in the spec (recursive) */\nfunction forEachOptionArray(\n spec: Subcommand,\n fn: (options: Option[], path: Subcommand[]) => void,\n path: Subcommand[] = [],\n): void {\n path = path.concat(spec);\n fn(makeArray(spec.options), path);\n for (const subcommand of makeArray(spec.subcommands)) {\n forEachOptionArray(subcommand, fn, path);\n }\n}\n\n/**\n * Run a function once for each `subcommands` property in the spec (recursive)\n *\n * This will also run the function for the root spec itself.\n */\nfunction forEachSubcommand(\n spec: Subcommand,\n fn: (spec: Subcommand, path: Subcommand[]) => void,\n path: Subcommand[] = [],\n): void {\n path = path.concat(spec);\n fn(spec, path);\n for (const subcommand of makeArray(spec.subcommands)) {\n forEachSubcommand(subcommand, fn, path);\n }\n}\n\nfunction joinNames(names: SingleOrArray<string>) {\n return makeArray(names)\n .sort((a, b) => a.length - b.length)\n .join(\"|\");\n}\n\nfunction isSameName(a: string | readonly string[], b: string | readonly string[]) {\n if (isArray(a) && isArray(b)) {\n return a.every((item) => b.includes(item)) && b.every((item) => a.includes(item));\n }\n // This might compare a string to an array, but if that happens the correct\n // result is `false` anyway, so this behaves correctly\n return a === b;\n}\n\n/** Compares spec values by shape. Any two functions count as the same shape. */\nfunction isSameStructure(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a === \"function\" && typeof b === \"function\") return true;\n if (typeof a !== \"object\" || typeof b !== \"object\" || a === null || b === null) return false;\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n const left = a as Record<string, unknown>;\n const right = b as Record<string, unknown>;\n const keys = new Set([...Object.keys(left), ...Object.keys(right)]);\n return [...keys].every((key) => isSameStructure(left[key], right[key]));\n}\n\nfunction namedArrayToString(...parts: { name: SingleOrArray<string> }[]) {\n const names = parts.map((named) => joinNames(named.name));\n return `\\`${names.join(\" \")}\\``;\n}\n\n/** Asserts that required arguments do not come after an optional argument */\nexport function assertRequiredArgumentsDoNotFollowOptionalArguments(spec: Subcommand): void {\n forEachArgArray(spec, (args, path) => {\n let remainingMustBeOptional = false;\n let firstOptionalArgIndex: number | null = null;\n for (const [index, arg] of args.entries()) {\n if (remainingMustBeOptional) {\n assert(\n arg.isOptional,\n `In ${namedArrayToString(...path)}, argument ${arg.name || index} is required, but it must be optional since the argument at index ${firstOptionalArgIndex} is optional`,\n );\n } else if (arg.isOptional) {\n remainingMustBeOptional = true;\n firstOptionalArgIndex ??= index;\n }\n }\n });\n}\n\n/** Asserts that `isRepeatable` is only assigned a positive integer */\nexport function assertRepeatableOptionsArePositiveIntegers(spec: Subcommand): void {\n forEachOptionArray(spec, (options, path) => {\n for (const [index, option] of options.entries()) {\n if (typeof option.isRepeatable === \"number\") {\n assert(\n Number.isSafeInteger(option.isRepeatable),\n `The option ${namedArrayToString(...path, option)} (index ${index}) has its \\`isRepeatable\\` value set to a number that is not an integer`,\n );\n assert(\n !(option.isRepeatable < 1),\n `The option ${namedArrayToString(...path, option)} (index ${index}) has its \\`isRepeatable\\` value set to a number below 1, which means it can't be used at all`,\n );\n assert(\n option.isRepeatable !== 1,\n `The option ${namedArrayToString(...path, option)} (index ${index}) has its \\`isRepeatable\\` value set to 1, which is no different that omitting the property entirely`,\n );\n }\n }\n });\n}\n\n/** Asserts that options have unique names in their scope */\nexport function assertOptionsHaveLocallyUniqueNames(spec: Subcommand): void {\n forEachSubcommand(spec, (spec, path) => {\n const optionNames = new Set<string>();\n for (const [index, option] of makeArray(spec.options).entries()) {\n for (const name of makeArray(option.name)) {\n assert(\n !optionNames.has(name),\n `Option ${namedArrayToString(...path, option)} (index ${index}) has a non-unique name, '${name}'. Option names must be unique.`,\n );\n optionNames.add(name);\n }\n }\n });\n}\n\n/** Asserts that options don't shadow a persistent option */\nexport function assertOptionsDoNotShadowPersistentOptions(spec: Subcommand): void {\n forEachOptionArray(spec, (options, path) => {\n const persistentOptionNames = new Set(\n path\n .slice(0, -1)\n .flatMap((subcommand) =>\n subcommand.options\n ? subcommand.options.filter((option) => option.isPersistent).flatMap((option) => option.name)\n : [],\n ),\n );\n for (const [index, option] of makeArray(options).entries()) {\n for (const name of makeArray(option.name)) {\n assert(\n !persistentOptionNames.has(name),\n `The option ${namedArrayToString(...path, option)} (index ${index}) shadows the name of a persistent option, ${repr(name)}. Option names can't shadow persistent options.`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that a subcommand's option isn't a different option with exactly the\n * same names as one on a parent.\n *\n * Parsed values are looked up by name, so that parent's value would be\n * unreadable. A shared name is fine when each option has a name of its own, and\n * when the options are identical, such as an option kept in a constant.\n *\n * This skips persistent parent options, because\n * {@link assertOptionsDoNotShadowPersistentOptions} covers those and\n * `allowShadowingPersistentOptions` opts out of it.\n */\nexport function assertOptionsHaveDifferentNamesFromParents(spec: Subcommand): void {\n forEachOptionArray(spec, (options, path) => {\n const parents = path.slice(0, -1);\n for (const [index, option] of options.entries()) {\n for (const parent of parents) {\n for (const parentOption of makeArray(parent.options)) {\n const isClash =\n !parentOption.isPersistent &&\n isSameName(parentOption.name, option.name) &&\n !isSameStructure({ ...parentOption, name: 0 }, { ...option, name: 0 });\n assert(\n !isClash,\n `The option ${namedArrayToString(...path, option)} (index ${index}) has the same names as a different option, ${namedArrayToString(parent, parentOption)}, so the parent's value can't be read. Add a name that only one of them uses.`,\n );\n }\n }\n }\n });\n}\n\n/** Asserts that subcommands don't share a name with a sibling subcommand */\nexport function assertSubcommandsHaveLocallyUniqueNames(spec: Subcommand): void {\n forEachSubcommand(spec, (spec, path) => {\n const names = new Set<string>();\n for (const [index, subcommand] of makeArray(spec.subcommands).entries()) {\n for (const name of makeArray(subcommand.name)) {\n assert(\n !names.has(name),\n `The subcommand ${namedArrayToString(...path, subcommand)} (index ${index}) has a non-unique name, ${repr(name)}. Subcommand names must be unique among the subcommands in the same array.`,\n );\n names.add(name);\n }\n }\n });\n}\n\n/**\n * Asserts that option names starting with a single dash aren't longer\n * than two characters, unless parserDirectives.flagsArePosixNoncompliant is\n * set on an ancestor command.\n */\nexport function assertLongOptionNamesDoNotStartWithSingleDash(spec: Subcommand): void {\n forEachOptionArray(spec, (options, path) => {\n // TODO: check if this is correct\n const skip =\n path\n .map((command) => command.parserDirectives?.flagsArePosixNoncompliant)\n .filter((value) => value !== undefined)\n .at(-1) || false;\n\n if (skip) return;\n\n for (const [index, option] of makeArray(options).entries()) {\n for (const name of makeArray(option.name)) {\n assert(\n !((name.startsWith(\"-\") || name.startsWith(\"+\")) && !name.startsWith(\"--\") && name.length > 2),\n `Option ${namedArrayToString(...path, option)} (index ${index}) has a name that the parser is unable to parse, as it starts with a single '${name[0]}'. Tokens starting with that character are interpreted as short options, so passing '${name}' will be interpreted as '${Array.from(name.slice(1), (letter) => name[0] + letter).join(\" \")}'. \\`parserDirectives.flagsArePosixNoncompliant\\` must be \\`true\\` on an ancestor command.`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that all option names start with dashes\n */\nexport function assertOptionNamesStartWithDashes(spec: Subcommand): void {\n forEachOptionArray(spec, (options, path) => {\n // TODO: check if this is correct\n const skip =\n path\n .map((command) => command.parserDirectives?.flagsArePosixNoncompliant)\n .filter((value) => value !== undefined)\n .at(-1) || false;\n\n if (skip) return;\n\n for (const [index, option] of makeArray(options).entries()) {\n for (const name of makeArray(option.name)) {\n assert(\n name.startsWith(\"-\") || name.startsWith(\"+\"),\n `Option ${namedArrayToString(...path, option)} (index ${index}) doesn't start with a dash or plus, the parser will be unable to find matching options without \\`parserDirectives.flagsAreNonPosixCompliant\\` being set to 'true' on an ancestor command`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that nothing is named exactly '--'\n */\nexport function assertNothingIsNamedDashDash(spec: Subcommand): void {\n forEachOptionArray(spec, (options, path) => {\n for (const [index, option] of makeArray(options).entries()) {\n for (const name of makeArray(option.name)) {\n assert(\n name !== \"--\",\n `Option ${namedArrayToString(...path, option)} (index ${index}) is named '--', which is a special instruction to the parser to treat all following tokens as arguments. This will never be matched`,\n );\n }\n }\n });\n forEachSubcommand(spec, (subcommands, path) => {\n for (const [index, subcommand] of makeArray(subcommands).entries()) {\n for (const name of makeArray(subcommand.name)) {\n assert(\n name !== \"--\",\n `Subcommand ${namedArrayToString(...path, subcommand)} (index ${index}) is named '--', which is a special instruction to the parser to treat all following tokens as arguments. This will never be matched`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that no option arg separator is an empty string\n */\nexport function assertOptionArgSeparatorsHaveCharacters(spec: Subcommand): void {\n // FIXME: `subcommands` isn't an array\n forEachSubcommand(spec, (subcommands, path) => {\n for (const [index, subcommand] of makeArray(subcommands).entries()) {\n const separators = makeArray(subcommand.parserDirectives?.optionArgSeparators);\n for (const [sepIndex, separator] of separators.entries()) {\n assert(\n separator !== \"\",\n `Subcommand ${namedArrayToString(...path, subcommand)} (index ${index}) has an empty string for an option arg separator at index ${sepIndex}. If you wanted to disable option arg separators, use an empty array.`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that options named \"+\" or \"-\" takes one arg\n */\nexport function assertPlusMinusOptionsTakeOneArg(spec: Subcommand): void {\n forEachOptionArray(spec, (options, path) => {\n // TODO: check if this is correct\n const skip =\n path\n .map((command) => command.parserDirectives?.flagsArePosixNoncompliant)\n .filter((value) => value !== undefined)\n .at(-1) || false;\n\n if (skip) return;\n\n for (const [index, option] of makeArray(options).entries()) {\n for (const name of makeArray(option.name)) {\n if (name !== \"-\" && name !== \"+\") {\n continue;\n }\n assert(\n option.args && !Array.isArray(option.args),\n `Option ${namedArrayToString(...path, option)} (index ${index}) must take exactly one argument`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that names do not have leading or trailing whitespace\n */\nexport function assertNamesHaveNoExtraWhitespace(spec: Subcommand): void {\n forEachOptionArray(spec, (options, path) => {\n for (const [index, option] of makeArray(options).entries()) {\n for (const name of makeArray(option.name)) {\n assert(\n name === name.trim(),\n `Option ${namedArrayToString(...path, option)} (index ${index}) has a name with extra whitespace`,\n );\n }\n }\n });\n // FIXME: `subcommands` isn't an array\n forEachSubcommand(spec, (subcommands, path) => {\n for (const [index, subcommand] of makeArray(subcommands).entries()) {\n for (const name of makeArray(subcommand.name)) {\n assert(\n name === name.trim(),\n `Subcommand ${namedArrayToString(...path, subcommand)} (index ${index}) has a name with extra whitespace`,\n );\n }\n }\n });\n forEachArgArray(spec, (args, path) => {\n for (const [index, arg] of makeArray(args).entries()) {\n for (const name of makeArray(arg.name)) {\n assert(\n name === name.trim(),\n `Arg in ${namedArrayToString(...path)} (at index ${index}) has a name with extra whitespace`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that everything has a description\n */\nexport function assertEverythingHasDescription(spec: Subcommand): void {\n assert(spec.description, `Spec has no description`);\n forEachOptionArray(spec, (options, path) => {\n for (const [index, option] of makeArray(options).entries()) {\n assert(\n option.description,\n `Option ${namedArrayToString(...path, option)} (index ${index}) has no description`,\n );\n }\n });\n // FIXME: `subcommands` isn't an array\n forEachSubcommand(spec, (subcommands, path) => {\n for (const [index, subcommand] of makeArray(subcommands).entries()) {\n assert(\n subcommand.description,\n `Subcommand ${namedArrayToString(...path, subcommand)} (index ${index}) has no description`,\n );\n }\n });\n}\n\n/**\n * Asserts that descriptions have line length < 69\n */\nexport function assertDescriptionLineLengthUnder69(spec: Subcommand): void {\n if (spec.description) {\n assert(\n spec.description.split(\"\\n\").every((line) => line.length <= 68),\n `Spec has a description line over 68 characters`,\n );\n }\n forEachOptionArray(spec, (options, path) => {\n for (const [index, option] of makeArray(options).entries()) {\n if (option.description) {\n assert(\n option.description.split(\"\\n\").every((line) => line.length <= 68),\n `Option ${namedArrayToString(...path, option)} (index ${index}) has a description line over 68 characters`,\n );\n }\n }\n });\n // FIXME: `subcommands` isn't an array\n forEachSubcommand(spec, (subcommands, path) => {\n for (const [index, subcommand] of makeArray(subcommands).entries()) {\n if (subcommand.description) {\n assert(\n subcommand.description.split(\"\\n\").every((line) => line.length <= 68),\n `Subcommand ${namedArrayToString(...path, subcommand)} (index ${index}) has a description line over 68 characters`,\n );\n }\n }\n });\n}\n\nexport function assertRequiresSeparatorTakesOneArg(spec: Subcommand): void {\n forEachOptionArray(spec, (options, path) => {\n for (const [index, option] of makeArray(options).entries()) {\n if (option.requiresSeparator) {\n const args = makeArray(option.args);\n assert(\n getMinArgs(args) <= 1,\n `Option ${namedArrayToString(...path, option)} (index ${index}) takes a minimum of ${getMinArgs(args)} arg(s), but because of requiresSeparator, it must instead be 0 or 1`,\n );\n assert(\n getMaxArgs(args) === 1,\n `Option ${namedArrayToString(...path, option)} (index ${index}) takes a maximum of ${getMaxArgs(args)} arg(s), but because of requiresSeparator, it's only able to take 1`,\n );\n }\n }\n });\n}\n\nexport function assertCommonOptionsArePersistent(spec: Subcommand): void {\n const failures: [string | readonly string[], string][] = [];\n forEachSubcommand(spec, (subcommand, path) => {\n if (!subcommand.subcommands) {\n return;\n }\n for (const option of makeArray(subcommand.options)) {\n const allChildSubcommands: Subcommand[] = [];\n forEachSubcommand(subcommand, (cmd) => allChildSubcommands.push(cmd));\n\n const allShareOption = allChildSubcommands.every((cmd) =>\n makeArray(cmd.options).some((o) => isSameName(option.name, o.name)),\n );\n\n if (allShareOption && !failures.some(([name]) => isSameName(name, option.name))) {\n failures.push([option.name, namedArrayToString(...path, option)]);\n }\n }\n });\n assert(\n failures.length === 0,\n `The following options were also defined by all subcommands. Instead, define the option once, and use \\`isPersistent: true\\` to persist it across all subcommands.\n${failures.map(([, line]) => \" * \" + line).join(\"\\n\")}\n`,\n );\n}\n\n/**\n * Asserts that references to other options by name actually refer to options\n * that exist in scope\n */\nexport function assertOptionNameReferencesExist(spec: Subcommand): void {\n forEachOptionArray(spec, (options, path) => {\n const optionNames = new Set([\n ...path\n .slice(0, -1)\n .flatMap((subcommand) =>\n subcommand.options\n ? subcommand.options.filter((option) => option.isPersistent).flatMap((option) => option.name)\n : [],\n ),\n ...options.flatMap((option) => option.name),\n ]);\n for (const [index, option] of makeArray(options).entries()) {\n for (const name of makeArray(option.dependsOn)) {\n assert(\n optionNames.has(name),\n `The option ${namedArrayToString(...path, option)} (index ${index}) depends on an option named ${repr(name)}, which doesn't exist in its scope`,\n );\n }\n for (const name of makeArray(option.exclusiveOn)) {\n assert(\n optionNames.has(name),\n `The option ${namedArrayToString(...path, option)} (index ${index}) is exclusive on an option named ${repr(name)}, which doesn't exist in its scope`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that commands that will match subcommands by prefix do not take arguments\n */\nexport function assertPrefixMatchCommandsHaveNoArguments(spec: Subcommand): void {\n forEachSubcommand(spec, (subcommand, path) => {\n // Mirror the parser's default: prefix matching is OFF unless a command on\n // the path turns it on. `scan` in parse.ts initializes the flag to `false` and\n // only ever sets it `true`, so the ambiguity this guards against can only\n // arise when some ancestor (or the command itself) opts in.\n const matchesPrefix = path.some((cmd) => cmd.parserDirectives?.subcommandsMatchUniquePrefix === true);\n\n if (!matchesPrefix) return;\n\n assert(\n !(subcommand.subcommands && subcommand.args),\n `The command ${namedArrayToString(\n ...path,\n )} has at least one argument and subcommand, but matches subcommands based on unique prefixes. To fix this, use \\`parserDirectives: { subcommandsMatchUniquePrefix: false }\\``,\n );\n });\n}\n\nexport type TestNamingStyle = \"sentence\" | \"function\";\n\n/** Options that can be provided to `test` */\nexport interface TestOptions {\n /**\n * Allows options to shadow persistent options.\n *\n * This behavior may be desirable if you want to override an option on a\n * particular subcommand, but not for others.\n *\n * Be aware that this is not idiomatic.\n */\n allowShadowingPersistentOptions?: boolean;\n\n /**\n * Allows subcommands and options to not have a description\n */\n allowNoDescription?: boolean;\n\n /**\n * Allows descriptions to have lines over 68 characters long\n */\n allowLongDescriptionLines?: boolean;\n\n /**\n * Allow commands to have `parserDirectives.subcommandsMatchUniquePrefix` with args\n *\n * This is not allowed by default because it's probably a mistake. It makes\n * arguments ambiguous, users may not know if their invocation will run a\n * subcommand or the command.\n */\n allowMatchingSubcommandPrefixAndArgs?: boolean;\n\n /**\n * Change the naming style of the tests.\n *\n * - `sentence`: Use proper sentence casing, punctuation, etc\n * - `function`: Use the name of the assert function that will be executed\n */\n namingStyle?: TestNamingStyle;\n}\n\nfunction getName(namingStyle: TestNamingStyle, names: { [K in TestNamingStyle]: string }) {\n return names[namingStyle];\n}\n\nexport interface TestContextLike {\n step(name: string, fn: () => unknown | Promise<unknown>): unknown | Promise<unknown>;\n}\n\nasync function runStep(\n context: TestContextLike | undefined,\n name: string,\n fn: () => unknown | Promise<unknown>,\n): Promise<void> {\n if (context) {\n await context.step(name, fn);\n return;\n }\n await fn();\n}\n\n/**\n * Validate your CLI in your test suite\n *\n * This enforces certain constraints that the type system cannot. The parser\n * may ignore these issues, producing correct output that _appears_ to be\n * wrong.\n */\nexport function test(spec: Subcommand, options: TestOptions = {}): (t?: TestContextLike) => Promise<void> {\n const {\n allowShadowingPersistentOptions = false,\n allowNoDescription = false,\n allowLongDescriptionLines = false,\n allowMatchingSubcommandPrefixAndArgs = false,\n namingStyle = \"sentence\",\n } = options;\n return async (t) => {\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Required arguments don't follow optional arguments\",\n function: \"assertRequiredArgumentsDoNotFollowOptionalArguments\",\n }),\n () => {\n assertRequiredArgumentsDoNotFollowOptionalArguments(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Repeatable options that are numbers are integers greater than 1\",\n function: \"assertRepeatableOptionsArePositiveIntegers\",\n }),\n () => {\n assertRepeatableOptionsArePositiveIntegers(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Long option names don't start with a single dash\",\n function: \"assertLongOptionNamesDoNotStartWithSingleDash\",\n }),\n () => {\n assertLongOptionNamesDoNotStartWithSingleDash(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Option names all start with dashes\",\n function: \"assertOptionNamesStartWithDashes\",\n }),\n () => {\n assertOptionNamesStartWithDashes(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Options have locally unique names\",\n function: \"assertOptionsHaveLocallyUniqueNames\",\n }),\n () => {\n assertOptionsHaveLocallyUniqueNames(spec);\n },\n );\n if (!allowShadowingPersistentOptions) {\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Options don't shadow persistent options\",\n function: \"assertOptionsDoNotShadowPersistentOptions\",\n }),\n () => {\n assertOptionsDoNotShadowPersistentOptions(spec);\n },\n );\n }\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Different options on a subcommand and its parents have different names\",\n function: \"assertOptionsHaveDifferentNamesFromParents\",\n }),\n () => {\n assertOptionsHaveDifferentNamesFromParents(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Subcommands have locally unique names\",\n function: \"assertSubcommandsHaveLocallyUniqueNames\",\n }),\n () => {\n assertSubcommandsHaveLocallyUniqueNames(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Nothing is named '--'\",\n function: \"assertNothingIsNamedDashDash\",\n }),\n () => {\n assertNothingIsNamedDashDash(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Option arg separators are not an empty string\",\n function: \"assertOptionArgSeparatorsHaveCharacters\",\n }),\n () => {\n assertOptionArgSeparatorsHaveCharacters(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Options named '-' or '+' take exactly one argument\",\n function: \"assertPlusMinusOptionsTakeOneArg\",\n }),\n () => {\n assertPlusMinusOptionsTakeOneArg(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Names have no extra leading or trailing whitespace\",\n function: \"assertNamesHaveNoExtraWhitespace\",\n }),\n () => {\n assertNamesHaveNoExtraWhitespace(spec);\n },\n );\n if (!allowNoDescription) {\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Everything has a description\",\n function: \"assertEverythingHasDescription\",\n }),\n () => {\n assertEverythingHasDescription(spec);\n },\n );\n }\n if (!allowLongDescriptionLines) {\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Each line in descriptions is less than or equal to 68 characters\",\n function: \"assertDescriptionLineLengthUnder69\",\n }),\n () => {\n assertDescriptionLineLengthUnder69(spec);\n },\n );\n }\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Options with `requiresSeparator` take exactly one argument\",\n function: \"assertRequiresSeparatorTakesOneArg\",\n }),\n () => {\n assertRequiresSeparatorTakesOneArg(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Common options are not defined on every subcommand\",\n function: \"assertCommonOptionsArePersistent\",\n }),\n () => {\n assertCommonOptionsArePersistent(spec);\n },\n );\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"References to other options by name are valid\",\n function: \"assertOptionNameReferencesExist\",\n }),\n () => {\n assertOptionNameReferencesExist(spec);\n },\n );\n if (!allowMatchingSubcommandPrefixAndArgs) {\n await runStep(\n t,\n getName(namingStyle, {\n sentence: \"Commands with `subcommandsMatchUniquePrefix` don't have arguments and subcommands\",\n function: \"assertPrefixMatchCommandsHaveNoArguments\",\n }),\n () => {\n assertPrefixMatchCommandsHaveNoArguments(spec);\n },\n );\n }\n };\n}\n\nexport const testSpec = test;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"testing.js","names":["repr","builtinUsageAction"],"sources":["../src/util.ts","../src/directives.ts","../src/subcommands.ts","../src/scope.ts","../src/help.ts","../src/errors.ts","../src/parse.ts","../src/testing.ts"],"sourcesContent":["import type { Arg, NonEmptyArray } from \"./types.js\";\n\nexport function isArray<T>(o: T | readonly T[]): o is readonly T[] {\n return Array.isArray(o);\n}\n\n/** Convert the value, if any, to an array with 0 or more elements */\nexport function makeArray<T>(thing: T | readonly T[] | undefined): T[] {\n if (thing === undefined) {\n return [];\n }\n if (isArray(thing)) {\n return thing.slice();\n }\n return [thing];\n}\n\n/**\n * Like {@link makeArray}, but without copying when the input is already an\n * array. Only safe when the caller treats the result as read-only — use it on\n * the hot path to avoid slicing read-only spec metadata.\n */\nexport function asArray<T>(thing: T | readonly T[] | undefined): readonly T[] {\n if (thing === undefined) {\n return [];\n }\n if (isArray(thing)) {\n return thing;\n }\n return [thing];\n}\n\n/** Convert the value to an array with at least one element */\nexport function makeArray1<T>(thing: T | NonEmptyArray<T>): [T, ...T[]] {\n if (isArray(thing)) {\n // We know that this array has at least one element in it\n return thing.slice() as [T, ...T[]];\n }\n return [thing];\n}\n\nexport function assert(expr: unknown, msg = \"\"): asserts expr {\n if (!expr) {\n throw new Error(msg);\n }\n}\n\n// Output {{{\n\ninterface WriteSyncFs {\n writeSync(fd: number, buffer: Uint8Array, offset: number, length: number): number;\n}\n\ninterface NodeProcess {\n getBuiltinModule?(id: \"node:fs\"): WriteSyncFs;\n stdout?: { write(data: Uint8Array): unknown };\n stderr?: { write(data: Uint8Array): unknown };\n}\n\nconst nodeProcess = (globalThis as { process?: NodeProcess }).process;\n\n/**\n * Write text to stdout (1) or stderr (2) with a synchronous `write` on the file\n * descriptor.\n *\n * The first `console.log` in a Node process builds the stdout stream, which\n * costs 1-3 ms. That's more than parsing takes, so all of this library's output\n * goes through here instead. Without `node:fs` it falls back to `console`.\n */\nfunction writeFd(fd: 1 | 2, text: string): void {\n const fs = nodeProcess?.getBuiltinModule?.(\"node:fs\");\n if (!fs) {\n (fd === 1 ? console.log : console.error)(text.endsWith(\"\\n\") ? text.slice(0, -1) : text);\n return;\n }\n const bytes = new TextEncoder().encode(text);\n let offset = 0;\n try {\n while (offset < bytes.length) {\n offset += fs.writeSync(fd, bytes, offset, bytes.length - offset);\n }\n } catch (error) {\n const code = (error as { code?: string }).code;\n // A non-blocking pipe that's full: let Node's stream queue the rest.\n if (code === \"EAGAIN\") {\n (fd === 1 ? nodeProcess?.stdout : nodeProcess?.stderr)?.write(bytes.subarray(offset));\n }\n // Anything else, like EPIPE from `cli --help | head -1`, is dropped, the\n // same as `console` does.\n }\n}\n\n/**\n * Where this library's output goes. Tests replace `write` to capture output.\n *\n * @internal\n */\nexport const output: { write: (fd: 1 | 2, text: string) => void } = { write: writeFd };\n\n/** Print a message to stdout, trimming trailing whitespace. */\nexport function print(text: string): void {\n output.write(1, `${text.trimEnd()}\\n`);\n}\n\n/** Print `Error:` and the given values to stderr, separated by spaces. */\nexport function printError(...strings: unknown[]): void {\n output.write(2, `${[\"Error:\", ...strings].map(String).join(\" \")}\\n`);\n}\n\n// }}}\n\n/**\n * Add the defaults of the arguments from index `from` on to `values`, stopping\n * at the first argument without one. The parser and help both use this, so\n * help only shows the defaults the parser uses.\n */\nexport function addDefaults(values: string[], args: readonly Arg[], from = 0): void {\n for (let i = from; i < args.length; i++) {\n const value = args[i].default;\n if (value === undefined) {\n return;\n }\n values.push(value);\n }\n}\n\n/**\n * Returns the minimum number of arguments that satisfies the args.\n *\n * Accepts the raw spec value (a single arg, an array, or `undefined`) so the\n * hot path doesn't have to copy it into an array first.\n */\nexport function getMinArgs(\n args: { isOptional?: boolean } | readonly { isOptional?: boolean }[] | undefined,\n): number {\n if (args === undefined) {\n return 0;\n }\n if (!isArray(args)) {\n return args.isOptional ? 0 : 1;\n }\n let count = 0;\n for (let i = 0; i < args.length; i++) {\n if (args[i].isOptional) {\n break;\n }\n count++;\n }\n return count;\n}\n\n/** Returns the maximum number of arguments that satisfies the args. */\nexport function getMaxArgs(\n args: { isVariadic?: boolean } | readonly { isVariadic?: boolean }[] | undefined,\n): number {\n if (args === undefined) {\n return 0;\n }\n if (!isArray(args)) {\n return args.isVariadic ? Infinity : 1;\n }\n // Loop over the array backwards because variadic arguments are\n // more likely to be at the end of the array. They don't _need_\n // to be, but it's more idiomatic.\n for (let i = 0; i < args.length; i++) {\n if (args[args.length - 1 - i].isVariadic) {\n return Infinity;\n }\n }\n // None of the arguments are variadic, max is the number of args\n return args.length;\n}\n","import type { Spec, Subcommand } from \"./types.js\";\nimport { asArray } from \"./util.js\";\n\n/** The parser directives in effect for a command, with defaults filled in. */\nexport interface Directives {\n optionArgSeparators: readonly string[];\n flagsArePosixNoncompliant: boolean;\n optionsMustPrecedeArguments: boolean;\n subcommandsMatchUniquePrefix: boolean;\n}\n\n/** The directives in effect when no command sets any. */\nexport function defaultDirectives(): Directives {\n return {\n optionArgSeparators: [\"=\"],\n flagsArePosixNoncompliant: false,\n optionsMustPrecedeArguments: false,\n subcommandsMatchUniquePrefix: false,\n };\n}\n\n/**\n * Update `directives` for entering `command`. A subcommand inherits each\n * directive until it sets its own.\n */\nexport function applyDirectives(directives: Directives, command: Spec | Subcommand): void {\n const configured = command.parserDirectives;\n if (!configured) {\n return;\n }\n if (configured.optionArgSeparators) {\n directives.optionArgSeparators = asArray(configured.optionArgSeparators);\n }\n if (typeof configured.subcommandsMatchUniquePrefix === \"boolean\") {\n directives.subcommandsMatchUniquePrefix = configured.subcommandsMatchUniquePrefix;\n }\n if (typeof configured.optionsMustPrecedeArguments === \"boolean\") {\n directives.optionsMustPrecedeArguments = configured.optionsMustPrecedeArguments;\n }\n if (typeof configured.flagsArePosixNoncompliant === \"boolean\") {\n directives.flagsArePosixNoncompliant = configured.flagsArePosixNoncompliant;\n }\n}\n","import type { Action, Subcommand } from \"./types.js\";\nimport type { DidYouMean } from \"./errors.js\";\nimport { asArray, print } from \"./util.js\";\n\n/**\n * A token that names no subcommand. The reason is only worked out when asked\n * for, since most tokens the parser tries aren't subcommands.\n */\nexport class NoSubcommand {\n readonly command = null;\n\n /**\n * `prefixOf` are the commands `token` is a prefix of a name of, where\n * prefixes match. There is never exactly one of them.\n */\n constructor(\n private readonly subcommands: readonly Subcommand[],\n private readonly token: string,\n private readonly prefixOf: readonly Subcommand[],\n ) {}\n\n /** Why the token names none of the subcommands, as an error message and suggestions. */\n reason(): { message: string; didYouMean?: DidYouMean } {\n const token = this.token;\n if (token === \"\") {\n return { message: \"Expected a command, but the value was empty\" };\n }\n if (this.prefixOf.length > 0) {\n const possible = this.prefixOf.flatMap((command) =>\n asArray(command.name).filter((name) => name.startsWith(token)),\n );\n return { message: `Ambiguous command '${token}', could be: ${possible.join(\", \")}` };\n }\n const choices = visibleSubcommands(this.subcommands).map((command) => asArray(command.name));\n return { message: `Unknown command '${token}'`, didYouMean: { input: token, choices } };\n }\n}\n\n/** The subcommands that help, completion and suggestions show. */\nexport function visibleSubcommands(subcommands: readonly Subcommand[] | undefined): Subcommand[] {\n return subcommands?.filter((subcommand) => !subcommand.hidden) ?? [];\n}\n\n/** The action of a command that has none of its own: print the command's help. */\nexport const usage: Action = ({ help }) => {\n print(help());\n return 0;\n};\n","import type { Option, Spec, Subcommand } from \"./types.js\";\nimport { applyDirectives, defaultDirectives } from \"./directives.js\";\nimport type { Directives } from \"./directives.js\";\nimport { NoSubcommand } from \"./subcommands.js\";\nimport { asArray, getMaxArgs, getMinArgs } from \"./util.js\";\n\n/** The subcommand a token names, or why it names none. See {@link CommandScope.matchSubcommand}. */\nexport type SubcommandMatch = { command: Subcommand } | NoSubcommand;\n\n/**\n * How the next token can match a subcommand: by any name the command's\n * directives allow, or only by an exact name.\n */\nexport interface SubcommandMatching {\n exactOnly: boolean;\n}\n\n/** An option that can be used here, and the names that still refer to it. */\nexport interface VisibleOption {\n option: Option;\n names: string[];\n}\n\n/** How one name of an option is written with its value, at one command. */\nexport interface OptionForm {\n name: string;\n /**\n * What joins the name to the option's first value in the same token, or null\n * if the value is the next token. It's the required separator for an option\n * that requires one, and \"\" for an option named \"-\" or \"+\", which reads its\n * value straight after the name, like `-5`. It's null for an option without\n * arguments.\n */\n join: string | null;\n}\n\n/**\n * What a name means at one command on a path: the options, subcommands,\n * directives and argument limits in effect there.\n *\n * Moving to a subcommand replaces the local options and adds its persistent\n * options to the inherited ones. A name refers to one option: a local option\n * wins over a persistent one, and a later option wins over an earlier one in\n * the same list. A subcommand wins over an option where the next token can\n * name a subcommand. The parser, help, completion and the spec checker all\n * ask this module what a name refers to, so they can't disagree.\n */\nexport class CommandScope {\n /** Non-persistent options of the current command, in definition order. */\n readonly local: Option[] = [];\n /** Persistent options from every command on the path, in definition order. */\n readonly persistent: Option[] = [];\n /**\n * Persistent subcommands of the commands above the current one, nearest\n * command first, so a nearer one wins a name.\n */\n readonly inheritedSubcommands: Subcommand[] = [];\n /** The directives in effect. A subcommand inherits each until it sets its own. */\n readonly directives: Directives = defaultDirectives();\n private current: Spec | Subcommand | null = null;\n /** The fewest positional arguments the current command takes. */\n argsMin = 0;\n /** The most positional arguments the current command takes. */\n argsMax = 0;\n\n /** The scope at the last command on `path`. */\n static at(path: readonly (Spec | Subcommand)[]): CommandScope {\n const scope = new CommandScope();\n for (const command of path) {\n scope.enter(command);\n }\n return scope;\n }\n\n /** Move to `command`, a subcommand of the current one. */\n enter(command: Spec | Subcommand): void {\n const parentSubcommands = this.current?.subcommands;\n if (parentSubcommands) {\n const persistent = parentSubcommands.filter((subcommand) => subcommand.isPersistent);\n if (persistent.length > 0) {\n this.inheritedSubcommands.unshift(...persistent);\n }\n }\n this.current = command;\n this.argsMin = getMinArgs(command.args);\n this.argsMax = getMaxArgs(command.args);\n this.local.length = 0;\n if (command.options) {\n for (const option of command.options) {\n (option.isPersistent ? this.persistent : this.local).push(option);\n }\n }\n applyDirectives(this.directives, command);\n }\n\n /** The current command. */\n get command(): Spec | Subcommand {\n if (!this.current) {\n throw new Error(\"The scope hasn't entered a command\");\n }\n return this.current;\n }\n\n /** Whether the current command has subcommands of its own or inherits any. */\n get hasSubcommands(): boolean {\n return this.current?.subcommands !== undefined || this.inheritedSubcommands.length > 0;\n }\n\n /**\n * The subcommands the next token can name: the current command's own,\n * followed by each inherited one that an earlier one doesn't shadow a name\n * of. Hidden ones are included.\n */\n subcommands(): readonly Subcommand[] {\n const own = this.current?.subcommands ?? [];\n if (this.inheritedSubcommands.length === 0) {\n return own;\n }\n const all = [...own];\n for (const candidate of this.inheritedSubcommands) {\n if (!asArray(candidate.name).some((name) => all.some((earlier) => hasName(earlier.name, name)))) {\n all.push(candidate);\n }\n }\n return all;\n }\n\n /**\n * Find the subcommand `token` names: one of the current command's own, or\n * else an inherited persistent one. An exact name always wins. With\n * `subcommandsMatchUniquePrefix`, a token that's a prefix of exactly one of\n * the command's own names matches that command, unless `exactOnly`. A hidden\n * or inherited command only matches its exact name, so it can't make a\n * visible command's prefix ambiguous or take a prefix meant as an argument,\n * and an empty token is no command's prefix.\n */\n matchSubcommand(token: string, exactOnly = false): SubcommandMatch {\n const own = this.current?.subcommands ?? [];\n for (const candidate of own) {\n if (hasName(candidate.name, token)) {\n return { command: candidate };\n }\n }\n for (const candidate of this.inheritedSubcommands) {\n if (hasName(candidate.name, token)) {\n return { command: candidate };\n }\n }\n const allowPrefix = this.directives.subcommandsMatchUniquePrefix && !exactOnly;\n const matches = allowPrefix ? prefixMatches(own, token) : [];\n if (matches.length === 1) {\n return { command: matches[0] };\n }\n return new NoSubcommand(this.subcommands(), token, matches);\n }\n\n /** The option `name` refers to, if any. */\n resolve(name: string): Option | null {\n const { local, persistent } = this;\n for (let i = local.length - 1; i >= 0; i--) {\n if (hasName(local[i].name, name)) {\n return local[i];\n }\n }\n for (let i = persistent.length - 1; i >= 0; i--) {\n if (hasName(persistent[i].name, name)) {\n return persistent[i];\n }\n }\n return null;\n }\n\n /**\n * The options that can be used here, in definition order, each with only\n * its live names: the names that still refer to it. Options with every name\n * shadowed are left out. Where the next token can name a subcommand, as\n * `subcommands` says, a name that one matches is that subcommand's.\n */\n live(subcommands: SubcommandMatching | null = null): {\n local: VisibleOption[];\n persistent: VisibleOption[];\n } {\n // Which option each name refers to, built in one pass so the later and the\n // local options overwrite the ones they shadow. Same answer as `resolve`.\n const owner = new Map<string, Option>();\n for (const options of [this.persistent, this.local]) {\n for (const option of options) {\n for (const name of asArray(option.name)) {\n owner.set(name, option);\n }\n }\n }\n const pick = (options: readonly Option[]) => {\n const picked: VisibleOption[] = [];\n for (const option of options) {\n const names = asArray(option.name).filter(\n (name) =>\n owner.get(name) === option &&\n !(subcommands && this.matchSubcommand(name, subcommands.exactOnly).command),\n );\n if (names.length > 0) {\n picked.push({ option, names });\n }\n }\n return picked;\n };\n return { local: pick(this.local), persistent: pick(this.persistent) };\n }\n\n /**\n * The options a user can see at the start of the current command: the\n * {@link live} ones that aren't hidden, without the names a subcommand takes.\n */\n visible(): { local: VisibleOption[]; persistent: VisibleOption[] } {\n const { local, persistent } = this.live(this.hasSubcommands ? { exactOnly: false } : null);\n const shown = (visible: VisibleOption) => !visible.option.hidden;\n return { local: local.filter(shown), persistent: persistent.filter(shown) };\n }\n\n /** The live names of each option a user could have meant, for \"did you mean\" suggestions. */\n suggestionNames(): string[][] {\n const { local, persistent } = this.live();\n const shown = (visible: VisibleOption) => !visible.option.hidden;\n return [...local, ...persistent].filter(shown).map((visible) => visible.names);\n }\n\n /** The options that must be used, local first. */\n required(): Option[] {\n return [...this.local, ...this.persistent].filter((option) => option.isRequired);\n }\n\n /*\n * How an option is written with its value, and how the parser splits a\n * token into an option name and a value. Both use the option arg separators\n * in effect, so what help shows and completion offers is what the parser\n * reads, as long as every separator an option requires is one of them. The\n * spec checker reports one that isn't.\n */\n\n /**\n * How each of `names` is written with `option`'s value here. Help shows\n * these, completion offers them, and the spec checker reads each one back\n * through the parser.\n */\n forms(option: Option, names: readonly string[] = asArray(option.name)): OptionForm[] {\n const join = (name: string): string | null => {\n if (getMaxArgs(option.args) === 0) {\n return null;\n }\n if (option.requiresSeparator) {\n return this.requiredSeparator(option);\n }\n const glued = !this.directives.flagsArePosixNoncompliant && (name === \"-\" || name === \"+\");\n return glued ? \"\" : null;\n };\n return names.map((name) => ({ name, join: join(name) }));\n }\n\n /**\n * The separator that must come between `option` and its value, or null if\n * it can take a value as a separate token.\n */\n requiredSeparator(option: Option): string | null {\n const required = option.requiresSeparator;\n if (typeof required === \"string\") {\n return required;\n }\n return required ? (this.directives.optionArgSeparators[0] ?? \"=\") : null;\n }\n\n /** Whether the parser splits an option from its value at `separator` here. */\n readsSeparator(separator: string): boolean {\n return this.directives.optionArgSeparators.includes(separator);\n }\n\n /** The separator that `text` starts with, or \"\" if none. Used after a short option. */\n leadingSeparator(text: string): string {\n for (const separator of this.directives.optionArgSeparators) {\n if (text.startsWith(separator)) {\n return separator;\n }\n }\n return \"\";\n }\n\n /**\n * The separator that appears first in `token`, so the value after it can\n * contain the other separators. When two separators start at the same place,\n * the longer one wins. Null if there's none, or if the one found is empty.\n */\n firstSeparator(token: string): { index: number; separator: string } | null {\n let found = \"\";\n let index = -1;\n for (const candidate of this.directives.optionArgSeparators) {\n const at = token.indexOf(candidate);\n if (at === -1) {\n continue;\n }\n if (index === -1 || at < index || (at === index && candidate.length > found.length)) {\n found = candidate;\n index = at;\n }\n }\n return found ? { index, separator: found } : null;\n }\n\n /**\n * Why `option`, used as `name`, can't take a value given after `separator`,\n * or null if it can. A separate token has the separator \"\".\n */\n separatorProblem(option: Option, name: string, separator: string): string | null {\n const required = option.requiresSeparator;\n if (typeof required === \"string\" && separator !== required) {\n return `Incorrect separator, use '${required}' instead of '${separator}'`;\n }\n if (required === true && separator === \"\") {\n return `Missing separator, use '${this.requiredSeparator(option)}' between ${name} and its value`;\n }\n return null;\n }\n}\n\nconst optionKeys = new WeakMap<Option, string>();\n\n/**\n * A key for the set of `option`'s names. Options with the same names, in any\n * order, get the same key and are one option: the parser continues a\n * repeatable option's uses across them, counts one as used when the other was,\n * and stores their values under the same names, which is how they're read.\n * Options that share only some names are different options, and each shared\n * name refers to whichever one `resolve` picks.\n */\nexport function optionKey(option: Option): string {\n let key = optionKeys.get(option);\n if (key === undefined) {\n key = typeof option.name === \"string\" ? option.name : [...option.name].sort().join(\"\\0\");\n optionKeys.set(option, key);\n }\n return key;\n}\n\nfunction hasName(names: string | readonly string[], name: string): boolean {\n return typeof names === \"string\" ? names === name : names.includes(name);\n}\n\n/** The visible commands that `token` is a prefix of a name of, each listed once. */\nfunction prefixMatches(subcommands: readonly Subcommand[], token: string): Subcommand[] {\n if (token === \"\") {\n return [];\n }\n return subcommands.filter(\n (candidate) => !candidate.hidden && asArray(candidate.name).some((name) => name.startsWith(token)),\n );\n}\n","import type { Arg, Option, NonEmptyArray, Subcommand } from \"./types.js\";\nimport { closestChoice } from \"./suggest.js\";\nimport { visibleSubcommands } from \"./subcommands.js\";\nimport { CommandScope } from \"./scope.js\";\nimport type { OptionForm, VisibleOption } from \"./scope.js\";\nimport type { DidYouMean } from \"./errors.js\";\nimport { addDefaults, asArray, getMaxArgs, makeArray, makeArray1, print, printError } from \"./util.js\";\n\nfunction dedent(str: string) {\n if (str[0] !== \"\\n\") {\n return str;\n }\n const lines = str.split(\"\\n\").slice(1, -1);\n const margin = lines[0].length - lines[0].trimStart().length;\n return lines.map((line) => line.slice(margin)).join(\"\\n\");\n}\n\nexport interface HelpConfig {\n /** Include the command description? Default: true. */\n description?: boolean;\n\n /** Include the usage summary? Default: true. */\n usage?: boolean;\n\n /** Ask if the user intended the input to be one of these choices. */\n didYouMean?: DidYouMean;\n}\n\n/** Get the help message used by the built-in help option and command. */\nexport function getHelp(path: NonEmptyArray<Subcommand>, config: HelpConfig = {}): string {\n const { description = true, usage = true, didYouMean } = config;\n const sections = getSections(path);\n if (didYouMean) {\n sections.didYouMean = closestChoice(didYouMean.input, didYouMean.choices);\n }\n if (!description) {\n sections.description = undefined;\n }\n if (!usage) {\n sections.usage = undefined;\n }\n return formatHelpSections(sections);\n}\n\n/**\n * Print `message` as an error, then the usage and flags of the last command on\n * `path`, suggesting the closest of `didYouMean.choices` if one is close.\n */\nexport function printUsageError(\n path: NonEmptyArray<Subcommand>,\n message: string,\n didYouMean?: DidYouMean,\n): void {\n printError(`${message}\\n\\n${getHelp(path, { description: false, didYouMean })}`);\n}\n\n/**\n * A subcommand that prints help for its parent, or for the command the names\n * after it lead to from there, so `cli help a b` prints the help of `cli a b`.\n * It reads names until one isn't a subcommand. A token where the command takes\n * arguments, or where it has no subcommands, ends the names, so\n * `cli help completion zsh` prints the help of `completion`. Any other token\n * is an unknown command. Add `{ ...helpCommand, isPersistent: true }` instead\n * to make `cli a b help` work too.\n */\nexport const helpCommand: Subcommand = {\n name: \"help\",\n description: \"Print a help message\",\n args: {\n name: \"command\",\n isOptional: true,\n isVariadic: true,\n },\n action({ path, args, help }) {\n const self = path[path.length - 1];\n const helpPath = path.slice(0, -1) as unknown as [Subcommand, ...Subcommand[]];\n // Match each name the way the parser would have matched it in place of `help`.\n const scope = CommandScope.at(helpPath);\n\n for (const name of args) {\n const command = helpPath[helpPath.length - 1];\n if (!command.subcommands) {\n break;\n }\n const match = scope.matchSubcommand(name);\n // With a persistent help command, `cli help a help` is `cli a help`.\n if (match.command === self && !command.subcommands.includes(self)) {\n break;\n }\n if (match.command) {\n helpPath.push(match.command);\n scope.enter(match.command);\n continue;\n }\n if (!command.requiresSubcommand && getMaxArgs(command.args) > 0) {\n break;\n }\n const { message, didYouMean } = match.reason();\n printUsageError(helpPath, message, didYouMean);\n return 1;\n }\n\n print(help({ path: helpPath }));\n return 0;\n },\n};\n\n/** A persistent help option that prints help for the selected command. */\nexport const help: Option = {\n name: [\"-h\", \"--help\"],\n description: \"Print a help message\",\n isPersistent: true,\n action({ path }) {\n print(formatHelpSections(getSections(path)));\n return 0;\n },\n};\n\ntype HelpSections = {\n description?: string;\n usage?: string;\n didYouMean?: string;\n args: [name: string, description: string][];\n options: [formattedName: string, description: string][];\n persistentOptions: [formattedName: string, description: string][];\n subcommands: [formattedName: string, description: string][];\n};\n\nfunction getSubcommandPathString(commands: NonEmptyArray<Subcommand>): string {\n return commands.map((command) => getLongestString(makeArray1(command.name))).join(\" \");\n}\n\nfunction getSections(commands: NonEmptyArray<Subcommand>): HelpSections {\n const command = commands[commands.length - 1];\n const scope = CommandScope.at(commands);\n const show = ({ option, names }: VisibleOption) => optionToString(option, scope.forms(option, names));\n\n const description = command.description;\n const defaultDesc = \"No description\";\n\n const subcommands: HelpSections[\"subcommands\"] = visibleSubcommands(command.subcommands).map(\n (subcommand) => [\n makeArray1(subcommand.name)\n .sort((a, b) => a.length - b.length)\n .join(\", \"),\n subcommand.description ?? defaultDesc,\n ],\n );\n\n const visible = scope.visible();\n let optionObjects = visible.local;\n let persistentOptionObjects = visible.persistent;\n // A command without parents or subcommands has no global flags to set apart.\n if (commands.length === 1 && subcommands.length === 0) {\n const byOption = new Map([...optionObjects, ...persistentOptionObjects].map((v) => [v.option, v]));\n optionObjects = (command.options ?? []).flatMap((option) => byOption.get(option) ?? []);\n persistentOptionObjects = [];\n }\n const row = (visible: VisibleOption): [string, string] => {\n const defaults: string[] = [];\n addDefaults(defaults, asArray(visible.option.args));\n return [show(visible), withDefaults(visible.option.description, defaults, defaultDesc)];\n };\n const options = optionObjects.map(row);\n const persistentOptions = persistentOptionObjects.map(row);\n\n const usage = (() => {\n const parts = [getSubcommandPathString(commands)];\n for (const visible of [...optionObjects, ...persistentOptionObjects]) {\n if (visible.option.isRequired) {\n parts.push(show(visible));\n }\n }\n if (options.length || persistentOptions.length) {\n parts.push(\"[flags]\");\n }\n if (command.requiresSubcommand) {\n parts.push(\"<command>\");\n } else {\n const args = makeArray(command.args);\n if (args.length > 0) {\n parts.push(summarizeArguments(args));\n }\n }\n return parts.join(\" \");\n })();\n\n // The positional arguments are only listed when there's more to say about\n // them than the usage line does. An argument's name is often description\n // enough, so one without a description is listed by name alone.\n const positionals = command.requiresSubcommand ? [] : asArray(command.args);\n const described = positionals.some((arg) => arg.description !== undefined || arg.default !== undefined);\n const args: HelpSections[\"args\"] = described\n ? positionals.map((arg) => [\n (arg.name || \"argument\") + (arg.isVariadic ? \"...\" : \"\"),\n withDefaults(arg.description, arg.default === undefined ? [] : [arg.default], \"\"),\n ])\n : [];\n\n return {\n usage,\n description,\n args,\n persistentOptions,\n options,\n subcommands,\n };\n}\n\n/**\n * A description ending with the defaults the parser uses. They go on a line of\n * their own when the last line would be too long for the 68 characters the\n * spec checks allow.\n */\nfunction withDefaults(\n description: string | undefined,\n defaults: readonly string[],\n defaultDesc: string,\n): string {\n if (defaults.length === 0) {\n return description ?? defaultDesc;\n }\n const shown = `(default: ${defaults.join(\" \")})`;\n if (description === undefined) {\n return shown;\n }\n const lastLine = description.slice(description.lastIndexOf(\"\\n\") + 1);\n return `${description}${lastLine.length + 1 + shown.length <= 68 ? \" \" : \"\\n\"}${shown}`;\n}\n\nexport function formatHelpSections(sections: HelpSections): string {\n const parts = [];\n\n const indent = \" \";\n\n if (sections.didYouMean) {\n parts.push(` Did you mean '${sections.didYouMean}'?`);\n }\n\n if (sections.description) {\n parts.push(dedent(sections.description));\n }\n\n if (sections.usage) {\n parts.push(`Usage:\\n${indent}${sections.usage}`);\n }\n\n const longestOptionName = Math.max(\n 0,\n ...sections.options.map(([name]) => name.length),\n ...sections.persistentOptions.map(([name]) => name.length),\n );\n const minSpacingBetweenNameAndDesc = 2;\n\n // Each name, then its description in a column `width` wide names leave.\n const formatRows = (rows: [string, string][], width: number) => {\n const lines = [];\n const newline = indent + \" \".repeat(width + minSpacingBetweenNameAndDesc);\n for (const [name, desc] of rows) {\n if (desc === \"\") {\n lines.push(`${indent}${name}`);\n continue;\n }\n const spaces = \" \".repeat(width - name.length + minSpacingBetweenNameAndDesc);\n const [head, ...tail] = desc.split(\"\\n\");\n const description = [head, ...tail.map((line) => newline + line)].join(\"\\n\");\n lines.push(`${indent}${name}${spaces}${description}`);\n }\n return lines;\n };\n const formatOptions = (options: [string, string][]) => formatRows(options, longestOptionName);\n\n if (sections.args.length > 0) {\n const longestArgName = Math.max(...sections.args.map(([name]) => name.length));\n parts.push([\"Arguments:\", ...formatRows(sections.args, longestArgName)].join(\"\\n\"));\n }\n\n if (sections.subcommands.length > 0) {\n const lines = [\"Commands:\"];\n const longestName = Math.max(...sections.subcommands.map(([name]) => name.length));\n const newline = indent + \" \".repeat(longestName + minSpacingBetweenNameAndDesc);\n for (const [name, desc] of sections.subcommands) {\n const spaces = \" \".repeat(longestName - name.length + minSpacingBetweenNameAndDesc);\n const [head, ...tail] = desc.split(\"\\n\\n\")[0].split(\"\\n\");\n const description = [head, ...tail.map((line) => newline + line)].join(\"\\n\");\n lines.push(`${indent}${name}${spaces}${description}`);\n }\n parts.push(lines.join(\"\\n\"));\n }\n\n if (sections.options.length > 0) {\n const lines = [\"Flags:\", ...formatOptions(sections.options)];\n parts.push(lines.join(\"\\n\"));\n }\n\n if (sections.persistentOptions.length > 0) {\n const lines = [\"Global flags:\", ...formatOptions(sections.persistentOptions)];\n parts.push(lines.join(\"\\n\"));\n }\n return parts.join(\"\\n\\n\") + \"\\n\";\n}\n\nexport function getLongestString(strings: NonEmptyArray<string>): string {\n let longest = strings[0];\n for (let i = 1; i < strings.length; i++) {\n const string = strings[i];\n if (string.length > longest.length) {\n longest = string;\n }\n }\n return longest;\n}\n\n/**\n * Show an option's names, each written with its arguments the way `forms`\n * says. Names written the same way share one copy of the arguments.\n */\nexport function optionToString(option: Option, forms: readonly OptionForm[]): string {\n const optionArgs = makeArray(option.args);\n const sorted = [...forms].sort((a, b) => a.name.length - b.name.length);\n const joins = [...new Set(sorted.map((form) => form.join))];\n return joins\n .map((join) => {\n const names = sorted.filter((form) => form.join === join).map((form) => form.name);\n return names.join(\", \") + argumentsAfterName(optionArgs, join);\n })\n .join(\", \");\n}\n\n/** The text after an option's name that shows its arguments, joined to the name by `join`. */\nfunction argumentsAfterName(args: Arg[], join: string | null): string {\n if (args.length === 0) {\n return \"\";\n }\n if (join === null) {\n return ` ${summarizeArguments(args)}`;\n }\n const [first, ...rest] = args;\n const name = first.name || \"argument\";\n const joined =\n (first.isOptional ? `[${join}${name}]` : `${join}<${name}>`) + (first.isVariadic ? \"...\" : \"\");\n return rest.length > 0 ? `${joined} ${summarizeArguments(rest)}` : joined;\n}\n\nexport function summarizeArguments(args: Arg[]) {\n return args.map((arg) => argToString(arg)).join(\" \");\n}\n\nexport function argToString(arg: Arg): string {\n const name = arg.name || \"argument\";\n let lhs = \"<\";\n let rhs = \">\";\n let suffix = \"\";\n if (arg.isOptional) {\n lhs = \"[\";\n rhs = \"]\";\n }\n if (arg.isVariadic) {\n suffix = \"...\";\n }\n return `${lhs}${name}${rhs}${suffix}`;\n}\n","import type { CommandPath } from \"./types.js\";\nimport type { Choice } from \"./suggest.js\";\n\nconst repr = JSON.stringify as (str: string) => string;\n\nexport interface ErrorContext {\n path: CommandPath;\n}\n\n/** What the user typed, and the names they could have meant. */\nexport interface DidYouMean {\n input: string;\n choices: readonly Choice[];\n}\n\n/**\n * A command line the parser can't accept. `run` prints the message with the\n * help for the command at `context.path`, and suggests the closest of\n * `didYouMean.choices` if there is one.\n */\nexport class ParseError extends Error {\n readonly context: ErrorContext;\n readonly didYouMean: DidYouMean | undefined;\n constructor(context: ErrorContext, message: string, didYouMean?: DidYouMean) {\n super(message);\n this.context = context;\n this.didYouMean = didYouMean;\n this.name = this.constructor.name;\n }\n}\n\nexport class UnknownOption extends ParseError {\n readonly option: string;\n constructor(option: string, validOptions: readonly Choice[], context: ErrorContext) {\n const msg = `${repr(option)} looks like a flag, but is unknown in this context`;\n super(context, msg, { input: option, choices: validOptions });\n this.option = option;\n }\n}\n\nexport class InvalidOptionArg extends ParseError {\n readonly option: string;\n constructor(option: string, context: ErrorContext) {\n super(context, `Option ${option} doesn't take arguments`);\n this.option = option;\n }\n}\n\nexport class TooManyArguments extends ParseError {\n constructor(value: string, context: ErrorContext) {\n super(context, `Too many arguments, ${repr(value)} was unexpected`);\n }\n}\n\nexport class TooFewOptionArguments extends ParseError {\n constructor(option: string, min: number, max: number, context: ErrorContext) {\n const msg =\n min === max\n ? `Option ${option} needs ${min} argument${min === 1 ? \"\" : \"s\"}`\n : !Number.isFinite(max)\n ? `Option ${option} needs at least ${min} argument${min === 1 ? \"\" : \"s\"}`\n : `Option ${option} needs between ${min} and ${max} arguments`;\n super(context, msg);\n }\n}\n\nexport class TooFewArguments extends ParseError {\n constructor(min: number, max: number, context: ErrorContext) {\n const msg =\n min === max\n ? `Expected ${min} argument${min === 1 ? \"\" : \"s\"}`\n : !Number.isFinite(max)\n ? `Expected at least ${min} argument${min === 1 ? \"\" : \"s\"}`\n : `Expected between ${min} and ${max} arguments`;\n super(context, msg);\n }\n}\n\nexport class MissingRequiredOption extends ParseError {\n constructor(name: string, context: ErrorContext) {\n const msg = `Option ${name} is required, but wasn't found`;\n super(context, msg);\n }\n}\n","import type { Action, Arg, CommandPath, Option, Spec, Subcommand } from \"./types.js\";\nimport { addDefaults, asArray, getMaxArgs, getMinArgs } from \"./util.js\";\nimport {\n InvalidOptionArg,\n MissingRequiredOption,\n ParseError,\n TooFewArguments,\n TooFewOptionArguments,\n TooManyArguments,\n UnknownOption,\n} from \"./errors.js\";\nimport type { ErrorContext } from \"./errors.js\";\nimport type { Directives } from \"./directives.js\";\nimport { CommandScope, optionKey } from \"./scope.js\";\nimport type { OptionForm, SubcommandMatch, SubcommandMatching } from \"./scope.js\";\nimport { usage as builtinUsageAction } from \"./subcommands.js\";\nimport type { NoSubcommand } from \"./subcommands.js\";\n\nexport interface ParseResult {\n args: string[];\n argSeparatorIndex: number;\n options: Map<string, string[]>;\n /**\n * The defaults of the arguments of the option `name` refers to, for an\n * option that wasn't used. Undefined if it was used, or if its first\n * argument is optional or has no default.\n */\n defaults(name: string): string[] | undefined;\n path: CommandPath;\n /**\n * The action to run: the last option action used, or else the selected\n * command's action. A command without an action prints its help.\n */\n action: Action;\n}\n\n/** What the token after a command line can be, as the parser would read it. */\nexport interface NextToken {\n /** The commands from the root to the current one. */\n path: CommandPath;\n /** The directives in effect. */\n directives: Readonly<Directives>;\n /** Whether the token can be an option. */\n optionsAllowed: boolean;\n /**\n * The subcommands the token can name, hidden ones included. While the open\n * option can still take a value, only an exact name matches.\n */\n subcommands: readonly Subcommand[];\n /**\n * The options the token can use, hidden ones included, local options first.\n * Empty when the token can't be an option.\n */\n options: readonly UsableOption[];\n /** The open option, if the token can be its value, and whether it must be. */\n value: { option: Option; arg: Arg | undefined; required: boolean } | null;\n /** The argument the token fills if it isn't an option, subcommand or value. */\n arg: Arg | undefined;\n /**\n * The partial token, if the parser reads it as an option with a value\n * attached. `prefix` is everything before the value.\n */\n attached: { option: Option; arg: Arg; prefix: string; value: string } | null;\n /**\n * Whether the parser reads the partial token as an option, known or\n * unknown, or as `--`. If it doesn't, the token is a value, argument or\n * subcommand.\n */\n partialIsOption: boolean;\n}\n\n/**\n * An option the next token can use without going over its repeat limit or\n * breaking an `exclusiveOn` rule.\n */\nexport interface UsableOption {\n option: Option;\n /**\n * How each name the parser reads as this option here is written. A name\n * that another option shadows, or that a subcommand matches, isn't one of\n * them.\n */\n forms: readonly OptionForm[];\n /**\n * Whether the option was used earlier on the line. Options with the same\n * names count as the same option, like a subcommand's copy of a parent's.\n */\n used: boolean;\n}\n\n/** What the parser read one token as. See {@link readToken}. */\nexport type TokenReading =\n /** `--`, the end of options. */\n | { kind: \"separator\" }\n | { kind: \"subcommand\"; command: Subcommand }\n /**\n * One option, or several chained short options, in the order used. If the\n * token also carries a value the option accepts, `attached` says where it starts.\n */\n | { kind: \"options\"; options: readonly Option[]; attached: { option: Option; start: number } | null }\n /** A value of the option before it. */\n | { kind: \"value\"; option: Option }\n | { kind: \"argument\" }\n /** An option that doesn't exist. */\n | { kind: \"unknown\" };\n\n/** The values a repeatable option has collected, and how many times it's been used. */\ninterface RepeatedUses {\n values: string[];\n count: number;\n}\n\n/** How many times `option` can be used. */\nfunction repeatLimit(option: Option): number {\n return typeof option.isRepeatable === \"number\" ? option.isRepeatable : Infinity;\n}\n\n/**\n * Throw if the options used break a `dependsOn` or `exclusiveOn` rule, or if\n * any of `required` is missing.\n */\nfunction checkOptionRules(\n options: ReadonlyMap<string, string[]>,\n seenOptions: readonly Option[],\n required: readonly Option[],\n context: ErrorContext,\n): void {\n for (const option of seenOptions) {\n if (!option.dependsOn) {\n continue;\n }\n for (const name of option.dependsOn) {\n if (!options.has(name)) {\n throw new ParseError(\n context,\n `${asArray(option.name).join(\"/\")} requires ${name}, add it to fix this error`,\n );\n }\n }\n }\n for (const option of seenOptions) {\n if (!option.exclusiveOn) {\n continue;\n }\n for (const name of option.exclusiveOn) {\n if (options.has(name)) {\n throw new ParseError(\n context,\n `${asArray(option.name).join(\"/\")} can't be used together with ${name}`,\n );\n }\n }\n }\n for (const option of required) {\n for (const name of asArray(option.name)) {\n if (!options.has(name)) {\n throw new MissingRequiredOption(name, context);\n }\n }\n }\n}\n\n/** Reads a command line one token at a time. See {@link tokenReader}. */\nexport interface TokenReader {\n /** Read the next token of the line, and say what it was read as. */\n read(token: string): TokenReading;\n}\n\n/**\n * The state of reading one command line, one token at a time. This is the\n * only code that decides what each input token is. It never throws: it skips\n * whatever is invalid and keeps going, so {@link readNext} can still read a\n * line that's wrong at the moment, and it keeps the first problem it finds for\n * {@link parse} to throw. Each method handles one kind of token, and says what\n * the token was read as.\n */\nclass Scanner implements TokenReader {\n private readonly path: [Spec, ...Subcommand[]];\n // The last option action used.\n private optionAction: Action | undefined = undefined;\n private readonly args: string[] = [];\n private readonly options: Map<string, string[]> = new Map();\n private readonly seenOptions: Option[] = [];\n private argSeparatorIndex = -1;\n\n // What the current command allows.\n private readonly scope: CommandScope = new CommandScope();\n private readonly directives: Directives = this.scope.directives;\n\n private hasFoundArg = false;\n\n // The last option used, and how many more separate tokens it can take as\n // values. While it has room, a token that isn't an option or `--` becomes its\n // value. A subcommand's exact name ends it unless a value is required.\n // `useOption` sets all of these and `closeOption` clears them.\n private openOption: Option | null = null;\n private openOptionName = \"\";\n private valueCount = 0;\n private valueMin = 0;\n private separateValueMax = 0;\n\n // The values of the last option, checked against its arity when it ends.\n // Unlike the counts above, this includes values attached with a separator.\n // A repeatable option keeps adding to the same array, so this use's values\n // start at `valuesStart`.\n private values: string[] | null = null;\n private valuesStart = 0;\n private valuesMin = 0;\n private valuesMax = 0;\n private valueArgs: readonly Arg[] = [];\n\n /**\n * Makes the error for the first token that can't be read the way it's\n * written, like an unknown option or a value an option doesn't take.\n * {@link parse} stops there.\n */\n problem: (() => ParseError) | null = null;\n\n // The first argument past the command's limit, or a subcommand that didn't\n // match. It's only an error once the whole line is read, because an option\n // action like --help allows it.\n private tooManyArgs: (() => ParseError) | null = null;\n\n // The uses of each repeatable option, keyed by `optionKey`.\n // A subcommand's copy of a parent's option has the same names, so it\n // continues the parent's uses. An option with other names, even a subset,\n // has uses of its own.\n private readonly repeatedUses: Map<string, RepeatedUses> = new Map();\n\n constructor(spec: Spec) {\n this.path = [spec];\n this.scope.enter(spec);\n }\n\n // A copy of the path, since reading carries on after a problem and can\n // enter a subcommand before the error is made.\n private ctx(): ErrorContext {\n return { path: [...this.path] };\n }\n\n /** Whether the open option can take the next token as a value. */\n private get hasRoomForValue(): boolean {\n return this.valueCount < this.separateValueMax;\n }\n\n private findOption(name: string): Option | null {\n return this.scope.resolve(name);\n }\n\n /**\n * Keep the problem `make` describes if it's the first. The error is only\n * made if {@link parse} throws it, since a lenient read never needs it and\n * an error is slow to make. So `make` can't read anything later tokens change.\n */\n private fail(make: (ctx: ErrorContext) => ParseError): void {\n if (!this.problem) {\n const ctx = this.ctx();\n this.problem = () => make(ctx);\n }\n }\n\n /** Keep the first argument the command has no room for, like {@link fail}. */\n private failArgs(make: (ctx: ErrorContext) => ParseError): void {\n if (!this.tooManyArgs) {\n const ctx = this.ctx();\n this.tooManyArgs = () => make(ctx);\n }\n }\n\n private unknownOption(option: string): void {\n if (!this.problem) {\n const names = this.scope.suggestionNames();\n this.fail((ctx) => new UnknownOption(option, names, ctx));\n }\n }\n\n // Every token except an option's value, or an unknown option, ends the\n // previous option. Then the defaults of the optional arguments that weren't\n // given are added, so a bare `--inspect` gets its port.\n private endOption(): void {\n const values = this.values;\n if (values) {\n const given = values.length - this.valuesStart;\n if (given < this.valuesMin) {\n const { openOptionName, valuesMin, valuesMax } = this;\n this.fail((ctx) => new TooFewOptionArguments(openOptionName, valuesMin, valuesMax, ctx));\n } else {\n addDefaults(values, this.valueArgs, given);\n }\n }\n this.values = null;\n }\n\n /** End the open option, so no later token can be its value. */\n private closeOption(): void {\n this.endOption();\n this.openOption = null;\n this.valueCount = this.valueMin = this.separateValueMax = 0;\n }\n\n private useOption(option: Option, name: string): void {\n this.endOption();\n this.openOption = option;\n this.openOptionName = name;\n this.valueCount = 0;\n this.valueMin = getMinArgs(option.args);\n // Options that require a separator only take attached values.\n this.separateValueMax = option.requiresSeparator ? 0 : getMaxArgs(option.args);\n this.seenOptions.push(option);\n if (option.action) {\n this.optionAction = option.action;\n }\n const names = asArray(option.name);\n const options = this.options;\n\n let optionValues: string[];\n if (option.isRepeatable) {\n // A repeatable option collects the values from every use. Without\n // arguments, each use adds an empty string, so the values count the uses.\n const key = optionKey(option);\n let uses = this.repeatedUses.get(key);\n if (!uses) {\n uses = { values: [], count: 0 };\n this.repeatedUses.set(key, uses);\n }\n if (uses.count >= repeatLimit(option)) {\n this.fail((ctx) => new ParseError(ctx, \"Too many repetitions\"));\n }\n uses.count += 1;\n // Another option may have taken one of the names since the last use.\n for (const other of names) {\n options.set(other, uses.values);\n }\n if (!option.args) {\n uses.values.push(\"\");\n return;\n }\n optionValues = uses.values;\n } else {\n // The last use of an option wins, so a user can override a flag that a\n // shell alias already sets.\n optionValues = [];\n for (const other of names) {\n options.set(other, optionValues);\n }\n }\n\n this.valuesMin = this.valueMin;\n this.valuesMax = getMaxArgs(option.args);\n if (this.valuesMax > 0) {\n this.values = optionValues;\n this.valuesStart = optionValues.length;\n this.valueArgs = asArray(option.args);\n }\n }\n\n /** Add a value to the open option. Returns whether it's a value the option accepts. */\n private addValue(value: string, separator: string): boolean {\n this.valueCount += 1;\n if (!this.values) {\n const name = this.openOptionName;\n this.fail((ctx) => new InvalidOptionArg(name, ctx));\n return false;\n }\n const problem = this.scope.separatorProblem(this.openOption!, this.openOptionName, separator);\n if (problem) {\n this.fail((ctx) => new ParseError(ctx, problem));\n }\n this.values.push(value);\n return problem === null;\n }\n\n /** Add a separate token as a value of the open option. */\n private value(token: string): TokenReading {\n this.addValue(token, \"\");\n return { kind: \"value\", option: this.openOption! };\n }\n\n /**\n * Add a value attached to the option's own token, starting at `start`. It's\n * the option's only value, so no later token can be one. Returns where the\n * value starts, or null if the option doesn't accept it.\n */\n private addAttachedValue(\n start: number,\n value: string,\n separator: string,\n ): { option: Option; start: number } | null {\n const option = this.openOption!;\n const accepted = this.addValue(value, separator);\n this.valueMin = this.separateValueMax = 0;\n return accepted ? { option, start } : null;\n }\n\n /**\n * Whether the command already has all the arguments it takes. A command that\n * requires a subcommand takes none.\n */\n private get argsAreFull(): boolean {\n return this.scope.command.requiresSubcommand === true || this.args.length >= this.scope.argsMax;\n }\n\n private addArg(value: string): TokenReading {\n this.endOption();\n if (this.argsAreFull) {\n this.failArgs((ctx) => new TooManyArguments(value, ctx));\n }\n this.args.push(value);\n return { kind: \"argument\" };\n }\n\n /** Read `--`. Every token after it is an argument. */\n private argSeparator(): TokenReading {\n this.closeOption();\n // A command that requires a subcommand allows `--` alone, and reports\n // any argument after it.\n const command = this.scope.command;\n if (this.argsAreFull && !command.requiresSubcommand) {\n this.failArgs(\n (ctx) => new ParseError(ctx, \"Unexpected argument '--', did you mean to use an option instead?\"),\n );\n }\n this.argSeparatorIndex = this.args.length;\n return { kind: \"separator\" };\n }\n\n /**\n * How the next token can name a subcommand, its own or an inherited one, or\n * null if it can't. It can't once an argument is found, or while the open\n * option needs the next token as its value. A required or variadic option\n * value takes priority over a subcommand. A short optional value could be a\n * prefix of a subcommand's name, so only an exact name can end an option\n * that still has room.\n */\n private get subcommandMatching(): SubcommandMatching | null {\n if (this.hasFoundArg || !this.scope.hasSubcommands) {\n return null;\n }\n if (this.valueCount < this.valueMin || (this.hasRoomForValue && this.separateValueMax === Infinity)) {\n return null;\n }\n return { exactOnly: this.hasRoomForValue };\n }\n\n /**\n * The subcommand the next token enters if it's `token`, or why it enters\n * none. Null if the next token can't be a subcommand at all.\n */\n private subcommandFor(token: string): SubcommandMatch | null {\n const matching = this.subcommandMatching;\n return matching && this.scope.matchSubcommand(token, matching.exactOnly);\n }\n\n private enterSubcommand(command: Subcommand): TokenReading {\n this.closeOption();\n this.path.push(command);\n this.scope.enter(command);\n return { kind: \"subcommand\", command };\n }\n\n /** Read a token like `-abc`, `+x` or `-ovalue`. */\n private shortOptions(token: string): TokenReading {\n const leadingChar = token[0];\n\n // Parse as a single dash or plus with an arg. Try dash and plus options\n // first if:\n // - the options exist\n // - the options take args\n // - the first non-leading character isn't an option\n const dashOption = this.findOption(leadingChar);\n if (dashOption?.args && !this.findOption(token.slice(0, 2))) {\n this.useOption(dashOption, leadingChar);\n const attached = this.addAttachedValue(1, token.slice(1), \"\");\n return { kind: \"options\", options: [dashOption], attached };\n }\n\n // Parse as chained short options. If we got here, the option wasn't `-` or `+`.\n const used: Option[] = [];\n let attached: { option: Option; start: number } | null = null;\n for (let char = 1; char < token.length; char++) {\n const optionName = leadingChar + token[char];\n const option = this.findOption(optionName);\n if (!option) {\n // An open option takes anything unknown as a value, like `-5`.\n if (char === 1 && this.hasRoomForValue) {\n return this.value(token);\n }\n this.unknownOption(optionName);\n continue;\n }\n\n this.useOption(option, optionName);\n used.push(option);\n if (char === token.length - 1) {\n break;\n }\n\n const sep = this.scope.leadingSeparator(token.slice(char + 1));\n // An option without args still takes a separated value, so that `-v=1`\n // fails like `--verbose=1`, unless the next character is an option.\n if (option.args || (sep && !this.findOption(leadingChar + token[char + 1]))) {\n const argStart = char + sep.length + 1;\n attached = this.addAttachedValue(argStart, token.slice(argStart), sep);\n break;\n }\n }\n return used.length > 0 ? { kind: \"options\", options: used, attached } : { kind: \"unknown\" };\n }\n\n /**\n * Read a token like `--name` or `--name=value`, or any token when options\n * aren't POSIX compliant. Returns null if the token should be an argument.\n */\n private longOption(token: string): TokenReading | null {\n const found = this.scope.firstSeparator(token);\n const optionName = found ? token.slice(0, found.index) : token;\n const option = this.findOption(optionName);\n if (option) {\n this.useOption(option, optionName);\n let attached: { option: Option; start: number } | null = null;\n if (found) {\n const valueStart = found.index + found.separator.length;\n attached = this.addAttachedValue(valueStart, token.slice(valueStart), found.separator);\n }\n return { kind: \"options\", options: [option], attached };\n }\n // POSIX-noncompliant option means that there's nothing \"option-like\". Any\n // token can be an option if it matches an option name, and if it's not an\n // option then it's just a regular argument.\n if (this.directives.flagsArePosixNoncompliant) {\n return null;\n }\n if (this.hasRoomForValue) {\n return this.value(token);\n }\n // The option is unknown and looks like a POSIX-compliant option, so\n // it's an unknown option instead of an arg.\n this.unknownOption(optionName);\n return { kind: \"unknown\" };\n }\n\n /**\n * Read a token that isn't `--`, a subcommand or an option. It's a value of\n * the open option if that has room, and otherwise an argument, which stops\n * later tokens from being subcommands. `unmatched` is why the token isn't a\n * subcommand, if it could have been one.\n */\n private valueOrArg(token: string, unmatched: NoSubcommand | null): TokenReading {\n if (this.hasRoomForValue) {\n return this.value(token);\n }\n // Where a subcommand could be, a token the command has no room for is a\n // subcommand that didn't match.\n if (unmatched && this.argsAreFull) {\n const command = this.scope.command;\n if (command.subcommands?.length || command.requiresSubcommand) {\n this.failArgs((ctx) => {\n const { message, didYouMean } = unmatched.reason();\n return new ParseError(ctx, message, didYouMean);\n });\n }\n }\n this.hasFoundArg = true;\n return this.addArg(token);\n }\n\n /**\n * Throw if the finished command line is missing anything. Returns what it\n * was parsed as. Only call this when there's no {@link problem}.\n */\n finish(): ParseResult {\n // An option with an action, like --help, works however the rest of the\n // command line is wrong, as long as every token could be read. So does the\n // usage a command shows when no subcommand is named.\n const command = this.scope.command;\n const showsUsage = command.requiresSubcommand && !command.action && this.args.length === 0;\n const skipsChecks = this.optionAction !== undefined || showsUsage;\n if (!skipsChecks && this.tooManyArgs) {\n throw this.tooManyArgs();\n }\n if (!skipsChecks && this.args.length < this.scope.argsMin) {\n throw new TooFewArguments(this.scope.argsMin, this.scope.argsMax, this.ctx());\n }\n this.endOption();\n if (this.problem) {\n throw this.problem();\n }\n if (!skipsChecks) {\n checkOptionRules(this.options, this.seenOptions, this.scope.required(), this.ctx());\n }\n // Defaults are added after the checks, so they never count as typed. An\n // option action can run with required arguments missing, and then the\n // first default would fill a required argument's place.\n if (!command.requiresSubcommand && this.args.length >= this.scope.argsMin) {\n addDefaults(this.args, asArray(command.args), this.args.length);\n }\n return {\n path: this.path,\n action: this.optionAction ?? command.action ?? builtinUsageAction,\n args: this.args,\n argSeparatorIndex: this.argSeparatorIndex,\n options: this.options,\n defaults: (name) => this.defaults(name),\n };\n }\n\n /** See {@link ParseResult.defaults}. */\n private defaults(name: string): string[] | undefined {\n if (this.options.has(name)) {\n return undefined;\n }\n const args = asArray(this.scope.resolve(name)?.args);\n // An option whose first argument is optional, like `--inspect[=port]`,\n // means something different when it's left out than when it's bare, so\n // its defaults are only for the bare option.\n if (args.length === 0 || args[0].isOptional) {\n return undefined;\n }\n const values: string[] = [];\n addDefaults(values, args);\n return values.length > 0 ? values : undefined;\n }\n\n /** Whether using `option` next would go over its repeat limit or break an `exclusiveOn` rule. */\n private conflicts(option: Option): boolean {\n if ((this.repeatedUses.get(optionKey(option))?.count ?? 0) >= repeatLimit(option)) {\n return true;\n }\n const options = this.options;\n if (option.exclusiveOn?.some((name) => options.has(name))) {\n return true;\n }\n const names = asArray(option.name);\n return this.seenOptions.some((seen) => seen.exclusiveOn?.some((name) => names.includes(name)));\n }\n\n /** The options the next token can use. See {@link NextToken.options}. */\n private usableOptions(): UsableOption[] {\n const used = new Set(this.seenOptions.map(optionKey));\n const { local, persistent } = this.scope.live(this.subcommandMatching);\n const usable: UsableOption[] = [];\n for (const { option, names } of [...local, ...persistent]) {\n if (this.conflicts(option)) {\n continue;\n }\n usable.push({ option, forms: this.scope.forms(option, names), used: used.has(optionKey(option)) });\n }\n return usable;\n }\n\n /**\n * What the next token can be. See {@link readNext}. Reading more tokens\n * doesn't change what this returns.\n */\n next(): Omit<NextToken, \"attached\" | \"partialIsOption\"> {\n const open = this.openOption && this.hasRoomForValue ? this.openOption : null;\n const command = this.scope.command;\n // Every token after `--` is an argument.\n const afterSeparator = this.argSeparatorIndex !== -1;\n const optionsAllowed = !afterSeparator && this.optionsAllowed;\n return {\n path: [...this.path],\n directives: { ...this.directives },\n optionsAllowed,\n subcommands: !afterSeparator && this.subcommandMatching ? this.scope.subcommands() : [],\n options: optionsAllowed ? this.usableOptions() : [],\n value: open && {\n option: open,\n arg: argAt(asArray(open.args), this.valueCount),\n required: this.valueCount < this.valueMin,\n },\n arg: open ? undefined : argAt(asArray(command.args), this.args.length),\n };\n }\n\n /** Whether the next token can be an option. Once options must stop, every token is an argument. */\n private get optionsAllowed(): boolean {\n return !(this.directives.optionsMustPrecedeArguments && this.hasFoundArg);\n }\n\n read(token: string): TokenReading {\n // Every token after `--` is an argument.\n if (this.argSeparatorIndex !== -1) {\n return this.addArg(token);\n }\n const optionsAllowed = this.optionsAllowed;\n\n // \"--\" disables option & subcommand parsing, so it's checked first.\n if (token === \"--\" && optionsAllowed) {\n return this.argSeparator();\n }\n\n const subcommand = this.subcommandFor(token);\n if (subcommand?.command) {\n return this.enterSubcommand(subcommand.command);\n }\n\n if (optionsAllowed) {\n const flagsArePosixNoncompliant = this.directives.flagsArePosixNoncompliant;\n const first = token.charCodeAt(0);\n const isDoubleDash = first === 45 /* - */ && token.charCodeAt(1) === 45;\n if (\n !flagsArePosixNoncompliant &&\n token.length > 1 &&\n (first === 45 || first === 43) /* + */ &&\n !isDoubleDash\n ) {\n return this.shortOptions(token);\n }\n if (flagsArePosixNoncompliant || (token.length > 2 && isDoubleDash)) {\n const reading = this.longOption(token);\n if (reading) {\n return reading;\n }\n }\n }\n\n return this.valueOrArg(token, subcommand);\n }\n}\n\n/** The argument at `index`, reusing a final variadic argument. */\nfunction argAt(args: readonly Arg[], index: number): Arg | undefined {\n if (index < args.length) {\n return args[index];\n }\n const last = args[args.length - 1];\n return last?.isVariadic ? last : undefined;\n}\n\n/**\n * Start reading a command line for `spec`, to say what each token is read as\n * in turn. Reads leniently, like {@link readNext}.\n */\nexport function tokenReader(spec: Spec): TokenReader {\n return new Scanner(spec);\n}\n\n/**\n * Work out what the token after `before` can be, and how the parser reads\n * `partial`: whether it's an option, and if so, whether it has a value\n * attached. Reads leniently, so a line that's wrong at the moment still has\n * an answer. Completion is built on this.\n */\nexport function readNext(spec: Spec, before: readonly string[], partial: string): NextToken {\n const s = new Scanner(spec);\n for (const token of before) {\n s.read(token);\n }\n const next = s.next();\n let attached: NextToken[\"attached\"] = null;\n let partialIsOption = false;\n if (partial !== \"\" && next.optionsAllowed) {\n const reading = s.read(partial);\n partialIsOption =\n reading.kind === \"options\" || reading.kind === \"unknown\" || reading.kind === \"separator\";\n const found = reading.kind === \"options\" ? reading.attached : null;\n const arg = found && asArray(found.option.args)[0];\n if (found && arg) {\n attached = {\n option: found.option,\n arg,\n prefix: partial.slice(0, found.start),\n value: partial.slice(found.start),\n };\n }\n }\n return { ...next, attached, partialIsOption };\n}\n\n/**\n * Say what the parser reads `token` as when it comes after `before`. Reads\n * leniently, like {@link readNext}. To read every token of a line, use\n * {@link tokenReader}.\n */\nexport function readToken(spec: Spec, before: readonly string[], token: string): TokenReading {\n const s = new Scanner(spec);\n for (const earlier of before) {\n s.read(earlier);\n }\n return s.read(token);\n}\n\n/**\n * Parse the input tokens using the given CLI spec.\n *\n * This returns a `ParseResult`, which contains the array of\n * subcommands used, the provided options, the arguments, and the action to\n * run.\n *\n * If parsing fails, this function throws.\n */\nexport function parse(input: readonly string[], spec: Spec): ParseResult {\n const s = new Scanner(spec);\n for (const token of input) {\n s.read(token);\n if (s.problem) {\n throw s.problem();\n }\n }\n return s.finish();\n}\n","/**\n * Supplementary module to make testing your CLI easier.\n *\n * @module\n */\n\nimport type { Arg, Option, SingleOrArray, Spec, Subcommand } from \"./types.js\";\nimport { assert, getMaxArgs, getMinArgs, makeArray } from \"./util.js\";\nimport { CommandScope, optionKey } from \"./scope.js\";\nimport type { OptionForm } from \"./scope.js\";\nimport { optionToString } from \"./help.js\";\nimport { readToken, tokenReader } from \"./parse.js\";\nimport type { TokenReading } from \"./parse.js\";\n\nconst repr = JSON.stringify;\n\n// TODO: one decorators are stable (ts 4.9?), use decorators this file\n\n/** An option, the path to the command that defines it, and its index there. */\ninterface Definition {\n option: Option;\n definedIn: Subcommand[];\n index: number;\n}\n\n/** One command in the spec, with what's in effect there. */\nclass CommandVisit {\n private built: CommandScope | null = null;\n\n constructor(\n /** The commands from the root to this one. */\n readonly path: Subcommand[],\n /** This command's options, in definition order. */\n readonly own: Definition[],\n /** The persistent options of the commands above, root first. */\n readonly inherited: Definition[],\n ) {}\n\n /** The last command on the path. */\n get command(): Subcommand {\n return this.path[this.path.length - 1];\n }\n\n /** The options, subcommands and directives in effect here, built on first use. */\n get scope(): CommandScope {\n return (this.built ??= CommandScope.at(this.path));\n }\n}\n\n/**\n * Run a function once for each command in the spec, parents before their\n * subcommands, starting with `spec`. Each visit's path and scope start at\n * `spec`.\n */\nfunction forEachCommand(spec: Subcommand, fn: (visit: CommandVisit) => void): void {\n const visit = (path: Subcommand[], inherited: Definition[]) => {\n const command = path[path.length - 1];\n const own = makeArray(command.options).map((option, index) => ({ option, definedIn: path, index }));\n fn(new CommandVisit(path, own, inherited));\n const next = [...inherited, ...own.filter(({ option }) => option.isPersistent)];\n for (const subcommand of makeArray(command.subcommands)) {\n visit([...path, subcommand], next);\n }\n };\n visit([spec], []);\n}\n\n/**\n * Run a function once for each `args` property in the spec: each command's,\n * then its options'. This will convert single args to an array with one item.\n */\nfunction forEachArgArray(spec: Subcommand, fn: (args: Arg[], path: Subcommand[]) => void): void {\n forEachCommand(spec, ({ command, path }) => {\n fn(makeArray(command.args), path);\n for (const option of makeArray(command.options)) {\n fn(makeArray(option.args), path);\n }\n });\n}\n\nfunction joinNames(names: SingleOrArray<string>) {\n return makeArray(names)\n .sort((a, b) => a.length - b.length)\n .join(\"|\");\n}\n\n/** Compares spec values by shape. Any two functions count as the same shape. */\nfunction isSameStructure(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true;\n }\n if (typeof a === \"function\" && typeof b === \"function\") {\n return true;\n }\n if (typeof a !== \"object\" || typeof b !== \"object\" || a === null || b === null) {\n return false;\n }\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n const left = a as Record<string, unknown>;\n const right = b as Record<string, unknown>;\n const keys = new Set([...Object.keys(left), ...Object.keys(right)]);\n return [...keys].every((key) => isSameStructure(left[key], right[key]));\n}\n\nfunction namedArrayToString(...parts: { name: SingleOrArray<string> }[]) {\n const names = parts.map((named) => joinNames(named.name));\n return `\\`${names.join(\" \")}\\``;\n}\n\n/** Name the last command on `path` in a message, with its index among its siblings. */\nfunction describeCommand(path: readonly Subcommand[]): string {\n const command = path[path.length - 1];\n const parent = path[path.length - 2];\n if (!parent) {\n return `Command ${namedArrayToString(command)}`;\n }\n const index = makeArray(parent.subcommands).indexOf(command);\n return `Subcommand ${namedArrayToString(...path)} (index ${index})`;\n}\n\n/**\n * Name the option at `index` on the last command on `definedIn` in a message,\n * and the command it's used in when that isn't the one that defines it.\n */\nfunction describeOption(definedIn: readonly Subcommand[], index: number, usedIn = definedIn): string {\n const option = makeArray(definedIn[definedIn.length - 1].options)[index];\n const name = `${namedArrayToString(...definedIn, option)} (index ${index})`;\n return usedIn === definedIn ? `Option ${name}` : `In ${namedArrayToString(...usedIn)}, option ${name}`;\n}\n\n/** One option, at one command it can be used in. */\ninterface OptionUse {\n option: Option;\n /** The commands from the root to the one the option is used in. */\n path: Subcommand[];\n /** The options and directives in effect there. */\n scope: CommandScope;\n /** Whether the command it's used in is the one that defines it. */\n isDefinedHere: boolean;\n /** Names the option at the start of a message. See {@link describeOption}. */\n where: string;\n}\n\n/**\n * Run a function once for each option at each command it can be used in: the\n * command's own options, in definition order, then the persistent ones it\n * inherits. A check that is about how the option is written skips the uses\n * that aren't `isDefinedHere`. A check that depends on the scope sees the\n * option the way the parser does at each command.\n */\nfunction forEachOption(spec: Subcommand, fn: (use: OptionUse) => void): void {\n forEachCommand(spec, ({ path, own, inherited, scope }) => {\n for (const { option, definedIn, index } of [...own, ...inherited]) {\n const where = describeOption(definedIn, index, path);\n fn({ option, path, scope, isDefinedHere: definedIn === path, where });\n }\n });\n}\n\n/** Asserts that required arguments do not come after an optional argument */\nexport function assertRequiredArgumentsDoNotFollowOptionalArguments(spec: Subcommand): void {\n forEachArgArray(spec, (args, path) => {\n let remainingMustBeOptional = false;\n let firstOptionalArgIndex: number | null = null;\n for (const [index, arg] of args.entries()) {\n if (remainingMustBeOptional) {\n assert(\n arg.isOptional,\n `In ${namedArrayToString(...path)}, argument ${arg.name || index} is required, but it must be optional since the argument at index ${firstOptionalArgIndex} is optional`,\n );\n } else if (arg.isOptional) {\n remainingMustBeOptional = true;\n firstOptionalArgIndex ??= index;\n }\n }\n });\n}\n\n/**\n * Asserts that the parser can use every default. A positional argument with a\n * default must be optional. A required option argument's default is only used\n * when the option is left out, so every argument before it needs a default\n * too, and the option can't be required.\n */\nexport function assertDefaultsCanBeUsed(spec: Subcommand): void {\n forEachCommand(spec, ({ command, path }) => {\n for (const [index, arg] of makeArray(command.args).entries()) {\n assert(\n arg.default === undefined || arg.isOptional,\n `In ${namedArrayToString(...path)}, argument ${arg.name || index} has a default, but it's required, so the default is never used`,\n );\n }\n });\n forEachOption(spec, ({ option, isDefinedHere, where }) => {\n if (!isDefinedHere) {\n return;\n }\n let firstWithout: number | null = null;\n for (const [index, arg] of makeArray(option.args).entries()) {\n if (arg.default === undefined) {\n firstWithout ??= index;\n continue;\n }\n if (arg.isOptional) {\n continue;\n }\n const name = `${where}, argument ${arg.name || index} has a default, but`;\n assert(!option.isRequired, `${name} the option is required, so the default is never used`);\n assert(\n firstWithout === null,\n `${name} the argument at index ${firstWithout} has none, so the default is never used`,\n );\n }\n });\n}\n\n/** Asserts that `isRepeatable` is only assigned a positive integer */\nexport function assertRepeatableOptionsArePositiveIntegers(spec: Subcommand): void {\n forEachOption(spec, ({ option, isDefinedHere, where }) => {\n if (!isDefinedHere || typeof option.isRepeatable !== \"number\") {\n return;\n }\n assert(\n Number.isSafeInteger(option.isRepeatable),\n `${where} has its \\`isRepeatable\\` value set to a number that is not an integer`,\n );\n assert(\n !(option.isRepeatable < 1),\n `${where} has its \\`isRepeatable\\` value set to a number below 1, which means it can't be used at all`,\n );\n assert(\n option.isRepeatable !== 1,\n `${where} has its \\`isRepeatable\\` value set to 1, which is no different that omitting the property entirely`,\n );\n });\n}\n\n/** Asserts that options have unique names in their scope */\nexport function assertOptionsHaveLocallyUniqueNames(spec: Subcommand): void {\n forEachCommand(spec, ({ path, own }) => {\n const optionNames = new Set<string>();\n for (const { option, index } of own) {\n for (const name of makeArray(option.name)) {\n assert(\n !optionNames.has(name),\n `${describeOption(path, index)} has a non-unique name, '${name}'. Option names must be unique.`,\n );\n optionNames.add(name);\n }\n }\n });\n}\n\n/** Asserts that options don't shadow a persistent option */\nexport function assertOptionsDoNotShadowPersistentOptions(spec: Subcommand): void {\n forEachCommand(spec, ({ path, own, inherited }) => {\n for (const { option, index } of own) {\n for (const name of makeArray(option.name)) {\n assert(\n !inherited.some((persistent) => makeArray(persistent.option.name).includes(name)),\n `${describeOption(path, index)} shadows the name of a persistent option, ${repr(name)}. Option names can't shadow persistent options.`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that when a subcommand's option and a different option on a parent\n * share a name, each of them has a name of its own.\n *\n * Parsed values are looked up by name, and an option sets every one of its\n * names when it's used. If every name of the parent's option is also the\n * subcommand's, using the subcommand's option replaces the parent's value, so\n * it can't be read. If every name of the subcommand's option is also the\n * parent's, its names hold the parent's value when it isn't used, so it can't\n * tell whether it was. Options with the same names are fine when they're\n * identical, such as an option kept in a constant, because the parser treats\n * them as one option.\n *\n * This skips persistent parent options, because\n * {@link assertOptionsDoNotShadowPersistentOptions} covers those and\n * `allowShadowingPersistentOptions` opts out of it.\n */\nexport function assertOptionsHaveDifferentNamesFromParents(spec: Subcommand): void {\n forEachOption(spec, ({ option, path, isDefinedHere, where }) => {\n if (!isDefinedHere) {\n return;\n }\n const names = makeArray(option.name);\n // A parent's non-persistent options aren't in this command's scope, so\n // they're found on the parents themselves.\n for (const parent of path.slice(0, -1)) {\n for (const parentOption of makeArray(parent.options)) {\n if (parentOption.isPersistent) {\n continue;\n }\n const parentNames = makeArray(parentOption.name);\n const other = namedArrayToString(parent, parentOption);\n if (optionKey(parentOption) === optionKey(option)) {\n assert(\n isSameStructure({ ...parentOption, name: 0 }, { ...option, name: 0 }),\n `${where} has the same names as a different option, ${other}, so the parent's value can't be read. Add a name that only one of them uses.`,\n );\n continue;\n }\n assert(\n !parentNames.every((name) => names.includes(name)),\n `${where} has every name of a different option, ${other}, so the parent's value can't be read. Add a name that only the parent's option uses.`,\n );\n assert(\n !names.every((name) => parentNames.includes(name)),\n `${where} only has names of a different option, ${other}, so it can't tell whether it was used. Add a name that only the subcommand's option uses.`,\n );\n }\n }\n });\n}\n\n/** Asserts that subcommands don't share a name with a sibling subcommand */\nexport function assertSubcommandsHaveLocallyUniqueNames(spec: Subcommand): void {\n forEachCommand(spec, ({ command, path }) => {\n const names = new Set<string>();\n for (const [index, subcommand] of makeArray(command.subcommands).entries()) {\n for (const name of makeArray(subcommand.name)) {\n assert(\n !names.has(name),\n `The subcommand ${namedArrayToString(...path, subcommand)} (index ${index}) has a non-unique name, ${repr(name)}. Subcommand names must be unique among the subcommands in the same array.`,\n );\n names.add(name);\n }\n }\n });\n}\n\n/**\n * Asserts that no option arg separator is an empty string\n */\nexport function assertOptionArgSeparatorsHaveCharacters(spec: Subcommand): void {\n forEachCommand(spec, ({ command, path }) => {\n const separators = makeArray(command.parserDirectives?.optionArgSeparators);\n for (const [sepIndex, separator] of separators.entries()) {\n assert(\n separator !== \"\",\n `${describeCommand(path)} has an empty string for an option arg separator at index ${sepIndex}. If you wanted to disable option arg separators, use an empty array.`,\n );\n }\n });\n}\n\n/**\n * Asserts that the parser reads options named \"+\" or \"-\" the way they're\n * written, which needs them to take one argument.\n *\n * @deprecated {@link assertNamesReadBack} checks this for every option.\n */\nexport function assertPlusMinusOptionsTakeOneArg(spec: Subcommand): void {\n assertOptionFormsReadBack(spec, (_, name) => name === \"-\" || name === \"+\");\n}\n\n/**\n * Asserts that names do not have leading or trailing whitespace\n */\nexport function assertNamesHaveNoExtraWhitespace(spec: Subcommand): void {\n forEachOption(spec, ({ option, isDefinedHere, where }) => {\n if (!isDefinedHere) {\n return;\n }\n for (const name of makeArray(option.name)) {\n assert(name === name.trim(), `${where} has a name with extra whitespace`);\n }\n });\n forEachCommand(spec, ({ command, path }) => {\n for (const name of makeArray(command.name)) {\n assert(name === name.trim(), `${describeCommand(path)} has a name with extra whitespace`);\n }\n });\n forEachArgArray(spec, (args, path) => {\n for (const [index, arg] of makeArray(args).entries()) {\n for (const name of makeArray(arg.name)) {\n assert(\n name === name.trim(),\n `Arg in ${namedArrayToString(...path)} (at index ${index}) has a name with extra whitespace`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that everything has a description\n */\nexport function assertEverythingHasDescription(spec: Subcommand): void {\n assert(spec.description, `Spec has no description`);\n forEachOption(spec, ({ option, isDefinedHere, where }) => {\n if (isDefinedHere) {\n assert(option.description, `${where} has no description`);\n }\n });\n forEachCommand(spec, ({ command, path }) => {\n assert(command.description, `${describeCommand(path)} has no description`);\n });\n}\n\n/**\n * Asserts that descriptions have line length < 69\n */\nexport function assertDescriptionLineLengthUnder69(spec: Subcommand): void {\n if (spec.description) {\n assert(\n spec.description.split(\"\\n\").every((line) => line.length <= 68),\n `Spec has a description line over 68 characters`,\n );\n }\n forEachOption(spec, ({ option, isDefinedHere, where }) => {\n if (!isDefinedHere || !option.description) {\n return;\n }\n assert(\n option.description.split(\"\\n\").every((line) => line.length <= 68),\n `${where} has a description line over 68 characters`,\n );\n });\n forEachCommand(spec, ({ command, path }) => {\n if (command.description) {\n assert(\n command.description.split(\"\\n\").every((line) => line.length <= 68),\n `${describeCommand(path)} has a description line over 68 characters`,\n );\n }\n // Help lists positional arguments with their descriptions.\n for (const [index, arg] of makeArray(command.args).entries()) {\n assert(\n !arg.description || arg.description.split(\"\\n\").every((line) => line.length <= 68),\n `In ${namedArrayToString(...path)}, argument ${arg.name || index} has a description line over 68 characters`,\n );\n }\n });\n}\n\n/**\n * Asserts that the parser reads options with `requiresSeparator` the way\n * they're written, which needs them to take at most one argument.\n *\n * @deprecated {@link assertNamesReadBack} checks this for every option.\n */\nexport function assertRequiresSeparatorTakesOneArg(spec: Subcommand): void {\n assertOptionFormsReadBack(spec, (option) => Boolean(option.requiresSeparator));\n}\n\n/**\n * What the parser read a token as, for a message. `path` is the command the\n * token came after.\n */\nfunction describeReading(reading: TokenReading, path: readonly Subcommand[]): string {\n switch (reading.kind) {\n case \"separator\":\n return \"the end of options, '--'\";\n case \"subcommand\":\n return `the subcommand ${namedArrayToString(...path, reading.command)}`;\n case \"options\":\n return reading.options.length === 1\n ? `the option ${namedArrayToString(reading.options[0])}`\n : `the options ${reading.options.map((option) => namedArrayToString(option)).join(\", \")}`;\n case \"value\":\n return `a value of the option ${namedArrayToString(reading.option)}`;\n case \"argument\":\n return \"an argument\";\n case \"unknown\":\n return \"an option that doesn't exist\";\n }\n}\n\n/** Whether the parser read a token as `option` alone. */\nfunction readsAs(reading: TokenReading, option: Option): boolean {\n return reading.kind === \"options\" && reading.options.length === 1 && reading.options[0] === option;\n}\n\n/**\n * The tokens that reach the last command on `path`, using each command's first\n * name. {@link assertNamesReadBack} checks subcommand names from the root down\n * before options, so each of these is a name the parser reads.\n */\nfunction tokensTo(path: readonly Subcommand[]): string[] {\n return path.slice(1).map((command) => makeArray(command.name)[0]);\n}\n\n/**\n * A value for writing options with at the last command on `path`. No name\n * there starts with it, or with it after '-' or '+', so the parser can only\n * read it as a value.\n */\nfunction placeholderValue(path: readonly Subcommand[], scope: CommandScope): string {\n const names = [\n ...[...scope.local, ...scope.persistent].flatMap((option) => makeArray(option.name)),\n ...makeArray(path[path.length - 1].subcommands).flatMap((command) => makeArray(command.name)),\n ];\n for (const value of \"0123456789abcdefghijklmnopqrstuvwxyz\") {\n const starts = [value, `-${value}`, `+${value}`];\n if (!names.some((name) => starts.some((start) => name.startsWith(start)))) {\n return value;\n }\n }\n return \"0\";\n}\n\n/**\n * The tokens that write `form` with every value `option` takes, or one more\n * than its minimum if it takes any number. The first value is joined to the\n * name if the form says so, and the rest are separate tokens.\n */\nfunction writeForm(option: Option, form: OptionForm, value: string): string[] {\n const max = getMaxArgs(option.args);\n const count = Number.isFinite(max) ? max : getMinArgs(option.args) + 1;\n const values: string[] = Array.from({ length: count }, () => value);\n if (form.join === null) {\n return [form.name, ...values];\n }\n return [form.name + form.join + values[0], ...values.slice(1)];\n}\n\n/**\n * Asserts that the parser reads each name of the options that `include`\n * picks the way the name is written. See {@link assertNamesReadBack}.\n */\nfunction assertOptionFormsReadBack(spec: Subcommand, include: (option: Option, name: string) => boolean) {\n const root = spec as Spec;\n forEachOption(spec, ({ option, where, scope, path }) => {\n const before = tokensTo(path);\n const value = placeholderValue(path, scope);\n // A name that another option shadows is that option's to check.\n const names = makeArray(option.name).filter((name) => scope.resolve(name) === option);\n for (const form of scope.forms(option, names)) {\n if (!include(option, form.name)) {\n continue;\n }\n const tokens = writeForm(option, form, value);\n const reader = tokenReader(root);\n for (const token of before) {\n reader.read(token);\n }\n const first = reader.read(tokens[0]);\n // A name joined to its value with nothing between isn't a token by itself.\n if (form.join !== \"\") {\n // Without a join, the first token is the name.\n const reading = form.join === null ? first : readToken(root, before, form.name);\n assert(\n readsAs(reading, option),\n `${where} has the name '${form.name}', but the parser reads it as ${describeReading(reading, path)}`,\n );\n }\n const written = `${where} is written '${optionToString(option, [form])}'`;\n if (form.join) {\n assert(\n scope.readsSeparator(form.join),\n `${written}, but '${form.join}' isn't one of the option arg separators there (${scope.directives.optionArgSeparators.map((separator) => `'${separator}'`).join(\", \") || \"none\"}). Add it to \\`parserDirectives.optionArgSeparators\\`.`,\n );\n }\n if (form.join !== null) {\n const joined = first.kind === \"options\" && first.attached?.option === option;\n assert(\n readsAs(first, option) && joined,\n `${written}, but the parser reads '${tokens[0]}' as ${describeReading(first, path)}${joined ? \"\" : \" without a value\"}`,\n );\n }\n for (let index = 1; index < tokens.length; index++) {\n const reading = reader.read(tokens[index]);\n assert(\n reading.kind === \"value\" && reading.option === option,\n `${written}, but in '${tokens.join(\" \")}' the parser reads '${tokens[index]}' as ${describeReading(reading, path)}`,\n );\n }\n }\n });\n}\n\n/**\n * Asserts that the parser reads every name the way it's written: each name of\n * a subcommand enters that subcommand, and each name of an option uses that\n * option, at every command the option can be used in. Each option is also\n * written the way help shows it, with every value it takes, and the parser has\n * to read all of those values as the option's.\n */\nexport function assertNamesReadBack(spec: Subcommand): void {\n const root = spec as Spec;\n forEachCommand(spec, ({ command, path }) => {\n const before = tokensTo(path);\n for (const subcommand of makeArray(command.subcommands)) {\n for (const name of makeArray(subcommand.name)) {\n const reading = readToken(root, before, name);\n if (reading.kind === \"subcommand\" && reading.command === subcommand) {\n continue;\n }\n assert(\n false,\n `${describeCommand([...path, subcommand])} has the name '${name}', but the parser reads it as ${describeReading(reading, path)}`,\n );\n }\n }\n });\n assertOptionFormsReadBack(spec, () => true);\n}\n\nexport function assertCommonOptionsArePersistent(spec: Subcommand): void {\n const failures: [string, string][] = [];\n forEachCommand(spec, ({ command, path }) => {\n if (!command.subcommands) {\n return;\n }\n // This command's options that every command below it defines too.\n let common = makeArray(command.options);\n forEachCommand(command, ({ command: below }) => {\n const keys = makeArray(below.options).map(optionKey);\n common = common.filter((option) => keys.includes(optionKey(option)));\n });\n for (const option of common) {\n const key = optionKey(option);\n if (!failures.some(([failed]) => failed === key)) {\n failures.push([key, namedArrayToString(...path, option)]);\n }\n }\n });\n assert(\n failures.length === 0,\n `The following options were also defined by all subcommands. Instead, define the option once, and use \\`isPersistent: true\\` to persist it across all subcommands.\n${failures.map(([, line]) => \" * \" + line).join(\"\\n\")}\n`,\n );\n}\n\n/**\n * Asserts that references to other options by name actually refer to options\n * that exist in scope, at every command the option can be used in\n */\nexport function assertOptionNameReferencesExist(spec: Subcommand): void {\n forEachOption(spec, ({ option, where, scope }) => {\n for (const name of makeArray(option.dependsOn)) {\n assert(\n scope.resolve(name) !== null,\n `${where} depends on an option named ${repr(name)}, which doesn't exist in its scope`,\n );\n }\n for (const name of makeArray(option.exclusiveOn)) {\n assert(\n scope.resolve(name) !== null,\n `${where} is exclusive on an option named ${repr(name)}, which doesn't exist in its scope`,\n );\n }\n });\n}\n\n/**\n * Asserts that commands that will match subcommands by prefix do not take arguments\n */\nexport function assertPrefixMatchCommandsHaveNoArguments(spec: Subcommand): void {\n forEachCommand(spec, ({ command, path, scope }) => {\n // The scope is at this command, so this is the setting that decides how\n // its own subcommands are matched.\n if (!scope.directives.subcommandsMatchUniquePrefix) {\n return;\n }\n\n assert(\n !(command.subcommands && command.args),\n `The command ${namedArrayToString(\n ...path,\n )} has at least one argument and subcommand, but matches subcommands based on unique prefixes. To fix this, use \\`parserDirectives: { subcommandsMatchUniquePrefix: false }\\``,\n );\n });\n}\n\nexport type TestNamingStyle = \"sentence\" | \"function\";\n\n/** Options that can be provided to `test` */\nexport interface TestOptions {\n /**\n * Allows options to shadow persistent options.\n *\n * This behavior may be desirable if you want to override an option on a\n * particular subcommand, but not for others.\n *\n * Be aware that this is not idiomatic.\n */\n allowShadowingPersistentOptions?: boolean;\n\n /**\n * Allows subcommands and options to not have a description\n */\n allowNoDescription?: boolean;\n\n /**\n * Allows descriptions to have lines over 68 characters long\n */\n allowLongDescriptionLines?: boolean;\n\n /**\n * Allow commands to have `parserDirectives.subcommandsMatchUniquePrefix` with args\n *\n * This is not allowed by default because it's probably a mistake. It makes\n * arguments ambiguous, users may not know if their invocation will run a\n * subcommand or the command.\n */\n allowMatchingSubcommandPrefixAndArgs?: boolean;\n\n /**\n * Change the naming style of the tests.\n *\n * - `sentence`: Use proper sentence casing, punctuation, etc\n * - `function`: Use the name of the assert function that will be executed\n */\n namingStyle?: TestNamingStyle;\n}\n\nexport interface TestContextLike {\n step(name: string, fn: () => unknown | Promise<unknown>): unknown | Promise<unknown>;\n}\n\nasync function runStep(\n context: TestContextLike | undefined,\n name: string,\n fn: () => unknown | Promise<unknown>,\n): Promise<void> {\n if (context) {\n await context.step(name, fn);\n return;\n }\n await fn();\n}\n\n/**\n * Validate your CLI in your test suite\n *\n * This enforces certain constraints that the type system cannot. The parser\n * may ignore these issues, producing correct output that _appears_ to be\n * wrong.\n */\nexport function test(spec: Subcommand, options: TestOptions = {}): (t?: TestContextLike) => Promise<void> {\n const {\n allowShadowingPersistentOptions = false,\n allowNoDescription = false,\n allowLongDescriptionLines = false,\n allowMatchingSubcommandPrefixAndArgs = false,\n namingStyle = \"sentence\",\n } = options;\n const checks: [\n sentence: string,\n functionName: string,\n check: (spec: Subcommand) => void,\n enabled: boolean,\n ][] = [\n [\n \"Required arguments don't follow optional arguments\",\n \"assertRequiredArgumentsDoNotFollowOptionalArguments\",\n assertRequiredArgumentsDoNotFollowOptionalArguments,\n true,\n ],\n [\"The parser can use every default\", \"assertDefaultsCanBeUsed\", assertDefaultsCanBeUsed, true],\n [\n \"Repeatable options that are numbers are integers greater than 1\",\n \"assertRepeatableOptionsArePositiveIntegers\",\n assertRepeatableOptionsArePositiveIntegers,\n true,\n ],\n [\n \"Options have locally unique names\",\n \"assertOptionsHaveLocallyUniqueNames\",\n assertOptionsHaveLocallyUniqueNames,\n true,\n ],\n [\n \"Options don't shadow persistent options\",\n \"assertOptionsDoNotShadowPersistentOptions\",\n assertOptionsDoNotShadowPersistentOptions,\n !allowShadowingPersistentOptions,\n ],\n [\n \"Different options on a subcommand and its parents have different names\",\n \"assertOptionsHaveDifferentNamesFromParents\",\n assertOptionsHaveDifferentNamesFromParents,\n true,\n ],\n [\n \"Subcommands have locally unique names\",\n \"assertSubcommandsHaveLocallyUniqueNames\",\n assertSubcommandsHaveLocallyUniqueNames,\n true,\n ],\n [\n \"The parser reads every option and subcommand the way it's written\",\n \"assertNamesReadBack\",\n assertNamesReadBack,\n true,\n ],\n [\n \"Option arg separators are not an empty string\",\n \"assertOptionArgSeparatorsHaveCharacters\",\n assertOptionArgSeparatorsHaveCharacters,\n true,\n ],\n [\n \"Names have no extra leading or trailing whitespace\",\n \"assertNamesHaveNoExtraWhitespace\",\n assertNamesHaveNoExtraWhitespace,\n true,\n ],\n [\n \"Everything has a description\",\n \"assertEverythingHasDescription\",\n assertEverythingHasDescription,\n !allowNoDescription,\n ],\n [\n \"Each line in descriptions is less than or equal to 68 characters\",\n \"assertDescriptionLineLengthUnder69\",\n assertDescriptionLineLengthUnder69,\n !allowLongDescriptionLines,\n ],\n [\n \"Common options are not defined on every subcommand\",\n \"assertCommonOptionsArePersistent\",\n assertCommonOptionsArePersistent,\n true,\n ],\n [\n \"References to other options by name are valid\",\n \"assertOptionNameReferencesExist\",\n assertOptionNameReferencesExist,\n true,\n ],\n [\n \"Commands with `subcommandsMatchUniquePrefix` don't have arguments and subcommands\",\n \"assertPrefixMatchCommandsHaveNoArguments\",\n assertPrefixMatchCommandsHaveNoArguments,\n !allowMatchingSubcommandPrefixAndArgs,\n ],\n ];\n return async (t) => {\n for (const [sentence, functionName, check, enabled] of checks) {\n if (!enabled) {\n continue;\n }\n await runStep(t, namingStyle === \"function\" ? functionName : sentence, () => check(spec));\n }\n };\n}\n\nexport const testSpec = test;\n"],"mappings":";AAEA,SAAgB,QAAW,GAAwC;CACjE,OAAO,MAAM,QAAQ,CAAC;AACxB;;AAGA,SAAgB,UAAa,OAA0C;CACrE,IAAI,UAAU,KAAA,GACZ,OAAO,CAAC;CAEV,IAAI,QAAQ,KAAK,GACf,OAAO,MAAM,MAAM;CAErB,OAAO,CAAC,KAAK;AACf;;;;;;AAOA,SAAgB,QAAW,OAAmD;CAC5E,IAAI,UAAU,KAAA,GACZ,OAAO,CAAC;CAEV,IAAI,QAAQ,KAAK,GACf,OAAO;CAET,OAAO,CAAC,KAAK;AACf;AAWA,SAAgB,OAAO,MAAe,MAAM,IAAkB;CAC5D,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,GAAG;AAEvB;AAcA,MAAM,cAAe,WAAyC;;;;;;;;;AAU9D,SAAS,QAAQ,IAAW,MAAoB;CAC9C,MAAM,KAAK,aAAa,mBAAmB,SAAS;CACpD,IAAI,CAAC,IAAI;EACP,CAAC,OAAO,IAAI,QAAQ,MAAM,QAAQ,MAAA,CAAO,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI,IAAI;EACvF;CACF;CACA,MAAM,QAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,IAAI;CAC3C,IAAI,SAAS;CACb,IAAI;EACF,OAAO,SAAS,MAAM,QACpB,UAAU,GAAG,UAAU,IAAI,OAAO,QAAQ,MAAM,SAAS,MAAM;CAEnE,SAAS,OAAO;EAGd,IAFc,MAA4B,SAE7B,UACX,CAAC,OAAO,IAAI,aAAa,SAAS,aAAa,OAAA,EAAS,MAAM,MAAM,SAAS,MAAM,CAAC;CAIxF;AACF;;;;;;AAOA,MAAa,SAAuD,EAAE,OAAO,QAAQ;;AAGrF,SAAgB,MAAM,MAAoB;CACxC,OAAO,MAAM,GAAG,GAAG,KAAK,QAAQ,EAAE,GAAG;AACvC;;;;;;AAcA,SAAgB,YAAY,QAAkB,MAAsB,OAAO,GAAS;CAClF,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,QAAQ,KAAK;EACvC,MAAM,QAAQ,KAAK,EAAE,CAAC;EACtB,IAAI,UAAU,KAAA,GACZ;EAEF,OAAO,KAAK,KAAK;CACnB;AACF;;;;;;;AAQA,SAAgB,WACd,MACQ;CACR,IAAI,SAAS,KAAA,GACX,OAAO;CAET,IAAI,CAAC,QAAQ,IAAI,GACf,OAAO,KAAK,aAAa,IAAI;CAE/B,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,IAAI,KAAK,EAAE,CAAC,YACV;EAEF;CACF;CACA,OAAO;AACT;;AAGA,SAAgB,WACd,MACQ;CACR,IAAI,SAAS,KAAA,GACX,OAAO;CAET,IAAI,CAAC,QAAQ,IAAI,GACf,OAAO,KAAK,aAAa,WAAW;CAKtC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAC/B,IAAI,KAAK,KAAK,SAAS,IAAI,EAAE,CAAC,YAC5B,OAAO;CAIX,OAAO,KAAK;AACd;;;AC/JA,SAAgB,oBAAgC;CAC9C,OAAO;EACL,qBAAqB,CAAC,GAAG;EACzB,2BAA2B;EAC3B,6BAA6B;EAC7B,8BAA8B;CAChC;AACF;;;;;AAMA,SAAgB,gBAAgB,YAAwB,SAAkC;CACxF,MAAM,aAAa,QAAQ;CAC3B,IAAI,CAAC,YACH;CAEF,IAAI,WAAW,qBACb,WAAW,sBAAsB,QAAQ,WAAW,mBAAmB;CAEzE,IAAI,OAAO,WAAW,iCAAiC,WACrD,WAAW,+BAA+B,WAAW;CAEvD,IAAI,OAAO,WAAW,gCAAgC,WACpD,WAAW,8BAA8B,WAAW;CAEtD,IAAI,OAAO,WAAW,8BAA8B,WAClD,WAAW,4BAA4B,WAAW;AAEtD;;;;;;AClCA,IAAa,eAAb,MAA0B;CAQL;CACA;CACA;CATnB,UAAmB;;;;;CAMnB,YACE,aACA,OACA,UACA;EAHiB,KAAA,cAAA;EACA,KAAA,QAAA;EACA,KAAA,WAAA;CAChB;;CAGH,SAAuD;EACrD,MAAM,QAAQ,KAAK;EACnB,IAAI,UAAU,IACZ,OAAO,EAAE,SAAS,8CAA8C;EAElE,IAAI,KAAK,SAAS,SAAS,GAIzB,OAAO,EAAE,SAAS,sBAAsB,MAAM,eAH7B,KAAK,SAAS,SAAS,YACtC,QAAQ,QAAQ,IAAI,CAAC,CAAC,QAAQ,SAAS,KAAK,WAAW,KAAK,CAAC,CAEK,CAAC,CAAC,KAAK,IAAI,IAAI;EAErF,MAAM,UAAU,mBAAmB,KAAK,WAAW,CAAC,CAAC,KAAK,YAAY,QAAQ,QAAQ,IAAI,CAAC;EAC3F,OAAO;GAAE,SAAS,oBAAoB,MAAM;GAAI,YAAY;IAAE,OAAO;IAAO;GAAQ;EAAE;CACxF;AACF;;AAGA,SAAgB,mBAAmB,aAA8D;CAC/F,OAAO,aAAa,QAAQ,eAAe,CAAC,WAAW,MAAM,KAAK,CAAC;AACrE;;AAGA,MAAa,SAAiB,EAAE,WAAW;CACzC,MAAM,KAAK,CAAC;CACZ,OAAO;AACT;;;;;;;;;;;;;ACAA,IAAa,eAAb,MAAa,aAAa;;CAExB,QAA2B,CAAC;;CAE5B,aAAgC,CAAC;;;;;CAKjC,uBAA8C,CAAC;;CAE/C,aAAkC,kBAAkB;CACpD,UAA4C;;CAE5C,UAAU;;CAEV,UAAU;;CAGV,OAAO,GAAG,MAAoD;EAC5D,MAAM,QAAQ,IAAI,aAAa;EAC/B,KAAK,MAAM,WAAW,MACpB,MAAM,MAAM,OAAO;EAErB,OAAO;CACT;;CAGA,MAAM,SAAkC;EACtC,MAAM,oBAAoB,KAAK,SAAS;EACxC,IAAI,mBAAmB;GACrB,MAAM,aAAa,kBAAkB,QAAQ,eAAe,WAAW,YAAY;GACnF,IAAI,WAAW,SAAS,GACtB,KAAK,qBAAqB,QAAQ,GAAG,UAAU;EAEnD;EACA,KAAK,UAAU;EACf,KAAK,UAAU,WAAW,QAAQ,IAAI;EACtC,KAAK,UAAU,WAAW,QAAQ,IAAI;EACtC,KAAK,MAAM,SAAS;EACpB,IAAI,QAAQ,SACV,KAAK,MAAM,UAAU,QAAQ,SAC3B,CAAC,OAAO,eAAe,KAAK,aAAa,KAAK,MAAA,CAAO,KAAK,MAAM;EAGpE,gBAAgB,KAAK,YAAY,OAAO;CAC1C;;CAGA,IAAI,UAA6B;EAC/B,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,MAAM,oCAAoC;EAEtD,OAAO,KAAK;CACd;;CAGA,IAAI,iBAA0B;EAC5B,OAAO,KAAK,SAAS,gBAAgB,KAAA,KAAa,KAAK,qBAAqB,SAAS;CACvF;;;;;;CAOA,cAAqC;EACnC,MAAM,MAAM,KAAK,SAAS,eAAe,CAAC;EAC1C,IAAI,KAAK,qBAAqB,WAAW,GACvC,OAAO;EAET,MAAM,MAAM,CAAC,GAAG,GAAG;EACnB,KAAK,MAAM,aAAa,KAAK,sBAC3B,IAAI,CAAC,QAAQ,UAAU,IAAI,CAAC,CAAC,MAAM,SAAS,IAAI,MAAM,YAAY,QAAQ,QAAQ,MAAM,IAAI,CAAC,CAAC,GAC5F,IAAI,KAAK,SAAS;EAGtB,OAAO;CACT;;;;;;;;;;CAWA,gBAAgB,OAAe,YAAY,OAAwB;EACjE,MAAM,MAAM,KAAK,SAAS,eAAe,CAAC;EAC1C,KAAK,MAAM,aAAa,KACtB,IAAI,QAAQ,UAAU,MAAM,KAAK,GAC/B,OAAO,EAAE,SAAS,UAAU;EAGhC,KAAK,MAAM,aAAa,KAAK,sBAC3B,IAAI,QAAQ,UAAU,MAAM,KAAK,GAC/B,OAAO,EAAE,SAAS,UAAU;EAIhC,MAAM,UADc,KAAK,WAAW,gCAAgC,CAAC,YACvC,cAAc,KAAK,KAAK,IAAI,CAAC;EAC3D,IAAI,QAAQ,WAAW,GACrB,OAAO,EAAE,SAAS,QAAQ,GAAG;EAE/B,OAAO,IAAI,aAAa,KAAK,YAAY,GAAG,OAAO,OAAO;CAC5D;;CAGA,QAAQ,MAA6B;EACnC,MAAM,EAAE,OAAO,eAAe;EAC9B,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KACrC,IAAI,QAAQ,MAAM,EAAE,CAAC,MAAM,IAAI,GAC7B,OAAO,MAAM;EAGjB,KAAK,IAAI,IAAI,WAAW,SAAS,GAAG,KAAK,GAAG,KAC1C,IAAI,QAAQ,WAAW,EAAE,CAAC,MAAM,IAAI,GAClC,OAAO,WAAW;EAGtB,OAAO;CACT;;;;;;;CAQA,KAAK,cAAyC,MAG5C;EAGA,MAAM,wBAAQ,IAAI,IAAoB;EACtC,KAAK,MAAM,WAAW,CAAC,KAAK,YAAY,KAAK,KAAK,GAChD,KAAK,MAAM,UAAU,SACnB,KAAK,MAAM,QAAQ,QAAQ,OAAO,IAAI,GACpC,MAAM,IAAI,MAAM,MAAM;EAI5B,MAAM,QAAQ,YAA+B;GAC3C,MAAM,SAA0B,CAAC;GACjC,KAAK,MAAM,UAAU,SAAS;IAC5B,MAAM,QAAQ,QAAQ,OAAO,IAAI,CAAC,CAAC,QAChC,SACC,MAAM,IAAI,IAAI,MAAM,UACpB,EAAE,eAAe,KAAK,gBAAgB,MAAM,YAAY,SAAS,CAAC,CAAC,QACvE;IACA,IAAI,MAAM,SAAS,GACjB,OAAO,KAAK;KAAE;KAAQ;IAAM,CAAC;GAEjC;GACA,OAAO;EACT;EACA,OAAO;GAAE,OAAO,KAAK,KAAK,KAAK;GAAG,YAAY,KAAK,KAAK,UAAU;EAAE;CACtE;;;;;CAMA,UAAmE;EACjE,MAAM,EAAE,OAAO,eAAe,KAAK,KAAK,KAAK,iBAAiB,EAAE,WAAW,MAAM,IAAI,IAAI;EACzF,MAAM,SAAS,YAA2B,CAAC,QAAQ,OAAO;EAC1D,OAAO;GAAE,OAAO,MAAM,OAAO,KAAK;GAAG,YAAY,WAAW,OAAO,KAAK;EAAE;CAC5E;;CAGA,kBAA8B;EAC5B,MAAM,EAAE,OAAO,eAAe,KAAK,KAAK;EACxC,MAAM,SAAS,YAA2B,CAAC,QAAQ,OAAO;EAC1D,OAAO,CAAC,GAAG,OAAO,GAAG,UAAU,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,YAAY,QAAQ,KAAK;CAC/E;;CAGA,WAAqB;EACnB,OAAO,CAAC,GAAG,KAAK,OAAO,GAAG,KAAK,UAAU,CAAC,CAAC,QAAQ,WAAW,OAAO,UAAU;CACjF;;;;;;CAeA,MAAM,QAAgB,QAA2B,QAAQ,OAAO,IAAI,GAAiB;EACnF,MAAM,QAAQ,SAAgC;GAC5C,IAAI,WAAW,OAAO,IAAI,MAAM,GAC9B,OAAO;GAET,IAAI,OAAO,mBACT,OAAO,KAAK,kBAAkB,MAAM;GAGtC,OADc,CAAC,KAAK,WAAW,8BAA8B,SAAS,OAAO,SAAS,OACvE,KAAK;EACtB;EACA,OAAO,MAAM,KAAK,UAAU;GAAE;GAAM,MAAM,KAAK,IAAI;EAAE,EAAE;CACzD;;;;;CAMA,kBAAkB,QAA+B;EAC/C,MAAM,WAAW,OAAO;EACxB,IAAI,OAAO,aAAa,UACtB,OAAO;EAET,OAAO,WAAY,KAAK,WAAW,oBAAoB,MAAM,MAAO;CACtE;;CAGA,eAAe,WAA4B;EACzC,OAAO,KAAK,WAAW,oBAAoB,SAAS,SAAS;CAC/D;;CAGA,iBAAiB,MAAsB;EACrC,KAAK,MAAM,aAAa,KAAK,WAAW,qBACtC,IAAI,KAAK,WAAW,SAAS,GAC3B,OAAO;EAGX,OAAO;CACT;;;;;;CAOA,eAAe,OAA4D;EACzE,IAAI,QAAQ;EACZ,IAAI,QAAQ;EACZ,KAAK,MAAM,aAAa,KAAK,WAAW,qBAAqB;GAC3D,MAAM,KAAK,MAAM,QAAQ,SAAS;GAClC,IAAI,OAAO,IACT;GAEF,IAAI,UAAU,MAAM,KAAK,SAAU,OAAO,SAAS,UAAU,SAAS,MAAM,QAAS;IACnF,QAAQ;IACR,QAAQ;GACV;EACF;EACA,OAAO,QAAQ;GAAE;GAAO,WAAW;EAAM,IAAI;CAC/C;;;;;CAMA,iBAAiB,QAAgB,MAAc,WAAkC;EAC/E,MAAM,WAAW,OAAO;EACxB,IAAI,OAAO,aAAa,YAAY,cAAc,UAChD,OAAO,6BAA6B,SAAS,gBAAgB,UAAU;EAEzE,IAAI,aAAa,QAAQ,cAAc,IACrC,OAAO,2BAA2B,KAAK,kBAAkB,MAAM,EAAE,YAAY,KAAK;EAEpF,OAAO;CACT;AACF;AAEA,MAAM,6BAAa,IAAI,QAAwB;;;;;;;;;AAU/C,SAAgB,UAAU,QAAwB;CAChD,IAAI,MAAM,WAAW,IAAI,MAAM;CAC/B,IAAI,QAAQ,KAAA,GAAW;EACrB,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI;EACvF,WAAW,IAAI,QAAQ,GAAG;CAC5B;CACA,OAAO;AACT;AAEA,SAAS,QAAQ,OAAmC,MAAuB;CACzE,OAAO,OAAO,UAAU,WAAW,UAAU,OAAO,MAAM,SAAS,IAAI;AACzE;;AAGA,SAAS,cAAc,aAAoC,OAA6B;CACtF,IAAI,UAAU,IACZ,OAAO,CAAC;CAEV,OAAO,YAAY,QAChB,cAAc,CAAC,UAAU,UAAU,QAAQ,UAAU,IAAI,CAAC,CAAC,MAAM,SAAS,KAAK,WAAW,KAAK,CAAC,CACnG;AACF;;;;;;ACpCA,SAAgB,eAAe,QAAgB,OAAsC;CACnF,MAAM,aAAa,UAAU,OAAO,IAAI;CACxC,MAAM,SAAS,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK,SAAS,EAAE,KAAK,MAAM;CAEtE,OAAO,CADQ,GAAG,IAAI,IAAI,OAAO,KAAK,SAAS,KAAK,IAAI,CAAC,CAC9C,CAAC,CACT,KAAK,SAAS;EAEb,OADc,OAAO,QAAQ,SAAS,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,SAAS,KAAK,IAClE,CAAC,CAAC,KAAK,IAAI,IAAI,mBAAmB,YAAY,IAAI;CAC/D,CAAC,CAAC,CACD,KAAK,IAAI;AACd;;AAGA,SAAS,mBAAmB,MAAa,MAA6B;CACpE,IAAI,KAAK,WAAW,GAClB,OAAO;CAET,IAAI,SAAS,MACX,OAAO,IAAI,mBAAmB,IAAI;CAEpC,MAAM,CAAC,OAAO,GAAG,QAAQ;CACzB,MAAM,OAAO,MAAM,QAAQ;CAC3B,MAAM,UACH,MAAM,aAAa,IAAI,OAAO,KAAK,KAAK,GAAG,KAAK,GAAG,KAAK,OAAO,MAAM,aAAa,QAAQ;CAC7F,OAAO,KAAK,SAAS,IAAI,GAAG,OAAO,GAAG,mBAAmB,IAAI,MAAM;AACrE;AAEA,SAAgB,mBAAmB,MAAa;CAC9C,OAAO,KAAK,KAAK,QAAQ,YAAY,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG;AACrD;AAEA,SAAgB,YAAY,KAAkB;CAC5C,MAAM,OAAO,IAAI,QAAQ;CACzB,IAAI,MAAM;CACV,IAAI,MAAM;CACV,IAAI,SAAS;CACb,IAAI,IAAI,YAAY;EAClB,MAAM;EACN,MAAM;CACR;CACA,IAAI,IAAI,YACN,SAAS;CAEX,OAAO,GAAG,MAAM,OAAO,MAAM;AAC/B;;ACtWA,MAAMA,SAAO,KAAK;;;;;;AAiBlB,IAAa,aAAb,cAAgC,MAAM;CACpC;CACA;CACA,YAAY,SAAuB,SAAiB,YAAyB;EAC3E,MAAM,OAAO;EACb,KAAK,UAAU;EACf,KAAK,aAAa;EAClB,KAAK,OAAO,KAAK,YAAY;CAC/B;AACF;AAEA,IAAa,gBAAb,cAAmC,WAAW;CAC5C;CACA,YAAY,QAAgB,cAAiC,SAAuB;EAClF,MAAM,MAAM,GAAGA,OAAK,MAAM,EAAE;EAC5B,MAAM,SAAS,KAAK;GAAE,OAAO;GAAQ,SAAS;EAAa,CAAC;EAC5D,KAAK,SAAS;CAChB;AACF;AAEA,IAAa,mBAAb,cAAsC,WAAW;CAC/C;CACA,YAAY,QAAgB,SAAuB;EACjD,MAAM,SAAS,UAAU,OAAO,wBAAwB;EACxD,KAAK,SAAS;CAChB;AACF;AAEA,IAAa,mBAAb,cAAsC,WAAW;CAC/C,YAAY,OAAe,SAAuB;EAChD,MAAM,SAAS,uBAAuBA,OAAK,KAAK,EAAE,gBAAgB;CACpE;AACF;AAEA,IAAa,wBAAb,cAA2C,WAAW;CACpD,YAAY,QAAgB,KAAa,KAAa,SAAuB;EAC3E,MAAM,MACJ,QAAQ,MACJ,UAAU,OAAO,SAAS,IAAI,WAAW,QAAQ,IAAI,KAAK,QAC1D,CAAC,OAAO,SAAS,GAAG,IAClB,UAAU,OAAO,kBAAkB,IAAI,WAAW,QAAQ,IAAI,KAAK,QACnE,UAAU,OAAO,iBAAiB,IAAI,OAAO,IAAI;EACzD,MAAM,SAAS,GAAG;CACpB;AACF;AAEA,IAAa,kBAAb,cAAqC,WAAW;CAC9C,YAAY,KAAa,KAAa,SAAuB;EAC3D,MAAM,MACJ,QAAQ,MACJ,YAAY,IAAI,WAAW,QAAQ,IAAI,KAAK,QAC5C,CAAC,OAAO,SAAS,GAAG,IAClB,qBAAqB,IAAI,WAAW,QAAQ,IAAI,KAAK,QACrD,oBAAoB,IAAI,OAAO,IAAI;EAC3C,MAAM,SAAS,GAAG;CACpB;AACF;AAEA,IAAa,wBAAb,cAA2C,WAAW;CACpD,YAAY,MAAc,SAAuB;EAC/C,MAAM,MAAM,UAAU,KAAK;EAC3B,MAAM,SAAS,GAAG;CACpB;AACF;;;AC8BA,SAAS,YAAY,QAAwB;CAC3C,OAAO,OAAO,OAAO,iBAAiB,WAAW,OAAO,eAAe;AACzE;;;;;AAMA,SAAS,iBACP,SACA,aACA,UACA,SACM;CACN,KAAK,MAAM,UAAU,aAAa;EAChC,IAAI,CAAC,OAAO,WACV;EAEF,KAAK,MAAM,QAAQ,OAAO,WACxB,IAAI,CAAC,QAAQ,IAAI,IAAI,GACnB,MAAM,IAAI,WACR,SACA,GAAG,QAAQ,OAAO,IAAI,CAAC,CAAC,KAAK,GAAG,EAAE,YAAY,KAAK,2BACrD;CAGN;CACA,KAAK,MAAM,UAAU,aAAa;EAChC,IAAI,CAAC,OAAO,aACV;EAEF,KAAK,MAAM,QAAQ,OAAO,aACxB,IAAI,QAAQ,IAAI,IAAI,GAClB,MAAM,IAAI,WACR,SACA,GAAG,QAAQ,OAAO,IAAI,CAAC,CAAC,KAAK,GAAG,EAAE,+BAA+B,MACnE;CAGN;CACA,KAAK,MAAM,UAAU,UACnB,KAAK,MAAM,QAAQ,QAAQ,OAAO,IAAI,GACpC,IAAI,CAAC,QAAQ,IAAI,IAAI,GACnB,MAAM,IAAI,sBAAsB,MAAM,OAAO;AAIrD;;;;;;;;;AAgBA,IAAM,UAAN,MAAqC;CACnC;CAEA,eAA2C,KAAA;CAC3C,OAAkC,CAAC;CACnC,0BAAkD,IAAI,IAAI;CAC1D,cAAyC,CAAC;CAC1C,oBAA4B;CAG5B,QAAuC,IAAI,aAAa;CACxD,aAA0C,KAAK,MAAM;CAErD,cAAsB;CAMtB,aAAoC;CACpC,iBAAyB;CACzB,aAAqB;CACrB,WAAmB;CACnB,mBAA2B;CAM3B,SAAkC;CAClC,cAAsB;CACtB,YAAoB;CACpB,YAAoB;CACpB,YAAoC,CAAC;;;;;;CAOrC,UAAqC;CAKrC,cAAiD;CAMjD,+BAA2D,IAAI,IAAI;CAEnE,YAAY,MAAY;EACtB,KAAK,OAAO,CAAC,IAAI;EACjB,KAAK,MAAM,MAAM,IAAI;CACvB;CAIA,MAA4B;EAC1B,OAAO,EAAE,MAAM,CAAC,GAAG,KAAK,IAAI,EAAE;CAChC;;CAGA,IAAY,kBAA2B;EACrC,OAAO,KAAK,aAAa,KAAK;CAChC;CAEA,WAAmB,MAA6B;EAC9C,OAAO,KAAK,MAAM,QAAQ,IAAI;CAChC;;;;;;CAOA,KAAa,MAA+C;EAC1D,IAAI,CAAC,KAAK,SAAS;GACjB,MAAM,MAAM,KAAK,IAAI;GACrB,KAAK,gBAAgB,KAAK,GAAG;EAC/B;CACF;;CAGA,SAAiB,MAA+C;EAC9D,IAAI,CAAC,KAAK,aAAa;GACrB,MAAM,MAAM,KAAK,IAAI;GACrB,KAAK,oBAAoB,KAAK,GAAG;EACnC;CACF;CAEA,cAAsB,QAAsB;EAC1C,IAAI,CAAC,KAAK,SAAS;GACjB,MAAM,QAAQ,KAAK,MAAM,gBAAgB;GACzC,KAAK,MAAM,QAAQ,IAAI,cAAc,QAAQ,OAAO,GAAG,CAAC;EAC1D;CACF;CAKA,YAA0B;EACxB,MAAM,SAAS,KAAK;EACpB,IAAI,QAAQ;GACV,MAAM,QAAQ,OAAO,SAAS,KAAK;GACnC,IAAI,QAAQ,KAAK,WAAW;IAC1B,MAAM,EAAE,gBAAgB,WAAW,cAAc;IACjD,KAAK,MAAM,QAAQ,IAAI,sBAAsB,gBAAgB,WAAW,WAAW,GAAG,CAAC;GACzF,OACE,YAAY,QAAQ,KAAK,WAAW,KAAK;EAE7C;EACA,KAAK,SAAS;CAChB;;CAGA,cAA4B;EAC1B,KAAK,UAAU;EACf,KAAK,aAAa;EAClB,KAAK,aAAa,KAAK,WAAW,KAAK,mBAAmB;CAC5D;CAEA,UAAkB,QAAgB,MAAoB;EACpD,KAAK,UAAU;EACf,KAAK,aAAa;EAClB,KAAK,iBAAiB;EACtB,KAAK,aAAa;EAClB,KAAK,WAAW,WAAW,OAAO,IAAI;EAEtC,KAAK,mBAAmB,OAAO,oBAAoB,IAAI,WAAW,OAAO,IAAI;EAC7E,KAAK,YAAY,KAAK,MAAM;EAC5B,IAAI,OAAO,QACT,KAAK,eAAe,OAAO;EAE7B,MAAM,QAAQ,QAAQ,OAAO,IAAI;EACjC,MAAM,UAAU,KAAK;EAErB,IAAI;EACJ,IAAI,OAAO,cAAc;GAGvB,MAAM,MAAM,UAAU,MAAM;GAC5B,IAAI,OAAO,KAAK,aAAa,IAAI,GAAG;GACpC,IAAI,CAAC,MAAM;IACT,OAAO;KAAE,QAAQ,CAAC;KAAG,OAAO;IAAE;IAC9B,KAAK,aAAa,IAAI,KAAK,IAAI;GACjC;GACA,IAAI,KAAK,SAAS,YAAY,MAAM,GAClC,KAAK,MAAM,QAAQ,IAAI,WAAW,KAAK,sBAAsB,CAAC;GAEhE,KAAK,SAAS;GAEd,KAAK,MAAM,SAAS,OAClB,QAAQ,IAAI,OAAO,KAAK,MAAM;GAEhC,IAAI,CAAC,OAAO,MAAM;IAChB,KAAK,OAAO,KAAK,EAAE;IACnB;GACF;GACA,eAAe,KAAK;EACtB,OAAO;GAGL,eAAe,CAAC;GAChB,KAAK,MAAM,SAAS,OAClB,QAAQ,IAAI,OAAO,YAAY;EAEnC;EAEA,KAAK,YAAY,KAAK;EACtB,KAAK,YAAY,WAAW,OAAO,IAAI;EACvC,IAAI,KAAK,YAAY,GAAG;GACtB,KAAK,SAAS;GACd,KAAK,cAAc,aAAa;GAChC,KAAK,YAAY,QAAQ,OAAO,IAAI;EACtC;CACF;;CAGA,SAAiB,OAAe,WAA4B;EAC1D,KAAK,cAAc;EACnB,IAAI,CAAC,KAAK,QAAQ;GAChB,MAAM,OAAO,KAAK;GAClB,KAAK,MAAM,QAAQ,IAAI,iBAAiB,MAAM,GAAG,CAAC;GAClD,OAAO;EACT;EACA,MAAM,UAAU,KAAK,MAAM,iBAAiB,KAAK,YAAa,KAAK,gBAAgB,SAAS;EAC5F,IAAI,SACF,KAAK,MAAM,QAAQ,IAAI,WAAW,KAAK,OAAO,CAAC;EAEjD,KAAK,OAAO,KAAK,KAAK;EACtB,OAAO,YAAY;CACrB;;CAGA,MAAc,OAA6B;EACzC,KAAK,SAAS,OAAO,EAAE;EACvB,OAAO;GAAE,MAAM;GAAS,QAAQ,KAAK;EAAY;CACnD;;;;;;CAOA,iBACE,OACA,OACA,WAC0C;EAC1C,MAAM,SAAS,KAAK;EACpB,MAAM,WAAW,KAAK,SAAS,OAAO,SAAS;EAC/C,KAAK,WAAW,KAAK,mBAAmB;EACxC,OAAO,WAAW;GAAE;GAAQ;EAAM,IAAI;CACxC;;;;;CAMA,IAAY,cAAuB;EACjC,OAAO,KAAK,MAAM,QAAQ,uBAAuB,QAAQ,KAAK,KAAK,UAAU,KAAK,MAAM;CAC1F;CAEA,OAAe,OAA6B;EAC1C,KAAK,UAAU;EACf,IAAI,KAAK,aACP,KAAK,UAAU,QAAQ,IAAI,iBAAiB,OAAO,GAAG,CAAC;EAEzD,KAAK,KAAK,KAAK,KAAK;EACpB,OAAO,EAAE,MAAM,WAAW;CAC5B;;CAGA,eAAqC;EACnC,KAAK,YAAY;EAGjB,MAAM,UAAU,KAAK,MAAM;EAC3B,IAAI,KAAK,eAAe,CAAC,QAAQ,oBAC/B,KAAK,UACF,QAAQ,IAAI,WAAW,KAAK,kEAAkE,CACjG;EAEF,KAAK,oBAAoB,KAAK,KAAK;EACnC,OAAO,EAAE,MAAM,YAAY;CAC7B;;;;;;;;;CAUA,IAAY,qBAAgD;EAC1D,IAAI,KAAK,eAAe,CAAC,KAAK,MAAM,gBAClC,OAAO;EAET,IAAI,KAAK,aAAa,KAAK,YAAa,KAAK,mBAAmB,KAAK,qBAAqB,UACxF,OAAO;EAET,OAAO,EAAE,WAAW,KAAK,gBAAgB;CAC3C;;;;;CAMA,cAAsB,OAAuC;EAC3D,MAAM,WAAW,KAAK;EACtB,OAAO,YAAY,KAAK,MAAM,gBAAgB,OAAO,SAAS,SAAS;CACzE;CAEA,gBAAwB,SAAmC;EACzD,KAAK,YAAY;EACjB,KAAK,KAAK,KAAK,OAAO;EACtB,KAAK,MAAM,MAAM,OAAO;EACxB,OAAO;GAAE,MAAM;GAAc;EAAQ;CACvC;;CAGA,aAAqB,OAA6B;EAChD,MAAM,cAAc,MAAM;EAO1B,MAAM,aAAa,KAAK,WAAW,WAAW;EAC9C,IAAI,YAAY,QAAQ,CAAC,KAAK,WAAW,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG;GAC3D,KAAK,UAAU,YAAY,WAAW;GACtC,MAAM,WAAW,KAAK,iBAAiB,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE;GAC5D,OAAO;IAAE,MAAM;IAAW,SAAS,CAAC,UAAU;IAAG;GAAS;EAC5D;EAGA,MAAM,OAAiB,CAAC;EACxB,IAAI,WAAqD;EACzD,KAAK,IAAI,OAAO,GAAG,OAAO,MAAM,QAAQ,QAAQ;GAC9C,MAAM,aAAa,cAAc,MAAM;GACvC,MAAM,SAAS,KAAK,WAAW,UAAU;GACzC,IAAI,CAAC,QAAQ;IAEX,IAAI,SAAS,KAAK,KAAK,iBACrB,OAAO,KAAK,MAAM,KAAK;IAEzB,KAAK,cAAc,UAAU;IAC7B;GACF;GAEA,KAAK,UAAU,QAAQ,UAAU;GACjC,KAAK,KAAK,MAAM;GAChB,IAAI,SAAS,MAAM,SAAS,GAC1B;GAGF,MAAM,MAAM,KAAK,MAAM,iBAAiB,MAAM,MAAM,OAAO,CAAC,CAAC;GAG7D,IAAI,OAAO,QAAS,OAAO,CAAC,KAAK,WAAW,cAAc,MAAM,OAAO,EAAE,GAAI;IAC3E,MAAM,WAAW,OAAO,IAAI,SAAS;IACrC,WAAW,KAAK,iBAAiB,UAAU,MAAM,MAAM,QAAQ,GAAG,GAAG;IACrE;GACF;EACF;EACA,OAAO,KAAK,SAAS,IAAI;GAAE,MAAM;GAAW,SAAS;GAAM;EAAS,IAAI,EAAE,MAAM,UAAU;CAC5F;;;;;CAMA,WAAmB,OAAoC;EACrD,MAAM,QAAQ,KAAK,MAAM,eAAe,KAAK;EAC7C,MAAM,aAAa,QAAQ,MAAM,MAAM,GAAG,MAAM,KAAK,IAAI;EACzD,MAAM,SAAS,KAAK,WAAW,UAAU;EACzC,IAAI,QAAQ;GACV,KAAK,UAAU,QAAQ,UAAU;GACjC,IAAI,WAAqD;GACzD,IAAI,OAAO;IACT,MAAM,aAAa,MAAM,QAAQ,MAAM,UAAU;IACjD,WAAW,KAAK,iBAAiB,YAAY,MAAM,MAAM,UAAU,GAAG,MAAM,SAAS;GACvF;GACA,OAAO;IAAE,MAAM;IAAW,SAAS,CAAC,MAAM;IAAG;GAAS;EACxD;EAIA,IAAI,KAAK,WAAW,2BAClB,OAAO;EAET,IAAI,KAAK,iBACP,OAAO,KAAK,MAAM,KAAK;EAIzB,KAAK,cAAc,UAAU;EAC7B,OAAO,EAAE,MAAM,UAAU;CAC3B;;;;;;;CAQA,WAAmB,OAAe,WAA8C;EAC9E,IAAI,KAAK,iBACP,OAAO,KAAK,MAAM,KAAK;EAIzB,IAAI,aAAa,KAAK,aAAa;GACjC,MAAM,UAAU,KAAK,MAAM;GAC3B,IAAI,QAAQ,aAAa,UAAU,QAAQ,oBACzC,KAAK,UAAU,QAAQ;IACrB,MAAM,EAAE,SAAS,eAAe,UAAU,OAAO;IACjD,OAAO,IAAI,WAAW,KAAK,SAAS,UAAU;GAChD,CAAC;EAEL;EACA,KAAK,cAAc;EACnB,OAAO,KAAK,OAAO,KAAK;CAC1B;;;;;CAMA,SAAsB;EAIpB,MAAM,UAAU,KAAK,MAAM;EAC3B,MAAM,aAAa,QAAQ,sBAAsB,CAAC,QAAQ,UAAU,KAAK,KAAK,WAAW;EACzF,MAAM,cAAc,KAAK,iBAAiB,KAAA,KAAa;EACvD,IAAI,CAAC,eAAe,KAAK,aACvB,MAAM,KAAK,YAAY;EAEzB,IAAI,CAAC,eAAe,KAAK,KAAK,SAAS,KAAK,MAAM,SAChD,MAAM,IAAI,gBAAgB,KAAK,MAAM,SAAS,KAAK,MAAM,SAAS,KAAK,IAAI,CAAC;EAE9E,KAAK,UAAU;EACf,IAAI,KAAK,SACP,MAAM,KAAK,QAAQ;EAErB,IAAI,CAAC,aACH,iBAAiB,KAAK,SAAS,KAAK,aAAa,KAAK,MAAM,SAAS,GAAG,KAAK,IAAI,CAAC;EAKpF,IAAI,CAAC,QAAQ,sBAAsB,KAAK,KAAK,UAAU,KAAK,MAAM,SAChE,YAAY,KAAK,MAAM,QAAQ,QAAQ,IAAI,GAAG,KAAK,KAAK,MAAM;EAEhE,OAAO;GACL,MAAM,KAAK;GACX,QAAQ,KAAK,gBAAgB,QAAQ,UAAUC;GAC/C,MAAM,KAAK;GACX,mBAAmB,KAAK;GACxB,SAAS,KAAK;GACd,WAAW,SAAS,KAAK,SAAS,IAAI;EACxC;CACF;;CAGA,SAAiB,MAAoC;EACnD,IAAI,KAAK,QAAQ,IAAI,IAAI,GACvB;EAEF,MAAM,OAAO,QAAQ,KAAK,MAAM,QAAQ,IAAI,CAAC,EAAE,IAAI;EAInD,IAAI,KAAK,WAAW,KAAK,KAAK,EAAE,CAAC,YAC/B;EAEF,MAAM,SAAmB,CAAC;EAC1B,YAAY,QAAQ,IAAI;EACxB,OAAO,OAAO,SAAS,IAAI,SAAS,KAAA;CACtC;;CAGA,UAAkB,QAAyB;EACzC,KAAK,KAAK,aAAa,IAAI,UAAU,MAAM,CAAC,CAAC,EAAE,SAAS,MAAM,YAAY,MAAM,GAC9E,OAAO;EAET,MAAM,UAAU,KAAK;EACrB,IAAI,OAAO,aAAa,MAAM,SAAS,QAAQ,IAAI,IAAI,CAAC,GACtD,OAAO;EAET,MAAM,QAAQ,QAAQ,OAAO,IAAI;EACjC,OAAO,KAAK,YAAY,MAAM,SAAS,KAAK,aAAa,MAAM,SAAS,MAAM,SAAS,IAAI,CAAC,CAAC;CAC/F;;CAGA,gBAAwC;EACtC,MAAM,OAAO,IAAI,IAAI,KAAK,YAAY,IAAI,SAAS,CAAC;EACpD,MAAM,EAAE,OAAO,eAAe,KAAK,MAAM,KAAK,KAAK,kBAAkB;EACrE,MAAM,SAAyB,CAAC;EAChC,KAAK,MAAM,EAAE,QAAQ,WAAW,CAAC,GAAG,OAAO,GAAG,UAAU,GAAG;GACzD,IAAI,KAAK,UAAU,MAAM,GACvB;GAEF,OAAO,KAAK;IAAE;IAAQ,OAAO,KAAK,MAAM,MAAM,QAAQ,KAAK;IAAG,MAAM,KAAK,IAAI,UAAU,MAAM,CAAC;GAAE,CAAC;EACnG;EACA,OAAO;CACT;;;;;CAMA,OAAwD;EACtD,MAAM,OAAO,KAAK,cAAc,KAAK,kBAAkB,KAAK,aAAa;EACzE,MAAM,UAAU,KAAK,MAAM;EAE3B,MAAM,iBAAiB,KAAK,sBAAsB;EAClD,MAAM,iBAAiB,CAAC,kBAAkB,KAAK;EAC/C,OAAO;GACL,MAAM,CAAC,GAAG,KAAK,IAAI;GACnB,YAAY,EAAE,GAAG,KAAK,WAAW;GACjC;GACA,aAAa,CAAC,kBAAkB,KAAK,qBAAqB,KAAK,MAAM,YAAY,IAAI,CAAC;GACtF,SAAS,iBAAiB,KAAK,cAAc,IAAI,CAAC;GAClD,OAAO,QAAQ;IACb,QAAQ;IACR,KAAK,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,UAAU;IAC9C,UAAU,KAAK,aAAa,KAAK;GACnC;GACA,KAAK,OAAO,KAAA,IAAY,MAAM,QAAQ,QAAQ,IAAI,GAAG,KAAK,KAAK,MAAM;EACvE;CACF;;CAGA,IAAY,iBAA0B;EACpC,OAAO,EAAE,KAAK,WAAW,+BAA+B,KAAK;CAC/D;CAEA,KAAK,OAA6B;EAEhC,IAAI,KAAK,sBAAsB,IAC7B,OAAO,KAAK,OAAO,KAAK;EAE1B,MAAM,iBAAiB,KAAK;EAG5B,IAAI,UAAU,QAAQ,gBACpB,OAAO,KAAK,aAAa;EAG3B,MAAM,aAAa,KAAK,cAAc,KAAK;EAC3C,IAAI,YAAY,SACd,OAAO,KAAK,gBAAgB,WAAW,OAAO;EAGhD,IAAI,gBAAgB;GAClB,MAAM,4BAA4B,KAAK,WAAW;GAClD,MAAM,QAAQ,MAAM,WAAW,CAAC;GAChC,MAAM,eAAe,UAAU,MAAc,MAAM,WAAW,CAAC,MAAM;GACrE,IACE,CAAC,6BACD,MAAM,SAAS,MACd,UAAU,MAAM,UAAU,OAC3B,CAAC,cAED,OAAO,KAAK,aAAa,KAAK;GAEhC,IAAI,6BAA8B,MAAM,SAAS,KAAK,cAAe;IACnE,MAAM,UAAU,KAAK,WAAW,KAAK;IACrC,IAAI,SACF,OAAO;GAEX;EACF;EAEA,OAAO,KAAK,WAAW,OAAO,UAAU;CAC1C;AACF;;AAGA,SAAS,MAAM,MAAsB,OAAgC;CACnE,IAAI,QAAQ,KAAK,QACf,OAAO,KAAK;CAEd,MAAM,OAAO,KAAK,KAAK,SAAS;CAChC,OAAO,MAAM,aAAa,OAAO,KAAA;AACnC;;;;;AAMA,SAAgB,YAAY,MAAyB;CACnD,OAAO,IAAI,QAAQ,IAAI;AACzB;;;;;;AAuCA,SAAgB,UAAU,MAAY,QAA2B,OAA6B;CAC5F,MAAM,IAAI,IAAI,QAAQ,IAAI;CAC1B,KAAK,MAAM,WAAW,QACpB,EAAE,KAAK,OAAO;CAEhB,OAAO,EAAE,KAAK,KAAK;AACrB;;AC/vBA,MAAM,OAAO,KAAK;;AAYlB,IAAM,eAAN,MAAmB;CAKN;CAEA;CAEA;CARX,QAAqC;CAErC,YAEE,MAEA,KAEA,WACA;EALS,KAAA,OAAA;EAEA,KAAA,MAAA;EAEA,KAAA,YAAA;CACR;;CAGH,IAAI,UAAsB;EACxB,OAAO,KAAK,KAAK,KAAK,KAAK,SAAS;CACtC;;CAGA,IAAI,QAAsB;EACxB,OAAQ,KAAK,UAAU,aAAa,GAAG,KAAK,IAAI;CAClD;AACF;;;;;;AAOA,SAAS,eAAe,MAAkB,IAAyC;CACjF,MAAM,SAAS,MAAoB,cAA4B;EAC7D,MAAM,UAAU,KAAK,KAAK,SAAS;EACnC,MAAM,MAAM,UAAU,QAAQ,OAAO,CAAC,CAAC,KAAK,QAAQ,WAAW;GAAE;GAAQ,WAAW;GAAM;EAAM,EAAE;EAClG,GAAG,IAAI,aAAa,MAAM,KAAK,SAAS,CAAC;EACzC,MAAM,OAAO,CAAC,GAAG,WAAW,GAAG,IAAI,QAAQ,EAAE,aAAa,OAAO,YAAY,CAAC;EAC9E,KAAK,MAAM,cAAc,UAAU,QAAQ,WAAW,GACpD,MAAM,CAAC,GAAG,MAAM,UAAU,GAAG,IAAI;CAErC;CACA,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;AAClB;;;;;AAMA,SAAS,gBAAgB,MAAkB,IAAqD;CAC9F,eAAe,OAAO,EAAE,SAAS,WAAW;EAC1C,GAAG,UAAU,QAAQ,IAAI,GAAG,IAAI;EAChC,KAAK,MAAM,UAAU,UAAU,QAAQ,OAAO,GAC5C,GAAG,UAAU,OAAO,IAAI,GAAG,IAAI;CAEnC,CAAC;AACH;AAEA,SAAS,UAAU,OAA8B;CAC/C,OAAO,UAAU,KAAK,CAAC,CACpB,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CACnC,KAAK,GAAG;AACb;;AAGA,SAAS,gBAAgB,GAAY,GAAqB;CACxD,IAAI,MAAM,GACR,OAAO;CAET,IAAI,OAAO,MAAM,cAAc,OAAO,MAAM,YAC1C,OAAO;CAET,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,MAAM,QAAQ,MAAM,MACxE,OAAO;CAET,IAAI,MAAM,QAAQ,CAAC,MAAM,MAAM,QAAQ,CAAC,GACtC,OAAO;CAET,MAAM,OAAO;CACb,MAAM,QAAQ;CAEd,OAAO,CAAC,mBAAG,IADM,IAAI,CAAC,GAAG,OAAO,KAAK,IAAI,GAAG,GAAG,OAAO,KAAK,KAAK,CAAC,CACnD,CAAC,CAAC,CAAC,OAAO,QAAQ,gBAAgB,KAAK,MAAM,MAAM,IAAI,CAAC;AACxE;AAEA,SAAS,mBAAmB,GAAG,OAA0C;CAEvE,OAAO,KADO,MAAM,KAAK,UAAU,UAAU,MAAM,IAAI,CACvC,CAAC,CAAC,KAAK,GAAG,EAAE;AAC9B;;AAGA,SAAS,gBAAgB,MAAqC;CAC5D,MAAM,UAAU,KAAK,KAAK,SAAS;CACnC,MAAM,SAAS,KAAK,KAAK,SAAS;CAClC,IAAI,CAAC,QACH,OAAO,WAAW,mBAAmB,OAAO;CAE9C,MAAM,QAAQ,UAAU,OAAO,WAAW,CAAC,CAAC,QAAQ,OAAO;CAC3D,OAAO,cAAc,mBAAmB,GAAG,IAAI,EAAE,UAAU,MAAM;AACnE;;;;;AAMA,SAAS,eAAe,WAAkC,OAAe,SAAS,WAAmB;CACnG,MAAM,SAAS,UAAU,UAAU,UAAU,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC;CAClE,MAAM,OAAO,GAAG,mBAAmB,GAAG,WAAW,MAAM,EAAE,UAAU,MAAM;CACzE,OAAO,WAAW,YAAY,UAAU,SAAS,MAAM,mBAAmB,GAAG,MAAM,EAAE,WAAW;AAClG;;;;;;;;AAsBA,SAAS,cAAc,MAAkB,IAAoC;CAC3E,eAAe,OAAO,EAAE,MAAM,KAAK,WAAW,YAAY;EACxD,KAAK,MAAM,EAAE,QAAQ,WAAW,WAAW,CAAC,GAAG,KAAK,GAAG,SAAS,GAAG;GACjE,MAAM,QAAQ,eAAe,WAAW,OAAO,IAAI;GACnD,GAAG;IAAE;IAAQ;IAAM;IAAO,eAAe,cAAc;IAAM;GAAM,CAAC;EACtE;CACF,CAAC;AACH;;AAGA,SAAgB,oDAAoD,MAAwB;CAC1F,gBAAgB,OAAO,MAAM,SAAS;EACpC,IAAI,0BAA0B;EAC9B,IAAI,wBAAuC;EAC3C,KAAK,MAAM,CAAC,OAAO,QAAQ,KAAK,QAAQ,GACtC,IAAI,yBACF,OACE,IAAI,YACJ,MAAM,mBAAmB,GAAG,IAAI,EAAE,aAAa,IAAI,QAAQ,MAAM,oEAAoE,sBAAsB,aAC7J;OACK,IAAI,IAAI,YAAY;GACzB,0BAA0B;GAC1B,0BAA0B;EAC5B;CAEJ,CAAC;AACH;;;;;;;AAQA,SAAgB,wBAAwB,MAAwB;CAC9D,eAAe,OAAO,EAAE,SAAS,WAAW;EAC1C,KAAK,MAAM,CAAC,OAAO,QAAQ,UAAU,QAAQ,IAAI,CAAC,CAAC,QAAQ,GACzD,OACE,IAAI,YAAY,KAAA,KAAa,IAAI,YACjC,MAAM,mBAAmB,GAAG,IAAI,EAAE,aAAa,IAAI,QAAQ,MAAM,gEACnE;CAEJ,CAAC;CACD,cAAc,OAAO,EAAE,QAAQ,eAAe,YAAY;EACxD,IAAI,CAAC,eACH;EAEF,IAAI,eAA8B;EAClC,KAAK,MAAM,CAAC,OAAO,QAAQ,UAAU,OAAO,IAAI,CAAC,CAAC,QAAQ,GAAG;GAC3D,IAAI,IAAI,YAAY,KAAA,GAAW;IAC7B,iBAAiB;IACjB;GACF;GACA,IAAI,IAAI,YACN;GAEF,MAAM,OAAO,GAAG,MAAM,aAAa,IAAI,QAAQ,MAAM;GACrD,OAAO,CAAC,OAAO,YAAY,GAAG,KAAK,sDAAsD;GACzF,OACE,iBAAiB,MACjB,GAAG,KAAK,yBAAyB,aAAa,wCAChD;EACF;CACF,CAAC;AACH;;AAGA,SAAgB,2CAA2C,MAAwB;CACjF,cAAc,OAAO,EAAE,QAAQ,eAAe,YAAY;EACxD,IAAI,CAAC,iBAAiB,OAAO,OAAO,iBAAiB,UACnD;EAEF,OACE,OAAO,cAAc,OAAO,YAAY,GACxC,GAAG,MAAM,uEACX;EACA,OACE,EAAE,OAAO,eAAe,IACxB,GAAG,MAAM,6FACX;EACA,OACE,OAAO,iBAAiB,GACxB,GAAG,MAAM,oGACX;CACF,CAAC;AACH;;AAGA,SAAgB,oCAAoC,MAAwB;CAC1E,eAAe,OAAO,EAAE,MAAM,UAAU;EACtC,MAAM,8BAAc,IAAI,IAAY;EACpC,KAAK,MAAM,EAAE,QAAQ,WAAW,KAC9B,KAAK,MAAM,QAAQ,UAAU,OAAO,IAAI,GAAG;GACzC,OACE,CAAC,YAAY,IAAI,IAAI,GACrB,GAAG,eAAe,MAAM,KAAK,EAAE,2BAA2B,KAAK,gCACjE;GACA,YAAY,IAAI,IAAI;EACtB;CAEJ,CAAC;AACH;;AAGA,SAAgB,0CAA0C,MAAwB;CAChF,eAAe,OAAO,EAAE,MAAM,KAAK,gBAAgB;EACjD,KAAK,MAAM,EAAE,QAAQ,WAAW,KAC9B,KAAK,MAAM,QAAQ,UAAU,OAAO,IAAI,GACtC,OACE,CAAC,UAAU,MAAM,eAAe,UAAU,WAAW,OAAO,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,GAChF,GAAG,eAAe,MAAM,KAAK,EAAE,4CAA4C,KAAK,IAAI,EAAE,gDACxF;CAGN,CAAC;AACH;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,2CAA2C,MAAwB;CACjF,cAAc,OAAO,EAAE,QAAQ,MAAM,eAAe,YAAY;EAC9D,IAAI,CAAC,eACH;EAEF,MAAM,QAAQ,UAAU,OAAO,IAAI;EAGnC,KAAK,MAAM,UAAU,KAAK,MAAM,GAAG,EAAE,GACnC,KAAK,MAAM,gBAAgB,UAAU,OAAO,OAAO,GAAG;GACpD,IAAI,aAAa,cACf;GAEF,MAAM,cAAc,UAAU,aAAa,IAAI;GAC/C,MAAM,QAAQ,mBAAmB,QAAQ,YAAY;GACrD,IAAI,UAAU,YAAY,MAAM,UAAU,MAAM,GAAG;IACjD,OACE,gBAAgB;KAAE,GAAG;KAAc,MAAM;IAAE,GAAG;KAAE,GAAG;KAAQ,MAAM;IAAE,CAAC,GACpE,GAAG,MAAM,6CAA6C,MAAM,8EAC9D;IACA;GACF;GACA,OACE,CAAC,YAAY,OAAO,SAAS,MAAM,SAAS,IAAI,CAAC,GACjD,GAAG,MAAM,yCAAyC,MAAM,sFAC1D;GACA,OACE,CAAC,MAAM,OAAO,SAAS,YAAY,SAAS,IAAI,CAAC,GACjD,GAAG,MAAM,yCAAyC,MAAM,2FAC1D;EACF;CAEJ,CAAC;AACH;;AAGA,SAAgB,wCAAwC,MAAwB;CAC9E,eAAe,OAAO,EAAE,SAAS,WAAW;EAC1C,MAAM,wBAAQ,IAAI,IAAY;EAC9B,KAAK,MAAM,CAAC,OAAO,eAAe,UAAU,QAAQ,WAAW,CAAC,CAAC,QAAQ,GACvE,KAAK,MAAM,QAAQ,UAAU,WAAW,IAAI,GAAG;GAC7C,OACE,CAAC,MAAM,IAAI,IAAI,GACf,kBAAkB,mBAAmB,GAAG,MAAM,UAAU,EAAE,UAAU,MAAM,2BAA2B,KAAK,IAAI,EAAE,2EAClH;GACA,MAAM,IAAI,IAAI;EAChB;CAEJ,CAAC;AACH;;;;AAKA,SAAgB,wCAAwC,MAAwB;CAC9E,eAAe,OAAO,EAAE,SAAS,WAAW;EAC1C,MAAM,aAAa,UAAU,QAAQ,kBAAkB,mBAAmB;EAC1E,KAAK,MAAM,CAAC,UAAU,cAAc,WAAW,QAAQ,GACrD,OACE,cAAc,IACd,GAAG,gBAAgB,IAAI,EAAE,4DAA4D,SAAS,sEAChG;CAEJ,CAAC;AACH;;;;;;;AAQA,SAAgB,iCAAiC,MAAwB;CACvE,0BAA0B,OAAO,GAAG,SAAS,SAAS,OAAO,SAAS,GAAG;AAC3E;;;;AAKA,SAAgB,iCAAiC,MAAwB;CACvE,cAAc,OAAO,EAAE,QAAQ,eAAe,YAAY;EACxD,IAAI,CAAC,eACH;EAEF,KAAK,MAAM,QAAQ,UAAU,OAAO,IAAI,GACtC,OAAO,SAAS,KAAK,KAAK,GAAG,GAAG,MAAM,kCAAkC;CAE5E,CAAC;CACD,eAAe,OAAO,EAAE,SAAS,WAAW;EAC1C,KAAK,MAAM,QAAQ,UAAU,QAAQ,IAAI,GACvC,OAAO,SAAS,KAAK,KAAK,GAAG,GAAG,gBAAgB,IAAI,EAAE,kCAAkC;CAE5F,CAAC;CACD,gBAAgB,OAAO,MAAM,SAAS;EACpC,KAAK,MAAM,CAAC,OAAO,QAAQ,UAAU,IAAI,CAAC,CAAC,QAAQ,GACjD,KAAK,MAAM,QAAQ,UAAU,IAAI,IAAI,GACnC,OACE,SAAS,KAAK,KAAK,GACnB,UAAU,mBAAmB,GAAG,IAAI,EAAE,aAAa,MAAM,mCAC3D;CAGN,CAAC;AACH;;;;AAKA,SAAgB,+BAA+B,MAAwB;CACrE,OAAO,KAAK,aAAa,yBAAyB;CAClD,cAAc,OAAO,EAAE,QAAQ,eAAe,YAAY;EACxD,IAAI,eACF,OAAO,OAAO,aAAa,GAAG,MAAM,oBAAoB;CAE5D,CAAC;CACD,eAAe,OAAO,EAAE,SAAS,WAAW;EAC1C,OAAO,QAAQ,aAAa,GAAG,gBAAgB,IAAI,EAAE,oBAAoB;CAC3E,CAAC;AACH;;;;AAKA,SAAgB,mCAAmC,MAAwB;CACzE,IAAI,KAAK,aACP,OACE,KAAK,YAAY,MAAM,IAAI,CAAC,CAAC,OAAO,SAAS,KAAK,UAAU,EAAE,GAC9D,gDACF;CAEF,cAAc,OAAO,EAAE,QAAQ,eAAe,YAAY;EACxD,IAAI,CAAC,iBAAiB,CAAC,OAAO,aAC5B;EAEF,OACE,OAAO,YAAY,MAAM,IAAI,CAAC,CAAC,OAAO,SAAS,KAAK,UAAU,EAAE,GAChE,GAAG,MAAM,2CACX;CACF,CAAC;CACD,eAAe,OAAO,EAAE,SAAS,WAAW;EAC1C,IAAI,QAAQ,aACV,OACE,QAAQ,YAAY,MAAM,IAAI,CAAC,CAAC,OAAO,SAAS,KAAK,UAAU,EAAE,GACjE,GAAG,gBAAgB,IAAI,EAAE,2CAC3B;EAGF,KAAK,MAAM,CAAC,OAAO,QAAQ,UAAU,QAAQ,IAAI,CAAC,CAAC,QAAQ,GACzD,OACE,CAAC,IAAI,eAAe,IAAI,YAAY,MAAM,IAAI,CAAC,CAAC,OAAO,SAAS,KAAK,UAAU,EAAE,GACjF,MAAM,mBAAmB,GAAG,IAAI,EAAE,aAAa,IAAI,QAAQ,MAAM,2CACnE;CAEJ,CAAC;AACH;;;;;;;AAQA,SAAgB,mCAAmC,MAAwB;CACzE,0BAA0B,OAAO,WAAW,QAAQ,OAAO,iBAAiB,CAAC;AAC/E;;;;;AAMA,SAAS,gBAAgB,SAAuB,MAAqC;CACnF,QAAQ,QAAQ,MAAhB;EACE,KAAK,aACH,OAAO;EACT,KAAK,cACH,OAAO,kBAAkB,mBAAmB,GAAG,MAAM,QAAQ,OAAO;EACtE,KAAK,WACH,OAAO,QAAQ,QAAQ,WAAW,IAC9B,cAAc,mBAAmB,QAAQ,QAAQ,EAAE,MACnD,eAAe,QAAQ,QAAQ,KAAK,WAAW,mBAAmB,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;EAC1F,KAAK,SACH,OAAO,yBAAyB,mBAAmB,QAAQ,MAAM;EACnE,KAAK,YACH,OAAO;EACT,KAAK,WACH,OAAO;CACX;AACF;;AAGA,SAAS,QAAQ,SAAuB,QAAyB;CAC/D,OAAO,QAAQ,SAAS,aAAa,QAAQ,QAAQ,WAAW,KAAK,QAAQ,QAAQ,OAAO;AAC9F;;;;;;AAOA,SAAS,SAAS,MAAuC;CACvD,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,YAAY,UAAU,QAAQ,IAAI,CAAC,CAAC,EAAE;AAClE;;;;;;AAOA,SAAS,iBAAiB,MAA6B,OAA6B;CAClF,MAAM,QAAQ,CACZ,GAAG,CAAC,GAAG,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,CAAC,SAAS,WAAW,UAAU,OAAO,IAAI,CAAC,GACnF,GAAG,UAAU,KAAK,KAAK,SAAS,EAAE,CAAC,WAAW,CAAC,CAAC,SAAS,YAAY,UAAU,QAAQ,IAAI,CAAC,CAC9F;CACA,KAAK,MAAM,SAAS,wCAAwC;EAC1D,MAAM,SAAS;GAAC;GAAO,IAAI;GAAS,IAAI;EAAO;EAC/C,IAAI,CAAC,MAAM,MAAM,SAAS,OAAO,MAAM,UAAU,KAAK,WAAW,KAAK,CAAC,CAAC,GACtE,OAAO;CAEX;CACA,OAAO;AACT;;;;;;AAOA,SAAS,UAAU,QAAgB,MAAkB,OAAyB;CAC5E,MAAM,MAAM,WAAW,OAAO,IAAI;CAClC,MAAM,QAAQ,OAAO,SAAS,GAAG,IAAI,MAAM,WAAW,OAAO,IAAI,IAAI;CACrE,MAAM,SAAmB,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS,KAAK;CAClE,IAAI,KAAK,SAAS,MAChB,OAAO,CAAC,KAAK,MAAM,GAAG,MAAM;CAE9B,OAAO,CAAC,KAAK,OAAO,KAAK,OAAO,OAAO,IAAI,GAAG,OAAO,MAAM,CAAC,CAAC;AAC/D;;;;;AAMA,SAAS,0BAA0B,MAAkB,SAAoD;CACvG,MAAM,OAAO;CACb,cAAc,OAAO,EAAE,QAAQ,OAAO,OAAO,WAAW;EACtD,MAAM,SAAS,SAAS,IAAI;EAC5B,MAAM,QAAQ,iBAAiB,MAAM,KAAK;EAE1C,MAAM,QAAQ,UAAU,OAAO,IAAI,CAAC,CAAC,QAAQ,SAAS,MAAM,QAAQ,IAAI,MAAM,MAAM;EACpF,KAAK,MAAM,QAAQ,MAAM,MAAM,QAAQ,KAAK,GAAG;GAC7C,IAAI,CAAC,QAAQ,QAAQ,KAAK,IAAI,GAC5B;GAEF,MAAM,SAAS,UAAU,QAAQ,MAAM,KAAK;GAC5C,MAAM,SAAS,YAAY,IAAI;GAC/B,KAAK,MAAM,SAAS,QAClB,OAAO,KAAK,KAAK;GAEnB,MAAM,QAAQ,OAAO,KAAK,OAAO,EAAE;GAEnC,IAAI,KAAK,SAAS,IAAI;IAEpB,MAAM,UAAU,KAAK,SAAS,OAAO,QAAQ,UAAU,MAAM,QAAQ,KAAK,IAAI;IAC9E,OACE,QAAQ,SAAS,MAAM,GACvB,GAAG,MAAM,iBAAiB,KAAK,KAAK,gCAAgC,gBAAgB,SAAS,IAAI,GACnG;GACF;GACA,MAAM,UAAU,GAAG,MAAM,eAAe,eAAe,QAAQ,CAAC,IAAI,CAAC,EAAE;GACvE,IAAI,KAAK,MACP,OACE,MAAM,eAAe,KAAK,IAAI,GAC9B,GAAG,QAAQ,SAAS,KAAK,KAAK,kDAAkD,MAAM,WAAW,oBAAoB,KAAK,cAAc,IAAI,UAAU,EAAE,CAAC,CAAC,KAAK,IAAI,KAAK,OAAO,uDACjL;GAEF,IAAI,KAAK,SAAS,MAAM;IACtB,MAAM,SAAS,MAAM,SAAS,aAAa,MAAM,UAAU,WAAW;IACtE,OACE,QAAQ,OAAO,MAAM,KAAK,QAC1B,GAAG,QAAQ,0BAA0B,OAAO,GAAG,OAAO,gBAAgB,OAAO,IAAI,IAAI,SAAS,KAAK,oBACrG;GACF;GACA,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS;IAClD,MAAM,UAAU,OAAO,KAAK,OAAO,MAAM;IACzC,OACE,QAAQ,SAAS,WAAW,QAAQ,WAAW,QAC/C,GAAG,QAAQ,YAAY,OAAO,KAAK,GAAG,EAAE,sBAAsB,OAAO,OAAO,OAAO,gBAAgB,SAAS,IAAI,GAClH;GACF;EACF;CACF,CAAC;AACH;;;;;;;;AASA,SAAgB,oBAAoB,MAAwB;CAC1D,MAAM,OAAO;CACb,eAAe,OAAO,EAAE,SAAS,WAAW;EAC1C,MAAM,SAAS,SAAS,IAAI;EAC5B,KAAK,MAAM,cAAc,UAAU,QAAQ,WAAW,GACpD,KAAK,MAAM,QAAQ,UAAU,WAAW,IAAI,GAAG;GAC7C,MAAM,UAAU,UAAU,MAAM,QAAQ,IAAI;GAC5C,IAAI,QAAQ,SAAS,gBAAgB,QAAQ,YAAY,YACvD;GAEF,OACE,OACA,GAAG,gBAAgB,CAAC,GAAG,MAAM,UAAU,CAAC,EAAE,iBAAiB,KAAK,gCAAgC,gBAAgB,SAAS,IAAI,GAC/H;EACF;CAEJ,CAAC;CACD,0BAA0B,YAAY,IAAI;AAC5C;AAEA,SAAgB,iCAAiC,MAAwB;CACvE,MAAM,WAA+B,CAAC;CACtC,eAAe,OAAO,EAAE,SAAS,WAAW;EAC1C,IAAI,CAAC,QAAQ,aACX;EAGF,IAAI,SAAS,UAAU,QAAQ,OAAO;EACtC,eAAe,UAAU,EAAE,SAAS,YAAY;GAC9C,MAAM,OAAO,UAAU,MAAM,OAAO,CAAC,CAAC,IAAI,SAAS;GACnD,SAAS,OAAO,QAAQ,WAAW,KAAK,SAAS,UAAU,MAAM,CAAC,CAAC;EACrE,CAAC;EACD,KAAK,MAAM,UAAU,QAAQ;GAC3B,MAAM,MAAM,UAAU,MAAM;GAC5B,IAAI,CAAC,SAAS,MAAM,CAAC,YAAY,WAAW,GAAG,GAC7C,SAAS,KAAK,CAAC,KAAK,mBAAmB,GAAG,MAAM,MAAM,CAAC,CAAC;EAE5D;CACF,CAAC;CACD,OACE,SAAS,WAAW,GACpB;EACF,SAAS,KAAK,GAAG,UAAU,QAAQ,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE;CAEpD;AACF;;;;;AAMA,SAAgB,gCAAgC,MAAwB;CACtE,cAAc,OAAO,EAAE,QAAQ,OAAO,YAAY;EAChD,KAAK,MAAM,QAAQ,UAAU,OAAO,SAAS,GAC3C,OACE,MAAM,QAAQ,IAAI,MAAM,MACxB,GAAG,MAAM,8BAA8B,KAAK,IAAI,EAAE,mCACpD;EAEF,KAAK,MAAM,QAAQ,UAAU,OAAO,WAAW,GAC7C,OACE,MAAM,QAAQ,IAAI,MAAM,MACxB,GAAG,MAAM,mCAAmC,KAAK,IAAI,EAAE,mCACzD;CAEJ,CAAC;AACH;;;;AAKA,SAAgB,yCAAyC,MAAwB;CAC/E,eAAe,OAAO,EAAE,SAAS,MAAM,YAAY;EAGjD,IAAI,CAAC,MAAM,WAAW,8BACpB;EAGF,OACE,EAAE,QAAQ,eAAe,QAAQ,OACjC,eAAe,mBACb,GAAG,IACL,EAAE,4KACJ;CACF,CAAC;AACH;AAgDA,eAAe,QACb,SACA,MACA,IACe;CACf,IAAI,SAAS;EACX,MAAM,QAAQ,KAAK,MAAM,EAAE;EAC3B;CACF;CACA,MAAM,GAAG;AACX;;;;;;;;AASA,SAAgB,KAAK,MAAkB,UAAuB,CAAC,GAA2C;CACxG,MAAM,EACJ,kCAAkC,OAClC,qBAAqB,OACrB,4BAA4B,OAC5B,uCAAuC,OACvC,cAAc,eACZ;CACJ,MAAM,SAKA;EACJ;GACE;GACA;GACA;GACA;EACF;EACA;GAAC;GAAoC;GAA2B;GAAyB;EAAI;EAC7F;GACE;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA,CAAC;EACH;EACA;GACE;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA,CAAC;EACH;EACA;GACE;GACA;GACA;GACA,CAAC;EACH;EACA;GACE;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA;EACF;EACA;GACE;GACA;GACA;GACA,CAAC;EACH;CACF;CACA,OAAO,OAAO,MAAM;EAClB,KAAK,MAAM,CAAC,UAAU,cAAc,OAAO,YAAY,QAAQ;GAC7D,IAAI,CAAC,SACH;GAEF,MAAM,QAAQ,GAAG,gBAAgB,aAAa,eAAe,gBAAgB,MAAM,IAAI,CAAC;EAC1F;CACF;AACF;AAEA,MAAa,WAAW"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clo4/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "clo4's CLI framework: fully declarative, fast",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"arg-parser",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"bench": "pnpm build && pnpm build:bench && node bench/dist/run.js",
|
|
43
43
|
"check": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit && tsc -p tsconfig.bench.json --noEmit",
|
|
44
44
|
"test": "vitest run",
|
|
45
|
+
"fuzz": "vitest run test/fuzz",
|
|
45
46
|
"lint": "oxlint",
|
|
46
47
|
"lint:fix": "oxlint --fix",
|
|
47
48
|
"fmt": "oxfmt",
|
|
@@ -49,12 +50,26 @@
|
|
|
49
50
|
"verify": "pnpm fmt:check && pnpm lint && pnpm check && pnpm build && pnpm test"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
53
|
+
"@cliffy/command": "jsr:^1.3.1",
|
|
54
|
+
"@drizzle-team/brocli": "^0.12.1",
|
|
55
|
+
"@effect/platform-node": "^4.1.2",
|
|
56
|
+
"@oclif/core": "^5.1.11",
|
|
57
|
+
"@optique/core": "^1.3.6",
|
|
58
|
+
"@optique/run": "^1.3.6",
|
|
59
|
+
"@stricli/core": "^1.3.0",
|
|
52
60
|
"@types/node": "^26.6.6",
|
|
53
61
|
"cac": "^7.1.0",
|
|
54
|
-
"
|
|
62
|
+
"citty": "^0.2.2",
|
|
63
|
+
"clerc": "^1.3.1",
|
|
64
|
+
"clipanion": "4.0.0-rc.4",
|
|
65
|
+
"cmd-ts": "^0.15.0",
|
|
66
|
+
"commander": "^15.1.0",
|
|
67
|
+
"effect": "^4.1.2",
|
|
68
|
+
"gunshi": "^0.37.3",
|
|
55
69
|
"oxfmt": "^0.75.0",
|
|
56
70
|
"oxlint": "^1.90.0",
|
|
57
71
|
"rolldown": "^1.2.16",
|
|
72
|
+
"sade": "^1.8.1",
|
|
58
73
|
"tsdown": "^0.23.4",
|
|
59
74
|
"typescript": "^7.0.2",
|
|
60
75
|
"vitest": "^5.0.5",
|