@guanghechen/commander 4.4.1 → 4.5.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add built-in coerce factories for numeric option parsing in commander.
8
+
3
9
  ## 4.4.1
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -202,6 +202,50 @@ new Command({ name: 'example', description: 'Option types demo' })
202
202
  })
203
203
  ```
204
204
 
205
+ ### Built-in Coerce Factories
206
+
207
+ ```typescript
208
+ import { Coerce, Command } from '@guanghechen/commander'
209
+
210
+ new Command({ name: 'example', desc: 'Coerce demo' })
211
+ .option({
212
+ long: 'offset',
213
+ type: 'number',
214
+ args: 'required',
215
+ coerce: Coerce.integer('--offset'),
216
+ desc: 'Signed offset',
217
+ })
218
+ .option({
219
+ long: 'parallel',
220
+ type: 'number',
221
+ args: 'required',
222
+ coerce: Coerce.positiveInteger('--parallel'),
223
+ desc: 'Parallel workers',
224
+ })
225
+ .option({
226
+ long: 'duration',
227
+ type: 'number',
228
+ args: 'required',
229
+ coerce: Coerce.positiveNumber('--duration'),
230
+ desc: 'Duration in seconds',
231
+ })
232
+ .option({
233
+ long: 'scale',
234
+ type: 'number',
235
+ args: 'required',
236
+ coerce: Coerce.number('--scale'),
237
+ desc: 'Scale factor',
238
+ })
239
+ ```
240
+
241
+ Default error message format:
242
+
243
+ ```text
244
+ {name} is expected as {coerce type}, but got {raw}
245
+ ```
246
+
247
+ You can still override the message via `Coerce.xxx(name, 'custom error message')`.
248
+
205
249
  ### Help Examples
206
250
 
207
251
  ```typescript
package/lib/cjs/index.cjs CHANGED
@@ -1186,6 +1186,31 @@ class Command {
1186
1186
  }
1187
1187
  }
1188
1188
 
1189
+ class Coerce {
1190
+ constructor() { }
1191
+ static create(name, expectedType, validator, errorMessage) {
1192
+ return (rawValue) => {
1193
+ const value = Number(rawValue);
1194
+ if (!validator(value)) {
1195
+ throw new Error(errorMessage ?? `${name} is expected as ${expectedType}, but got ${rawValue}`);
1196
+ }
1197
+ return value;
1198
+ };
1199
+ }
1200
+ static number(name, errorMessage) {
1201
+ return this.create(name, 'a finite number', value => Number.isFinite(value), errorMessage);
1202
+ }
1203
+ static integer(name, errorMessage) {
1204
+ return this.create(name, 'an integer', value => Number.isInteger(value), errorMessage);
1205
+ }
1206
+ static positiveInteger(name, errorMessage) {
1207
+ return this.create(name, 'a positive integer', value => Number.isInteger(value) && value > 0, errorMessage);
1208
+ }
1209
+ static positiveNumber(name, errorMessage) {
1210
+ return this.create(name, 'a positive number', value => Number.isFinite(value) && value > 0, errorMessage);
1211
+ }
1212
+ }
1213
+
1189
1214
  function camelToKebabCase(str) {
1190
1215
  return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
1191
1216
  }
@@ -1545,6 +1570,7 @@ class PwshCompletion {
1545
1570
  }
1546
1571
 
1547
1572
  exports.BashCompletion = BashCompletion;
1573
+ exports.Coerce = Coerce;
1548
1574
  exports.Command = Command;
1549
1575
  exports.CommanderError = CommanderError;
1550
1576
  exports.CompletionCommand = CompletionCommand;
package/lib/esm/index.mjs CHANGED
@@ -1164,6 +1164,31 @@ class Command {
1164
1164
  }
1165
1165
  }
1166
1166
 
1167
+ class Coerce {
1168
+ constructor() { }
1169
+ static create(name, expectedType, validator, errorMessage) {
1170
+ return (rawValue) => {
1171
+ const value = Number(rawValue);
1172
+ if (!validator(value)) {
1173
+ throw new Error(errorMessage ?? `${name} is expected as ${expectedType}, but got ${rawValue}`);
1174
+ }
1175
+ return value;
1176
+ };
1177
+ }
1178
+ static number(name, errorMessage) {
1179
+ return this.create(name, 'a finite number', value => Number.isFinite(value), errorMessage);
1180
+ }
1181
+ static integer(name, errorMessage) {
1182
+ return this.create(name, 'an integer', value => Number.isInteger(value), errorMessage);
1183
+ }
1184
+ static positiveInteger(name, errorMessage) {
1185
+ return this.create(name, 'a positive integer', value => Number.isInteger(value) && value > 0, errorMessage);
1186
+ }
1187
+ static positiveNumber(name, errorMessage) {
1188
+ return this.create(name, 'a positive number', value => Number.isFinite(value) && value > 0, errorMessage);
1189
+ }
1190
+ }
1191
+
1167
1192
  function camelToKebabCase(str) {
1168
1193
  return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
1169
1194
  }
@@ -1522,4 +1547,4 @@ class PwshCompletion {
1522
1547
  }
1523
1548
  }
1524
1549
 
1525
- export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
1550
+ export { BashCompletion, Coerce, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
@@ -308,6 +308,20 @@ declare class Command implements ICommand {
308
308
  getCompletionMeta(): ICompletionMeta;
309
309
  }
310
310
 
311
+ /**
312
+ * Pre-defined coerce factory methods for @guanghechen/commander.
313
+ *
314
+ * @module @guanghechen/commander/coerce
315
+ */
316
+ declare class Coerce {
317
+ private constructor();
318
+ private static create;
319
+ static number(name: string, errorMessage?: string): (rawValue: string) => number;
320
+ static integer(name: string, errorMessage?: string): (rawValue: string) => number;
321
+ static positiveInteger(name: string, errorMessage?: string): (rawValue: string) => number;
322
+ static positiveNumber(name: string, errorMessage?: string): (rawValue: string) => number;
323
+ }
324
+
311
325
  /**
312
326
  * Shell completion generators
313
327
  *
@@ -436,5 +450,5 @@ declare const logColorfulOption: ICommandOptionConfig<boolean>;
436
450
  */
437
451
  declare const silentOption: ICommandOptionConfig<boolean>;
438
452
 
439
- export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
453
+ export { BashCompletion, Coerce, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
440
454
  export type { ICommand, ICommandAction, ICommandActionParams, ICommandArgumentConfig, ICommandArgumentKind, ICommandArgumentType, ICommandBuiltinCommandConfig, ICommandBuiltinConfig, ICommandBuiltinOptionConfig, ICommandConfig, ICommandContext, ICommandExample, ICommandOptionArgs, ICommandOptionConfig, ICommandOptionType, ICommandParseResult, ICommandParsedArgs, ICommandParsedOpts, ICommandResolveResult, ICommandRouteResult, ICommandRunParams, ICommandShiftResult, ICommandToken, ICommandTokenType, ICommandTokenizeResult, ICommanderErrorKind, ICompletionCommandConfig, ICompletionMeta, ICompletionOptionMeta, ICompletionPaths, ICompletionShellType };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guanghechen/commander",
3
- "version": "4.4.1",
3
+ "version": "4.5.0",
4
4
  "description": "A minimal, type-safe command-line interface builder with fluent API",
5
5
  "author": {
6
6
  "name": "guanghechen",