@optique/core 1.1.0-dev.2096 → 1.1.0-dev.2146

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.
Files changed (69) hide show
  1. package/dist/annotation-state.cjs +26 -26
  2. package/dist/annotation-state.d.cts +133 -1
  3. package/dist/annotation-state.d.ts +133 -1
  4. package/dist/annotations.cjs +2 -2
  5. package/dist/constructs.cjs +141 -73
  6. package/dist/constructs.js +70 -2
  7. package/dist/dependency-metadata.cjs +12 -12
  8. package/dist/dependency-metadata.d.cts +34 -3
  9. package/dist/dependency-metadata.d.ts +34 -3
  10. package/dist/dependency-runtime.cjs +37 -13
  11. package/dist/dependency-runtime.d.cts +197 -2
  12. package/dist/dependency-runtime.d.ts +197 -2
  13. package/dist/dependency-runtime.js +22 -1
  14. package/dist/dependency.cjs +7 -7
  15. package/dist/displaywidth.d.cts +12 -0
  16. package/dist/displaywidth.d.ts +12 -0
  17. package/dist/execution-context.d.cts +23 -0
  18. package/dist/execution-context.d.ts +23 -0
  19. package/dist/extension.cjs +14 -14
  20. package/dist/facade.cjs +46 -36
  21. package/dist/facade.js +31 -21
  22. package/dist/index.cjs +22 -21
  23. package/dist/index.d.cts +2 -2
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.js +3 -3
  26. package/dist/input-trace.d.cts +2 -1
  27. package/dist/input-trace.d.ts +2 -1
  28. package/dist/internal/annotations.cjs +3 -0
  29. package/dist/internal/annotations.d.cts +47 -5
  30. package/dist/internal/annotations.d.ts +47 -5
  31. package/dist/internal/annotations.js +1 -1
  32. package/dist/internal/command-alias.cjs +16 -0
  33. package/dist/internal/command-alias.js +14 -0
  34. package/dist/internal/dependency.cjs +131 -0
  35. package/dist/internal/dependency.d.cts +311 -2
  36. package/dist/internal/dependency.d.ts +311 -2
  37. package/dist/internal/dependency.js +119 -1
  38. package/dist/internal/parser.cjs +35 -13
  39. package/dist/internal/parser.d.cts +44 -3
  40. package/dist/internal/parser.d.ts +44 -3
  41. package/dist/internal/parser.js +28 -6
  42. package/dist/modifiers.cjs +41 -41
  43. package/dist/parser.cjs +11 -11
  44. package/dist/phase2-seed.cjs +2 -2
  45. package/dist/phase2-seed.d.cts +50 -0
  46. package/dist/phase2-seed.d.ts +50 -0
  47. package/dist/primitives.cjs +74 -33
  48. package/dist/primitives.d.cts +10 -0
  49. package/dist/primitives.d.ts +10 -0
  50. package/dist/primitives.js +54 -13
  51. package/dist/suggestion.cjs +72 -2
  52. package/dist/suggestion.d.cts +188 -0
  53. package/dist/suggestion.d.ts +188 -0
  54. package/dist/suggestion.js +71 -3
  55. package/dist/usage-internals.cjs +5 -1
  56. package/dist/usage-internals.js +5 -1
  57. package/dist/usage.cjs +9 -1
  58. package/dist/usage.d.cts +14 -0
  59. package/dist/usage.d.ts +14 -0
  60. package/dist/usage.js +9 -1
  61. package/dist/validate.cjs +1 -0
  62. package/dist/validate.d.cts +99 -0
  63. package/dist/validate.d.ts +99 -0
  64. package/dist/validate.js +1 -1
  65. package/dist/valueparser.cjs +333 -79
  66. package/dist/valueparser.d.cts +197 -1
  67. package/dist/valueparser.d.ts +197 -1
  68. package/dist/valueparser.js +334 -81
  69. package/package.json +19 -4
@@ -1,4 +1,6 @@
1
1
  const require_message = require('./message.cjs');
2
+ const require_internal_dependency = require('./internal/dependency.cjs');
3
+ const require_suggestion = require('./suggestion.cjs');
2
4
  const require_nonempty = require('./nonempty.cjs');
3
5
 
4
6
  //#region src/valueparser.ts
@@ -29,8 +31,8 @@ function choice(choices, options = {}) {
29
31
  const isNumber = typeof choices[0] === "number";
30
32
  for (const c of choices) if (isNumber ? typeof c !== "number" : typeof c !== "string") throw new TypeError(`Expected every choice to be the same type, but got both ${isNumber ? "number" : "string"} and ${typeof c}.`);
31
33
  if (isNumber && choices.some((v) => Number.isNaN(v))) throw new TypeError("NaN is not allowed in number choices.");
32
- const metavar = options.metavar ?? "TYPE";
33
- require_nonempty.ensureNonEmptyString(metavar);
34
+ const metavar$1 = options.metavar ?? "TYPE";
35
+ require_nonempty.ensureNonEmptyString(metavar$1);
34
36
  if (isNumber) {
35
37
  const numberChoices = (() => {
36
38
  const seen = /* @__PURE__ */ new Set();
@@ -57,7 +59,7 @@ function choice(choices, options = {}) {
57
59
  const frozenNumberChoices = Object.freeze(numberChoices);
58
60
  return {
59
61
  mode: "sync",
60
- metavar,
62
+ metavar: metavar$1,
61
63
  placeholder: choices[0],
62
64
  choices: frozenNumberChoices,
63
65
  parse(input) {
@@ -139,7 +141,7 @@ function choice(choices, options = {}) {
139
141
  const stringInvalidChoice = stringOptions.errors?.invalidChoice;
140
142
  return {
141
143
  mode: "sync",
142
- metavar,
144
+ metavar: metavar$1,
143
145
  placeholder: choices[0],
144
146
  choices: stringChoices,
145
147
  parse(input) {
@@ -294,14 +296,14 @@ function formatDefaultChoiceError(input, choices) {
294
296
  */
295
297
  function string(options = {}) {
296
298
  if (options.pattern != null && !(options.pattern instanceof RegExp)) throw new TypeError(`Expected pattern to be a RegExp, but got: ${Object.prototype.toString.call(options.pattern)}`);
297
- const metavar = options.metavar ?? "STRING";
298
- require_nonempty.ensureNonEmptyString(metavar);
299
+ const metavar$1 = options.metavar ?? "STRING";
300
+ require_nonempty.ensureNonEmptyString(metavar$1);
299
301
  const patternSource = options.pattern?.source ?? null;
300
302
  const patternFlags = options.pattern?.flags ?? null;
301
303
  const patternMismatch = options.errors?.patternMismatch;
302
304
  return {
303
305
  mode: "sync",
304
- metavar,
306
+ metavar: metavar$1,
305
307
  placeholder: options.placeholder ?? "",
306
308
  parse(input) {
307
309
  if (patternSource != null && patternFlags != null) {
@@ -370,11 +372,11 @@ function integer(options) {
370
372
  }
371
373
  if (options?.min != null && options?.max != null && options.min > options.max) throw new RangeError(`Expected min to be less than or equal to max, but got min: ${options.min} and max: ${options.max}.`);
372
374
  if (options?.type === "bigint") {
373
- const metavar$1 = options.metavar ?? "INTEGER";
374
- require_nonempty.ensureNonEmptyString(metavar$1);
375
+ const metavar$2 = options.metavar ?? "INTEGER";
376
+ require_nonempty.ensureNonEmptyString(metavar$2);
375
377
  return {
376
378
  mode: "sync",
377
- metavar: metavar$1,
379
+ metavar: metavar$2,
378
380
  placeholder: options?.placeholder ?? (options?.min != null && options.min > 0n ? options.min : options?.max != null && options.max < 0n ? options.max : 0n),
379
381
  parse(input) {
380
382
  if (!input.match(/^-?\d+$/)) return {
@@ -400,8 +402,8 @@ function integer(options) {
400
402
  }
401
403
  };
402
404
  }
403
- const metavar = options?.metavar ?? "INTEGER";
404
- require_nonempty.ensureNonEmptyString(metavar);
405
+ const metavar$1 = options?.metavar ?? "INTEGER";
406
+ require_nonempty.ensureNonEmptyString(metavar$1);
405
407
  const maxSafe = BigInt(Number.MAX_SAFE_INTEGER);
406
408
  const minSafe = BigInt(Number.MIN_SAFE_INTEGER);
407
409
  const safeMin = Math.max(options?.min ?? Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
@@ -418,7 +420,7 @@ function integer(options) {
418
420
  }
419
421
  return {
420
422
  mode: "sync",
421
- metavar,
423
+ metavar: metavar$1,
422
424
  placeholder: options?.placeholder ?? (firstAllowed > 0 ? firstAllowed : lastAllowed < 0 ? lastAllowed : 0),
423
425
  parse(input) {
424
426
  if (!input.match(/^-?\d+$/)) return {
@@ -465,11 +467,11 @@ function float(options = {}) {
465
467
  if (options.max != null && !Number.isFinite(options.max)) throw new RangeError(`Expected max to be a finite number, but got: ${options.max}`);
466
468
  if (options.min != null && options.max != null && options.min > options.max) throw new RangeError(`Expected min to be less than or equal to max, but got min: ${options.min} and max: ${options.max}.`);
467
469
  const floatRegex = /^[+-]?(?:(?:\d+\.?\d*)|(?:\d*\.\d+))(?:[eE][+-]?\d+)?$/;
468
- const metavar = options.metavar ?? "NUMBER";
469
- require_nonempty.ensureNonEmptyString(metavar);
470
+ const metavar$1 = options.metavar ?? "NUMBER";
471
+ require_nonempty.ensureNonEmptyString(metavar$1);
470
472
  return {
471
473
  mode: "sync",
472
- metavar,
474
+ metavar: metavar$1,
473
475
  placeholder: options?.placeholder ?? (options?.min != null && options.min > 0 ? options.min : options?.max != null && options.max < 0 ? options.max : 0),
474
476
  parse(input) {
475
477
  const invalidNumber = (i) => ({
@@ -741,8 +743,8 @@ const FILE_SIZE_UNITS = [
741
743
  */
742
744
  function fileSize(options = {}) {
743
745
  if (options.type !== void 0 && options.type !== "number" && options.type !== "bigint") throw new TypeError(`Expected type to be "number" or "bigint", but got: ${String(options.type)}.`);
744
- const metavar = options.metavar ?? "SIZE";
745
- require_nonempty.ensureNonEmptyString(metavar);
746
+ const metavar$1 = options.metavar ?? "SIZE";
747
+ require_nonempty.ensureNonEmptyString(metavar$1);
746
748
  checkBooleanOption(options, "allowNegative");
747
749
  checkBooleanOption(options, "siAsBinary");
748
750
  checkEnumOption(options, "defaultUnit", FILE_SIZE_UNITS);
@@ -762,7 +764,7 @@ function fileSize(options = {}) {
762
764
  const numberFormatUnits = siAsBinary ? FORMAT_UNITS_SI_AS_BINARY : FORMAT_UNITS_DEFAULT;
763
765
  return {
764
766
  mode: "sync",
765
- metavar,
767
+ metavar: metavar$1,
766
768
  placeholder: options.placeholder ?? 0n,
767
769
  parse(input) {
768
770
  const match = FILE_SIZE_REGEX.exec(input.trim());
@@ -803,7 +805,7 @@ function fileSize(options = {}) {
803
805
  const formatUnits = siAsBinary ? FORMAT_UNITS_SI_AS_BINARY : FORMAT_UNITS_DEFAULT;
804
806
  return {
805
807
  mode: "sync",
806
- metavar,
808
+ metavar: metavar$1,
807
809
  placeholder: options.placeholder ?? 0,
808
810
  parse(input) {
809
811
  const match = FILE_SIZE_REGEX.exec(input.trim());
@@ -1802,8 +1804,8 @@ const VALID_COLOR_FORMATS = [
1802
1804
  * @since 1.1.0
1803
1805
  */
1804
1806
  function color(options = {}) {
1805
- const metavar = options.metavar ?? "COLOR";
1806
- require_nonempty.ensureNonEmptyString(metavar);
1807
+ const metavar$1 = options.metavar ?? "COLOR";
1808
+ require_nonempty.ensureNonEmptyString(metavar$1);
1807
1809
  if (options.formats !== void 0) {
1808
1810
  for (const fmt of options.formats) if (!VALID_COLOR_FORMATS.includes(fmt)) throw new TypeError(`Expected formats to contain only ${VALID_COLOR_FORMATS.map((v) => JSON.stringify(v)).join(", ")}, but got: ${JSON.stringify(fmt)}.`);
1809
1811
  }
@@ -1835,7 +1837,7 @@ function color(options = {}) {
1835
1837
  }
1836
1838
  return {
1837
1839
  mode: "sync",
1838
- metavar,
1840
+ metavar: metavar$1,
1839
1841
  placeholder: options.placeholder ?? defaultPlaceholder,
1840
1842
  parse(input) {
1841
1843
  const trimmed = input.trim();
@@ -2009,13 +2011,13 @@ function url(options = {}) {
2009
2011
  }
2010
2012
  const originalProtocols = options.allowedProtocols != null ? Object.freeze(originalProtocolsList) : void 0;
2011
2013
  const allowedProtocols = options.allowedProtocols != null ? Object.freeze(normalizedProtocolsList) : void 0;
2012
- const metavar = options.metavar ?? "URL";
2013
- require_nonempty.ensureNonEmptyString(metavar);
2014
+ const metavar$1 = options.metavar ?? "URL";
2015
+ require_nonempty.ensureNonEmptyString(metavar$1);
2014
2016
  const invalidUrl = options.errors?.invalidUrl;
2015
2017
  const disallowedProtocol = options.errors?.disallowedProtocol;
2016
2018
  return {
2017
2019
  mode: "sync",
2018
- metavar,
2020
+ metavar: metavar$1,
2019
2021
  get placeholder() {
2020
2022
  return new URL(`${allowedProtocols?.[0] ?? "http:"}//0.invalid`);
2021
2023
  },
@@ -2083,11 +2085,11 @@ function url(options = {}) {
2083
2085
  * objects.
2084
2086
  */
2085
2087
  function locale(options = {}) {
2086
- const metavar = options.metavar ?? "LOCALE";
2087
- require_nonempty.ensureNonEmptyString(metavar);
2088
+ const metavar$1 = options.metavar ?? "LOCALE";
2089
+ require_nonempty.ensureNonEmptyString(metavar$1);
2088
2090
  return {
2089
2091
  mode: "sync",
2090
- metavar,
2092
+ metavar: metavar$1,
2091
2093
  placeholder: new Intl.Locale("und"),
2092
2094
  parse(input) {
2093
2095
  let locale$1;
@@ -2365,8 +2367,8 @@ function locale(options = {}) {
2365
2367
  */
2366
2368
  function uuid(options = {}) {
2367
2369
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2368
- const metavar = options.metavar ?? "UUID";
2369
- require_nonempty.ensureNonEmptyString(metavar);
2370
+ const metavar$1 = options.metavar ?? "UUID";
2371
+ require_nonempty.ensureNonEmptyString(metavar$1);
2370
2372
  checkBooleanOption(options, "strict");
2371
2373
  const strict = options.strict !== false;
2372
2374
  const allowedVersions = options.allowedVersions != null ? (() => {
@@ -2383,7 +2385,7 @@ function uuid(options = {}) {
2383
2385
  const invalidVariant = options.errors?.invalidVariant;
2384
2386
  return {
2385
2387
  mode: "sync",
2386
- metavar,
2388
+ metavar: metavar$1,
2387
2389
  placeholder: "00000000-0000-0000-0000-000000000000",
2388
2390
  parse(input) {
2389
2391
  if (!uuidRegex.test(input)) return {
@@ -2483,15 +2485,15 @@ function port(options) {
2483
2485
  checkBooleanOption(options, "disallowWellKnown");
2484
2486
  if (options?.type !== void 0 && options.type !== "number" && options.type !== "bigint") throw new TypeError(`Expected type to be "number" or "bigint", but got: ${String(options.type)}.`);
2485
2487
  if (options?.type === "bigint") {
2486
- const metavar$1 = options.metavar ?? "PORT";
2487
- require_nonempty.ensureNonEmptyString(metavar$1);
2488
+ const metavar$2 = options.metavar ?? "PORT";
2489
+ require_nonempty.ensureNonEmptyString(metavar$2);
2488
2490
  const min$1 = options.min ?? 1n;
2489
2491
  const max$1 = options.max ?? 65535n;
2490
2492
  if (min$1 > max$1) throw new RangeError(`Expected min to be less than or equal to max, but got min: ${min$1} and max: ${max$1}.`);
2491
2493
  if (options.disallowWellKnown && min$1 < 1024n && max$1 < 1024n) throw new RangeError(`disallowWellKnown is incompatible with the configured port range: all ports ${min$1}..${max$1} are well-known.`);
2492
2494
  return {
2493
2495
  mode: "sync",
2494
- metavar: metavar$1,
2496
+ metavar: metavar$2,
2495
2497
  placeholder: options.placeholder ?? (options.disallowWellKnown && min$1 < 1024n ? 1024n > min$1 ? 1024n : min$1 : min$1),
2496
2498
  parse(input) {
2497
2499
  if (!input.match(/^-?\d+$/)) return {
@@ -2523,15 +2525,15 @@ function port(options) {
2523
2525
  }
2524
2526
  if (options?.min != null && !Number.isFinite(options.min)) throw new RangeError(`Expected min to be a finite number, but got: ${options.min}`);
2525
2527
  if (options?.max != null && !Number.isFinite(options.max)) throw new RangeError(`Expected max to be a finite number, but got: ${options.max}`);
2526
- const metavar = options?.metavar ?? "PORT";
2527
- require_nonempty.ensureNonEmptyString(metavar);
2528
+ const metavar$1 = options?.metavar ?? "PORT";
2529
+ require_nonempty.ensureNonEmptyString(metavar$1);
2528
2530
  const min = options?.min ?? 1;
2529
2531
  const max = options?.max ?? 65535;
2530
2532
  if (min > max) throw new RangeError(`Expected min to be less than or equal to max, but got min: ${min} and max: ${max}.`);
2531
2533
  if (options?.disallowWellKnown && min < 1024 && max < 1024) throw new RangeError(`disallowWellKnown is incompatible with the configured port range: all ports ${min}..${max} are well-known.`);
2532
2534
  return {
2533
2535
  mode: "sync",
2534
- metavar,
2536
+ metavar: metavar$1,
2535
2537
  placeholder: options?.placeholder ?? (options?.disallowWellKnown && min < 1024 ? Math.max(1024, min) : min),
2536
2538
  parse(input) {
2537
2539
  if (!input.match(/^-?\d+$/)) return {
@@ -2615,8 +2617,8 @@ function isZeroIp(octets) {
2615
2617
  * ```
2616
2618
  */
2617
2619
  function ipv4(options) {
2618
- const metavar = options?.metavar ?? "IPV4";
2619
- require_nonempty.ensureNonEmptyString(metavar);
2620
+ const metavar$1 = options?.metavar ?? "IPV4";
2621
+ require_nonempty.ensureNonEmptyString(metavar$1);
2620
2622
  const allowPrivate = options?.allowPrivate ?? true;
2621
2623
  const allowLoopback = options?.allowLoopback ?? true;
2622
2624
  const allowLinkLocal = options?.allowLinkLocal ?? true;
@@ -2625,7 +2627,7 @@ function ipv4(options) {
2625
2627
  const allowZero = options?.allowZero ?? true;
2626
2628
  return {
2627
2629
  mode: "sync",
2628
- metavar,
2630
+ metavar: metavar$1,
2629
2631
  placeholder: allowZero ? "0.0.0.0" : allowLoopback ? "127.0.0.1" : "192.0.2.1",
2630
2632
  parse(input) {
2631
2633
  const octets = parseIpv4Octets(input);
@@ -2730,8 +2732,8 @@ function ipv4(options) {
2730
2732
  * ```
2731
2733
  */
2732
2734
  function hostname(options) {
2733
- const metavar = options?.metavar ?? "HOST";
2734
- require_nonempty.ensureNonEmptyString(metavar);
2735
+ const metavar$1 = options?.metavar ?? "HOST";
2736
+ require_nonempty.ensureNonEmptyString(metavar$1);
2735
2737
  checkBooleanOption(options, "allowWildcard");
2736
2738
  checkBooleanOption(options, "allowUnderscore");
2737
2739
  checkBooleanOption(options, "allowLocalhost");
@@ -2742,7 +2744,7 @@ function hostname(options) {
2742
2744
  if (!Number.isInteger(maxLength) || maxLength < 1) throw new RangeError("maxLength must be an integer greater than or equal to 1.");
2743
2745
  return {
2744
2746
  mode: "sync",
2745
- metavar,
2747
+ metavar: metavar$1,
2746
2748
  placeholder: options?.placeholder ?? (allowLocalhost ? maxLength >= 9 ? "localhost" : "a.bc" : maxLength >= 11 ? "example.com" : "a.bc"),
2747
2749
  parse(input) {
2748
2750
  if (input.length > maxLength) {
@@ -2860,8 +2862,8 @@ function hostname(options) {
2860
2862
  };
2861
2863
  }
2862
2864
  function email(options) {
2863
- const metavar = options?.metavar ?? "EMAIL";
2864
- require_nonempty.ensureNonEmptyString(metavar);
2865
+ const metavar$1 = options?.metavar ?? "EMAIL";
2866
+ require_nonempty.ensureNonEmptyString(metavar$1);
2865
2867
  const allowMultiple = options?.allowMultiple ?? false;
2866
2868
  if (options?.placeholder != null) {
2867
2869
  if (allowMultiple && !Array.isArray(options.placeholder)) throw new TypeError("email() placeholder must be an array when allowMultiple is true.");
@@ -2962,7 +2964,7 @@ function email(options) {
2962
2964
  }
2963
2965
  return {
2964
2966
  mode: "sync",
2965
- metavar,
2967
+ metavar: metavar$1,
2966
2968
  placeholder: options?.placeholder ?? (options?.allowMultiple ? [`user@${options?.allowedDomains?.[0] ?? "example.com"}`] : `user@${options?.allowedDomains?.[0] ?? "example.com"}`),
2967
2969
  parse(input) {
2968
2970
  if (allowMultiple) {
@@ -3121,8 +3123,8 @@ function socketAddress(options) {
3121
3123
  if (separator === "") throw new TypeError("Expected separator to not be empty.");
3122
3124
  if (/\p{Nd}/u.test(separator)) throw new TypeError(`Expected separator to not contain digits, but got: ${JSON.stringify(separator)}.`);
3123
3125
  const formatExample = `host${JSON.stringify(separator).slice(1, -1)}port`;
3124
- const metavar = options?.metavar ?? `HOST${separator}PORT`;
3125
- require_nonempty.ensureNonEmptyString(metavar);
3126
+ const metavar$1 = options?.metavar ?? `HOST${separator}PORT`;
3127
+ require_nonempty.ensureNonEmptyString(metavar$1);
3126
3128
  const defaultPort = options?.defaultPort;
3127
3129
  const requirePort = options?.requirePort ?? false;
3128
3130
  const hostType = options?.host?.type ?? "both";
@@ -3197,7 +3199,7 @@ function socketAddress(options) {
3197
3199
  }
3198
3200
  return {
3199
3201
  mode: "sync",
3200
- metavar,
3202
+ metavar: metavar$1,
3201
3203
  get placeholder() {
3202
3204
  return {
3203
3205
  host: hostType === "ip" ? ipParser.placeholder : hostnameParser.placeholder,
@@ -3416,8 +3418,8 @@ function portRange(options) {
3416
3418
  const separator = options?.separator ?? "-";
3417
3419
  if (separator === "") throw new TypeError("Expected separator to not be empty.");
3418
3420
  if (/\p{Nd}/u.test(separator)) throw new TypeError(`Expected separator to not contain digits, but got: ${JSON.stringify(separator)}.`);
3419
- const metavar = options?.metavar ?? `PORT${separator}PORT`;
3420
- require_nonempty.ensureNonEmptyString(metavar);
3421
+ const metavar$1 = options?.metavar ?? `PORT${separator}PORT`;
3422
+ require_nonempty.ensureNonEmptyString(metavar$1);
3421
3423
  const allowSingle = options?.allowSingle ?? false;
3422
3424
  const isBigInt = options?.type === "bigint";
3423
3425
  const portParser = isBigInt ? port({
@@ -3435,7 +3437,7 @@ function portRange(options) {
3435
3437
  });
3436
3438
  return {
3437
3439
  mode: "sync",
3438
- metavar,
3440
+ metavar: metavar$1,
3439
3441
  get placeholder() {
3440
3442
  return isBigInt ? {
3441
3443
  start: portParser.placeholder,
@@ -3595,7 +3597,7 @@ function macAddress(options) {
3595
3597
  const separator = options?.separator ?? "any";
3596
3598
  const caseOption = options?.case ?? "preserve";
3597
3599
  const outputSeparator = options?.outputSeparator;
3598
- const metavar = options?.metavar ?? "MAC";
3600
+ const metavar$1 = options?.metavar ?? "MAC";
3599
3601
  const colonRegex = /^([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2})$/;
3600
3602
  const hyphenRegex = /^([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})-([0-9a-fA-F]{1,2})$/;
3601
3603
  const dotRegex = /^([0-9a-fA-F]{4})\.([0-9a-fA-F]{4})\.([0-9a-fA-F]{4})$/;
@@ -3627,7 +3629,7 @@ function macAddress(options) {
3627
3629
  }
3628
3630
  const parserObj = {
3629
3631
  mode: "sync",
3630
- metavar,
3632
+ metavar: metavar$1,
3631
3633
  get placeholder() {
3632
3634
  const octets = [
3633
3635
  "00",
@@ -3709,7 +3711,7 @@ function macAddress(options) {
3709
3711
  };
3710
3712
  },
3711
3713
  format(value) {
3712
- if (typeof value !== "string") return metavar;
3714
+ if (typeof value !== "string") return metavar$1;
3713
3715
  return normalizeMacValue(value, value);
3714
3716
  },
3715
3717
  normalize(value) {
@@ -3758,7 +3760,7 @@ function macAddress(options) {
3758
3760
  * @since 0.10.0
3759
3761
  */
3760
3762
  function domain(options) {
3761
- const metavar = options?.metavar ?? "DOMAIN";
3763
+ const metavar$1 = options?.metavar ?? "DOMAIN";
3762
3764
  checkBooleanOption(options, "allowSubdomains");
3763
3765
  checkBooleanOption(options, "lowercase");
3764
3766
  const allowSubdomains = options?.allowSubdomains ?? true;
@@ -3791,7 +3793,7 @@ function domain(options) {
3791
3793
  const tldNotAllowed = options?.errors?.tldNotAllowed;
3792
3794
  const domainParserObj = {
3793
3795
  mode: "sync",
3794
- metavar,
3796
+ metavar: metavar$1,
3795
3797
  placeholder: options?.placeholder ?? `example.${allowedTldsLower?.[0] ?? "com"}`,
3796
3798
  parse(input) {
3797
3799
  if (input.length > maxLength) {
@@ -3997,7 +3999,7 @@ function domain(options) {
3997
3999
  };
3998
4000
  },
3999
4001
  format(value) {
4000
- if (typeof value !== "string") return metavar;
4002
+ if (typeof value !== "string") return metavar$1;
4001
4003
  if (!lowercase) return value;
4002
4004
  return value.split(".").length >= minLabels ? value.toLowerCase() : value;
4003
4005
  }
@@ -4007,7 +4009,7 @@ function domain(options) {
4007
4009
  let domParsing = false;
4008
4010
  Object.defineProperty(domainParserObj, "format", {
4009
4011
  value(v) {
4010
- if (typeof v !== "string") return metavar;
4012
+ if (typeof v !== "string") return metavar$1;
4011
4013
  if (domParsing) return v;
4012
4014
  domParsing = true;
4013
4015
  try {
@@ -4072,10 +4074,10 @@ function ipv6(options) {
4072
4074
  const allowMulticast = options?.allowMulticast ?? true;
4073
4075
  const allowZero = options?.allowZero ?? true;
4074
4076
  const errors = options?.errors;
4075
- const metavar = options?.metavar ?? "IPV6";
4077
+ const metavar$1 = options?.metavar ?? "IPV6";
4076
4078
  const ipv6ParserObj = {
4077
4079
  mode: "sync",
4078
- metavar,
4080
+ metavar: metavar$1,
4079
4081
  placeholder: allowZero ? "::" : allowLoopback ? "::1" : "2001:db8::1",
4080
4082
  parse(input) {
4081
4083
  const normalized = parseAndNormalizeIpv6(input);
@@ -4227,14 +4229,14 @@ function ipv6(options) {
4227
4229
  };
4228
4230
  },
4229
4231
  format(value) {
4230
- if (typeof value !== "string") return metavar;
4232
+ if (typeof value !== "string") return metavar$1;
4231
4233
  return parseAndNormalizeIpv6(value) ?? value;
4232
4234
  }
4233
4235
  };
4234
4236
  let ipv6Parsing = false;
4235
4237
  Object.defineProperty(ipv6ParserObj, "format", {
4236
4238
  value(v) {
4237
- if (typeof v !== "string") return metavar;
4239
+ if (typeof v !== "string") return metavar$1;
4238
4240
  if (ipv6Parsing) return v;
4239
4241
  ipv6Parsing = true;
4240
4242
  try {
@@ -4511,7 +4513,7 @@ function checkIpv4MappedRestrictions(octets, normalizedIpv6, ipv4Opts, errors) {
4511
4513
  */
4512
4514
  function ip(options) {
4513
4515
  const version = options?.version ?? "both";
4514
- const metavar = options?.metavar ?? "IP";
4516
+ const metavar$1 = options?.metavar ?? "IP";
4515
4517
  const errors = options?.errors;
4516
4518
  const ipv4Parser = version === 4 || version === "both" ? ipv4({
4517
4519
  ...options?.ipv4,
@@ -4554,7 +4556,7 @@ function ip(options) {
4554
4556
  } : void 0;
4555
4557
  const ipParserObj = {
4556
4558
  mode: "sync",
4557
- metavar,
4559
+ metavar: metavar$1,
4558
4560
  placeholder: version === 6 ? ipv6Parser.placeholder : ipv4Parser.placeholder,
4559
4561
  parse(input) {
4560
4562
  let ipv4Error = null;
@@ -4613,14 +4615,14 @@ function ip(options) {
4613
4615
  };
4614
4616
  },
4615
4617
  format(value) {
4616
- if (typeof value !== "string") return metavar;
4618
+ if (typeof value !== "string") return metavar$1;
4617
4619
  return parseAndNormalizeIpv6(value) ?? value;
4618
4620
  }
4619
4621
  };
4620
4622
  let ipParsing = false;
4621
4623
  Object.defineProperty(ipParserObj, "format", {
4622
4624
  value(v) {
4623
- if (typeof v !== "string") return metavar;
4625
+ if (typeof v !== "string") return metavar$1;
4624
4626
  if (ipParsing) return v;
4625
4627
  ipParsing = true;
4626
4628
  try {
@@ -4690,7 +4692,7 @@ function cidr(options) {
4690
4692
  const minPrefix = options?.minPrefix;
4691
4693
  const maxPrefix = options?.maxPrefix;
4692
4694
  const errors = options?.errors;
4693
- const metavar = options?.metavar ?? "CIDR";
4695
+ const metavar$1 = options?.metavar ?? "CIDR";
4694
4696
  const genericIpSentinel = [];
4695
4697
  const ipv4Parser = version === 4 || version === "both" ? ipv4({
4696
4698
  ...options?.ipv4,
@@ -4733,7 +4735,7 @@ function cidr(options) {
4733
4735
  } : void 0;
4734
4736
  const cidrParserObj = {
4735
4737
  mode: "sync",
4736
- metavar,
4738
+ metavar: metavar$1,
4737
4739
  get placeholder() {
4738
4740
  return version === 6 || version === "both" && (minPrefix ?? 0) > 32 ? {
4739
4741
  address: ipv6Parser.placeholder,
@@ -5102,12 +5104,12 @@ function cidr(options) {
5102
5104
  }
5103
5105
  };
5104
5106
  },
5105
- format: ((_) => metavar)
5107
+ format: ((_) => metavar$1)
5106
5108
  };
5107
5109
  let cidrParsing = false;
5108
5110
  Object.defineProperty(cidrParserObj, "format", {
5109
5111
  value(value) {
5110
- if (typeof value !== "object" || value == null || !("address" in value) || !("prefix" in value) || !("version" in value)) return metavar;
5112
+ if (typeof value !== "object" || value == null || !("address" in value) || !("prefix" in value) || !("version" in value)) return metavar$1;
5111
5113
  if (cidrParsing) return `${value.address}/${value.prefix}`;
5112
5114
  cidrParsing = true;
5113
5115
  try {
@@ -5155,8 +5157,8 @@ const SEMVER_SUGGESTIONS = Object.freeze([
5155
5157
  ]);
5156
5158
  const SEMVER_SUGGESTIONS_WITH_PREFIX = Object.freeze([...SEMVER_SUGGESTIONS, ...SEMVER_SUGGESTIONS.map((s) => `v${s}`)]);
5157
5159
  function semVer(options = {}) {
5158
- const metavar = options.metavar ?? "SEMVER";
5159
- require_nonempty.ensureNonEmptyString(metavar);
5160
+ const metavar$1 = options.metavar ?? "SEMVER";
5161
+ require_nonempty.ensureNonEmptyString(metavar$1);
5160
5162
  checkEnumOption(options, "type", ["string", "object"]);
5161
5163
  checkBooleanOption(options, "allowPrefix");
5162
5164
  const allowPrefix = options.allowPrefix ?? false;
@@ -5171,7 +5173,7 @@ function semVer(options = {}) {
5171
5173
  }
5172
5174
  if (objectMode) return {
5173
5175
  mode: "sync",
5174
- metavar,
5176
+ metavar: metavar$1,
5175
5177
  placeholder: {
5176
5178
  major: 0,
5177
5179
  minor: 0,
@@ -5212,7 +5214,7 @@ function semVer(options = {}) {
5212
5214
  };
5213
5215
  return {
5214
5216
  mode: "sync",
5215
- metavar,
5217
+ metavar: metavar$1,
5216
5218
  placeholder: "0.0.0",
5217
5219
  parse(input) {
5218
5220
  const m = SEMVER_REGEX.exec(input);
@@ -5267,8 +5269,8 @@ function semVer(options = {}) {
5267
5269
  * @since 1.1.0
5268
5270
  */
5269
5271
  function json(options) {
5270
- const metavar = options?.metavar ?? "JSON";
5271
- require_nonempty.ensureNonEmptyString(metavar);
5272
+ const metavar$1 = options?.metavar ?? "JSON";
5273
+ require_nonempty.ensureNonEmptyString(metavar$1);
5272
5274
  checkEnumOption(options, "rootType", [
5273
5275
  "string",
5274
5276
  "number",
@@ -5290,7 +5292,7 @@ function json(options) {
5290
5292
  const placeholder = options?.placeholder ?? defaultPlaceholder;
5291
5293
  return {
5292
5294
  mode: "sync",
5293
- metavar,
5295
+ metavar: metavar$1,
5294
5296
  placeholder,
5295
5297
  parse(input) {
5296
5298
  let value;
@@ -5369,6 +5371,257 @@ function findNonFiniteNumber(root) {
5369
5371
  }
5370
5372
  return void 0;
5371
5373
  }
5374
+ /**
5375
+ * Implementation of the {@link firstOf} combinator.
5376
+ */
5377
+ function firstOf(...rawArgs) {
5378
+ const args = rawArgs.length > 0 && rawArgs.at(-1) === void 0 ? rawArgs.slice(0, -1) : rawArgs;
5379
+ let parsers;
5380
+ let options;
5381
+ if (args.length > 0 && Array.isArray(args[0])) {
5382
+ parsers = [...args[0]];
5383
+ options = args[1] ?? {};
5384
+ } else {
5385
+ const last = args.at(-1);
5386
+ if (args.length > 0 && typeof last === "object" && last != null && !isValueParser(last)) {
5387
+ options = last;
5388
+ parsers = args.slice(0, -1);
5389
+ } else {
5390
+ options = {};
5391
+ parsers = args;
5392
+ }
5393
+ }
5394
+ if (parsers.length < 2) throw new TypeError("firstOf() requires at least two value parsers.");
5395
+ for (const parser of parsers) {
5396
+ if (!isValueParser(parser)) throw new TypeError("Every firstOf() constituent must be a value parser.");
5397
+ if (parser.mode !== "sync") throw new TypeError("firstOf() only supports sync value parsers, but an async one was given.");
5398
+ if (require_internal_dependency.isDerivedValueParser(parser)) throw new TypeError("firstOf() does not support dependency-derived value parsers (created via deriveFrom() or dependency().derive()); pass the derived parser directly to option() or argument() instead.");
5399
+ }
5400
+ const metavar$1 = options.metavar ?? parsers.map((parser) => parser.metavar).join("|");
5401
+ require_nonempty.ensureNonEmptyString(metavar$1);
5402
+ const mergedChoices = parsers.every((parser) => parser.choices != null) ? Object.freeze(parsers.flatMap((parser) => [...parser.choices]).filter((value, index, all) => all.findIndex((other) => Object.is(other, value)) === index)) : void 0;
5403
+ function findOwner(value) {
5404
+ let canonicalizing;
5405
+ for (const parser of parsers) {
5406
+ if (typeof parser.validate === "function") {
5407
+ let result$1;
5408
+ try {
5409
+ result$1 = parser.validate(value);
5410
+ } catch {
5411
+ continue;
5412
+ }
5413
+ if (result$1.success) return {
5414
+ parser,
5415
+ result: result$1
5416
+ };
5417
+ continue;
5418
+ }
5419
+ let formatted;
5420
+ try {
5421
+ formatted = parser.format(value);
5422
+ } catch {
5423
+ continue;
5424
+ }
5425
+ if (typeof formatted !== "string") continue;
5426
+ const result = parser.parse(formatted);
5427
+ if (!result.success) continue;
5428
+ if (ownsRoundTrippedValue(parser, result.value, value)) return {
5429
+ parser,
5430
+ result
5431
+ };
5432
+ if (canonicalizing == null && value !== null && typeof value !== "object" && typeof result.value === typeof value) canonicalizing = {
5433
+ parser,
5434
+ result
5435
+ };
5436
+ }
5437
+ return canonicalizing;
5438
+ }
5439
+ const hasNormalize = parsers.some((parser) => typeof parser.normalize === "function");
5440
+ const hasSuggest = parsers.some((parser) => typeof parser.suggest === "function");
5441
+ return {
5442
+ mode: "sync",
5443
+ metavar: metavar$1,
5444
+ placeholder: parsers[0].placeholder,
5445
+ ...mergedChoices != null ? { choices: mergedChoices } : {},
5446
+ parse(input) {
5447
+ const errors = [];
5448
+ for (const parser of parsers) {
5449
+ const result = parser.parse(input);
5450
+ if (result.success) return result;
5451
+ errors.push(result.error);
5452
+ }
5453
+ const noMatch = options.errors?.noMatch;
5454
+ return {
5455
+ success: false,
5456
+ error: noMatch == null ? firstOfNoMatchError(errors) : typeof noMatch === "function" ? noMatch(input, errors) : noMatch
5457
+ };
5458
+ },
5459
+ format(value) {
5460
+ let canonicalizing;
5461
+ let fallback;
5462
+ let firstError;
5463
+ let hasError = false;
5464
+ for (const parser of parsers) {
5465
+ let formatted;
5466
+ try {
5467
+ formatted = parser.format(value);
5468
+ } catch (e) {
5469
+ if (!hasError) {
5470
+ firstError = e;
5471
+ hasError = true;
5472
+ }
5473
+ continue;
5474
+ }
5475
+ if (typeof formatted !== "string") continue;
5476
+ if (typeof parser.validate === "function") {
5477
+ let owned = false;
5478
+ try {
5479
+ owned = parser.validate(value).success;
5480
+ } catch {}
5481
+ if (owned) return formatted;
5482
+ } else {
5483
+ const result = parser.parse(formatted);
5484
+ if (result.success) {
5485
+ if (ownsRoundTrippedValue(parser, result.value, value)) return formatted;
5486
+ if (canonicalizing == null && value !== null && typeof value !== "object" && typeof result.value === typeof value) canonicalizing = formatted;
5487
+ }
5488
+ }
5489
+ fallback ??= formatted;
5490
+ }
5491
+ if (canonicalizing !== void 0) return canonicalizing;
5492
+ if (fallback !== void 0) return fallback;
5493
+ if (hasError) throw firstError;
5494
+ throw new TypeError("No constituent parser could format the given value.");
5495
+ },
5496
+ validate(value) {
5497
+ const owner = findOwner(value);
5498
+ if (owner == null) return {
5499
+ success: false,
5500
+ error: require_message.message`Expected a value matching ${require_message.metavar(metavar$1)}.`
5501
+ };
5502
+ return owner.result;
5503
+ },
5504
+ ...hasNormalize ? { normalize(value) {
5505
+ const owner = findOwner(value);
5506
+ if (owner == null || typeof owner.parser.normalize !== "function") return value;
5507
+ return owner.parser.normalize(value);
5508
+ } } : {},
5509
+ ...hasSuggest ? { *suggest(prefix) {
5510
+ const collected = [];
5511
+ for (const parser of parsers) {
5512
+ if (typeof parser.suggest !== "function") continue;
5513
+ for (const suggestion of parser.suggest(prefix)) collected.push(suggestion);
5514
+ }
5515
+ yield* require_suggestion.deduplicateSuggestions(collected);
5516
+ } } : {}
5517
+ };
5518
+ }
5519
+ /**
5520
+ * Builds the default error message for {@link firstOf} when every
5521
+ * constituent parser fails: a header followed by each constituent's error
5522
+ * on its own line.
5523
+ */
5524
+ function firstOfNoMatchError(errors) {
5525
+ const terms = [require_message.text("Expected one of the following:")];
5526
+ for (const error of errors) terms.push(require_message.lineBreak(), require_message.text("- "), ...require_message.cloneMessage(error));
5527
+ return terms;
5528
+ }
5529
+ /**
5530
+ * Determines whether a {@link firstOf} constituent owns a value, given the
5531
+ * result of round-tripping the value through the constituent's `format()`
5532
+ * and `parse()`. The constituent owns the value when the round-trip
5533
+ * preserves it exactly, when it yields the constituent's own normalization
5534
+ * of it (e.g. a MAC address parser canonicalizing separators and case), or
5535
+ * when the round-trip is a recognized parse-level canonicalization: a
5536
+ * case-insensitive string match (e.g. a case-insensitive `choice()`
5537
+ * folding `"INFO"` to `"info"`) or numeric equality (a number parser
5538
+ * folding `-0` to `0`)—the same acceptance the constituent alone would
5539
+ * grant a fallback value through round-trip validation. Parsers with
5540
+ * richer parse-level canonicalization should expose it via `normalize()`.
5541
+ * A merely *successful* round-trip is not enough otherwise: an arbitrary
5542
+ * same-type change means data loss rather than canonicalization (e.g. a
5543
+ * clamping `format()` folding 15 into 10), a round-trip that changes the
5544
+ * primitive type means the string form belongs to a different branch of
5545
+ * the union (e.g. `choice(["1"])` capturing the integer 1), and for
5546
+ * object values structural equality is the only way to tell
5547
+ * canonicalization from data loss (e.g. a lossy `color()` `format()`
5548
+ * dropping fields that belong to a later, more faithful constituent).
5549
+ */
5550
+ function ownsRoundTrippedValue(parser, roundTripped, value) {
5551
+ if (valuesEqual(roundTripped, value)) return true;
5552
+ if (typeof parser.normalize === "function") {
5553
+ let normalized;
5554
+ try {
5555
+ normalized = parser.normalize(value);
5556
+ } catch {
5557
+ return false;
5558
+ }
5559
+ if (valuesEqual(roundTripped, normalized)) return true;
5560
+ }
5561
+ if (typeof value === "string" && typeof roundTripped === "string") return value.toLowerCase() === roundTripped.toLowerCase();
5562
+ if (typeof value === "number" && typeof roundTripped === "number") return value === roundTripped;
5563
+ return false;
5564
+ }
5565
+ /**
5566
+ * Structural equality for parsed CLI values: primitives compare with
5567
+ * `Object.is` (so `NaN` equals itself and `0` differs from `-0`, matching
5568
+ * the distinction `choice()` makes), `Date` and `URL` instances compare by
5569
+ * time value and href respectively, arrays and plain objects compare
5570
+ * recursively, and other class instances compare by their overridden
5571
+ * `toString()` serialization. Recursion is bounded by the structure of
5572
+ * the second argument, which in {@link firstOf} is always a freshly
5573
+ * parsed (acyclic) value.
5574
+ */
5575
+ function valuesEqual(a, b) {
5576
+ if (Object.is(a, b)) return true;
5577
+ if (typeof a !== "object" || typeof b !== "object" || a == null || b == null) return false;
5578
+ if (Array.isArray(a) || Array.isArray(b)) return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((item, i) => valuesEqual(item, b[i]));
5579
+ if (a instanceof Date || b instanceof Date) return a instanceof Date && b instanceof Date && a.getTime() === b.getTime();
5580
+ if (a instanceof URL || b instanceof URL) return a instanceof URL && b instanceof URL && a.href === b.href;
5581
+ const prototypeA = Object.getPrototypeOf(a);
5582
+ const prototypeB = Object.getPrototypeOf(b);
5583
+ const plainA = prototypeA === Object.prototype || prototypeA === null;
5584
+ const plainB = prototypeB === Object.prototype || prototypeB === null;
5585
+ if (plainA !== plainB) return false;
5586
+ if (!plainA) {
5587
+ if (prototypeA !== prototypeB) return false;
5588
+ const overridesA = hasCustomToString(a);
5589
+ const overridesB = hasCustomToString(b);
5590
+ if (overridesA !== overridesB) return false;
5591
+ const hasKeys = Object.keys(a).length > 0 || Object.keys(b).length > 0;
5592
+ if (hasKeys && !plainObjectsEqual(a, b)) return false;
5593
+ if (!overridesA) return hasKeys;
5594
+ try {
5595
+ return String(a) === String(b);
5596
+ } catch {
5597
+ return false;
5598
+ }
5599
+ }
5600
+ return plainObjectsEqual(a, b);
5601
+ }
5602
+ /**
5603
+ * Checks whether an object provides a `toString()` implementation other
5604
+ * than the generic `Object.prototype.toString`.
5605
+ */
5606
+ function hasCustomToString(value) {
5607
+ try {
5608
+ const toString = value.toString;
5609
+ return typeof toString === "function" && toString !== Object.prototype.toString;
5610
+ } catch {
5611
+ return false;
5612
+ }
5613
+ }
5614
+ /**
5615
+ * Compares two objects by their enumerable own keys, recursing into the
5616
+ * values with {@link valuesEqual}.
5617
+ */
5618
+ function plainObjectsEqual(a, b) {
5619
+ const aKeys = Object.keys(a);
5620
+ const bKeys = Object.keys(b);
5621
+ if (aKeys.length !== bKeys.length) return false;
5622
+ const bRecord = b;
5623
+ return aKeys.every((key) => Object.hasOwn(b, key) && valuesEqual(a[key], bRecord[key]));
5624
+ }
5372
5625
 
5373
5626
  //#endregion
5374
5627
  exports.checkBooleanOption = checkBooleanOption;
@@ -5380,6 +5633,7 @@ exports.domain = domain;
5380
5633
  exports.email = email;
5381
5634
  exports.ensureNonEmptyString = require_nonempty.ensureNonEmptyString;
5382
5635
  exports.fileSize = fileSize;
5636
+ exports.firstOf = firstOf;
5383
5637
  exports.float = float;
5384
5638
  exports.hostname = hostname;
5385
5639
  exports.integer = integer;