icore 1.0.9 → 1.0.11

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/dist/argv.d.ts CHANGED
@@ -22,4 +22,3 @@ export type ParsedArgv = {
22
22
  * Parses raw CLI arguments into positionals and raw long-option values.
23
23
  */
24
24
  export declare function parseArgv(args: readonly string[], schema?: OptionsSchema): ParsedArgv;
25
- //# sourceMappingURL=argv.d.ts.map
package/dist/argv.js CHANGED
@@ -138,4 +138,3 @@ function assertShortAlias(name, alias) {
138
138
  function isShortOptionToken(arg) {
139
139
  return arg.length === 2 && arg.startsWith('-') && !arg.startsWith('--');
140
140
  }
141
- //# sourceMappingURL=argv.js.map
package/dist/cli.d.ts CHANGED
@@ -9,6 +9,5 @@
9
9
  * This file must not contain parser, validator, or command runtime logic.
10
10
  */
11
11
  export { parseArgv, type ParsedArgv } from './argv';
12
- export { defineCommand, defineCommandRegistry, isCommandName, resolveCommand, resolveCommandFromArgs, runCommand, runCommandFromRegistry, type CommandDefinition, type CommandInput, type CommandName, type CommandRegistry, type ResolvedCommand } from './commands';
12
+ export { defineCommand, defineCommandRegistry, isCommandName, prepareCommandFromArgs, resolveCommand, resolveCommandFromArgs, runCommand, runPreparedCommand, runCommandFromRegistry, type CommandDefinition, type CommandInput, type CommandName, type CommandRegistry, type PreparedCommand, type PreparedCommandInput, type ResolvedCommand } from './commands';
13
13
  export { mergeOptionsSchema, parseOptions, parseOptionsDetailed, type BooleanOption, type InferOptions, type InferProvidedOptions, type MergeOptionsSchemas, type NumberOption, type OptionDefinition, type OptionsSchema, type ParseOptionsResult, type RawOptionValue, type StringOption } from './options';
14
- //# sourceMappingURL=cli.d.ts.map
package/dist/cli.js CHANGED
@@ -10,19 +10,20 @@
10
10
  * This file must not contain parser, validator, or command runtime logic.
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.parseOptionsDetailed = exports.parseOptions = exports.mergeOptionsSchema = exports.runCommandFromRegistry = exports.runCommand = exports.resolveCommandFromArgs = exports.resolveCommand = exports.isCommandName = exports.defineCommandRegistry = exports.defineCommand = exports.parseArgv = void 0;
13
+ exports.parseOptionsDetailed = exports.parseOptions = exports.mergeOptionsSchema = exports.runCommandFromRegistry = exports.runPreparedCommand = exports.runCommand = exports.resolveCommandFromArgs = exports.resolveCommand = exports.prepareCommandFromArgs = exports.isCommandName = exports.defineCommandRegistry = exports.defineCommand = exports.parseArgv = void 0;
14
14
  var argv_1 = require("./argv");
15
15
  Object.defineProperty(exports, "parseArgv", { enumerable: true, get: function () { return argv_1.parseArgv; } });
16
16
  var commands_1 = require("./commands");
17
17
  Object.defineProperty(exports, "defineCommand", { enumerable: true, get: function () { return commands_1.defineCommand; } });
18
18
  Object.defineProperty(exports, "defineCommandRegistry", { enumerable: true, get: function () { return commands_1.defineCommandRegistry; } });
19
19
  Object.defineProperty(exports, "isCommandName", { enumerable: true, get: function () { return commands_1.isCommandName; } });
20
+ Object.defineProperty(exports, "prepareCommandFromArgs", { enumerable: true, get: function () { return commands_1.prepareCommandFromArgs; } });
20
21
  Object.defineProperty(exports, "resolveCommand", { enumerable: true, get: function () { return commands_1.resolveCommand; } });
21
22
  Object.defineProperty(exports, "resolveCommandFromArgs", { enumerable: true, get: function () { return commands_1.resolveCommandFromArgs; } });
22
23
  Object.defineProperty(exports, "runCommand", { enumerable: true, get: function () { return commands_1.runCommand; } });
24
+ Object.defineProperty(exports, "runPreparedCommand", { enumerable: true, get: function () { return commands_1.runPreparedCommand; } });
23
25
  Object.defineProperty(exports, "runCommandFromRegistry", { enumerable: true, get: function () { return commands_1.runCommandFromRegistry; } });
24
26
  var options_1 = require("./options");
25
27
  Object.defineProperty(exports, "mergeOptionsSchema", { enumerable: true, get: function () { return options_1.mergeOptionsSchema; } });
26
28
  Object.defineProperty(exports, "parseOptions", { enumerable: true, get: function () { return options_1.parseOptions; } });
27
29
  Object.defineProperty(exports, "parseOptionsDetailed", { enumerable: true, get: function () { return options_1.parseOptionsDetailed; } });
28
- //# sourceMappingURL=cli.js.map
@@ -12,12 +12,18 @@
12
12
  */
13
13
  import { type InferOptions, type InferProvidedOptions, type OptionsSchema } from './options';
14
14
  /**
15
- * Input passed to a command handler after command path and option validation.
15
+ * Input produced after command path and option validation, before runtime
16
+ * context is attached.
16
17
  */
17
- export type CommandInput<TSchema extends OptionsSchema, TContext> = {
18
+ export type PreparedCommandInput<TSchema extends OptionsSchema> = {
18
19
  options: InferOptions<TSchema>;
19
20
  provided: InferProvidedOptions<TSchema>;
20
21
  positionals: string[];
22
+ };
23
+ /**
24
+ * Input passed to a command handler after command path and option validation.
25
+ */
26
+ export type CommandInput<TSchema extends OptionsSchema, TContext> = PreparedCommandInput<TSchema> & {
21
27
  context: TContext;
22
28
  };
23
29
  /**
@@ -27,19 +33,22 @@ export type CommandInput<TSchema extends OptionsSchema, TContext> = {
27
33
  * application-specific work such as API calls, request building, and output
28
34
  * formatting.
29
35
  */
30
- export type CommandDefinition<TSchema extends OptionsSchema, TContext, TResult, TPath extends readonly [string, ...string[]] = readonly [string, ...string[]]> = {
36
+ export type CommandDefinition<TSchema extends OptionsSchema, TContext, TResult, TPath extends readonly [string, ...string[]] = readonly [string, ...string[]], TMetadata = unknown> = {
31
37
  path: TPath;
32
38
  options: TSchema;
39
+ metadata?: TMetadata;
33
40
  allowExtraPositionals?: boolean;
41
+ prepare?(input: PreparedCommandInput<TSchema>): void | Promise<void>;
34
42
  handle(input: CommandInput<TSchema, TContext>): TResult | Promise<TResult>;
35
43
  };
36
- type AnyCommandDefinition = CommandDefinition<OptionsSchema, unknown, unknown>;
44
+ type AnyCommandDefinition = CommandDefinition<OptionsSchema, unknown, unknown, readonly [string, ...string[]], unknown>;
37
45
  type CommandPathName<TPath extends readonly string[]> = number extends TPath['length'] ? string : TPath extends readonly [infer THead extends string] ? THead : TPath extends readonly [
38
46
  infer THead extends string,
39
47
  ...infer TRest extends readonly string[]
40
48
  ] ? `${THead} ${CommandPathName<TRest>}` : never;
41
49
  type CommandContext<TCommand extends AnyCommandDefinition> = TCommand extends CommandDefinition<OptionsSchema, infer TContext, unknown> ? TContext : never;
42
50
  type CommandResult<TCommand extends AnyCommandDefinition> = TCommand extends CommandDefinition<OptionsSchema, unknown, infer TResult> ? Awaited<TResult> : never;
51
+ type CommandSchema<TCommand extends AnyCommandDefinition> = TCommand extends CommandDefinition<infer TSchema, unknown, unknown> ? TSchema : never;
43
52
  /**
44
53
  * Infers the public command name from a command path.
45
54
  */
@@ -60,10 +69,21 @@ export type ResolvedCommand<TCommand extends AnyCommandDefinition> = {
60
69
  command: TCommand;
61
70
  positionals: string[];
62
71
  };
72
+ /**
73
+ * Command resolved and validated without runtime context.
74
+ */
75
+ export type PreparedCommand<TCommand extends AnyCommandDefinition> = {
76
+ name: CommandName<TCommand>;
77
+ path: TCommand['path'];
78
+ command: TCommand;
79
+ options: InferOptions<CommandSchema<TCommand>>;
80
+ provided: InferProvidedOptions<CommandSchema<TCommand>>;
81
+ positionals: string[];
82
+ };
63
83
  /**
64
84
  * Defines a command while preserving literal option schema types.
65
85
  */
66
- export declare function defineCommand<const TSchema extends OptionsSchema, const TPath extends readonly [string, ...string[]], TContext = undefined, TResult = unknown>(command: CommandDefinition<TSchema, TContext, TResult, TPath>): CommandDefinition<TSchema, TContext, TResult, TPath>;
86
+ export declare function defineCommand<const TSchema extends OptionsSchema, const TPath extends readonly [string, ...string[]], TContext = undefined, TResult = unknown, TMetadata = unknown>(command: CommandDefinition<TSchema, TContext, TResult, TPath, TMetadata>): CommandDefinition<TSchema, TContext, TResult, TPath, TMetadata>;
67
87
  /**
68
88
  * Defines a command registry while preserving literal command path types.
69
89
  */
@@ -80,6 +100,14 @@ export declare function resolveCommand<const TCommands extends readonly AnyComma
80
100
  * Resolves a command from raw CLI arguments using each command's option schema.
81
101
  */
82
102
  export declare function resolveCommandFromArgs<const TCommands extends readonly AnyCommandDefinition[]>(registry: CommandRegistry<TCommands>, args: readonly string[]): ResolvedCommand<TCommands[number]>;
103
+ /**
104
+ * Resolves and validates a command without requiring runtime context.
105
+ */
106
+ export declare function prepareCommandFromArgs<const TCommands extends readonly AnyCommandDefinition[]>(registry: CommandRegistry<TCommands>, args: readonly string[]): Promise<PreparedCommand<TCommands[number]>>;
107
+ /**
108
+ * Runs a prepared command with caller-provided runtime context.
109
+ */
110
+ export declare function runPreparedCommand<TCommand extends AnyCommandDefinition>(prepared: PreparedCommand<TCommand>, context: CommandContext<TCommand>): Promise<CommandResult<TCommand>>;
83
111
  /**
84
112
  * Resolves a command from a registry and runs its handler.
85
113
  */
@@ -90,4 +118,3 @@ export declare function runCommandFromRegistry<const TCommands extends readonly
90
118
  */
91
119
  export declare function runCommand<const TSchema extends OptionsSchema, TContext, TResult>(command: CommandDefinition<TSchema, TContext, TResult>, args: readonly string[], context: TContext): Promise<TResult>;
92
120
  export {};
93
- //# sourceMappingURL=commands.d.ts.map
package/dist/commands.js CHANGED
@@ -17,6 +17,8 @@ exports.defineCommandRegistry = defineCommandRegistry;
17
17
  exports.isCommandName = isCommandName;
18
18
  exports.resolveCommand = resolveCommand;
19
19
  exports.resolveCommandFromArgs = resolveCommandFromArgs;
20
+ exports.prepareCommandFromArgs = prepareCommandFromArgs;
21
+ exports.runPreparedCommand = runPreparedCommand;
20
22
  exports.runCommandFromRegistry = runCommandFromRegistry;
21
23
  exports.runCommand = runCommand;
22
24
  const argv_1 = require("./argv");
@@ -70,30 +72,77 @@ function resolveCommandFromArgs(registry, args) {
70
72
  }
71
73
  throw new Error(`Unknown command: ${formatCommandPositionals((0, argv_1.parseArgv)(args).positionals)}`);
72
74
  }
75
+ /**
76
+ * Resolves and validates a command without requiring runtime context.
77
+ */
78
+ async function prepareCommandFromArgs(registry, args) {
79
+ for (const command of commandsBySpecificity(registry.commands)) {
80
+ const argv = (0, argv_1.parseArgv)(args, command.options);
81
+ const resolved = resolveCommandCandidate(command, argv.positionals);
82
+ if (resolved !== undefined) {
83
+ return prepareResolvedCommand(resolved, argv.options);
84
+ }
85
+ }
86
+ throw new Error(`Unknown command: ${formatCommandPositionals((0, argv_1.parseArgv)(args).positionals)}`);
87
+ }
88
+ /**
89
+ * Runs a prepared command with caller-provided runtime context.
90
+ */
91
+ async function runPreparedCommand(prepared, context) {
92
+ const result = await prepared.command.handle({
93
+ options: prepared.options,
94
+ provided: prepared.provided,
95
+ positionals: prepared.positionals,
96
+ context
97
+ });
98
+ return result;
99
+ }
73
100
  /**
74
101
  * Resolves a command from a registry and runs its handler.
75
102
  */
76
103
  async function runCommandFromRegistry(registry, args, context) {
77
- const resolved = resolveCommandFromArgs(registry, args);
78
- return runCommand(resolved.command, args, context);
104
+ const prepared = await prepareCommandFromArgs(registry, args);
105
+ return runPreparedCommand(prepared, context);
79
106
  }
80
107
  /**
81
108
  * Parses arguments, validates command mechanics, and executes a command
82
109
  * handler.
83
110
  */
84
111
  async function runCommand(command, args, context) {
112
+ const prepared = await prepareCommand(command, args);
113
+ return runPreparedCommand(prepared, context);
114
+ }
115
+ async function prepareCommand(command, args) {
85
116
  const argv = (0, argv_1.parseArgv)(args, command.options);
86
117
  const extraPositionals = resolveCommandPositionals(command.path, argv.positionals);
87
- if (extraPositionals.length > 0 && command.allowExtraPositionals !== true) {
88
- throw new Error(`Unexpected positional argument for '${command.path.join(' ')}': ${extraPositionals[0] ?? ''}`);
118
+ const resolved = {
119
+ name: commandPathToName(command.path),
120
+ path: command.path,
121
+ command,
122
+ positionals: extraPositionals
123
+ };
124
+ return prepareResolvedCommand(resolved, argv.options);
125
+ }
126
+ async function prepareResolvedCommand(resolved, rawOptions) {
127
+ const { command } = resolved;
128
+ if (resolved.positionals.length > 0 && command.allowExtraPositionals !== true) {
129
+ throw new Error(`Unexpected positional argument for '${command.path.join(' ')}': ${resolved.positionals[0] ?? ''}`);
89
130
  }
90
- const parsed = (0, options_1.parseOptionsDetailed)(command.options, argv.options);
91
- return command.handle({
131
+ const parsed = (0, options_1.parseOptionsDetailed)(command.options, rawOptions);
132
+ const input = {
92
133
  options: parsed.options,
93
134
  provided: parsed.provided,
94
- positionals: extraPositionals,
95
- context
96
- });
135
+ positionals: resolved.positionals
136
+ };
137
+ await command.prepare?.(input);
138
+ return {
139
+ name: resolved.name,
140
+ path: resolved.path,
141
+ command,
142
+ options: parsed.options,
143
+ provided: parsed.provided,
144
+ positionals: resolved.positionals
145
+ };
97
146
  }
98
147
  function resolveCommandPositionals(path, positionals) {
99
148
  for (let index = 0; index < path.length; index += 1) {
@@ -141,4 +190,3 @@ function resolveMatchingCommandPositionals(path, positionals) {
141
190
  function formatCommandPositionals(positionals) {
142
191
  return positionals.length === 0 ? '<empty>' : positionals.join(' ');
143
192
  }
144
- //# sourceMappingURL=commands.js.map
package/dist/index.d.ts CHANGED
@@ -1,2 +1 @@
1
- export { defineCommand, defineCommandRegistry, isCommandName, mergeOptionsSchema, parseArgv, parseOptions, parseOptionsDetailed, resolveCommand, resolveCommandFromArgs, runCommand, runCommandFromRegistry, type BooleanOption, type CommandDefinition, type CommandInput, type CommandName, type CommandRegistry, type InferOptions, type InferProvidedOptions, type MergeOptionsSchemas, type NumberOption, type OptionDefinition, type OptionsSchema, type ParseOptionsResult, type ParsedArgv, type RawOptionValue, type ResolvedCommand, type StringOption } from './cli';
2
- //# sourceMappingURL=index.d.ts.map
1
+ export { defineCommand, defineCommandRegistry, isCommandName, mergeOptionsSchema, parseArgv, parseOptions, parseOptionsDetailed, prepareCommandFromArgs, resolveCommand, resolveCommandFromArgs, runCommand, runPreparedCommand, runCommandFromRegistry, type BooleanOption, type CommandDefinition, type CommandInput, type CommandName, type CommandRegistry, type InferOptions, type InferProvidedOptions, type MergeOptionsSchemas, type NumberOption, type OptionDefinition, type OptionsSchema, type ParseOptionsResult, type ParsedArgv, type PreparedCommand, type PreparedCommandInput, type RawOptionValue, type ResolvedCommand, type StringOption } from './cli';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runCommandFromRegistry = exports.runCommand = exports.resolveCommandFromArgs = exports.resolveCommand = exports.parseOptionsDetailed = exports.parseOptions = exports.parseArgv = exports.mergeOptionsSchema = exports.isCommandName = exports.defineCommandRegistry = exports.defineCommand = void 0;
3
+ exports.runCommandFromRegistry = exports.runPreparedCommand = exports.runCommand = exports.resolveCommandFromArgs = exports.resolveCommand = exports.prepareCommandFromArgs = exports.parseOptionsDetailed = exports.parseOptions = exports.parseArgv = exports.mergeOptionsSchema = exports.isCommandName = exports.defineCommandRegistry = exports.defineCommand = void 0;
4
4
  var cli_1 = require("./cli");
5
5
  Object.defineProperty(exports, "defineCommand", { enumerable: true, get: function () { return cli_1.defineCommand; } });
6
6
  Object.defineProperty(exports, "defineCommandRegistry", { enumerable: true, get: function () { return cli_1.defineCommandRegistry; } });
@@ -9,8 +9,9 @@ Object.defineProperty(exports, "mergeOptionsSchema", { enumerable: true, get: fu
9
9
  Object.defineProperty(exports, "parseArgv", { enumerable: true, get: function () { return cli_1.parseArgv; } });
10
10
  Object.defineProperty(exports, "parseOptions", { enumerable: true, get: function () { return cli_1.parseOptions; } });
11
11
  Object.defineProperty(exports, "parseOptionsDetailed", { enumerable: true, get: function () { return cli_1.parseOptionsDetailed; } });
12
+ Object.defineProperty(exports, "prepareCommandFromArgs", { enumerable: true, get: function () { return cli_1.prepareCommandFromArgs; } });
12
13
  Object.defineProperty(exports, "resolveCommand", { enumerable: true, get: function () { return cli_1.resolveCommand; } });
13
14
  Object.defineProperty(exports, "resolveCommandFromArgs", { enumerable: true, get: function () { return cli_1.resolveCommandFromArgs; } });
14
15
  Object.defineProperty(exports, "runCommand", { enumerable: true, get: function () { return cli_1.runCommand; } });
16
+ Object.defineProperty(exports, "runPreparedCommand", { enumerable: true, get: function () { return cli_1.runPreparedCommand; } });
15
17
  Object.defineProperty(exports, "runCommandFromRegistry", { enumerable: true, get: function () { return cli_1.runCommandFromRegistry; } });
16
- //# sourceMappingURL=index.js.map
package/dist/options.d.ts CHANGED
@@ -35,9 +35,12 @@ export type StringOption<TChoices extends readonly string[] = readonly string[]>
35
35
  /**
36
36
  * Declarative boolean flag contract.
37
37
  *
38
- * Boolean options accept flag form and explicit `true` / `false` values.
38
+ * Boolean options accept flag form and explicit `true` / `false` values unless
39
+ * `flagOnly` is enabled.
39
40
  */
40
- export type BooleanOption = OptionBase<'boolean', boolean>;
41
+ export type BooleanOption = OptionBase<'boolean', boolean> & {
42
+ flagOnly?: boolean;
43
+ };
41
44
  /**
42
45
  * Declarative number option contract.
43
46
  *
@@ -129,4 +132,3 @@ export declare function parseOptions<const TSchema extends OptionsSchema>(schema
129
132
  */
130
133
  export declare function parseOptionsDetailed<const TSchema extends OptionsSchema>(schema: TSchema, values: Record<string, RawOptionValue>): ParseOptionsResult<TSchema>;
131
134
  export {};
132
- //# sourceMappingURL=options.d.ts.map
package/dist/options.js CHANGED
@@ -71,7 +71,7 @@ function parseOptionValue(name, definition, value) {
71
71
  return parseStringOption(name, definition, value);
72
72
  }
73
73
  if (definition.type === 'boolean') {
74
- return parseBooleanOption(name, value);
74
+ return parseBooleanOption(name, definition, value);
75
75
  }
76
76
  return parseNumberOption(name, definition, value);
77
77
  }
@@ -103,7 +103,13 @@ function parseStringOption(name, definition, value) {
103
103
  assertChoice(name, definition.choices, value);
104
104
  return value;
105
105
  }
106
- function parseBooleanOption(name, value) {
106
+ function parseBooleanOption(name, definition, value) {
107
+ if (definition.flagOnly === true) {
108
+ if (value === true) {
109
+ return true;
110
+ }
111
+ throw new Error(`Expected '--${name}' as boolean flag`);
112
+ }
107
113
  if (value === true || value === 'true') {
108
114
  return true;
109
115
  }
@@ -144,4 +150,3 @@ function assertChoice(name, choices, value) {
144
150
  }
145
151
  throw new Error(`Expected '--${name}' as one of: ${choices.join(', ')}`);
146
152
  }
147
- //# sourceMappingURL=options.js.map
package/package.json CHANGED
@@ -1,12 +1,7 @@
1
1
  {
2
2
  "name": "icore",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Declarative command line interface mechanics for Node.js",
5
- "author": {
6
- "name": "Stanislav Potemkin",
7
- "email": "woodger@ya.ru"
8
- },
9
- "license": "MIT",
10
5
  "keywords": [
11
6
  "command-line",
12
7
  "argv",
@@ -17,9 +12,14 @@
17
12
  "typed-cli",
18
13
  "declarative-cli"
19
14
  ],
15
+ "author": {
16
+ "name": "Stanislav Potemkin",
17
+ "email": "woodger@ya.ru"
18
+ },
19
+ "license": "MIT",
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "git+ssh://git@github.com/woodger/icore.git"
22
+ "url": "git+https://github.com/woodger/icore.git"
23
23
  },
24
24
  "engines": {
25
25
  "node": ">=16.9.0"
@@ -29,9 +29,8 @@
29
29
  "scripts": {
30
30
  "build": "tsc",
31
31
  "test": "node --test dist/*.test.js",
32
- "lint": "eslint src eslint.config.mjs"
32
+ "lint": "eslint src"
33
33
  },
34
- "dependencies": {},
35
34
  "devDependencies": {
36
35
  "@eslint/js": "^9.39.4",
37
36
  "@types/node": "^26.0.1",
package/readme.md CHANGED
@@ -10,7 +10,7 @@ Small dependency-free command line interface mechanics for [Node.js®](https://n
10
10
  Supports a practical GNU-style option syntax:
11
11
 
12
12
  - long options: `--name value`, `--name=value`;
13
- - boolean flags: `--flag`, `--flag=true`, `--flag=false`, `--no-flag`;
13
+ - boolean flags: `--flag`, `--flag=true`, `--flag=false`, `--no-flag` by default;
14
14
  - short aliases: `-f`, `-n value`;
15
15
  - option terminator: `--`.
16
16
 
@@ -74,8 +74,8 @@ Result:
74
74
  }
75
75
  ```
76
76
 
77
- When an option schema is provided, boolean options are parsed as flag-only
78
- options without consuming the following positional argument:
77
+ When an option schema is provided, boolean options are parsed as flags without
78
+ consuming the following positional argument:
79
79
 
80
80
  ```ts
81
81
  const argv = parseArgv([
@@ -455,6 +455,21 @@ Invalid explicit values are rejected:
455
455
  `--uppercase false` keeps `--uppercase` as `true` and leaves `false` as a positional
456
456
  argument.
457
457
 
458
+ Use `flagOnly: true` when a boolean option should accept only flag form:
459
+
460
+ ```ts
461
+ const schema = {
462
+ uppercase: {
463
+ type: 'boolean',
464
+ default: false,
465
+ flagOnly: true
466
+ }
467
+ } as const;
468
+ ```
469
+
470
+ With `flagOnly: true`, `--uppercase` is accepted, while `--uppercase=true`,
471
+ `--uppercase=false`, and `--no-uppercase` are rejected.
472
+
458
473
  ### `type: 'number'`
459
474
 
460
475
  ```ts
@@ -552,8 +567,9 @@ Attached short values such as `-nvalue` and grouped short booleans such as
552
567
  compatibility.
553
568
 
554
569
  Negated syntax such as `--no-cache` is interpreted as `cache: false` when
555
- `cache` is a known boolean option. Unknown negated options and negation for
556
- string or number options are rejected.
570
+ `cache` is a known boolean option without `flagOnly: true`. Unknown negated
571
+ options, negation for string or number options, and negation for flag-only
572
+ boolean options are rejected.
557
573
 
558
574
  ## Error Messages
559
575