@guanghechen/commander 4.4.1 → 4.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Add built-in host and network validators (ip, domain, host), expose is helpers, and extend coerce
8
+ factories with port and choice support.
9
+
10
+ ## 4.5.0
11
+
12
+ ### Minor Changes
13
+
14
+ - Add built-in coerce factories for numeric option parsing in commander.
15
+
3
16
  ## 4.4.1
4
17
 
5
18
  ### Patch Changes
package/README.md CHANGED
@@ -202,6 +202,96 @@ 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: 'port',
234
+ type: 'number',
235
+ args: 'required',
236
+ coerce: Coerce.port('--port'),
237
+ desc: 'Server port',
238
+ })
239
+ .option({
240
+ long: 'domain',
241
+ type: 'string',
242
+ args: 'required',
243
+ coerce: Coerce.domain('--domain'),
244
+ desc: 'Domain name',
245
+ })
246
+ .option({
247
+ long: 'ip',
248
+ type: 'string',
249
+ args: 'required',
250
+ coerce: Coerce.ip('--ip'),
251
+ desc: 'IP address',
252
+ })
253
+ .option({
254
+ long: 'host',
255
+ type: 'string',
256
+ args: 'required',
257
+ coerce: Coerce.host('--host'),
258
+ desc: 'Host (IP or domain)',
259
+ })
260
+ .option({
261
+ long: 'mode',
262
+ type: 'string',
263
+ args: 'required',
264
+ coerce: Coerce.choice('--mode', ['dev', 'test', 'prod'] as const),
265
+ desc: 'Deploy mode',
266
+ })
267
+ .option({
268
+ long: 'scale',
269
+ type: 'number',
270
+ args: 'required',
271
+ coerce: Coerce.number('--scale'),
272
+ desc: 'Scale factor',
273
+ })
274
+ ```
275
+
276
+ Default error message format:
277
+
278
+ ```text
279
+ {name} is expected as {coerce type}, but got {raw}
280
+ ```
281
+
282
+ You can still override the message via `Coerce.xxx(name, 'custom error message')`.
283
+
284
+ ### Built-in Is Helpers
285
+
286
+ ```typescript
287
+ import { isDomain, isIp, isIpv4, isIpv6 } from '@guanghechen/commander'
288
+
289
+ isIpv4('127.0.0.1') // true
290
+ isIpv6('::1') // true
291
+ isIp('2001:db8::1') // true
292
+ isDomain('example.com') // true
293
+ ```
294
+
205
295
  ### Help Examples
206
296
 
207
297
  ```typescript
@@ -219,11 +309,11 @@ await cli.run({ argv: ['--help'], envs: process.env })
219
309
 
220
310
  `usage` 是相对当前 command path 的片段,help 中会自动补齐前缀,例如 `mycli build --watch`。
221
311
 
222
- `--color` / `--no-color` 仅控制 help 文本的终端着色;
223
- `--log-colorful` / `--no-log-colorful` 控制 `Reporter` 的日志着色。
312
+ `--color` / `--no-color` 仅控制 help 文本的终端着色; `--log-colorful` / `--no-log-colorful` 控制
313
+ `Reporter` 的日志着色。
224
314
 
225
- 当环境变量 `NO_COLOR` 存在时,help 渲染默认视为 `--no-color`;
226
- 显式传入 `--color` 可以覆盖这个默认值。
315
+ 当环境变量 `NO_COLOR` 存在时,help 渲染默认视为 `--no-color`;显式传入 `--color`
316
+ 可以覆盖这个默认值。
227
317
 
228
318
  ## Reference
229
319
 
package/lib/cjs/index.cjs CHANGED
@@ -1186,6 +1186,156 @@ class Command {
1186
1186
  }
1187
1187
  }
1188
1188
 
1189
+ function isIpv4(rawValue) {
1190
+ const parts = rawValue.split('.');
1191
+ if (parts.length !== 4) {
1192
+ return false;
1193
+ }
1194
+ for (const part of parts) {
1195
+ if (part.length < 1 || !/^\d+$/.test(part)) {
1196
+ return false;
1197
+ }
1198
+ if (part.length > 1 && part.startsWith('0')) {
1199
+ return false;
1200
+ }
1201
+ const value = Number(part);
1202
+ if (!Number.isInteger(value) || value < 0 || value > 255) {
1203
+ return false;
1204
+ }
1205
+ }
1206
+ return true;
1207
+ }
1208
+ function countIpv6Segments(part, allowIpv4Tail) {
1209
+ if (!part) {
1210
+ return { count: 0, hasIpv4Tail: false };
1211
+ }
1212
+ const segments = part.split(':');
1213
+ let count = 0;
1214
+ let hasIpv4Tail = false;
1215
+ for (let i = 0; i < segments.length; ++i) {
1216
+ const segment = segments[i];
1217
+ const isLastSegment = i === segments.length - 1;
1218
+ if (!segment) {
1219
+ return null;
1220
+ }
1221
+ if (segment.includes('.')) {
1222
+ if (!allowIpv4Tail || !isLastSegment || hasIpv4Tail || !isIpv4(segment)) {
1223
+ return null;
1224
+ }
1225
+ hasIpv4Tail = true;
1226
+ count += 2;
1227
+ continue;
1228
+ }
1229
+ if (!/^[0-9A-Fa-f]{1,4}$/.test(segment)) {
1230
+ return null;
1231
+ }
1232
+ count += 1;
1233
+ }
1234
+ return { count, hasIpv4Tail };
1235
+ }
1236
+ function isIpv6(rawValue) {
1237
+ if (!rawValue || !/^[0-9A-Fa-f:.]+$/.test(rawValue)) {
1238
+ return false;
1239
+ }
1240
+ const doubleColonCount = rawValue.split('::').length - 1;
1241
+ if (doubleColonCount > 1) {
1242
+ return false;
1243
+ }
1244
+ if (doubleColonCount === 0) {
1245
+ const full = countIpv6Segments(rawValue, true);
1246
+ return full !== null && full.count === 8;
1247
+ }
1248
+ const [left, right] = rawValue.split('::');
1249
+ const leftPart = countIpv6Segments(left, right.length === 0);
1250
+ const rightPart = countIpv6Segments(right, true);
1251
+ if (!leftPart || !rightPart) {
1252
+ return false;
1253
+ }
1254
+ const totalSegments = leftPart.count + rightPart.count;
1255
+ return totalSegments < 8;
1256
+ }
1257
+ function isIp(rawValue) {
1258
+ return isIpv4(rawValue) || isIpv6(rawValue);
1259
+ }
1260
+ function isDomain(rawValue) {
1261
+ if (rawValue.length < 1 || rawValue.length > 253 || rawValue.endsWith('.')) {
1262
+ return false;
1263
+ }
1264
+ const labels = rawValue.split('.');
1265
+ if (labels.length < 2) {
1266
+ return false;
1267
+ }
1268
+ if (labels.some(label => label.length < 1 || label.length > 63)) {
1269
+ return false;
1270
+ }
1271
+ const labelPattern = /^[A-Za-z0-9-]+$/;
1272
+ if (labels.some(label => !labelPattern.test(label) || label.startsWith('-') || label.endsWith('-'))) {
1273
+ return false;
1274
+ }
1275
+ const topLevelLabel = labels[labels.length - 1];
1276
+ return /[A-Za-z]/.test(topLevelLabel);
1277
+ }
1278
+
1279
+ class Coerce {
1280
+ constructor() { }
1281
+ static create(name, expectedType, validator, errorMessage) {
1282
+ return (rawValue) => {
1283
+ const value = Number(rawValue);
1284
+ if (!validator(value)) {
1285
+ throw new Error(errorMessage ?? `${name} is expected as ${expectedType}, but got ${rawValue}`);
1286
+ }
1287
+ return value;
1288
+ };
1289
+ }
1290
+ static choice(name, values, errorMessage) {
1291
+ return (rawValue) => {
1292
+ if (values.includes(rawValue)) {
1293
+ return rawValue;
1294
+ }
1295
+ throw new Error(errorMessage ?? `${name} is expected as one of [${values.join(', ')}], but got ${rawValue}`);
1296
+ };
1297
+ }
1298
+ static domain(name, errorMessage) {
1299
+ return (rawValue) => {
1300
+ if (isDomain(rawValue)) {
1301
+ return rawValue;
1302
+ }
1303
+ throw new Error(errorMessage ?? `${name} is expected as a valid domain, but got ${rawValue}`);
1304
+ };
1305
+ }
1306
+ static host(name, errorMessage) {
1307
+ return (rawValue) => {
1308
+ if (isIp(rawValue) || isDomain(rawValue)) {
1309
+ return rawValue;
1310
+ }
1311
+ throw new Error(errorMessage ?? `${name} is expected as a valid host (IP or domain), but got ${rawValue}`);
1312
+ };
1313
+ }
1314
+ static integer(name, errorMessage) {
1315
+ return this.create(name, 'an integer', value => Number.isInteger(value), errorMessage);
1316
+ }
1317
+ static ip(name, errorMessage) {
1318
+ return (rawValue) => {
1319
+ if (isIp(rawValue)) {
1320
+ return rawValue;
1321
+ }
1322
+ throw new Error(errorMessage ?? `${name} is expected as a valid IP address, but got ${rawValue}`);
1323
+ };
1324
+ }
1325
+ static number(name, errorMessage) {
1326
+ return this.create(name, 'a finite number', value => Number.isFinite(value), errorMessage);
1327
+ }
1328
+ static port(name, errorMessage) {
1329
+ return this.create(name, 'a valid port number (0-65535)', value => Number.isInteger(value) && value >= 0 && value <= 65535, errorMessage);
1330
+ }
1331
+ static positiveInteger(name, errorMessage) {
1332
+ return this.create(name, 'a positive integer', value => Number.isInteger(value) && value > 0, errorMessage);
1333
+ }
1334
+ static positiveNumber(name, errorMessage) {
1335
+ return this.create(name, 'a positive number', value => Number.isFinite(value) && value > 0, errorMessage);
1336
+ }
1337
+ }
1338
+
1189
1339
  function camelToKebabCase(str) {
1190
1340
  return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
1191
1341
  }
@@ -1545,11 +1695,16 @@ class PwshCompletion {
1545
1695
  }
1546
1696
 
1547
1697
  exports.BashCompletion = BashCompletion;
1698
+ exports.Coerce = Coerce;
1548
1699
  exports.Command = Command;
1549
1700
  exports.CommanderError = CommanderError;
1550
1701
  exports.CompletionCommand = CompletionCommand;
1551
1702
  exports.FishCompletion = FishCompletion;
1552
1703
  exports.PwshCompletion = PwshCompletion;
1704
+ exports.isDomain = isDomain;
1705
+ exports.isIp = isIp;
1706
+ exports.isIpv4 = isIpv4;
1707
+ exports.isIpv6 = isIpv6;
1553
1708
  exports.logColorfulOption = logColorfulOption;
1554
1709
  exports.logDateOption = logDateOption;
1555
1710
  exports.logLevelOption = logLevelOption;
package/lib/esm/index.mjs CHANGED
@@ -1164,6 +1164,156 @@ class Command {
1164
1164
  }
1165
1165
  }
1166
1166
 
1167
+ function isIpv4(rawValue) {
1168
+ const parts = rawValue.split('.');
1169
+ if (parts.length !== 4) {
1170
+ return false;
1171
+ }
1172
+ for (const part of parts) {
1173
+ if (part.length < 1 || !/^\d+$/.test(part)) {
1174
+ return false;
1175
+ }
1176
+ if (part.length > 1 && part.startsWith('0')) {
1177
+ return false;
1178
+ }
1179
+ const value = Number(part);
1180
+ if (!Number.isInteger(value) || value < 0 || value > 255) {
1181
+ return false;
1182
+ }
1183
+ }
1184
+ return true;
1185
+ }
1186
+ function countIpv6Segments(part, allowIpv4Tail) {
1187
+ if (!part) {
1188
+ return { count: 0, hasIpv4Tail: false };
1189
+ }
1190
+ const segments = part.split(':');
1191
+ let count = 0;
1192
+ let hasIpv4Tail = false;
1193
+ for (let i = 0; i < segments.length; ++i) {
1194
+ const segment = segments[i];
1195
+ const isLastSegment = i === segments.length - 1;
1196
+ if (!segment) {
1197
+ return null;
1198
+ }
1199
+ if (segment.includes('.')) {
1200
+ if (!allowIpv4Tail || !isLastSegment || hasIpv4Tail || !isIpv4(segment)) {
1201
+ return null;
1202
+ }
1203
+ hasIpv4Tail = true;
1204
+ count += 2;
1205
+ continue;
1206
+ }
1207
+ if (!/^[0-9A-Fa-f]{1,4}$/.test(segment)) {
1208
+ return null;
1209
+ }
1210
+ count += 1;
1211
+ }
1212
+ return { count, hasIpv4Tail };
1213
+ }
1214
+ function isIpv6(rawValue) {
1215
+ if (!rawValue || !/^[0-9A-Fa-f:.]+$/.test(rawValue)) {
1216
+ return false;
1217
+ }
1218
+ const doubleColonCount = rawValue.split('::').length - 1;
1219
+ if (doubleColonCount > 1) {
1220
+ return false;
1221
+ }
1222
+ if (doubleColonCount === 0) {
1223
+ const full = countIpv6Segments(rawValue, true);
1224
+ return full !== null && full.count === 8;
1225
+ }
1226
+ const [left, right] = rawValue.split('::');
1227
+ const leftPart = countIpv6Segments(left, right.length === 0);
1228
+ const rightPart = countIpv6Segments(right, true);
1229
+ if (!leftPart || !rightPart) {
1230
+ return false;
1231
+ }
1232
+ const totalSegments = leftPart.count + rightPart.count;
1233
+ return totalSegments < 8;
1234
+ }
1235
+ function isIp(rawValue) {
1236
+ return isIpv4(rawValue) || isIpv6(rawValue);
1237
+ }
1238
+ function isDomain(rawValue) {
1239
+ if (rawValue.length < 1 || rawValue.length > 253 || rawValue.endsWith('.')) {
1240
+ return false;
1241
+ }
1242
+ const labels = rawValue.split('.');
1243
+ if (labels.length < 2) {
1244
+ return false;
1245
+ }
1246
+ if (labels.some(label => label.length < 1 || label.length > 63)) {
1247
+ return false;
1248
+ }
1249
+ const labelPattern = /^[A-Za-z0-9-]+$/;
1250
+ if (labels.some(label => !labelPattern.test(label) || label.startsWith('-') || label.endsWith('-'))) {
1251
+ return false;
1252
+ }
1253
+ const topLevelLabel = labels[labels.length - 1];
1254
+ return /[A-Za-z]/.test(topLevelLabel);
1255
+ }
1256
+
1257
+ class Coerce {
1258
+ constructor() { }
1259
+ static create(name, expectedType, validator, errorMessage) {
1260
+ return (rawValue) => {
1261
+ const value = Number(rawValue);
1262
+ if (!validator(value)) {
1263
+ throw new Error(errorMessage ?? `${name} is expected as ${expectedType}, but got ${rawValue}`);
1264
+ }
1265
+ return value;
1266
+ };
1267
+ }
1268
+ static choice(name, values, errorMessage) {
1269
+ return (rawValue) => {
1270
+ if (values.includes(rawValue)) {
1271
+ return rawValue;
1272
+ }
1273
+ throw new Error(errorMessage ?? `${name} is expected as one of [${values.join(', ')}], but got ${rawValue}`);
1274
+ };
1275
+ }
1276
+ static domain(name, errorMessage) {
1277
+ return (rawValue) => {
1278
+ if (isDomain(rawValue)) {
1279
+ return rawValue;
1280
+ }
1281
+ throw new Error(errorMessage ?? `${name} is expected as a valid domain, but got ${rawValue}`);
1282
+ };
1283
+ }
1284
+ static host(name, errorMessage) {
1285
+ return (rawValue) => {
1286
+ if (isIp(rawValue) || isDomain(rawValue)) {
1287
+ return rawValue;
1288
+ }
1289
+ throw new Error(errorMessage ?? `${name} is expected as a valid host (IP or domain), but got ${rawValue}`);
1290
+ };
1291
+ }
1292
+ static integer(name, errorMessage) {
1293
+ return this.create(name, 'an integer', value => Number.isInteger(value), errorMessage);
1294
+ }
1295
+ static ip(name, errorMessage) {
1296
+ return (rawValue) => {
1297
+ if (isIp(rawValue)) {
1298
+ return rawValue;
1299
+ }
1300
+ throw new Error(errorMessage ?? `${name} is expected as a valid IP address, but got ${rawValue}`);
1301
+ };
1302
+ }
1303
+ static number(name, errorMessage) {
1304
+ return this.create(name, 'a finite number', value => Number.isFinite(value), errorMessage);
1305
+ }
1306
+ static port(name, errorMessage) {
1307
+ return this.create(name, 'a valid port number (0-65535)', value => Number.isInteger(value) && value >= 0 && value <= 65535, errorMessage);
1308
+ }
1309
+ static positiveInteger(name, errorMessage) {
1310
+ return this.create(name, 'a positive integer', value => Number.isInteger(value) && value > 0, errorMessage);
1311
+ }
1312
+ static positiveNumber(name, errorMessage) {
1313
+ return this.create(name, 'a positive number', value => Number.isFinite(value) && value > 0, errorMessage);
1314
+ }
1315
+ }
1316
+
1167
1317
  function camelToKebabCase(str) {
1168
1318
  return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
1169
1319
  }
@@ -1522,4 +1672,4 @@ class PwshCompletion {
1522
1672
  }
1523
1673
  }
1524
1674
 
1525
- export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
1675
+ export { BashCompletion, Coerce, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, isDomain, isIp, isIpv4, isIpv6, logColorfulOption, logDateOption, logLevelOption, silentOption };
@@ -223,6 +223,56 @@ interface ICommandParseResult {
223
223
  /** Raw argument strings */
224
224
  rawArgs: string[];
225
225
  }
226
+ /** Built-in option resolution result (internal) */
227
+ interface ICommandBuiltinOptionResolved {
228
+ color: boolean;
229
+ logLevel: boolean;
230
+ silent: boolean;
231
+ logDate: boolean;
232
+ logColorful: boolean;
233
+ }
234
+ /** Built-in config resolution result (internal) */
235
+ interface ICommandBuiltinResolved {
236
+ option: ICommandBuiltinOptionResolved;
237
+ command: {
238
+ help: boolean;
239
+ };
240
+ }
241
+ /** Subcommand registry entry (internal) */
242
+ interface ISubcommandEntry<TCommand = ICommand> {
243
+ name: string;
244
+ aliases: string[];
245
+ command: TCommand;
246
+ }
247
+ /** Internal route result */
248
+ interface IInternalRouteResult<TCommand = ICommand> {
249
+ chain: TCommand[];
250
+ remaining: string[];
251
+ }
252
+ /** Help option line (internal) */
253
+ interface IHelpOptionLine {
254
+ sig: string;
255
+ desc: string;
256
+ }
257
+ /** Help command line (internal) */
258
+ interface IHelpCommandLine {
259
+ name: string;
260
+ desc: string;
261
+ }
262
+ /** Help example line (internal) */
263
+ interface IHelpExampleLine {
264
+ title: string;
265
+ usage: string;
266
+ desc: string;
267
+ }
268
+ /** Structured help data for rendering (internal) */
269
+ interface IHelpData {
270
+ desc: string;
271
+ usage: string;
272
+ options: IHelpOptionLine[];
273
+ commands: IHelpCommandLine[];
274
+ examples: IHelpExampleLine[];
275
+ }
226
276
  /** Error kinds for command parsing */
227
277
  type ICommanderErrorKind = 'InvalidOptionFormat' | 'InvalidNegativeOption' | 'NegativeOptionWithValue' | 'NegativeOptionType' | 'UnknownOption' | 'UnknownSubcommand' | 'UnexpectedArgument' | 'MissingValue' | 'InvalidType' | 'UnsupportedShortSyntax' | 'OptionConflict' | 'MissingRequired' | 'InvalidChoice' | 'InvalidBooleanValue' | 'MissingRequiredArgument' | 'TooManyArguments' | 'ConfigurationError';
228
278
  /** Commander error with structured information */
@@ -308,6 +358,30 @@ declare class Command implements ICommand {
308
358
  getCompletionMeta(): ICompletionMeta;
309
359
  }
310
360
 
361
+ /**
362
+ * Pre-defined coerce factory methods for @guanghechen/commander.
363
+ *
364
+ * @module @guanghechen/commander/coerce
365
+ */
366
+ declare class Coerce {
367
+ private constructor();
368
+ private static create;
369
+ static choice<TValue extends string>(name: string, values: ReadonlyArray<TValue>, errorMessage?: string): (rawValue: string) => TValue;
370
+ static domain(name: string, errorMessage?: string): (rawValue: string) => string;
371
+ static host(name: string, errorMessage?: string): (rawValue: string) => string;
372
+ static integer(name: string, errorMessage?: string): (rawValue: string) => number;
373
+ static ip(name: string, errorMessage?: string): (rawValue: string) => string;
374
+ static number(name: string, errorMessage?: string): (rawValue: string) => number;
375
+ static port(name: string, errorMessage?: string): (rawValue: string) => number;
376
+ static positiveInteger(name: string, errorMessage?: string): (rawValue: string) => number;
377
+ static positiveNumber(name: string, errorMessage?: string): (rawValue: string) => number;
378
+ }
379
+
380
+ declare function isIpv4(rawValue: string): boolean;
381
+ declare function isIpv6(rawValue: string): boolean;
382
+ declare function isIp(rawValue: string): boolean;
383
+ declare function isDomain(rawValue: string): boolean;
384
+
311
385
  /**
312
386
  * Shell completion generators
313
387
  *
@@ -436,5 +510,5 @@ declare const logColorfulOption: ICommandOptionConfig<boolean>;
436
510
  */
437
511
  declare const silentOption: ICommandOptionConfig<boolean>;
438
512
 
439
- export { BashCompletion, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, logColorfulOption, logDateOption, logLevelOption, silentOption };
440
- 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 };
513
+ export { BashCompletion, Coerce, Command, CommanderError, CompletionCommand, FishCompletion, PwshCompletion, isDomain, isIp, isIpv4, isIpv6, logColorfulOption, logDateOption, logLevelOption, silentOption };
514
+ export type { ICommand, ICommandAction, ICommandActionParams, ICommandArgumentConfig, ICommandArgumentKind, ICommandArgumentType, ICommandBuiltinCommandConfig, ICommandBuiltinConfig, ICommandBuiltinOptionConfig, ICommandBuiltinOptionResolved, ICommandBuiltinResolved, ICommandConfig, ICommandContext, ICommandExample, ICommandOptionArgs, ICommandOptionConfig, ICommandOptionType, ICommandParseResult, ICommandParsedArgs, ICommandParsedOpts, ICommandResolveResult, ICommandRouteResult, ICommandRunParams, ICommandShiftResult, ICommandToken, ICommandTokenType, ICommandTokenizeResult, ICommanderErrorKind, ICompletionCommandConfig, ICompletionMeta, ICompletionOptionMeta, ICompletionPaths, ICompletionShellType, IHelpCommandLine, IHelpData, IHelpExampleLine, IHelpOptionLine, IInternalRouteResult, ISubcommandEntry };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guanghechen/commander",
3
- "version": "4.4.1",
3
+ "version": "4.5.1",
4
4
  "description": "A minimal, type-safe command-line interface builder with fluent API",
5
5
  "author": {
6
6
  "name": "guanghechen",