@optique/core 0.3.0-dev.35 → 0.3.0-dev.38

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/parser.cjs CHANGED
@@ -525,12 +525,13 @@ function optional(parser) {
525
525
  * a specified default value.
526
526
  * @template TValue The type of the value returned by the wrapped parser.
527
527
  * @template TState The type of the state used by the wrapped parser.
528
+ * @template TDefault The type of the default value.
528
529
  * @param parser The {@link Parser} to wrap with default behavior.
529
530
  * @param defaultValue The default value to return when the wrapped parser
530
531
  * doesn't match or consume input. Can be a value of type
531
- * {@link TValue} or a function that returns such a value.
532
+ * {@link TDefault} or a function that returns such a value.
532
533
  * @returns A {@link Parser} that produces either the result of the wrapped parser
533
- * or the default value if the wrapped parser fails to match.
534
+ * or the default value if the wrapped parser fails to match (union type {@link TValue} | {@link TDefault}).
534
535
  */
535
536
  function withDefault(parser, defaultValue) {
536
537
  return {
@@ -565,7 +566,7 @@ function withDefault(parser, defaultValue) {
565
566
  return parser.complete(state[0]);
566
567
  },
567
568
  getDocFragments(state, upperDefaultValue) {
568
- return parser.getDocFragments(typeof state === "undefined" ? parser.initialState : state[0], upperDefaultValue == null ? typeof defaultValue === "function" ? defaultValue() : defaultValue : upperDefaultValue);
569
+ return parser.getDocFragments(typeof state === "undefined" ? parser.initialState : state[0], upperDefaultValue != null ? upperDefaultValue : typeof defaultValue === "function" ? defaultValue() : defaultValue);
569
570
  }
570
571
  };
571
572
  }
@@ -716,30 +717,44 @@ function object(labelOrParsers, maybeParsers) {
716
717
  consumed: 0,
717
718
  error: context.buffer.length > 0 ? require_message.message`Unexpected option or argument: ${context.buffer[0]}.` : require_message.message`Expected an option or argument, but got end of input.`
718
719
  };
719
- for (const [field, parser] of parserPairs) {
720
- const result = parser.parse({
721
- ...context,
722
- state: context.state[field]
723
- });
724
- if (result.success && result.consumed.length > 0) return {
725
- success: true,
726
- next: {
727
- ...context,
728
- buffer: result.next.buffer,
729
- optionsTerminated: result.next.optionsTerminated,
730
- state: {
731
- ...context.state,
732
- [field]: result.next.state
733
- }
734
- },
735
- consumed: result.consumed
736
- };
737
- else if (!result.success && error.consumed < result.consumed) error = result;
720
+ let currentContext = context;
721
+ let anySuccess = false;
722
+ const allConsumed = [];
723
+ let madeProgress = true;
724
+ while (madeProgress && currentContext.buffer.length > 0) {
725
+ madeProgress = false;
726
+ for (const [field, parser] of parserPairs) {
727
+ const result = parser.parse({
728
+ ...currentContext,
729
+ state: currentContext.state && typeof currentContext.state === "object" && field in currentContext.state ? currentContext.state[field] : parser.initialState
730
+ });
731
+ if (result.success && result.consumed.length > 0) {
732
+ currentContext = {
733
+ ...currentContext,
734
+ buffer: result.next.buffer,
735
+ optionsTerminated: result.next.optionsTerminated,
736
+ state: {
737
+ ...currentContext.state,
738
+ [field]: result.next.state
739
+ }
740
+ };
741
+ allConsumed.push(...result.consumed);
742
+ anySuccess = true;
743
+ madeProgress = true;
744
+ break;
745
+ } else if (!result.success && error.consumed < result.consumed) error = result;
746
+ }
738
747
  }
748
+ if (anySuccess) return {
749
+ success: true,
750
+ next: currentContext,
751
+ consumed: allConsumed
752
+ };
739
753
  if (context.buffer.length === 0) {
740
754
  let allCanComplete = true;
741
755
  for (const [field, parser] of parserPairs) {
742
- const completeResult = parser.complete(context.state[field]);
756
+ const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
757
+ const completeResult = parser.complete(fieldState);
743
758
  if (!completeResult.success) {
744
759
  allCanComplete = false;
745
760
  break;
@@ -991,7 +1006,7 @@ function or(...parsers) {
991
1006
  function merge(...parsers) {
992
1007
  parsers = parsers.toSorted((a, b) => b.priority - a.priority);
993
1008
  const initialState = {};
994
- for (const parser of parsers) for (const field in parser.initialState) initialState[field] = parser.initialState[field];
1009
+ for (const parser of parsers) if (parser.initialState && typeof parser.initialState === "object") for (const field in parser.initialState) initialState[field] = parser.initialState[field];
995
1010
  return {
996
1011
  $valueType: [],
997
1012
  $stateType: [],
@@ -999,22 +1014,41 @@ function merge(...parsers) {
999
1014
  usage: parsers.flatMap((p) => p.usage),
1000
1015
  initialState,
1001
1016
  parse(context) {
1002
- for (const parser of parsers) {
1003
- const result = parser.parse(context);
1004
- if (result.success) return {
1005
- success: true,
1006
- next: {
1007
- ...context,
1008
- buffer: result.next.buffer,
1009
- optionsTerminated: result.next.optionsTerminated,
1010
- state: {
1011
- ...context.state,
1012
- ...result.next.state
1013
- }
1014
- },
1015
- consumed: result.consumed
1016
- };
1017
- else if (result.consumed < 1) continue;
1017
+ for (let i = 0; i < parsers.length; i++) {
1018
+ const parser = parsers[i];
1019
+ let parserState;
1020
+ if (parser.initialState === void 0) parserState = void 0;
1021
+ else if (parser.initialState && typeof parser.initialState === "object") if (context.state && typeof context.state === "object") {
1022
+ const extractedState = {};
1023
+ for (const field in parser.initialState) extractedState[field] = field in context.state ? context.state[field] : parser.initialState[field];
1024
+ parserState = extractedState;
1025
+ } else parserState = parser.initialState;
1026
+ else parserState = parser.initialState;
1027
+ const result = parser.parse({
1028
+ ...context,
1029
+ state: parserState
1030
+ });
1031
+ if (result.success) {
1032
+ let newState;
1033
+ if (parser.initialState === void 0) newState = {
1034
+ ...context.state,
1035
+ [`__parser_${i}`]: result.next.state
1036
+ };
1037
+ else newState = {
1038
+ ...context.state,
1039
+ ...result.next.state
1040
+ };
1041
+ return {
1042
+ success: true,
1043
+ next: {
1044
+ ...context,
1045
+ buffer: result.next.buffer,
1046
+ optionsTerminated: result.next.optionsTerminated,
1047
+ state: newState
1048
+ },
1049
+ consumed: result.consumed
1050
+ };
1051
+ } else if (result.consumed < 1) continue;
1018
1052
  else return result;
1019
1053
  }
1020
1054
  return {
@@ -1025,8 +1059,20 @@ function merge(...parsers) {
1025
1059
  },
1026
1060
  complete(state) {
1027
1061
  const object$1 = {};
1028
- for (const parser of parsers) {
1029
- const result = parser.complete(state);
1062
+ for (let i = 0; i < parsers.length; i++) {
1063
+ const parser = parsers[i];
1064
+ let parserState;
1065
+ if (parser.initialState === void 0) {
1066
+ const key = `__parser_${i}`;
1067
+ if (state && typeof state === "object" && key in state) parserState = state[key];
1068
+ else parserState = void 0;
1069
+ } else if (parser.initialState && typeof parser.initialState === "object") if (state && typeof state === "object") {
1070
+ const extractedState = {};
1071
+ for (const field in parser.initialState) extractedState[field] = field in state ? state[field] : parser.initialState[field];
1072
+ parserState = extractedState;
1073
+ } else parserState = parser.initialState;
1074
+ else parserState = parser.initialState;
1075
+ const result = parser.complete(parserState);
1030
1076
  if (!result.success) return result;
1031
1077
  for (const field in result.value) object$1[field] = result.value[field];
1032
1078
  }
package/dist/parser.d.cts CHANGED
@@ -271,14 +271,15 @@ declare function optional<TValue, TState>(parser: Parser<TValue, TState>): Parse
271
271
  * a specified default value.
272
272
  * @template TValue The type of the value returned by the wrapped parser.
273
273
  * @template TState The type of the state used by the wrapped parser.
274
+ * @template TDefault The type of the default value.
274
275
  * @param parser The {@link Parser} to wrap with default behavior.
275
276
  * @param defaultValue The default value to return when the wrapped parser
276
277
  * doesn't match or consume input. Can be a value of type
277
- * {@link TValue} or a function that returns such a value.
278
+ * {@link TDefault} or a function that returns such a value.
278
279
  * @returns A {@link Parser} that produces either the result of the wrapped parser
279
- * or the default value if the wrapped parser fails to match.
280
+ * or the default value if the wrapped parser fails to match (union type {@link TValue} | {@link TDefault}).
280
281
  */
281
- declare function withDefault<TValue, TState>(parser: Parser<TValue, TState>, defaultValue: TValue | (() => TValue)): Parser<TValue, [TState] | undefined>;
282
+ declare function withDefault<TValue, TState, TDefault = TValue>(parser: Parser<TValue, TState>, defaultValue: TDefault | (() => TDefault)): Parser<TValue | TDefault, [TState] | undefined>;
282
283
  /**
283
284
  * Creates a parser that transforms the result value of another parser using
284
285
  * a mapping function. This enables value transformation while preserving
@@ -635,6 +636,16 @@ declare function or<TA, TB, TC, TD, TE, TF, TG, TH, TI, TStateA, TStateB, TState
635
636
  * in order, returning the result of the first successful parser.
636
637
  */
637
638
  declare function or<TA, TB, TC, TD, TE, TF, TG, TH, TI, TJ, TStateA, TStateB, TStateC, TStateD, TStateE, TStateF, TStateG, TStateH, TStateI, TStateJ>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>, c: Parser<TC, TStateC>, d: Parser<TD, TStateD>, e: Parser<TE, TStateE>, f: Parser<TF, TStateF>, g: Parser<TG, TStateG>, h: Parser<TH, TStateH>, i: Parser<TI, TStateI>, j: Parser<TJ, TStateJ>): Parser<TA | TB | TC | TD | TE | TF | TG | TH | TI | TJ, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>] | [2, ParserResult<TStateC>] | [3, ParserResult<TStateD>] | [4, ParserResult<TStateE>] | [5, ParserResult<TStateF>] | [6, ParserResult<TStateG>] | [7, ParserResult<TStateH>] | [8, ParserResult<TStateI>] | [9, ParserResult<TStateJ>]>;
639
+ /**
640
+ * Helper type to check if all members of a union are object-like.
641
+ * This allows merge() to work with parsers like withDefault() that produce union types.
642
+ */
643
+ type AllObjectLike<T> = T extends Record<string | symbol, unknown> ? T : never;
644
+ /**
645
+ * Helper type to extract object-like types from parser value types,
646
+ * including union types where all members are objects.
647
+ */
648
+ type ExtractObjectTypes<P> = P extends Parser<infer V, unknown> ? [AllObjectLike<V>] extends [never] ? never : V : never;
638
649
  /**
639
650
  * Merges multiple {@link object} parsers into a single {@link object} parser.
640
651
  * It is useful for combining multiple {@link object} parsers so that
@@ -648,7 +659,7 @@ declare function or<TA, TB, TC, TD, TE, TF, TG, TH, TI, TJ, TStateA, TStateB, TS
648
659
  * @return A new {@link object} parser that combines the values and states
649
660
  * of the two parsers into a single object.
650
661
  */
651
- declare function merge<TA extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TB extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>>(a: TA, b: TB): Parser<{ readonly [K in keyof TA["$valueType"][number]]: TA["$valueType"][number][K] extends (infer U) ? U : never } & { readonly [K in keyof TB["$valueType"][number]]: TB["$valueType"][number][K] extends (infer U2) ? U2 : never }, { readonly [K in keyof TA]: unknown } & { readonly [K in keyof TB]: unknown }>;
662
+ declare function merge<TA extends Parser<unknown, unknown>, TB extends Parser<unknown, unknown>>(a: TA, b: TB): ExtractObjectTypes<TA> extends never ? never : ExtractObjectTypes<TB> extends never ? never : Parser<ExtractObjectTypes<TA> & ExtractObjectTypes<TB>, Record<string | symbol, unknown>>;
652
663
  /**
653
664
  * Merges multiple {@link object} parsers into a single {@link object} parser.
654
665
  * It is useful for combining multiple {@link object} parsers so that
@@ -664,7 +675,7 @@ declare function merge<TA extends Parser<Record<string | symbol, unknown>, Recor
664
675
  * @return A new {@link object} parser that combines the values and states
665
676
  * of the two parsers into a single object.
666
677
  */
667
- declare function merge<TA extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TB extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TC extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>>(a: TA, b: TB, c: TC): Parser<{ readonly [K in keyof TA["$valueType"][number]]: TA["$valueType"][number][K] extends (infer U) ? U : never } & { readonly [K in keyof TB["$valueType"][number]]: TB["$valueType"][number][K] extends (infer U2) ? U2 : never } & { readonly [K in keyof TC["$valueType"][number]]: TC["$valueType"][number][K] extends (infer U3) ? U3 : never }, { readonly [K in keyof TA]: unknown } & { readonly [K in keyof TB]: unknown } & { readonly [K in keyof TC]: unknown }>;
678
+ declare function merge<TA extends Parser<unknown, unknown>, TB extends Parser<unknown, unknown>, TC extends Parser<unknown, unknown>>(a: TA, b: TB, c: TC): ExtractObjectTypes<TA> extends never ? never : ExtractObjectTypes<TB> extends never ? never : ExtractObjectTypes<TC> extends never ? never : Parser<ExtractObjectTypes<TA> & ExtractObjectTypes<TB> & ExtractObjectTypes<TC>, Record<string | symbol, unknown>>;
668
679
  /**
669
680
  * Merges multiple {@link object} parsers into a single {@link object} parser.
670
681
  * It is useful for combining multiple {@link object} parsers so that
@@ -682,7 +693,7 @@ declare function merge<TA extends Parser<Record<string | symbol, unknown>, Recor
682
693
  * @return A new {@link object} parser that combines the values and states
683
694
  * of the two parsers into a single object.
684
695
  */
685
- declare function merge<TA extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TB extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TC extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TD extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>>(a: TA, b: TB, c: TC, d: TD): Parser<{ readonly [K in keyof TA["$valueType"][number]]: TA["$valueType"][number][K] extends (infer U) ? U : never } & { readonly [K in keyof TB["$valueType"][number]]: TB["$valueType"][number][K] extends (infer U2) ? U2 : never } & { readonly [K in keyof TC["$valueType"][number]]: TC["$valueType"][number][K] extends (infer U3) ? U3 : never } & { readonly [K in keyof TD["$valueType"][number]]: TD["$valueType"][number][K] extends (infer U4) ? U4 : never }, { readonly [K in keyof TA]: unknown } & { readonly [K in keyof TB]: unknown } & { readonly [K in keyof TC]: unknown } & { readonly [K in keyof TD]: unknown }>;
696
+ declare function merge<TA extends Parser<unknown, unknown>, TB extends Parser<unknown, unknown>, TC extends Parser<unknown, unknown>, TD extends Parser<unknown, unknown>>(a: TA, b: TB, c: TC, d: TD): ExtractObjectTypes<TA> extends never ? never : ExtractObjectTypes<TB> extends never ? never : ExtractObjectTypes<TC> extends never ? never : ExtractObjectTypes<TD> extends never ? never : Parser<ExtractObjectTypes<TA> & ExtractObjectTypes<TB> & ExtractObjectTypes<TC> & ExtractObjectTypes<TD>, Record<string | symbol, unknown>>;
686
697
  /**
687
698
  * Merges multiple {@link object} parsers into a single {@link object} parser.
688
699
  * It is useful for combining multiple {@link object} parsers so that
@@ -702,7 +713,7 @@ declare function merge<TA extends Parser<Record<string | symbol, unknown>, Recor
702
713
  * @return A new {@link object} parser that combines the values and states
703
714
  * of the two parsers into a single object.
704
715
  */
705
- declare function merge<TA extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TB extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TC extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TD extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TE extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>>(a: TA, b: TB, c: TC, d: TD, e: TE): Parser<{ readonly [K in keyof TA["$valueType"][number]]: TA["$valueType"][number][K] extends (infer U) ? U : never } & { readonly [K in keyof TB["$valueType"][number]]: TB["$valueType"][number][K] extends (infer U2) ? U2 : never } & { readonly [K in keyof TC["$valueType"][number]]: TC["$valueType"][number][K] extends (infer U3) ? U3 : never } & { readonly [K in keyof TD["$valueType"][number]]: TD["$valueType"][number][K] extends (infer U4) ? U4 : never } & { readonly [K in keyof TE["$valueType"][number]]: TE["$valueType"][number][K] extends (infer U5) ? U5 : never }, { readonly [K in keyof TA]: unknown } & { readonly [K in keyof TB]: unknown } & { readonly [K in keyof TC]: unknown } & { readonly [K in keyof TD]: unknown } & { readonly [K in keyof TE]: unknown }>;
716
+ declare function merge<TA extends Parser<unknown, unknown>, TB extends Parser<unknown, unknown>, TC extends Parser<unknown, unknown>, TD extends Parser<unknown, unknown>, TE extends Parser<unknown, unknown>>(a: TA, b: TB, c: TC, d: TD, e: TE): ExtractObjectTypes<TA> extends never ? never : ExtractObjectTypes<TB> extends never ? never : ExtractObjectTypes<TC> extends never ? never : ExtractObjectTypes<TD> extends never ? never : ExtractObjectTypes<TE> extends never ? never : Parser<ExtractObjectTypes<TA> & ExtractObjectTypes<TB> & ExtractObjectTypes<TC> & ExtractObjectTypes<TD> & ExtractObjectTypes<TE>, Record<string | symbol, unknown>>;
706
717
  /**
707
718
  * Concatenates two {@link tuple} parsers into a single parser that produces
708
719
  * a flattened tuple containing the values from both parsers in order.
package/dist/parser.d.ts CHANGED
@@ -271,14 +271,15 @@ declare function optional<TValue, TState>(parser: Parser<TValue, TState>): Parse
271
271
  * a specified default value.
272
272
  * @template TValue The type of the value returned by the wrapped parser.
273
273
  * @template TState The type of the state used by the wrapped parser.
274
+ * @template TDefault The type of the default value.
274
275
  * @param parser The {@link Parser} to wrap with default behavior.
275
276
  * @param defaultValue The default value to return when the wrapped parser
276
277
  * doesn't match or consume input. Can be a value of type
277
- * {@link TValue} or a function that returns such a value.
278
+ * {@link TDefault} or a function that returns such a value.
278
279
  * @returns A {@link Parser} that produces either the result of the wrapped parser
279
- * or the default value if the wrapped parser fails to match.
280
+ * or the default value if the wrapped parser fails to match (union type {@link TValue} | {@link TDefault}).
280
281
  */
281
- declare function withDefault<TValue, TState>(parser: Parser<TValue, TState>, defaultValue: TValue | (() => TValue)): Parser<TValue, [TState] | undefined>;
282
+ declare function withDefault<TValue, TState, TDefault = TValue>(parser: Parser<TValue, TState>, defaultValue: TDefault | (() => TDefault)): Parser<TValue | TDefault, [TState] | undefined>;
282
283
  /**
283
284
  * Creates a parser that transforms the result value of another parser using
284
285
  * a mapping function. This enables value transformation while preserving
@@ -635,6 +636,16 @@ declare function or<TA, TB, TC, TD, TE, TF, TG, TH, TI, TStateA, TStateB, TState
635
636
  * in order, returning the result of the first successful parser.
636
637
  */
637
638
  declare function or<TA, TB, TC, TD, TE, TF, TG, TH, TI, TJ, TStateA, TStateB, TStateC, TStateD, TStateE, TStateF, TStateG, TStateH, TStateI, TStateJ>(a: Parser<TA, TStateA>, b: Parser<TB, TStateB>, c: Parser<TC, TStateC>, d: Parser<TD, TStateD>, e: Parser<TE, TStateE>, f: Parser<TF, TStateF>, g: Parser<TG, TStateG>, h: Parser<TH, TStateH>, i: Parser<TI, TStateI>, j: Parser<TJ, TStateJ>): Parser<TA | TB | TC | TD | TE | TF | TG | TH | TI | TJ, undefined | [0, ParserResult<TStateA>] | [1, ParserResult<TStateB>] | [2, ParserResult<TStateC>] | [3, ParserResult<TStateD>] | [4, ParserResult<TStateE>] | [5, ParserResult<TStateF>] | [6, ParserResult<TStateG>] | [7, ParserResult<TStateH>] | [8, ParserResult<TStateI>] | [9, ParserResult<TStateJ>]>;
639
+ /**
640
+ * Helper type to check if all members of a union are object-like.
641
+ * This allows merge() to work with parsers like withDefault() that produce union types.
642
+ */
643
+ type AllObjectLike<T> = T extends Record<string | symbol, unknown> ? T : never;
644
+ /**
645
+ * Helper type to extract object-like types from parser value types,
646
+ * including union types where all members are objects.
647
+ */
648
+ type ExtractObjectTypes<P> = P extends Parser<infer V, unknown> ? [AllObjectLike<V>] extends [never] ? never : V : never;
638
649
  /**
639
650
  * Merges multiple {@link object} parsers into a single {@link object} parser.
640
651
  * It is useful for combining multiple {@link object} parsers so that
@@ -648,7 +659,7 @@ declare function or<TA, TB, TC, TD, TE, TF, TG, TH, TI, TJ, TStateA, TStateB, TS
648
659
  * @return A new {@link object} parser that combines the values and states
649
660
  * of the two parsers into a single object.
650
661
  */
651
- declare function merge<TA extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TB extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>>(a: TA, b: TB): Parser<{ readonly [K in keyof TA["$valueType"][number]]: TA["$valueType"][number][K] extends (infer U) ? U : never } & { readonly [K in keyof TB["$valueType"][number]]: TB["$valueType"][number][K] extends (infer U2) ? U2 : never }, { readonly [K in keyof TA]: unknown } & { readonly [K in keyof TB]: unknown }>;
662
+ declare function merge<TA extends Parser<unknown, unknown>, TB extends Parser<unknown, unknown>>(a: TA, b: TB): ExtractObjectTypes<TA> extends never ? never : ExtractObjectTypes<TB> extends never ? never : Parser<ExtractObjectTypes<TA> & ExtractObjectTypes<TB>, Record<string | symbol, unknown>>;
652
663
  /**
653
664
  * Merges multiple {@link object} parsers into a single {@link object} parser.
654
665
  * It is useful for combining multiple {@link object} parsers so that
@@ -664,7 +675,7 @@ declare function merge<TA extends Parser<Record<string | symbol, unknown>, Recor
664
675
  * @return A new {@link object} parser that combines the values and states
665
676
  * of the two parsers into a single object.
666
677
  */
667
- declare function merge<TA extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TB extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TC extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>>(a: TA, b: TB, c: TC): Parser<{ readonly [K in keyof TA["$valueType"][number]]: TA["$valueType"][number][K] extends (infer U) ? U : never } & { readonly [K in keyof TB["$valueType"][number]]: TB["$valueType"][number][K] extends (infer U2) ? U2 : never } & { readonly [K in keyof TC["$valueType"][number]]: TC["$valueType"][number][K] extends (infer U3) ? U3 : never }, { readonly [K in keyof TA]: unknown } & { readonly [K in keyof TB]: unknown } & { readonly [K in keyof TC]: unknown }>;
678
+ declare function merge<TA extends Parser<unknown, unknown>, TB extends Parser<unknown, unknown>, TC extends Parser<unknown, unknown>>(a: TA, b: TB, c: TC): ExtractObjectTypes<TA> extends never ? never : ExtractObjectTypes<TB> extends never ? never : ExtractObjectTypes<TC> extends never ? never : Parser<ExtractObjectTypes<TA> & ExtractObjectTypes<TB> & ExtractObjectTypes<TC>, Record<string | symbol, unknown>>;
668
679
  /**
669
680
  * Merges multiple {@link object} parsers into a single {@link object} parser.
670
681
  * It is useful for combining multiple {@link object} parsers so that
@@ -682,7 +693,7 @@ declare function merge<TA extends Parser<Record<string | symbol, unknown>, Recor
682
693
  * @return A new {@link object} parser that combines the values and states
683
694
  * of the two parsers into a single object.
684
695
  */
685
- declare function merge<TA extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TB extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TC extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TD extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>>(a: TA, b: TB, c: TC, d: TD): Parser<{ readonly [K in keyof TA["$valueType"][number]]: TA["$valueType"][number][K] extends (infer U) ? U : never } & { readonly [K in keyof TB["$valueType"][number]]: TB["$valueType"][number][K] extends (infer U2) ? U2 : never } & { readonly [K in keyof TC["$valueType"][number]]: TC["$valueType"][number][K] extends (infer U3) ? U3 : never } & { readonly [K in keyof TD["$valueType"][number]]: TD["$valueType"][number][K] extends (infer U4) ? U4 : never }, { readonly [K in keyof TA]: unknown } & { readonly [K in keyof TB]: unknown } & { readonly [K in keyof TC]: unknown } & { readonly [K in keyof TD]: unknown }>;
696
+ declare function merge<TA extends Parser<unknown, unknown>, TB extends Parser<unknown, unknown>, TC extends Parser<unknown, unknown>, TD extends Parser<unknown, unknown>>(a: TA, b: TB, c: TC, d: TD): ExtractObjectTypes<TA> extends never ? never : ExtractObjectTypes<TB> extends never ? never : ExtractObjectTypes<TC> extends never ? never : ExtractObjectTypes<TD> extends never ? never : Parser<ExtractObjectTypes<TA> & ExtractObjectTypes<TB> & ExtractObjectTypes<TC> & ExtractObjectTypes<TD>, Record<string | symbol, unknown>>;
686
697
  /**
687
698
  * Merges multiple {@link object} parsers into a single {@link object} parser.
688
699
  * It is useful for combining multiple {@link object} parsers so that
@@ -702,7 +713,7 @@ declare function merge<TA extends Parser<Record<string | symbol, unknown>, Recor
702
713
  * @return A new {@link object} parser that combines the values and states
703
714
  * of the two parsers into a single object.
704
715
  */
705
- declare function merge<TA extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TB extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TC extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TD extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>, TE extends Parser<Record<string | symbol, unknown>, Record<string | symbol, unknown>>>(a: TA, b: TB, c: TC, d: TD, e: TE): Parser<{ readonly [K in keyof TA["$valueType"][number]]: TA["$valueType"][number][K] extends (infer U) ? U : never } & { readonly [K in keyof TB["$valueType"][number]]: TB["$valueType"][number][K] extends (infer U2) ? U2 : never } & { readonly [K in keyof TC["$valueType"][number]]: TC["$valueType"][number][K] extends (infer U3) ? U3 : never } & { readonly [K in keyof TD["$valueType"][number]]: TD["$valueType"][number][K] extends (infer U4) ? U4 : never } & { readonly [K in keyof TE["$valueType"][number]]: TE["$valueType"][number][K] extends (infer U5) ? U5 : never }, { readonly [K in keyof TA]: unknown } & { readonly [K in keyof TB]: unknown } & { readonly [K in keyof TC]: unknown } & { readonly [K in keyof TD]: unknown } & { readonly [K in keyof TE]: unknown }>;
716
+ declare function merge<TA extends Parser<unknown, unknown>, TB extends Parser<unknown, unknown>, TC extends Parser<unknown, unknown>, TD extends Parser<unknown, unknown>, TE extends Parser<unknown, unknown>>(a: TA, b: TB, c: TC, d: TD, e: TE): ExtractObjectTypes<TA> extends never ? never : ExtractObjectTypes<TB> extends never ? never : ExtractObjectTypes<TC> extends never ? never : ExtractObjectTypes<TD> extends never ? never : ExtractObjectTypes<TE> extends never ? never : Parser<ExtractObjectTypes<TA> & ExtractObjectTypes<TB> & ExtractObjectTypes<TC> & ExtractObjectTypes<TD> & ExtractObjectTypes<TE>, Record<string | symbol, unknown>>;
706
717
  /**
707
718
  * Concatenates two {@link tuple} parsers into a single parser that produces
708
719
  * a flattened tuple containing the values from both parsers in order.
package/dist/parser.js CHANGED
@@ -525,12 +525,13 @@ function optional(parser) {
525
525
  * a specified default value.
526
526
  * @template TValue The type of the value returned by the wrapped parser.
527
527
  * @template TState The type of the state used by the wrapped parser.
528
+ * @template TDefault The type of the default value.
528
529
  * @param parser The {@link Parser} to wrap with default behavior.
529
530
  * @param defaultValue The default value to return when the wrapped parser
530
531
  * doesn't match or consume input. Can be a value of type
531
- * {@link TValue} or a function that returns such a value.
532
+ * {@link TDefault} or a function that returns such a value.
532
533
  * @returns A {@link Parser} that produces either the result of the wrapped parser
533
- * or the default value if the wrapped parser fails to match.
534
+ * or the default value if the wrapped parser fails to match (union type {@link TValue} | {@link TDefault}).
534
535
  */
535
536
  function withDefault(parser, defaultValue) {
536
537
  return {
@@ -565,7 +566,7 @@ function withDefault(parser, defaultValue) {
565
566
  return parser.complete(state[0]);
566
567
  },
567
568
  getDocFragments(state, upperDefaultValue) {
568
- return parser.getDocFragments(typeof state === "undefined" ? parser.initialState : state[0], upperDefaultValue == null ? typeof defaultValue === "function" ? defaultValue() : defaultValue : upperDefaultValue);
569
+ return parser.getDocFragments(typeof state === "undefined" ? parser.initialState : state[0], upperDefaultValue != null ? upperDefaultValue : typeof defaultValue === "function" ? defaultValue() : defaultValue);
569
570
  }
570
571
  };
571
572
  }
@@ -716,30 +717,44 @@ function object(labelOrParsers, maybeParsers) {
716
717
  consumed: 0,
717
718
  error: context.buffer.length > 0 ? message`Unexpected option or argument: ${context.buffer[0]}.` : message`Expected an option or argument, but got end of input.`
718
719
  };
719
- for (const [field, parser] of parserPairs) {
720
- const result = parser.parse({
721
- ...context,
722
- state: context.state[field]
723
- });
724
- if (result.success && result.consumed.length > 0) return {
725
- success: true,
726
- next: {
727
- ...context,
728
- buffer: result.next.buffer,
729
- optionsTerminated: result.next.optionsTerminated,
730
- state: {
731
- ...context.state,
732
- [field]: result.next.state
733
- }
734
- },
735
- consumed: result.consumed
736
- };
737
- else if (!result.success && error.consumed < result.consumed) error = result;
720
+ let currentContext = context;
721
+ let anySuccess = false;
722
+ const allConsumed = [];
723
+ let madeProgress = true;
724
+ while (madeProgress && currentContext.buffer.length > 0) {
725
+ madeProgress = false;
726
+ for (const [field, parser] of parserPairs) {
727
+ const result = parser.parse({
728
+ ...currentContext,
729
+ state: currentContext.state && typeof currentContext.state === "object" && field in currentContext.state ? currentContext.state[field] : parser.initialState
730
+ });
731
+ if (result.success && result.consumed.length > 0) {
732
+ currentContext = {
733
+ ...currentContext,
734
+ buffer: result.next.buffer,
735
+ optionsTerminated: result.next.optionsTerminated,
736
+ state: {
737
+ ...currentContext.state,
738
+ [field]: result.next.state
739
+ }
740
+ };
741
+ allConsumed.push(...result.consumed);
742
+ anySuccess = true;
743
+ madeProgress = true;
744
+ break;
745
+ } else if (!result.success && error.consumed < result.consumed) error = result;
746
+ }
738
747
  }
748
+ if (anySuccess) return {
749
+ success: true,
750
+ next: currentContext,
751
+ consumed: allConsumed
752
+ };
739
753
  if (context.buffer.length === 0) {
740
754
  let allCanComplete = true;
741
755
  for (const [field, parser] of parserPairs) {
742
- const completeResult = parser.complete(context.state[field]);
756
+ const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
757
+ const completeResult = parser.complete(fieldState);
743
758
  if (!completeResult.success) {
744
759
  allCanComplete = false;
745
760
  break;
@@ -991,7 +1006,7 @@ function or(...parsers) {
991
1006
  function merge(...parsers) {
992
1007
  parsers = parsers.toSorted((a, b) => b.priority - a.priority);
993
1008
  const initialState = {};
994
- for (const parser of parsers) for (const field in parser.initialState) initialState[field] = parser.initialState[field];
1009
+ for (const parser of parsers) if (parser.initialState && typeof parser.initialState === "object") for (const field in parser.initialState) initialState[field] = parser.initialState[field];
995
1010
  return {
996
1011
  $valueType: [],
997
1012
  $stateType: [],
@@ -999,22 +1014,41 @@ function merge(...parsers) {
999
1014
  usage: parsers.flatMap((p) => p.usage),
1000
1015
  initialState,
1001
1016
  parse(context) {
1002
- for (const parser of parsers) {
1003
- const result = parser.parse(context);
1004
- if (result.success) return {
1005
- success: true,
1006
- next: {
1007
- ...context,
1008
- buffer: result.next.buffer,
1009
- optionsTerminated: result.next.optionsTerminated,
1010
- state: {
1011
- ...context.state,
1012
- ...result.next.state
1013
- }
1014
- },
1015
- consumed: result.consumed
1016
- };
1017
- else if (result.consumed < 1) continue;
1017
+ for (let i = 0; i < parsers.length; i++) {
1018
+ const parser = parsers[i];
1019
+ let parserState;
1020
+ if (parser.initialState === void 0) parserState = void 0;
1021
+ else if (parser.initialState && typeof parser.initialState === "object") if (context.state && typeof context.state === "object") {
1022
+ const extractedState = {};
1023
+ for (const field in parser.initialState) extractedState[field] = field in context.state ? context.state[field] : parser.initialState[field];
1024
+ parserState = extractedState;
1025
+ } else parserState = parser.initialState;
1026
+ else parserState = parser.initialState;
1027
+ const result = parser.parse({
1028
+ ...context,
1029
+ state: parserState
1030
+ });
1031
+ if (result.success) {
1032
+ let newState;
1033
+ if (parser.initialState === void 0) newState = {
1034
+ ...context.state,
1035
+ [`__parser_${i}`]: result.next.state
1036
+ };
1037
+ else newState = {
1038
+ ...context.state,
1039
+ ...result.next.state
1040
+ };
1041
+ return {
1042
+ success: true,
1043
+ next: {
1044
+ ...context,
1045
+ buffer: result.next.buffer,
1046
+ optionsTerminated: result.next.optionsTerminated,
1047
+ state: newState
1048
+ },
1049
+ consumed: result.consumed
1050
+ };
1051
+ } else if (result.consumed < 1) continue;
1018
1052
  else return result;
1019
1053
  }
1020
1054
  return {
@@ -1025,8 +1059,20 @@ function merge(...parsers) {
1025
1059
  },
1026
1060
  complete(state) {
1027
1061
  const object$1 = {};
1028
- for (const parser of parsers) {
1029
- const result = parser.complete(state);
1062
+ for (let i = 0; i < parsers.length; i++) {
1063
+ const parser = parsers[i];
1064
+ let parserState;
1065
+ if (parser.initialState === void 0) {
1066
+ const key = `__parser_${i}`;
1067
+ if (state && typeof state === "object" && key in state) parserState = state[key];
1068
+ else parserState = void 0;
1069
+ } else if (parser.initialState && typeof parser.initialState === "object") if (state && typeof state === "object") {
1070
+ const extractedState = {};
1071
+ for (const field in parser.initialState) extractedState[field] = field in state ? state[field] : parser.initialState[field];
1072
+ parserState = extractedState;
1073
+ } else parserState = parser.initialState;
1074
+ else parserState = parser.initialState;
1075
+ const result = parser.complete(parserState);
1030
1076
  if (!result.success) return result;
1031
1077
  for (const field in result.value) object$1[field] = result.value[field];
1032
1078
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "0.3.0-dev.35+3445f3b8",
3
+ "version": "0.3.0-dev.38+3b6c02a6",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",