diff --git a/.codex/config.toml b/.codex/config.toml index 7d2d3e0..7503b7e 100644 --- a/.codex/config.toml +++ b/.codex/config.toml @@ -1,5 +1,5 @@ -model = "gpt-5.5" -review_model = "gpt-5.5" +model = "gpt-5.3-codex" +review_model = "gpt-5.3-codex" model_provider = "openai" approval_policy = "untrusted" diff --git a/docs/en/v0/api/command/create.md b/docs/en/v0/api/command/create.md index 7da283c..edcd099 100644 --- a/docs/en/v0/api/command/create.md +++ b/docs/en/v0/api/command/create.md @@ -4,15 +4,15 @@ prev: text: "execOptions" link: "/en/v0/api/command/execOptions" next: - text: "createBooleanOption" - link: "/en/v0/api/command/createBooleanOption" -description: "Creates a CLI command with a name, optional options/subject, and an execute handler." + text: "createArgument" + link: "/en/v0/api/command/createArgument" +description: "Creates a CLI command with a name, optional options/subjects, and an execute handler." --- # create `create` declares a CLI command. -You provide a name and an execute function, and you can also add options, a subject for positional arguments, or child commands. +You provide a name and an execute function, and you can also add options, positional arguments, or child commands. ## Example @@ -31,12 +31,12 @@ function create( function create< GenericOptions extends readonly Option[], - GenericSubject extends Subject + GenericSubjects extends Subjects >( name: string, - params: CreateCommandParams, + params: CreateCommandParams, execute: ( - params: CreateCommandExecuteParams + params: CreateCommandExecuteParams ) => MaybePromise ): Command ``` @@ -47,8 +47,8 @@ function create< - `params` (`CreateCommandParams`, optional) : command configuration. - `params.description` (`string`, optional) : help description. - `params.options` (`Option[]`, optional) : option parsers. -- `params.subject` (`Subject | Command[]`, optional) : parser-like contract for positional data or sub-commands list. -- `execute` : command handler. Receives typed `options` and, when present, a typed `subject`. +- `params.subjects` (`Argument[] | Command[]`, optional) : either a list of positional arguments built with [`createArgument`](/en/v0/api/command/createArgument), or a list of child commands. +- `execute` : command handler. Receives typed `options` and, when positional arguments are declared, typed `args`. ## Return value @@ -66,5 +66,6 @@ function create< ## See also - [`exec`](/en/v0/api/command/exec) - Runs a root command from process arguments. +- [`createArgument`](/en/v0/api/command/createArgument) - Builds a positional argument used in `subjects`. - [`createOption`](/en/v0/api/command/createOption) - Builds a single-value option. - [`createArrayOption`](/en/v0/api/command/createArrayOption) - Builds an array option. diff --git a/docs/en/v0/api/command/createArgument.md b/docs/en/v0/api/command/createArgument.md new file mode 100644 index 0000000..3658bd5 --- /dev/null +++ b/docs/en/v0/api/command/createArgument.md @@ -0,0 +1,72 @@ +--- +outline: [2, 3] +prev: + text: "create" + link: "/en/v0/api/command/create" +next: + text: "createBooleanOption" + link: "/en/v0/api/command/createBooleanOption" +description: "Creates a positional argument parser for command subjects." +--- + +# createArgument + +Creates a positional argument parser to use in command `subjects`. + +## Example + +```ts twoslash +// @version: 0 + +``` + +## Syntax + +```typescript +function createArgument< + GenericName extends string, + GenericSpec extends EligibleSpec +>( + name: GenericName, + spec: GenericSpec, + params?: { + description?: string + optional?: false + } +): Argument> + +function createArgument< + GenericName extends string, + GenericSpec extends EligibleSpec +>( + name: GenericName, + spec: GenericSpec, + params?: { + description?: string + optional: boolean + } +): Argument | undefined> +``` + +## Parameters + +- `name` (`string`) : argument key exposed in `args`. +- `spec` (`EligibleSpec`) : parser/clean spec used to parse and validate the received positional value. +- `params` (optional) : argument metadata. +- `params.description` (`string`, optional) : help description. +- `params.optional` (`boolean`, default `false`) : allows the argument to be omitted. + +## Return value + +- `Argument` : argument definition to place inside `subjects` in [`create`](/en/v0/api/command/create) or [`exec`](/en/v0/api/command/exec). + +## Notes + +- Positional arguments are consumed in declaration order. +- In execute handlers, parsed values are available as `args.`. +- Use only `EligibleSpec` values (primitive-like specs, literals, unions, pipes/transforms, file, clean specs). + +## See also + +- [`create`](/en/v0/api/command/create) - Builds a command node using `subjects`. +- [`exec`](/en/v0/api/command/exec) - Runs a root command from process arguments. diff --git a/docs/en/v0/api/command/createArrayOption.md b/docs/en/v0/api/command/createArrayOption.md index 8a9914b..06640f8 100644 --- a/docs/en/v0/api/command/createArrayOption.md +++ b/docs/en/v0/api/command/createArrayOption.md @@ -25,11 +25,11 @@ Creates an option that parses a delimited list into a typed array. ```typescript function createArrayOption< GenericName extends string, - GenericContract extends EligibleContract, + GenericSpec extends EligibleSpec, GenericMinValues extends number >( name: GenericName, - contract: GenericContract, + spec: GenericSpec, params: { description?: string aliases?: readonly string[] @@ -41,18 +41,18 @@ function createArrayOption< ): Option< GenericName, [ - ...A.CreateTuple, GenericMinValues>, - ...ComputeOptionContract[] + ...A.CreateTuple, GenericMinValues>, + ...ComputeOptionSpec[] ] > function createArrayOption< GenericName extends string, - GenericContract extends EligibleContract, + GenericSpec extends EligibleSpec, GenericMinValues extends number >( name: GenericName, - contract: GenericContract, + spec: GenericSpec, params?: { description?: string aliases?: readonly string[] @@ -63,8 +63,8 @@ function createArrayOption< ): Option< GenericName, | [ - ...A.CreateTuple, GenericMinValues>, - ...ComputeOptionContract[] + ...A.CreateTuple, GenericMinValues>, + ...ComputeOptionSpec[] ] | undefined > @@ -73,7 +73,7 @@ function createArrayOption< ## Parameters - `name` (`string`) : option name used as `--name`. -- `contract` (`EligibleContract`) : parser or clean contract for each array element. +- `spec` (`EligibleSpec`) : parser or clean spec for each array element. - `params` (optional) : option metadata and array constraints. - `params.required` (`true`, optional) : throws when option is missing. - `params.min` (`number`, optional) : minimum number of values. diff --git a/docs/en/v0/api/command/createBooleanOption.md b/docs/en/v0/api/command/createBooleanOption.md index ff36400..6cc8a47 100644 --- a/docs/en/v0/api/command/createBooleanOption.md +++ b/docs/en/v0/api/command/createBooleanOption.md @@ -1,8 +1,8 @@ --- outline: [2, 3] prev: - text: "create" - link: "/en/v0/api/command/create" + text: "createArgument" + link: "/en/v0/api/command/createArgument" next: text: "createOption" link: "/en/v0/api/command/createOption" diff --git a/docs/en/v0/api/command/createOption.md b/docs/en/v0/api/command/createOption.md index 95a2ada..2f20096 100644 --- a/docs/en/v0/api/command/createOption.md +++ b/docs/en/v0/api/command/createOption.md @@ -25,11 +25,11 @@ Creates an option with a single parsed value from a DataParser or clean contract ```typescript function createOption< GenericName extends string, - GenericContract extends EligibleContract, - GenericOutput extends ComputeOptionContract = ComputeOptionContract + GenericSpec extends EligibleSpec, + GenericOutput extends ComputeOptionSpec = ComputeOptionSpec >( name: GenericName, - contract: GenericContract, + spec: GenericSpec, params: { description?: string aliases?: readonly string[] @@ -39,11 +39,11 @@ function createOption< function createOption< GenericName extends string, - GenericContract extends EligibleContract, - GenericOutput extends ComputeOptionContract = ComputeOptionContract + GenericSpec extends EligibleSpec, + GenericOutput extends ComputeOptionSpec = ComputeOptionSpec >( name: GenericName, - contract: GenericContract, + spec: GenericSpec, params?: { description?: string aliases?: readonly string[] @@ -54,7 +54,7 @@ function createOption< ## Parameters - `name` (`string`) : option name used as `--name`. -- `contract` (`EligibleContract`) : parser or clean contract used to validate/transform the value. +- `spec` (`EligibleSpec`) : parser or clean spec used to validate/transform the value. - `params` (optional) : option metadata and requirement behavior. - `params.required` (`true`, optional) : throws when option is missing. - `params.description` (`string`, optional) : help description. diff --git a/docs/en/v0/api/command/exec.md b/docs/en/v0/api/command/exec.md index 558b8e3..d8cb276 100644 --- a/docs/en/v0/api/command/exec.md +++ b/docs/en/v0/api/command/exec.md @@ -31,11 +31,11 @@ function exec( function exec< GenericOptions extends readonly Option[], - GenericSubject extends Subject + GenericSubjects extends Subjects >( - params: CreateCommandParams, + params: CreateCommandParams, execute: ( - params: CreateCommandExecuteParams + params: CreateCommandExecuteParams ) => MaybePromise ): Promise ``` @@ -46,8 +46,8 @@ function exec< - `params` (`CreateCommandParams`) : command configuration for root. - `params.description` (`string`, optional) : displayed in help output. - `params.options` (`Option[]`, optional) : option definitions parsed before execute. -- `params.subject` (`Subject | Command[]`, optional) : DataParser subject or sub-command list. -- `execute` (overload 2) : receives typed `options` and optional typed `subject`. +- `params.subjects` (`Argument[] | Command[]`, optional) : positional arguments list or sub-command list. +- `execute` (overload 2) : receives typed `options` and optional typed `args`. ## Return value @@ -72,6 +72,7 @@ function exec< ## See also - [`create`](/en/v0/api/command/create) - Builds a command node. +- [`createArgument`](/en/v0/api/command/createArgument) - Builds positional arguments used in `subjects`. - [`createBooleanOption`](/en/v0/api/command/createBooleanOption) - Builds a boolean flag option. - [`createOption`](/en/v0/api/command/createOption) - Builds a single-value option. - [`createArrayOption`](/en/v0/api/command/createArrayOption) - Builds an array option. diff --git a/docs/en/v0/api/command/index.md b/docs/en/v0/api/command/index.md index 1cb5889..62f22db 100644 --- a/docs/en/v0/api/command/index.md +++ b/docs/en/v0/api/command/index.md @@ -11,7 +11,7 @@ next: # Command -CLI command utilities to compose command trees, parse options/subjects, render help, and execute handlers. +CLI command utilities to compose command trees, parse options/arguments, render help, and execute handlers. ## How to import? @@ -34,7 +34,10 @@ only parses options from process arguments. ## Command builder ### [`create`](/en/v0/api/command/create) -creates a command with optional description, options, and subject. +creates a command with optional description, options, and subjects. + +### [`createArgument`](/en/v0/api/command/createArgument) +creates a positional argument parser used in command `subjects`. ## Option builders diff --git a/docs/en/v0/guide/command.md b/docs/en/v0/guide/command.md index 85603ec..8c7ed82 100644 --- a/docs/en/v0/guide/command.md +++ b/docs/en/v0/guide/command.md @@ -17,10 +17,10 @@ The `command` feature helps you write CLIs that are simple to call and solid to A command is made of three parts: - options, such as `--port 3000` or `--verbose`; -- a subject, meaning the positional arguments after options; +- subjects, meaning either positional arguments after options, or subcommands; - a handler, called only when parsing succeeds. -Options and subjects rely on `DataParser` from `@duplojs/utils`. This turns CLI input, which always starts as text, into typed domain values. +Options and arguments rely on `DataParser` from `@duplojs/utils`. This turns CLI input, which always starts as text, into typed domain values. ## A First Command @@ -29,7 +29,7 @@ Options and subjects rely on `DataParser` from `@duplojs/utils`. This turns CLI ``` -Here, `exec` creates the root command. The `DP.tuple([DP.string(), DP.string()])` subject requires two positional arguments: the searched pattern and the file to inspect. +Here, `exec` creates the root command. The `subjects` list declares two positional arguments (`pattern` and `filePath`), and parsed values are exposed as `args.pattern` and `args.filePath`. $ grep-like "TODO" ./src/index.ts --ignore-case @@ -53,7 +53,7 @@ The type of `options.type` becomes `"file" | "directory"`. If the received value ## Understand Errors -When parsing fails, `exec` prints an interpreted error and exits with code `1`. The error shows the command, the failing option or subject, the received value, and what was expected. +When parsing fails, `exec` prints an interpreted error and exits with code `1`. The error shows the command path, the failing option/argument, the received value, and what was expected. $ find-like --type socket @@ -69,7 +69,7 @@ This is useful for internal tools: you can keep strict contracts without writing ## Subcommands -For a CLI with several actions, create commands with `SC.create`, then pass them as the subject of a parent command. +For a CLI with several actions, create commands with `SC.create`, then pass them as `subjects` of a parent command. ```ts twoslash // @version: 0 @@ -81,7 +81,7 @@ For a CLI with several actions, create commands with `SC.create`, then pass them install typescript without prompt -Each subcommand can have its own description, options, subject, and handler. Help follows the command tree. +Each subcommand can have its own description, options, argument subjects, and handler. Help follows the command tree. ## Generated Help @@ -90,23 +90,24 @@ Each subcommand can have its own description, options, subject, and handler. Hel $ apt-like --help -NAME:root +COMMAND: root DESCRIPTION: Package manager -NAME:install +COMMAND: install DESCRIPTION: Install a package OPTIONS: - yes: -y, --yes Answer yes to prompts -SUBJECT:<string> +ARGUMENTS: <packageName> +- packageName: string This makes command and option descriptions important: they become the embedded documentation of your tool. ## Lightweight Version With execOptions -When your script has no subcommands and no positional subject, `execOptions` is enough. It only parses process options and returns a typed object. +When your script has no subcommands and no positional argument, `execOptions` is enough. It only parses process options and returns a typed object. ```ts twoslash // @version: 0 diff --git a/docs/examples/v0/api/command/create/advanced.ts b/docs/examples/v0/api/command/create/advanced.ts index d18b6db..454ef50 100644 --- a/docs/examples/v0/api/command/create/advanced.ts +++ b/docs/examples/v0/api/command/create/advanced.ts @@ -12,21 +12,26 @@ const deployCommand = SC.create( { required: true }, ), ], - subject: DP.union([ - DP.templateLiteral([ - "v", - DP.number(), - ".", - DP.number(), - ".", - DP.number(), - ]), - DP.literal("latest"), - ]), + subjects: [ + SC.createArgument( + "version", + DP.union([ + DP.templateLiteral([ + "v", + DP.number(), + ".", + DP.number(), + ".", + DP.number(), + ]), + DP.literal("latest"), + ]), + ), + ], }, - ({ options: { environment }, subject }) => { + ({ options: { environment }, args: { version } }) => { type check = ExpectType< - typeof subject, + typeof version, `v${number}.${number}.${number}` | "latest", "strict" >; @@ -41,10 +46,9 @@ const deployCommand = SC.create( const releaseCommand = SC.create( "release", { - subject: [deployCommand], + subjects: [deployCommand], }, () => { console.log("select a release sub-command"); }, ); - diff --git a/docs/examples/v0/api/command/createArgument/main.ts b/docs/examples/v0/api/command/createArgument/main.ts new file mode 100644 index 0000000..f603bb9 --- /dev/null +++ b/docs/examples/v0/api/command/createArgument/main.ts @@ -0,0 +1,36 @@ +import { SC } from "@server-utils/v0"; +import { DP } from "@duplojs/utils"; + +const sourceArgument = SC.createArgument( + "source", + DP.string(), + { + description: "Source file path", + }, +); + +const targetArgument = SC.createArgument( + "target", + DP.string(), + { + description: "Target file path", + optional: true, + }, +); + +SC.create( + "copy", + { + subjects: [sourceArgument, targetArgument], + }, + ({ args }) => { + // ^? + + + + + + + console.log("copy from", args.source, "to", args.target ?? "(stdout)"); + }, +); diff --git a/docs/examples/v0/api/command/createArrayOption/main.ts b/docs/examples/v0/api/command/createArrayOption/main.ts index d73f1de..f485ff5 100644 --- a/docs/examples/v0/api/command/createArrayOption/main.ts +++ b/docs/examples/v0/api/command/createArrayOption/main.ts @@ -1,5 +1,5 @@ import { SC } from "@server-utils/v0"; -import { C, DP, type ExpectType } from "@duplojs/utils"; +import { C, DP } from "@duplojs/utils"; const UserId = C.createNewType("user-id", DP.number(), C.Positive); @@ -22,14 +22,14 @@ await SC.exec({ SC.createArrayOption("userIds", UserId), ], }, ({ options }) => { - type check = ExpectType< - typeof options, - { - tags: string[] | undefined; - files: [string, ...string[]]; - emails: C.Email[] | undefined; - userIds: C.GetNewType[] | undefined; - }, - "strict" - >; + // ^? + + + + + + + + + }); diff --git a/docs/examples/v0/api/command/createBooleanOption/main.ts b/docs/examples/v0/api/command/createBooleanOption/main.ts index 1755162..00d10c5 100644 --- a/docs/examples/v0/api/command/createBooleanOption/main.ts +++ b/docs/examples/v0/api/command/createBooleanOption/main.ts @@ -14,12 +14,11 @@ const forceOption = SC.createBooleanOption("force"); await SC.exec({ options: [verboseOption, forceOption], }, ({ options }) => { - type check = ExpectType< - typeof options, - { - verbose: boolean; - force: boolean; - }, - "strict" - >; + // ^? + + + + + + }); diff --git a/docs/examples/v0/api/command/createOption/main.ts b/docs/examples/v0/api/command/createOption/main.ts index bbd2e33..373a8ac 100644 --- a/docs/examples/v0/api/command/createOption/main.ts +++ b/docs/examples/v0/api/command/createOption/main.ts @@ -1,5 +1,5 @@ import { SC } from "@server-utils/v0"; -import { C, DP, type ExpectType } from "@duplojs/utils"; +import { C, DP } from "@duplojs/utils"; const UserId = C.createNewType("user-id", DP.number(), C.Positive); @@ -19,15 +19,14 @@ await SC.exec({ SC.createOption("userId", UserId), ], }, ({ options }) => { - type check = ExpectType< - typeof options, - { - host: string | undefined; - port: number; - environment: "dev" | "prod" | undefined; - email: C.Email | undefined; - userId: C.GetNewType | undefined; - }, - "strict" - >; + // ^? + + + + + + + + + }); diff --git a/docs/examples/v0/api/command/exec/advanced.ts b/docs/examples/v0/api/command/exec/advanced.ts index dacf18d..a806114 100644 --- a/docs/examples/v0/api/command/exec/advanced.ts +++ b/docs/examples/v0/api/command/exec/advanced.ts @@ -19,19 +19,24 @@ const migrateCommand = SC.create( { required: true }, ), ], - subject: DP.union([ - DP.templateLiteral([ - "v", - DP.number(), - ".", - DP.number(), - ".", - DP.number(), - ]), - DP.literal("latest"), - ]), + subjects: [ + SC.createArgument( + "targetVersion", + DP.union([ + DP.templateLiteral([ + "v", + DP.number(), + ".", + DP.number(), + ".", + DP.number(), + ]), + DP.literal("latest"), + ]), + ), + ], }, - ({ options: { dryRun, environment }, subject: targetVersion }) => { + ({ options: { dryRun, environment }, args: { targetVersion } }) => { const mode = dryRun ? "preview" : "apply"; console.log( @@ -61,7 +66,7 @@ await SC.exec( { description: "Project CLI entrypoint", options: [SC.createBooleanOption("verbose", { aliases: ["v"] })], - subject: [migrateCommand, seedCommand], + subjects: [migrateCommand, seedCommand], }, ({ options }) => { if (options.verbose) { diff --git a/docs/examples/v0/api/command/exec/main.ts b/docs/examples/v0/api/command/exec/main.ts index 6649ac4..8d4bf85 100644 --- a/docs/examples/v0/api/command/exec/main.ts +++ b/docs/examples/v0/api/command/exec/main.ts @@ -1,18 +1,21 @@ -import { SC } from "@server-utils/v0"; import { DP } from "@duplojs/utils"; +import { SC } from "@server-utils/v0"; await SC.exec( { options: [SC.createBooleanOption("version")], - subject: DP.tuple([DP.string(), DP.string()]), + subjects: [ + SC.createArgument("sourcePath", DP.string()), + SC.createArgument("targetPath", DP.string()), + ], }, - ({ subject, options }) => { + ({ args, options }) => { if (options.version) { console.log("1.0.0"); return; } - const [sourcePath, targetPath] = subject; + const { sourcePath, targetPath } = args; console.log(`copy ${sourcePath} to ${targetPath}`); }, ); diff --git a/docs/examples/v0/guide/command/firstCommand.ts b/docs/examples/v0/guide/command/firstCommand.ts index f6c3475..f6cf680 100644 --- a/docs/examples/v0/guide/command/firstCommand.ts +++ b/docs/examples/v0/guide/command/firstCommand.ts @@ -13,10 +13,12 @@ await SC.exec( }, ), ], - subject: DP.tuple([DP.string(), DP.string()]), + subjects: [ + SC.createArgument("pattern", DP.string()), + SC.createArgument("filePath", DP.string()), + ], }, - ({ options, subject }) => { - const [pattern, filePath] = subject; + ({ options, args: { pattern, filePath } }) => { const sensitivity = options["ignore-case"] ? "case-insensitive" : "case-sensitive"; console.log(`search "${pattern}" in ${filePath} (${sensitivity})`); diff --git a/docs/examples/v0/guide/command/subCommands.ts b/docs/examples/v0/guide/command/subCommands.ts index 92d97ef..9b0c30f 100644 --- a/docs/examples/v0/guide/command/subCommands.ts +++ b/docs/examples/v0/guide/command/subCommands.ts @@ -14,17 +14,17 @@ const installCommand = SC.create( }, ), ], - subject: DP.string(), + subjects: [SC.createArgument("packageName", DP.string())], }, - ({ options, subject }) => { - console.log(`install ${subject}${options.yes ? " without prompt" : ""}`); + ({ options, args: { packageName } }) => { + console.log(`install ${packageName}${options.yes ? " without prompt" : ""}`); }, ); await SC.exec( { description: "Package manager", - subject: [installCommand], + subjects: [installCommand], }, () => { console.log("select a package command"); diff --git a/docs/examples/v0/guide/quickStart/command.ts b/docs/examples/v0/guide/quickStart/command.ts index 0090224..a89f549 100644 --- a/docs/examples/v0/guide/quickStart/command.ts +++ b/docs/examples/v0/guide/quickStart/command.ts @@ -5,10 +5,10 @@ await SC.exec( { description: "Greet someone", options: [SC.createBooleanOption("shout", { aliases: ["s"] })], - subject: DP.string(), + subjects: [SC.createArgument("name", DP.string())], }, - ({ options, subject }) => { - const message = `hello ${subject}`; + ({ options, args: { name } }) => { + const message = `hello ${name}`; console.log(options.shout ? message.toUpperCase() : message); }, diff --git a/docs/fr/v0/api/command/create.md b/docs/fr/v0/api/command/create.md index 714f210..4828c8a 100644 --- a/docs/fr/v0/api/command/create.md +++ b/docs/fr/v0/api/command/create.md @@ -4,15 +4,15 @@ prev: text: "execOptions" link: "/fr/v0/api/command/execOptions" next: - text: "createBooleanOption" - link: "/fr/v0/api/command/createBooleanOption" + text: "createArgument" + link: "/fr/v0/api/command/createArgument" description: "Crée une commande CLI avec un nom, des options/sujets optionnels et un handler d'exécution." --- # create `create` sert à déclarer une commande CLI. -Vous fournissez un nom et une fonction d'exécution, et vous pouvez aussi ajouter des options, un sujet pour les arguments positionnels, ou des sous-commandes. +Vous fournissez un nom et une fonction d'exécution, et vous pouvez aussi ajouter des options, des arguments positionnels, ou des sous-commandes. ## Exemple @@ -31,12 +31,12 @@ function create( function create< GenericOptions extends readonly Option[], - GenericSubject extends Subject + GenericSubjects extends Subjects >( name: string, - params: CreateCommandParams, + params: CreateCommandParams, execute: ( - params: CreateCommandExecuteParams + params: CreateCommandExecuteParams ) => MaybePromise ): Command ``` @@ -47,8 +47,8 @@ function create< - `params` (`CreateCommandParams`, optionnel) : configuration de la commande. - `params.description` (`string`, optionnel) : description affichée dans le help. - `params.options` (`Option[]`, optionnel) : parseurs d'options. -- `params.subject` (`Subject | Command[]`, optionnel) : contrat de parsing pour les données positionnelles ou liste de sous-commandes. -- `execute` : handler de commande. Reçoit des `options` typées et, si présent, un `subject` typé. +- `params.subjects` (`Argument[] | Command[]`, optionnel) : soit une liste d'arguments positionnels construits avec [`createArgument`](/fr/v0/api/command/createArgument), soit une liste de sous-commandes. +- `execute` : handler de commande. Reçoit des `options` typées et, quand des arguments positionnels sont déclarés, des `args` typés. ## Valeur de retour @@ -66,5 +66,6 @@ function create< ## Voir aussi - [`exec`](/fr/v0/api/command/exec) - Exécute une commande racine depuis les arguments du process. +- [`createArgument`](/fr/v0/api/command/createArgument) - Construit un argument positionnel utilisé dans `subjects`. - [`createOption`](/fr/v0/api/command/createOption) - Construit une option à valeur unique. - [`createArrayOption`](/fr/v0/api/command/createArrayOption) - Construit une option tableau. diff --git a/docs/fr/v0/api/command/createArgument.md b/docs/fr/v0/api/command/createArgument.md new file mode 100644 index 0000000..694376e --- /dev/null +++ b/docs/fr/v0/api/command/createArgument.md @@ -0,0 +1,72 @@ +--- +outline: [2, 3] +prev: + text: "create" + link: "/fr/v0/api/command/create" +next: + text: "createBooleanOption" + link: "/fr/v0/api/command/createBooleanOption" +description: "Crée un parseur d'argument positionnel pour les sujets de commande." +--- + +# createArgument + +Crée un parseur d'argument positionnel à utiliser dans `subjects`. + +## Exemple + +```ts twoslash +// @version: 0 + +``` + +## Syntaxe + +```typescript +function createArgument< + GenericName extends string, + GenericSpec extends EligibleSpec +>( + name: GenericName, + spec: GenericSpec, + params?: { + description?: string + optional?: false + } +): Argument> + +function createArgument< + GenericName extends string, + GenericSpec extends EligibleSpec +>( + name: GenericName, + spec: GenericSpec, + params?: { + description?: string + optional: boolean + } +): Argument | undefined> +``` + +## Paramètres + +- `name` (`string`) : clé d'argument exposée dans `args`. +- `spec` (`EligibleSpec`) : spec parser/clean utilisée pour parser et valider la valeur positionnelle reçue. +- `params` (optionnel) : métadonnées de l'argument. +- `params.description` (`string`, optionnel) : description dans le help. +- `params.optional` (`boolean`, défaut `false`) : autorise l'absence de l'argument. + +## Valeur de retour + +- `Argument` : définition d'argument à placer dans `subjects` de [`create`](/fr/v0/api/command/create) ou [`exec`](/fr/v0/api/command/exec). + +## Notes + +- Les arguments positionnels sont consommés dans l'ordre de déclaration. +- Dans les handlers d'exécution, les valeurs parsées sont disponibles via `args.`. +- Utiliser uniquement des valeurs `EligibleSpec` (specs primitives, literals, unions, pipe/transform, file, specs clean). + +## Voir aussi + +- [`create`](/fr/v0/api/command/create) - Construit un noeud de commande avec `subjects`. +- [`exec`](/fr/v0/api/command/exec) - Exécute une commande racine depuis les arguments du process. diff --git a/docs/fr/v0/api/command/createArrayOption.md b/docs/fr/v0/api/command/createArrayOption.md index 707b157..e7bbf95 100644 --- a/docs/fr/v0/api/command/createArrayOption.md +++ b/docs/fr/v0/api/command/createArrayOption.md @@ -25,11 +25,11 @@ Crée une option qui parse une liste séparée en tableau typé. ```typescript function createArrayOption< GenericName extends string, - GenericContract extends EligibleContract, + GenericSpec extends EligibleSpec, GenericMinValues extends number >( name: GenericName, - contract: GenericContract, + spec: GenericSpec, params: { description?: string aliases?: readonly string[] @@ -41,18 +41,18 @@ function createArrayOption< ): Option< GenericName, [ - ...A.CreateTuple, GenericMinValues>, - ...ComputeOptionContract[] + ...A.CreateTuple, GenericMinValues>, + ...ComputeOptionSpec[] ] > function createArrayOption< GenericName extends string, - GenericContract extends EligibleContract, + GenericSpec extends EligibleSpec, GenericMinValues extends number >( name: GenericName, - contract: GenericContract, + spec: GenericSpec, params?: { description?: string aliases?: readonly string[] @@ -63,8 +63,8 @@ function createArrayOption< ): Option< GenericName, | [ - ...A.CreateTuple, GenericMinValues>, - ...ComputeOptionContract[] + ...A.CreateTuple, GenericMinValues>, + ...ComputeOptionSpec[] ] | undefined > @@ -73,7 +73,7 @@ function createArrayOption< ## Paramètres - `name` (`string`) : nom de l'option utilisé comme `--name`. -- `contract` (`EligibleContract`) : parseur ou contrat clean pour chaque élément du tableau. +- `spec` (`EligibleSpec`) : parseur ou spec clean pour chaque élément du tableau. - `params` (optionnel) : métadonnées et contraintes de tableau. - `params.required` (`true`, optionnel) : déclenche une erreur si l'option est absente. - `params.min` (`number`, optionnel) : nombre minimal de valeurs. diff --git a/docs/fr/v0/api/command/createBooleanOption.md b/docs/fr/v0/api/command/createBooleanOption.md index 858889f..0b71f6d 100644 --- a/docs/fr/v0/api/command/createBooleanOption.md +++ b/docs/fr/v0/api/command/createBooleanOption.md @@ -1,8 +1,8 @@ --- outline: [2, 3] prev: - text: "create" - link: "/fr/v0/api/command/create" + text: "createArgument" + link: "/fr/v0/api/command/createArgument" next: text: "createOption" link: "/fr/v0/api/command/createOption" diff --git a/docs/fr/v0/api/command/createOption.md b/docs/fr/v0/api/command/createOption.md index 20bc87d..e74f482 100644 --- a/docs/fr/v0/api/command/createOption.md +++ b/docs/fr/v0/api/command/createOption.md @@ -25,11 +25,11 @@ Crée une option à valeur unique depuis un DataParser ou un contrat clean. ```typescript function createOption< GenericName extends string, - GenericContract extends EligibleContract, - GenericOutput extends ComputeOptionContract = ComputeOptionContract + GenericSpec extends EligibleSpec, + GenericOutput extends ComputeOptionSpec = ComputeOptionSpec >( name: GenericName, - contract: GenericContract, + spec: GenericSpec, params: { description?: string aliases?: readonly string[] @@ -39,11 +39,11 @@ function createOption< function createOption< GenericName extends string, - GenericContract extends EligibleContract, - GenericOutput extends ComputeOptionContract = ComputeOptionContract + GenericSpec extends EligibleSpec, + GenericOutput extends ComputeOptionSpec = ComputeOptionSpec >( name: GenericName, - contract: GenericContract, + spec: GenericSpec, params?: { description?: string aliases?: readonly string[] @@ -54,7 +54,7 @@ function createOption< ## Paramètres - `name` (`string`) : nom de l'option utilisé comme `--name`. -- `contract` (`EligibleContract`) : parseur ou contrat clean utilisé pour valider/transformer la valeur. +- `spec` (`EligibleSpec`) : parseur ou spec clean utilisée pour valider/transformer la valeur. - `params` (optionnel) : métadonnées d'option et comportement d'obligation. - `params.required` (`true`, optionnel) : déclenche une erreur si l'option est absente. - `params.description` (`string`, optionnel) : description dans le help. diff --git a/docs/fr/v0/api/command/exec.md b/docs/fr/v0/api/command/exec.md index 091727b..f56498b 100644 --- a/docs/fr/v0/api/command/exec.md +++ b/docs/fr/v0/api/command/exec.md @@ -31,11 +31,11 @@ function exec( function exec< GenericOptions extends readonly Option[], - GenericSubject extends Subject + GenericSubjects extends Subjects >( - params: CreateCommandParams, + params: CreateCommandParams, execute: ( - params: CreateCommandExecuteParams + params: CreateCommandExecuteParams ) => MaybePromise ): Promise ``` @@ -46,8 +46,8 @@ function exec< - `params` (`CreateCommandParams`) : configuration de la commande racine. - `params.description` (`string`, optionnel) : affiché dans le rendu du help. - `params.options` (`Option[]`, optionnel) : définitions d'options parsées avant exécution. -- `params.subject` (`Subject | Command[]`, optionnel) : sujet DataParser ou liste de sous-commandes. -- `execute` (surcharge 2) : reçoit `options` typées et `subject` typé optionnel. +- `params.subjects` (`Argument[] | Command[]`, optionnel) : liste d'arguments positionnels ou liste de sous-commandes. +- `execute` (surcharge 2) : reçoit `options` typées et `args` typés optionnels. ## Valeur de retour @@ -72,6 +72,7 @@ function exec< ## Voir aussi - [`create`](/fr/v0/api/command/create) - Construit un noeud de commande. +- [`createArgument`](/fr/v0/api/command/createArgument) - Construit des arguments positionnels utilisés dans `subjects`. - [`createBooleanOption`](/fr/v0/api/command/createBooleanOption) - Construit une option drapeau booléenne. - [`createOption`](/fr/v0/api/command/createOption) - Construit une option à valeur unique. - [`createArrayOption`](/fr/v0/api/command/createArrayOption) - Construit une option tableau. diff --git a/docs/fr/v0/api/command/index.md b/docs/fr/v0/api/command/index.md index 5cfcc5d..101201a 100644 --- a/docs/fr/v0/api/command/index.md +++ b/docs/fr/v0/api/command/index.md @@ -11,7 +11,7 @@ next: # Command -Utilitaires de commandes CLI pour composer des arbres de commandes, parser options/sujets, afficher le help et exécuter les handlers. +Utilitaires de commandes CLI pour composer des arbres de commandes, parser options/arguments, afficher le help et exécuter les handlers. ## Comment faire les imports ? @@ -34,7 +34,10 @@ parse uniquement les options depuis les arguments du process. ## Construction de commandes ### [`create`](/fr/v0/api/command/create) -crée une commande avec description, options et sujet optionnels. +crée une commande avec description, options et sujets optionnels. + +### [`createArgument`](/fr/v0/api/command/createArgument) +crée un parseur d'argument positionnel à utiliser dans `subjects`. ## Construction d'options diff --git a/docs/fr/v0/guide/command.md b/docs/fr/v0/guide/command.md index 92f87a5..91f6fe4 100644 --- a/docs/fr/v0/guide/command.md +++ b/docs/fr/v0/guide/command.md @@ -17,10 +17,10 @@ La feature `command` sert à écrire des CLI qui restent simples à appeler et s Une commande est composée de trois éléments: - des options, comme `--port 3000` ou `--verbose`; -- un sujet, c'est-à-dire les arguments positionnels après les options; +- des sujets, c'est-à-dire soit des arguments positionnels après les options, soit des sous-commandes; - un handler, appelé uniquement quand le parsing est valide. -Les options et les sujets s'appuient sur les `DataParser` de `@duplojs/utils`. C'est ce qui permet de transformer une entrée CLI, toujours textuelle au départ, en valeur métier typée. +Les options et les arguments s'appuient sur les `DataParser` de `@duplojs/utils`. C'est ce qui permet de transformer une entrée CLI, toujours textuelle au départ, en valeur métier typée. ## Une première commande @@ -29,7 +29,7 @@ Les options et les sujets s'appuient sur les `DataParser` de `@duplojs/utils`. C ``` -Ici, `exec` crée la commande racine. Le sujet `DP.tuple([DP.string(), DP.string()])` impose deux arguments positionnels: le motif recherché et le fichier à inspecter. +Ici, `exec` crée la commande racine. La liste `subjects` déclare deux arguments positionnels (`pattern` et `filePath`), puis les valeurs parsées sont exposées dans `args.pattern` et `args.filePath`. $ grep-like "TODO" ./src/index.ts --ignore-case @@ -53,7 +53,7 @@ Le type de `options.type` devient `"file" | "directory"`. Si la valeur reçue ne ## Comprendre les erreurs -Quand le parsing échoue, `exec` affiche une erreur interprétée puis sort avec le code `1`. L'erreur indique la commande concernée, l'option ou le sujet fautif, la valeur reçue et ce qui était attendu. +Quand le parsing échoue, `exec` affiche une erreur interprétée puis sort avec le code `1`. L'erreur indique le chemin de commande, l'option/l'argument fautif, la valeur reçue et ce qui était attendu. $ find-like --type socket @@ -69,7 +69,7 @@ Ce comportement est utile pour les outils internes: vous pouvez garder des contr ## Sous-commandes -Pour une CLI avec plusieurs actions, créez des commandes avec `SC.create`, puis passez-les comme sujet d'une commande parente. +Pour une CLI avec plusieurs actions, créez des commandes avec `SC.create`, puis passez-les comme `subjects` d'une commande parente. ```ts twoslash // @version: 0 @@ -81,7 +81,7 @@ Pour une CLI avec plusieurs actions, créez des commandes avec `SC.create`, puis install typescript without prompt -Chaque sous-commande peut avoir sa propre description, ses options, son sujet et son handler. Le help suit l'arbre de commandes. +Chaque sous-commande peut avoir sa propre description, ses options, ses arguments de sujet et son handler. Le help suit l'arbre de commandes. ## Help généré @@ -90,23 +90,24 @@ Chaque sous-commande peut avoir sa propre description, ses options, son sujet et $ apt-like --help -NAME:root +COMMAND: root DESCRIPTION: Package manager -NAME:install +COMMAND: install DESCRIPTION: Install a package OPTIONS: - yes: -y, --yes Answer yes to prompts -SUBJECT:<string> +ARGUMENTS: <packageName> +- packageName: string Il est donc important de renseigner les descriptions des commandes et des options: elles deviennent la documentation embarquée de votre outil. ## Version légère avec execOptions -Quand vous écrivez un script qui n'a pas de sous-commandes ni de sujet positionnel, `execOptions` suffit. Il parse seulement les options du process et retourne un objet typé. +Quand vous écrivez un script qui n'a pas de sous-commandes ni d'argument positionnel, `execOptions` suffit. Il parse seulement les options du process et retourne un objet typé. ```ts twoslash // @version: 0 diff --git a/docs/libs/v0/dist/command/argument.cjs b/docs/libs/v0/dist/command/argument.cjs new file mode 100644 index 0000000..8f0149e --- /dev/null +++ b/docs/libs/v0/dist/command/argument.cjs @@ -0,0 +1,66 @@ +'use strict'; + +var utils = require('@duplojs/utils'); +var EE = require('@duplojs/utils/either'); +var kind = require('../kind.cjs'); +var error = require('./error.cjs'); +var spec = require('./spec.cjs'); + +function _interopNamespaceDefault(e) { + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(function (k) { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { return e[k]; } + }); + } + }); + } + n.default = e; + return Object.freeze(n); +} + +var EE__namespace = /*#__PURE__*/_interopNamespaceDefault(EE); + +const argumentKind = kind.createDuplojsServerUtilsKind("command-argument"); +function createArgument(name, spec$1, params) { + const dataParser = spec.specToDataParser(spec$1); + const self = argumentKind.setTo({ + name, + spec: spec$1, + dataParser, + description: params?.description, + optional: params?.optional ?? false, + execute: async (argument, error$1) => { + if (self.optional === false && argument === undefined) { + return error.addIssue(error$1, { + type: "argument", + target: name, + expected: `required argument ${name}`, + received: argument, + message: `Argument "${name}" is required.`, + }); + } + if (self.optional === true && argument === undefined) { + return undefined; + } + const result = dataParser.isAsynchronous() + ? await dataParser.asyncParse(argument) + : dataParser.parse(argument); + if (EE__namespace.isLeft(result)) { + return error.addIssueDataParser(error$1, utils.unwrap(result), { + type: "argument", + target: name, + }); + } + return utils.unwrap(result); + }, + }); + return self; +} + +exports.argumentKind = argumentKind; +exports.createArgument = createArgument; diff --git a/docs/libs/v0/dist/command/argument.d.ts b/docs/libs/v0/dist/command/argument.d.ts new file mode 100644 index 0000000..d5d7738 --- /dev/null +++ b/docs/libs/v0/dist/command/argument.d.ts @@ -0,0 +1,69 @@ +import { type Kind } from "@duplojs/utils"; +import type * as DDP from "@duplojs/utils/dataParser"; +import type { EligibleSpec, EligibleSpecOutput } from "./types"; +import { type CommandError, type SymbolCommandError } from "./error"; +export declare const argumentKind: import("@duplojs/utils").KindHandler>; +export interface Argument extends Kind { + readonly name: GenericName; + readonly spec: EligibleSpec; + readonly dataParser: DDP.DataParser; + readonly optional: boolean; + readonly description?: string; + execute(argument: string | undefined, error: CommandError): Promise; +} +/** + * Create a positional argument parser for command subjects. + * + * Use this builder to define an argument name, a parsing spec, and optional metadata (`description`, `optional`) used by command help and execution. + * + * ```ts + * const source = SC.createArgument("source", DP.string()); + * const target = SC.createArgument( + * "target", + * DP.string(), + * { + * optional: true, + * description: "Optional output file path", + * }, + * ); + * + * SC.create( + * "copy", + * { + * subjects: [source, target], + * }, + * ({ args }) => { + * // args.source: string + * // args.target: string | undefined + * }, + * ); + * + * const UserId = C.createNewType("user-id", DP.number(), C.Positive); + * const userId = SC.createArgument("userId", UserId); + * + * await SC.exec( + * { + * subjects: [userId], + * }, + * ({ args }) => { + * // args.userId: C.GetNewType + * }, + * ); + * ``` + * + * @remarks + * `createArgument` is designed to be used inside `subjects` for [`create`](/en/v0/api/command/create) or [`exec`](/en/v0/api/command/exec). + * Parsed values are exposed in the execute callback as `args.`. + * + * @see https://server-utils.duplojs.dev/en/v0/api/command/createArgument + * @namespace SC + * + */ +export declare function createArgument(name: GenericName, spec: GenericEligibleSpec, params?: { + readonly description?: string; + readonly optional?: false; +}): Argument>; +export declare function createArgument(name: GenericName, spec: GenericEligibleSpec, params?: { + readonly description?: string; + readonly optional: boolean; +}): Argument | undefined>; diff --git a/docs/libs/v0/dist/command/argument.mjs b/docs/libs/v0/dist/command/argument.mjs new file mode 100644 index 0000000..cf5b0fb --- /dev/null +++ b/docs/libs/v0/dist/command/argument.mjs @@ -0,0 +1,44 @@ +import { unwrap } from '@duplojs/utils'; +import * as EE from '@duplojs/utils/either'; +import { createDuplojsServerUtilsKind } from '../kind.mjs'; +import { addIssue, addIssueDataParser } from './error.mjs'; +import { specToDataParser } from './spec.mjs'; + +const argumentKind = createDuplojsServerUtilsKind("command-argument"); +function createArgument(name, spec, params) { + const dataParser = specToDataParser(spec); + const self = argumentKind.setTo({ + name, + spec, + dataParser, + description: params?.description, + optional: params?.optional ?? false, + execute: async (argument, error) => { + if (self.optional === false && argument === undefined) { + return addIssue(error, { + type: "argument", + target: name, + expected: `required argument ${name}`, + received: argument, + message: `Argument "${name}" is required.`, + }); + } + if (self.optional === true && argument === undefined) { + return undefined; + } + const result = dataParser.isAsynchronous() + ? await dataParser.asyncParse(argument) + : dataParser.parse(argument); + if (EE.isLeft(result)) { + return addIssueDataParser(error, unwrap(result), { + type: "argument", + target: name, + }); + } + return unwrap(result); + }, + }); + return self; +} + +export { argumentKind, createArgument }; diff --git a/docs/libs/v0/dist/command/create/index.cjs b/docs/libs/v0/dist/command/create.cjs similarity index 66% rename from docs/libs/v0/dist/command/create/index.cjs rename to docs/libs/v0/dist/command/create.cjs index 9f30011..4dca4f9 100644 --- a/docs/libs/v0/dist/command/create/index.cjs +++ b/docs/libs/v0/dist/command/create.cjs @@ -4,12 +4,10 @@ var utils = require('@duplojs/utils'); var AA = require('@duplojs/utils/array'); var GG = require('@duplojs/utils/generator'); var OO = require('@duplojs/utils/object'); -var EE = require('@duplojs/utils/either'); -var kind = require('../../kind.cjs'); -var exitProcess = require('../../common/exitProcess.cjs'); -var error = require('../error.cjs'); -var help = require('../help.cjs'); -var subject = require('./subject.cjs'); +var kind = require('../kind.cjs'); +var exitProcess = require('../common/exitProcess.cjs'); +var error = require('./error.cjs'); +var help = require('./help.cjs'); function _interopNamespaceDefault(e) { var n = Object.create(null); @@ -31,13 +29,12 @@ function _interopNamespaceDefault(e) { var AA__namespace = /*#__PURE__*/_interopNamespaceDefault(AA); var GG__namespace = /*#__PURE__*/_interopNamespaceDefault(GG); var OO__namespace = /*#__PURE__*/_interopNamespaceDefault(OO); -var EE__namespace = /*#__PURE__*/_interopNamespaceDefault(EE); const commandKind = kind.createDuplojsServerUtilsKind("command"); -function isCommand(input) { +function isCommands(input) { return input instanceof Array ? input.every(commandKind.has) - : commandKind.has(input); + : false; } function create(...args) { const [name, params, execute] = args.length === 2 @@ -47,25 +44,24 @@ function create(...args) { name, description: params.description ?? null, options: params.options ?? [], - children: utils.justExec(() => { - if (isCommand(params.subject)) { + subject: utils.justExec(() => { + if (isCommands(params.subjects)) { return { type: "subCommand", - subCommands: AA__namespace.coalescing(params.subject), + subCommands: params.subjects, }; } - else if (params.subject) { + else if (params.subjects) { return { - type: "subject", - subject: params.subject, - dataParser: subject.subjectToDataParser(params.subject), + type: "argument", + args: params.subjects, }; } return null; }), execute: async (args, error$1) => { - if (self.children?.type === "subCommand") { - for (const command of self.children.subCommands) { + if (self.subject?.type === "subCommand") { + for (const command of self.subject.subCommands) { if (args[0] === command.name) { error$1.currentCommandPath[error$1.currentCommandPath.length] = command.name; return command.execute(AA__namespace.shift(args), error$1); @@ -98,33 +94,38 @@ function create(...args) { if (commandOptions === error.SymbolCommandError) { return error.SymbolCommandError; } - if (self.children?.type === "subject") { - const hasMultiSubject = subject.isMultiSubject(self.children.subject); - if (!hasMultiSubject - && commandOptions.restArgs.length > 1) { + if (self.subject?.type === "argument") { + if (self.subject.args.length !== commandOptions.restArgs.length) { + const expectedCount = self.subject.args.length; + const receivedCount = commandOptions.restArgs.length; error.addIssue(error$1, { type: "command", - expected: "exactly one subject argument", + expected: `${expectedCount} declared argument${expectedCount > 1 ? "s" : ""}`, received: commandOptions.restArgs, - message: `Expected exactly one subject argument, received ${commandOptions.restArgs.length}.`, + message: `Declared arguments count does not match received arguments count: expected ${expectedCount}, received ${receivedCount}.`, }); return error.SymbolCommandError; } - const subjectInput = hasMultiSubject - ? commandOptions.restArgs - : commandOptions.restArgs[0]; - const subjectResult = self.children.dataParser.isAsynchronous() - ? await self.children.dataParser.asyncParse(subjectInput) - : self.children.dataParser.parse(subjectInput); - if (EE__namespace.isLeft(subjectResult)) { - error.addIssueDataParser(error$1, utils.unwrap(subjectResult), { - type: "subject", + const commandArguments = await GG__namespace.asyncReduce(self.subject.args, GG__namespace.reduceFrom({ + args: {}, + restArgs: commandOptions.restArgs, + }), async ({ element: argument, lastValue, next, exit }) => { + const firstArgument = AA__namespace.first(lastValue.restArgs); + const argumentResult = await argument.execute(firstArgument, error$1); + if (argumentResult === error.SymbolCommandError) { + return exit(error.SymbolCommandError); + } + return next({ + args: OO__namespace.override(lastValue.args, { [argument.name]: argumentResult }), + restArgs: AA__namespace.shift(lastValue.restArgs), }); + }); + if (commandArguments === error.SymbolCommandError) { return error.SymbolCommandError; } await execute({ options: commandOptions.options, - subject: utils.unwrap(subjectResult), + args: commandArguments.args, }); } else { @@ -146,4 +147,4 @@ function create(...args) { } exports.create = create; -exports.isCommand = isCommand; +exports.isCommands = isCommands; diff --git a/docs/libs/v0/dist/command/create.d.ts b/docs/libs/v0/dist/command/create.d.ts new file mode 100644 index 0000000..c68a841 --- /dev/null +++ b/docs/libs/v0/dist/command/create.d.ts @@ -0,0 +1,104 @@ +import { type Kind, type MaybePromise, type AnyTuple, type ComputedTypeError, type IsEqual, type And, type Not, type UnionContain, type NeverCoalescing } from "@duplojs/utils"; +import type { Option } from "./options"; +import { SymbolCommandError, type CommandError } from "./error"; +import { type Argument } from "./argument"; +import { type ForbiddenDuplicateName } from "./types"; +declare const commandKind: import("@duplojs/utils").KindHandler>; +export declare function isCommands(input: unknown): input is AnyTuple; +type CommandSubject = { + readonly type: "subCommand"; + readonly subCommands: readonly Command[]; +} | { + readonly type: "argument"; + readonly args: readonly Argument[]; +}; +export interface Command extends Kind { + readonly name: GenericName; + readonly description: string | null; + readonly subject: CommandSubject | null; + readonly options: readonly Option[]; + execute(args: readonly string[], error: CommandError): Promise; +} +export type Subjects = AnyTuple | AnyTuple; +export type ForbiddenBadOrderArguments = GenericSubject extends readonly [ + Argument, + ...infer InferredRest extends Argument[] +] ? And<[ + IsEqual, + Not> +]> extends true ? ComputedTypeError<"Optional argument can't be define before required argument"> : ForbiddenBadOrderArguments> : unknown; +export interface CreateCommandParams = AnyTuple