Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 65 additions & 17 deletions docs/guide/essentials/declarative-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ const command = {
short: 'n',
description: 'Name to greet'
},
// Add a positional argument using 'file' as the key
file: {
type: 'positional',
description: 'Input file to process'
},
greeting: {
type: 'string',
short: 'g',
Expand Down Expand Up @@ -75,27 +80,29 @@ const command = {

// Command examples
examples: `# Examples
$ node index.js --name World
$ node index.js <input-file.txt> --name World

$ node index.js -n World -g "Hey there" -t 3
$ node index.js <input-file.txt> -n World -g "Hey there" -t 3

# Boolean short options can be grouped: -V -b is the same as -Vb
$ node index.js -Vb -n World
$ node index.js <input-file.txt> -Vb -n World

# Using the negatable option
$ node index.js --no-verbose -n World
$ node index.js <input-file.txt> --no-verbose -n World

# Using rest arguments after \`--\` (arguments after \`--\` are not parsed by gunshi)
$ node index.js -n User -- --foo --bar buz
`,
$ node index.js <input-file.txt> -n User -- --foo --bar buz
`, // Added comma here

// Command execution function
run: ctx => {
// If 'verbose' is defined with negatable: true:
// - true if -V or --verbose is passed
// - false if --no-verbose is passed
// - undefined if neither is passed (or default value if set)
const { name = 'World', greeting, times, verbose, banner } = ctx.values // Added banner

// Access positional argument 'file' via ctx.values.file
const { name = 'World', greeting, times, verbose, banner, file } = ctx.values

if (banner) {
// Added check for banner
Expand All @@ -104,9 +111,13 @@ $ node index.js -n User -- --foo --bar buz
if (verbose) {
console.log('Running in verbose mode...')
console.log('Context values:', ctx.values)
console.log('Positional arguments:', ctx.positionals) // Show positionals
console.log('Input file (from positional via ctx.values.file):', file)
console.log('Raw positional array (ctx.positionals):', ctx.positionals) // Still available
}

// Process the input file (example placeholder)
console.log(`\nProcessing file: ${file}...`)

// Repeat the greeting the specified number of times
for (let i = 0; i < times; i++) {
console.log(`${greeting}, ${name}!`)
Expand Down Expand Up @@ -149,7 +160,39 @@ Each option can have the following properties:
<!-- eslint-enable markdown/no-missing-label-refs -->
- `description`: A description of what the option does
- `default`: Default value if the option is not provided
- `required`: Set to `true` if the option is required
- `required`: Set to `true` if the option is required (Note: Positional arguments defined with `type: 'positional'` are implicitly required by the parser).

#### Positional Arguments

To define arguments that are identified by their position rather than a name/flag (like `--name`), set their `type` to `'positional'`. The _key_ you use for the argument in the `args` object serves as its name for accessing the value later.

```js
const command = {
args: {
// ... other options

// 'source' is the key and the name used to access the value
source: {
type: 'positional',
description: 'The source file path'
},

// 'destination' is the key and the name used to access the value
destination: {
type: 'positional',
description: 'The destination file path'
}
// ... potentially more positional arguments
}
}
```

- **Implicitly Required**: When you define an argument with `type: 'positional'` in the schema, Gunshi (via `args-tokens`) expects it to be present on the command line. If it's missing, a validation error will occur. They cannot be truly optional like named flags.
- **Order Matters**: Positional arguments are matched based on the order they appear on the command line and the order they are defined in the `args` object.
- **Accessing Values**: The resolved value is accessible via `ctx.values`, using the _key_ you defined in the `args` object (e.g., `ctx.values.source`, `ctx.values.destination`).
- **`ctx.positionals`**: This array still exists and contains the raw string values of positional arguments in the order they were parsed (e.g., `ctx.positionals[0]`, `ctx.positionals[1]`). While available, using `ctx.values.<key>` is generally preferred for clarity and consistency.
- **Descriptions**: The `description` property is used for generating help/usage messages.
- **Type Conversion**: `args-tokens` resolves positional arguments as strings. You typically need to perform type conversions or further validation on the values accessed via `ctx.values.<key>` within your `run` function based on your application's needs.

#### Negatable Boolean Options

Expand All @@ -172,14 +215,19 @@ The `examples` property provides example commands showing how to use the CLI.

The `run` function receives a command context object (`ctx`) with:

- `args`: The command arguments configuration
- `values`: The resolved option values
- `positionals`: Positional arguments
- `rest`: Rest arguments (arguments appearing after `--`)
- `_`: The raw arguments is passed from `cli` function
- `name`: The command name
- `description`: The command description
- `env`: The command environment
- `args`: The command arguments configuration (`ArgSchema` object).
- `values`: An object containing the resolved values for both named options (e.g., `ctx.values.name`) and positional arguments (accessed via their _key_ from the `args` definition, e.g., `ctx.values.file`). Positional values are stored as strings.
- `positionals`: An array of strings containing the raw values of the arguments identified as positional, in the order they were parsed. Useful if you need the original order, but `ctx.values.<key>` is generally recommended.
- `rest`: An array of strings containing arguments that appear after the `--` separator.
- `argv`: The raw argument array passed to the `cli` function.
- `tokens`: The raw tokens parsed by `args-tokens`.
- `omitted`: A boolean indicating if the command was run without specifying a subcommand name.
- `command`: The resolved command definition object itself.
- `commandOptions`: The resolved command options passed to `cli`.
- `name`: The name of the _currently executing_ command.
- `description`: The description of the _currently executing_ command.
- `env`: The command environment settings (version, logger, renderers, etc.).
- `log`: Logger function (defaults to `console.log`).

## CLI Configuration

Expand Down
18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,18 @@
"typecheck:tsc": "tsc --noEmit"
},
"dependencies": {
"args-tokens": "^0.17.0"
"args-tokens": "^0.17.1"
},
"devDependencies": {
"@eslint/markdown": "^6.4.0",
"@intlify/core": "next",
"@kazupon/eslint-config": "^0.29.0",
"@kazupon/prettier-config": "^0.1.1",
"@types/node": "^22.15.3",
"@vitest/eslint-plugin": "^1.1.43",
"@vitest/eslint-plugin": "^1.1.44",
"bumpp": "^10.1.0",
"deno": "^2.2.12",
"eslint": "^9.25.1",
"deno": "^2.3.1",
"eslint": "^9.26.0",
"eslint-config-prettier": "^10.1.2",
"eslint-import-resolver-typescript": "^4.3.4",
"eslint-plugin-import": "^2.31.0",
Expand All @@ -130,27 +130,27 @@
"eslint-plugin-regexp": "^2.7.0",
"eslint-plugin-unicorn": "^58.0.0",
"eslint-plugin-unused-imports": "^4.1.4",
"eslint-plugin-vue": "^10.0.1",
"eslint-plugin-vue": "^10.1.0",
"eslint-plugin-vue-composable": "^1.0.0",
"eslint-plugin-yml": "^1.18.0",
"gh-changelogen": "^0.2.8",
"jsr": "^0.13.4",
"jsr-exports-lint": "^0.2.0",
"knip": "^5.50.5",
"knip": "^5.53.0",
"lint-staged": "^15.5.1",
"messageformat": "4.0.0-10",
"pkg-pr-new": "^0.0.43",
"prettier": "^3.5.3",
"publint": "^0.3.12",
"tsdown": "^0.10.0",
"typedoc": "^0.28.3",
"tsdown": "^0.10.2",
"typedoc": "^0.28.4",
"typedoc-plugin-markdown": "^4.6.3",
"typedoc-vitepress-theme": "^1.1.2",
"typescript": "^5.8.3",
"typescript-eslint": "^8.31.1",
"vitepress": "^1.6.3",
"vitepress-plugin-group-icons": "^1.5.2",
"vitepress-plugin-llms": "^1.1.1",
"vitepress-plugin-llms": "^1.1.3",
"vitest": "^3.1.2",
"vue": "^3.5.13"
},
Expand Down
Loading