@optique/core 0.8.0-dev.164 → 0.8.0-dev.165

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/index.cjs CHANGED
@@ -50,6 +50,7 @@ exports.optionNames = require_message.optionNames;
50
50
  exports.optional = require_modifiers.optional;
51
51
  exports.or = require_constructs.or;
52
52
  exports.parse = require_parser.parse;
53
+ exports.passThrough = require_primitives.passThrough;
53
54
  exports.pwsh = require_completion.pwsh;
54
55
  exports.run = require_facade.run;
55
56
  exports.string = require_valueparser.string;
package/dist/index.d.cts CHANGED
@@ -3,9 +3,9 @@ import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOption
3
3
  import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, ShowDefaultOptions, formatDocPage } from "./doc.cjs";
4
4
  import { ChoiceOptions, FloatOptions, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.cjs";
5
5
  import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, optional, withDefault } from "./modifiers.cjs";
6
- import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, argument, command, constant, flag, option } from "./primitives.cjs";
6
+ import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.cjs";
7
7
  import { DocState, InferValue, Parser, ParserContext, ParserResult, Result, Suggestion, getDocPage, parse, suggest } from "./parser.cjs";
8
8
  import { ConditionalErrorOptions, ConditionalOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
9
9
  import { ShellCompletion, bash, fish, nu, pwsh, zsh } from "./completion.cjs";
10
10
  import { RunError, RunOptions, run } from "./facade.cjs";
11
- export { ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagErrorOptions, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Message, MessageFormatOptions, MessageTerm, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, ShellCompletion, ShowDefaultOptions, StringOptions, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, WithDefaultOptions, argument, bash, choice, command, commandLine, concat, conditional, constant, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
11
+ export { ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagErrorOptions, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Message, MessageFormatOptions, MessageTerm, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, RunError, RunOptions, ShellCompletion, ShowDefaultOptions, StringOptions, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, WithDefaultOptions, argument, bash, choice, command, commandLine, concat, conditional, constant, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, passThrough, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
package/dist/index.d.ts CHANGED
@@ -3,9 +3,9 @@ import { OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOption
3
3
  import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, ShowDefaultOptions, formatDocPage } from "./doc.js";
4
4
  import { ChoiceOptions, FloatOptions, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.js";
5
5
  import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, optional, withDefault } from "./modifiers.js";
6
- import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, argument, command, constant, flag, option } from "./primitives.js";
6
+ import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.js";
7
7
  import { DocState, InferValue, Parser, ParserContext, ParserResult, Result, Suggestion, getDocPage, parse, suggest } from "./parser.js";
8
8
  import { ConditionalErrorOptions, ConditionalOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
9
9
  import { ShellCompletion, bash, fish, nu, pwsh, zsh } from "./completion.js";
10
10
  import { RunError, RunOptions, run } from "./facade.js";
11
- export { ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagErrorOptions, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Message, MessageFormatOptions, MessageTerm, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, RunError, RunOptions, ShellCompletion, ShowDefaultOptions, StringOptions, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, WithDefaultOptions, argument, bash, choice, command, commandLine, concat, conditional, constant, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
11
+ export { ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, FlagErrorOptions, FlagOptions, FloatOptions, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Message, MessageFormatOptions, MessageTerm, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, RunError, RunOptions, ShellCompletion, ShowDefaultOptions, StringOptions, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, WithDefaultError, WithDefaultOptions, argument, bash, choice, command, commandLine, concat, conditional, constant, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, passThrough, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
package/dist/index.js CHANGED
@@ -5,8 +5,8 @@ import { formatDocPage } from "./doc.js";
5
5
  import { bash, fish, nu, pwsh, zsh } from "./completion.js";
6
6
  import { WithDefaultError, map, multiple, optional, withDefault } from "./modifiers.js";
7
7
  import { choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.js";
8
- import { argument, command, constant, flag, option } from "./primitives.js";
8
+ import { argument, command, constant, flag, option, passThrough } from "./primitives.js";
9
9
  import { getDocPage, parse, suggest } from "./parser.js";
10
10
  import { RunError, run } from "./facade.js";
11
11
 
12
- export { RunError, WithDefaultError, argument, bash, choice, command, commandLine, concat, conditional, constant, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
12
+ export { RunError, WithDefaultError, argument, bash, choice, command, commandLine, concat, conditional, constant, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getDocPage, group, integer, isValueParser, locale, longestMatch, map, merge, message, metavar, multiple, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, passThrough, pwsh, run, string, suggest, text, tuple, url, uuid, value, values, withDefault, zsh };
package/dist/parser.cjs CHANGED
@@ -190,6 +190,7 @@ exports.option = require_primitives.option;
190
190
  exports.optional = require_modifiers.optional;
191
191
  exports.or = require_constructs.or;
192
192
  exports.parse = parse;
193
+ exports.passThrough = require_primitives.passThrough;
193
194
  exports.suggest = suggest;
194
195
  exports.tuple = require_constructs.tuple;
195
196
  exports.withDefault = require_modifiers.withDefault;
package/dist/parser.d.cts CHANGED
@@ -3,7 +3,7 @@ import { Usage } from "./usage.cjs";
3
3
  import { DocFragments, DocPage } from "./doc.cjs";
4
4
  import { ValueParserResult } from "./valueparser.cjs";
5
5
  import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, optional, withDefault } from "./modifiers.cjs";
6
- import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, argument, command, constant, flag, option } from "./primitives.cjs";
6
+ import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.cjs";
7
7
  import { ConditionalErrorOptions, ConditionalOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
8
8
 
9
9
  //#region src/parser.d.ts
@@ -323,4 +323,4 @@ declare function suggest<T>(parser: Parser<T, unknown>, args: readonly [string,
323
323
  */
324
324
  declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
325
325
  //#endregion
326
- export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, suggest, tuple, withDefault };
326
+ export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, passThrough, suggest, tuple, withDefault };
package/dist/parser.d.ts CHANGED
@@ -3,7 +3,7 @@ import { Usage } from "./usage.js";
3
3
  import { DocFragments, DocPage } from "./doc.js";
4
4
  import { ValueParserResult } from "./valueparser.js";
5
5
  import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, optional, withDefault } from "./modifiers.js";
6
- import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, argument, command, constant, flag, option } from "./primitives.js";
6
+ import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.js";
7
7
  import { ConditionalErrorOptions, ConditionalOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
8
8
 
9
9
  //#region src/parser.d.ts
@@ -323,4 +323,4 @@ declare function suggest<T>(parser: Parser<T, unknown>, args: readonly [string,
323
323
  */
324
324
  declare function getDocPage(parser: Parser<unknown, unknown>, args?: readonly string[]): DocPage | undefined;
325
325
  //#endregion
326
- export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, suggest, tuple, withDefault };
326
+ export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, FlagErrorOptions, FlagOptions, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OrErrorOptions, OrOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, passThrough, suggest, tuple, withDefault };
package/dist/parser.js CHANGED
@@ -2,7 +2,7 @@ import { message } from "./message.js";
2
2
  import { normalizeUsage } from "./usage.js";
3
3
  import { concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
4
4
  import { WithDefaultError, map, multiple, optional, withDefault } from "./modifiers.js";
5
- import { argument, command, constant, flag, option } from "./primitives.js";
5
+ import { argument, command, constant, flag, option, passThrough } from "./primitives.js";
6
6
 
7
7
  //#region src/parser.ts
8
8
  /**
@@ -172,4 +172,4 @@ function getDocPage(parser, args = []) {
172
172
  }
173
173
 
174
174
  //#endregion
175
- export { WithDefaultError, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, suggest, tuple, withDefault };
175
+ export { WithDefaultError, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, passThrough, suggest, tuple, withDefault };
@@ -723,10 +723,176 @@ function command(name, parser, options = {}) {
723
723
  }
724
724
  };
725
725
  }
726
+ /**
727
+ * Creates a parser that collects unrecognized options and passes them through.
728
+ * This is useful for building wrapper CLI tools that need to forward unknown
729
+ * options to an underlying tool.
730
+ *
731
+ * **Important**: This parser intentionally weakens Optique's strict parsing
732
+ * philosophy where "all input must be recognized." The benefit is enabling
733
+ * legitimate wrapper/proxy tool patterns, but the trade-off is that typos
734
+ * in pass-through options won't be caught.
735
+ *
736
+ * @param options Configuration for how to capture options.
737
+ * @returns A {@link Parser} that captures unrecognized options as an array
738
+ * of strings.
739
+ *
740
+ * @example
741
+ * ```typescript
742
+ * // Default format: only captures --opt=val
743
+ * const parser = object({
744
+ * debug: option("--debug"),
745
+ * extra: passThrough(),
746
+ * });
747
+ *
748
+ * // mycli --debug --foo=bar --baz=qux
749
+ * // → { debug: true, extra: ["--foo=bar", "--baz=qux"] }
750
+ *
751
+ * // nextToken format: captures --opt val pairs
752
+ * const parser = object({
753
+ * debug: option("--debug"),
754
+ * extra: passThrough({ format: "nextToken" }),
755
+ * });
756
+ *
757
+ * // mycli --debug --foo bar
758
+ * // → { debug: true, extra: ["--foo", "bar"] }
759
+ *
760
+ * // greedy format: captures all remaining tokens
761
+ * const parser = command("exec", object({
762
+ * container: argument(string()),
763
+ * args: passThrough({ format: "greedy" }),
764
+ * }));
765
+ *
766
+ * // myproxy exec mycontainer --verbose -it bash
767
+ * // → { container: "mycontainer", args: ["--verbose", "-it", "bash"] }
768
+ * ```
769
+ *
770
+ * @since 0.8.0
771
+ */
772
+ function passThrough(options = {}) {
773
+ const format = options.format ?? "equalsOnly";
774
+ const optionPattern = /^-[a-z0-9-]|^--[a-z0-9-]+/i;
775
+ const equalsOptionPattern = /^--[a-z0-9-]+=/i;
776
+ return {
777
+ $valueType: [],
778
+ $stateType: [],
779
+ priority: -10,
780
+ usage: [{ type: "passthrough" }],
781
+ initialState: [],
782
+ parse(context) {
783
+ if (context.buffer.length < 1) return {
784
+ success: false,
785
+ consumed: 0,
786
+ error: require_message.message`No input to pass through.`
787
+ };
788
+ const token = context.buffer[0];
789
+ if (format === "greedy") {
790
+ const captured = [...context.buffer];
791
+ return {
792
+ success: true,
793
+ next: {
794
+ ...context,
795
+ buffer: [],
796
+ state: [...context.state, ...captured]
797
+ },
798
+ consumed: captured
799
+ };
800
+ }
801
+ if (context.optionsTerminated) return {
802
+ success: false,
803
+ consumed: 0,
804
+ error: require_message.message`Options terminated; cannot capture pass-through options.`
805
+ };
806
+ if (format === "equalsOnly") {
807
+ if (!equalsOptionPattern.test(token)) return {
808
+ success: false,
809
+ consumed: 0,
810
+ error: require_message.message`Expected --option=value format, but got: ${token}.`
811
+ };
812
+ return {
813
+ success: true,
814
+ next: {
815
+ ...context,
816
+ buffer: context.buffer.slice(1),
817
+ state: [...context.state, token]
818
+ },
819
+ consumed: [token]
820
+ };
821
+ }
822
+ if (format === "nextToken") {
823
+ if (!optionPattern.test(token)) return {
824
+ success: false,
825
+ consumed: 0,
826
+ error: require_message.message`Expected option, but got: ${token}.`
827
+ };
828
+ if (token.includes("=")) return {
829
+ success: true,
830
+ next: {
831
+ ...context,
832
+ buffer: context.buffer.slice(1),
833
+ state: [...context.state, token]
834
+ },
835
+ consumed: [token]
836
+ };
837
+ const nextToken = context.buffer[1];
838
+ if (nextToken !== void 0 && !optionPattern.test(nextToken)) return {
839
+ success: true,
840
+ next: {
841
+ ...context,
842
+ buffer: context.buffer.slice(2),
843
+ state: [
844
+ ...context.state,
845
+ token,
846
+ nextToken
847
+ ]
848
+ },
849
+ consumed: [token, nextToken]
850
+ };
851
+ return {
852
+ success: true,
853
+ next: {
854
+ ...context,
855
+ buffer: context.buffer.slice(1),
856
+ state: [...context.state, token]
857
+ },
858
+ consumed: [token]
859
+ };
860
+ }
861
+ return {
862
+ success: false,
863
+ consumed: 0,
864
+ error: require_message.message`Unknown passThrough format: ${format}.`
865
+ };
866
+ },
867
+ complete(state) {
868
+ return {
869
+ success: true,
870
+ value: state
871
+ };
872
+ },
873
+ suggest(_context, _prefix) {
874
+ return [];
875
+ },
876
+ getDocFragments(_state, _defaultValue) {
877
+ return {
878
+ fragments: [{
879
+ type: "entry",
880
+ term: { type: "passthrough" },
881
+ description: options.description
882
+ }],
883
+ description: options.description
884
+ };
885
+ },
886
+ [Symbol.for("Deno.customInspect")]() {
887
+ return `passThrough(${format})`;
888
+ }
889
+ };
890
+ }
726
891
 
727
892
  //#endregion
728
893
  exports.argument = argument;
729
894
  exports.command = command;
730
895
  exports.constant = constant;
731
896
  exports.flag = flag;
732
- exports.option = option;
897
+ exports.option = option;
898
+ exports.passThrough = passThrough;
@@ -307,5 +307,82 @@ type CommandState<TState> = undefined | ["matched", string] | ["parsing", TState
307
307
  * to the inner parser for the remaining arguments.
308
308
  */
309
309
  declare function command<T, TState>(name: string, parser: Parser<T, TState>, options?: CommandOptions): Parser<T, CommandState<TState>>;
310
+ /**
311
+ * Format options for how {@link passThrough} captures options.
312
+ * @since 0.8.0
313
+ */
314
+ type PassThroughFormat = "equalsOnly" | "nextToken" | "greedy";
315
+ /**
316
+ * Options for the {@link passThrough} parser.
317
+ * @since 0.8.0
318
+ */
319
+ interface PassThroughOptions {
320
+ /**
321
+ * How to capture option values:
322
+ *
323
+ * - `"equalsOnly"`: Only capture `--opt=val` format (default, safest).
324
+ * Values with spaces (`--opt val`) are not captured.
325
+ *
326
+ * - `"nextToken"`: Capture `--opt` and its value as separate tokens
327
+ * (`--opt val`). The next token is captured if it doesn't start with `-`.
328
+ *
329
+ * - `"greedy"`: Capture *all* remaining tokens from first unrecognized token.
330
+ * This is useful for wrapper/proxy tools that pass everything through.
331
+ *
332
+ * @default `"equalsOnly"`
333
+ */
334
+ readonly format?: PassThroughFormat;
335
+ /**
336
+ * A description of what pass-through options are used for.
337
+ */
338
+ readonly description?: Message;
339
+ }
340
+ /**
341
+ * Creates a parser that collects unrecognized options and passes them through.
342
+ * This is useful for building wrapper CLI tools that need to forward unknown
343
+ * options to an underlying tool.
344
+ *
345
+ * **Important**: This parser intentionally weakens Optique's strict parsing
346
+ * philosophy where "all input must be recognized." The benefit is enabling
347
+ * legitimate wrapper/proxy tool patterns, but the trade-off is that typos
348
+ * in pass-through options won't be caught.
349
+ *
350
+ * @param options Configuration for how to capture options.
351
+ * @returns A {@link Parser} that captures unrecognized options as an array
352
+ * of strings.
353
+ *
354
+ * @example
355
+ * ```typescript
356
+ * // Default format: only captures --opt=val
357
+ * const parser = object({
358
+ * debug: option("--debug"),
359
+ * extra: passThrough(),
360
+ * });
361
+ *
362
+ * // mycli --debug --foo=bar --baz=qux
363
+ * // → { debug: true, extra: ["--foo=bar", "--baz=qux"] }
364
+ *
365
+ * // nextToken format: captures --opt val pairs
366
+ * const parser = object({
367
+ * debug: option("--debug"),
368
+ * extra: passThrough({ format: "nextToken" }),
369
+ * });
370
+ *
371
+ * // mycli --debug --foo bar
372
+ * // → { debug: true, extra: ["--foo", "bar"] }
373
+ *
374
+ * // greedy format: captures all remaining tokens
375
+ * const parser = command("exec", object({
376
+ * container: argument(string()),
377
+ * args: passThrough({ format: "greedy" }),
378
+ * }));
379
+ *
380
+ * // myproxy exec mycontainer --verbose -it bash
381
+ * // → { container: "mycontainer", args: ["--verbose", "-it", "bash"] }
382
+ * ```
383
+ *
384
+ * @since 0.8.0
385
+ */
386
+ declare function passThrough(options?: PassThroughOptions): Parser<readonly string[], readonly string[]>;
310
387
  //#endregion
311
- export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, argument, command, constant, flag, option };
388
+ export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough };
@@ -307,5 +307,82 @@ type CommandState<TState> = undefined | ["matched", string] | ["parsing", TState
307
307
  * to the inner parser for the remaining arguments.
308
308
  */
309
309
  declare function command<T, TState>(name: string, parser: Parser<T, TState>, options?: CommandOptions): Parser<T, CommandState<TState>>;
310
+ /**
311
+ * Format options for how {@link passThrough} captures options.
312
+ * @since 0.8.0
313
+ */
314
+ type PassThroughFormat = "equalsOnly" | "nextToken" | "greedy";
315
+ /**
316
+ * Options for the {@link passThrough} parser.
317
+ * @since 0.8.0
318
+ */
319
+ interface PassThroughOptions {
320
+ /**
321
+ * How to capture option values:
322
+ *
323
+ * - `"equalsOnly"`: Only capture `--opt=val` format (default, safest).
324
+ * Values with spaces (`--opt val`) are not captured.
325
+ *
326
+ * - `"nextToken"`: Capture `--opt` and its value as separate tokens
327
+ * (`--opt val`). The next token is captured if it doesn't start with `-`.
328
+ *
329
+ * - `"greedy"`: Capture *all* remaining tokens from first unrecognized token.
330
+ * This is useful for wrapper/proxy tools that pass everything through.
331
+ *
332
+ * @default `"equalsOnly"`
333
+ */
334
+ readonly format?: PassThroughFormat;
335
+ /**
336
+ * A description of what pass-through options are used for.
337
+ */
338
+ readonly description?: Message;
339
+ }
340
+ /**
341
+ * Creates a parser that collects unrecognized options and passes them through.
342
+ * This is useful for building wrapper CLI tools that need to forward unknown
343
+ * options to an underlying tool.
344
+ *
345
+ * **Important**: This parser intentionally weakens Optique's strict parsing
346
+ * philosophy where "all input must be recognized." The benefit is enabling
347
+ * legitimate wrapper/proxy tool patterns, but the trade-off is that typos
348
+ * in pass-through options won't be caught.
349
+ *
350
+ * @param options Configuration for how to capture options.
351
+ * @returns A {@link Parser} that captures unrecognized options as an array
352
+ * of strings.
353
+ *
354
+ * @example
355
+ * ```typescript
356
+ * // Default format: only captures --opt=val
357
+ * const parser = object({
358
+ * debug: option("--debug"),
359
+ * extra: passThrough(),
360
+ * });
361
+ *
362
+ * // mycli --debug --foo=bar --baz=qux
363
+ * // → { debug: true, extra: ["--foo=bar", "--baz=qux"] }
364
+ *
365
+ * // nextToken format: captures --opt val pairs
366
+ * const parser = object({
367
+ * debug: option("--debug"),
368
+ * extra: passThrough({ format: "nextToken" }),
369
+ * });
370
+ *
371
+ * // mycli --debug --foo bar
372
+ * // → { debug: true, extra: ["--foo", "bar"] }
373
+ *
374
+ * // greedy format: captures all remaining tokens
375
+ * const parser = command("exec", object({
376
+ * container: argument(string()),
377
+ * args: passThrough({ format: "greedy" }),
378
+ * }));
379
+ *
380
+ * // myproxy exec mycontainer --verbose -it bash
381
+ * // → { container: "mycontainer", args: ["--verbose", "-it", "bash"] }
382
+ * ```
383
+ *
384
+ * @since 0.8.0
385
+ */
386
+ declare function passThrough(options?: PassThroughOptions): Parser<readonly string[], readonly string[]>;
310
387
  //#endregion
311
- export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, argument, command, constant, flag, option };
388
+ export { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough };
@@ -723,6 +723,171 @@ function command(name, parser, options = {}) {
723
723
  }
724
724
  };
725
725
  }
726
+ /**
727
+ * Creates a parser that collects unrecognized options and passes them through.
728
+ * This is useful for building wrapper CLI tools that need to forward unknown
729
+ * options to an underlying tool.
730
+ *
731
+ * **Important**: This parser intentionally weakens Optique's strict parsing
732
+ * philosophy where "all input must be recognized." The benefit is enabling
733
+ * legitimate wrapper/proxy tool patterns, but the trade-off is that typos
734
+ * in pass-through options won't be caught.
735
+ *
736
+ * @param options Configuration for how to capture options.
737
+ * @returns A {@link Parser} that captures unrecognized options as an array
738
+ * of strings.
739
+ *
740
+ * @example
741
+ * ```typescript
742
+ * // Default format: only captures --opt=val
743
+ * const parser = object({
744
+ * debug: option("--debug"),
745
+ * extra: passThrough(),
746
+ * });
747
+ *
748
+ * // mycli --debug --foo=bar --baz=qux
749
+ * // → { debug: true, extra: ["--foo=bar", "--baz=qux"] }
750
+ *
751
+ * // nextToken format: captures --opt val pairs
752
+ * const parser = object({
753
+ * debug: option("--debug"),
754
+ * extra: passThrough({ format: "nextToken" }),
755
+ * });
756
+ *
757
+ * // mycli --debug --foo bar
758
+ * // → { debug: true, extra: ["--foo", "bar"] }
759
+ *
760
+ * // greedy format: captures all remaining tokens
761
+ * const parser = command("exec", object({
762
+ * container: argument(string()),
763
+ * args: passThrough({ format: "greedy" }),
764
+ * }));
765
+ *
766
+ * // myproxy exec mycontainer --verbose -it bash
767
+ * // → { container: "mycontainer", args: ["--verbose", "-it", "bash"] }
768
+ * ```
769
+ *
770
+ * @since 0.8.0
771
+ */
772
+ function passThrough(options = {}) {
773
+ const format = options.format ?? "equalsOnly";
774
+ const optionPattern = /^-[a-z0-9-]|^--[a-z0-9-]+/i;
775
+ const equalsOptionPattern = /^--[a-z0-9-]+=/i;
776
+ return {
777
+ $valueType: [],
778
+ $stateType: [],
779
+ priority: -10,
780
+ usage: [{ type: "passthrough" }],
781
+ initialState: [],
782
+ parse(context) {
783
+ if (context.buffer.length < 1) return {
784
+ success: false,
785
+ consumed: 0,
786
+ error: message`No input to pass through.`
787
+ };
788
+ const token = context.buffer[0];
789
+ if (format === "greedy") {
790
+ const captured = [...context.buffer];
791
+ return {
792
+ success: true,
793
+ next: {
794
+ ...context,
795
+ buffer: [],
796
+ state: [...context.state, ...captured]
797
+ },
798
+ consumed: captured
799
+ };
800
+ }
801
+ if (context.optionsTerminated) return {
802
+ success: false,
803
+ consumed: 0,
804
+ error: message`Options terminated; cannot capture pass-through options.`
805
+ };
806
+ if (format === "equalsOnly") {
807
+ if (!equalsOptionPattern.test(token)) return {
808
+ success: false,
809
+ consumed: 0,
810
+ error: message`Expected --option=value format, but got: ${token}.`
811
+ };
812
+ return {
813
+ success: true,
814
+ next: {
815
+ ...context,
816
+ buffer: context.buffer.slice(1),
817
+ state: [...context.state, token]
818
+ },
819
+ consumed: [token]
820
+ };
821
+ }
822
+ if (format === "nextToken") {
823
+ if (!optionPattern.test(token)) return {
824
+ success: false,
825
+ consumed: 0,
826
+ error: message`Expected option, but got: ${token}.`
827
+ };
828
+ if (token.includes("=")) return {
829
+ success: true,
830
+ next: {
831
+ ...context,
832
+ buffer: context.buffer.slice(1),
833
+ state: [...context.state, token]
834
+ },
835
+ consumed: [token]
836
+ };
837
+ const nextToken = context.buffer[1];
838
+ if (nextToken !== void 0 && !optionPattern.test(nextToken)) return {
839
+ success: true,
840
+ next: {
841
+ ...context,
842
+ buffer: context.buffer.slice(2),
843
+ state: [
844
+ ...context.state,
845
+ token,
846
+ nextToken
847
+ ]
848
+ },
849
+ consumed: [token, nextToken]
850
+ };
851
+ return {
852
+ success: true,
853
+ next: {
854
+ ...context,
855
+ buffer: context.buffer.slice(1),
856
+ state: [...context.state, token]
857
+ },
858
+ consumed: [token]
859
+ };
860
+ }
861
+ return {
862
+ success: false,
863
+ consumed: 0,
864
+ error: message`Unknown passThrough format: ${format}.`
865
+ };
866
+ },
867
+ complete(state) {
868
+ return {
869
+ success: true,
870
+ value: state
871
+ };
872
+ },
873
+ suggest(_context, _prefix) {
874
+ return [];
875
+ },
876
+ getDocFragments(_state, _defaultValue) {
877
+ return {
878
+ fragments: [{
879
+ type: "entry",
880
+ term: { type: "passthrough" },
881
+ description: options.description
882
+ }],
883
+ description: options.description
884
+ };
885
+ },
886
+ [Symbol.for("Deno.customInspect")]() {
887
+ return `passThrough(${format})`;
888
+ }
889
+ };
890
+ }
726
891
 
727
892
  //#endregion
728
- export { argument, command, constant, flag, option };
893
+ export { argument, command, constant, flag, option, passThrough };
package/dist/usage.cjs CHANGED
@@ -331,7 +331,13 @@ function* formatUsageTermInternal(term, options) {
331
331
  text: term.value,
332
332
  width: term.value.length
333
333
  };
334
- else throw new TypeError(`Unknown usage term type: ${term["type"]}.`);
334
+ else if (term.type === "passthrough") {
335
+ const text = "[...]";
336
+ yield {
337
+ text: options?.colors ? `\x1b[2m${text}\x1b[0m` : text,
338
+ width: 5
339
+ };
340
+ } else throw new TypeError(`Unknown usage term type: ${term["type"]}.`);
335
341
  }
336
342
 
337
343
  //#endregion
package/dist/usage.d.cts CHANGED
@@ -123,6 +123,16 @@ type UsageTerm =
123
123
  * The literal value that must be provided exactly as written.
124
124
  */
125
125
  readonly value: string;
126
+ }
127
+ /**
128
+ * A pass-through term, which represents unrecognized options that are
129
+ * collected and passed through to an underlying tool or command.
130
+ * @since 0.8.0
131
+ */ | {
132
+ /**
133
+ * The type of the term, which is always `"passthrough"` for this term.
134
+ */
135
+ readonly type: "passthrough";
126
136
  };
127
137
  /**
128
138
  * Represents a command-line usage description, which is a sequence of
package/dist/usage.d.ts CHANGED
@@ -123,6 +123,16 @@ type UsageTerm =
123
123
  * The literal value that must be provided exactly as written.
124
124
  */
125
125
  readonly value: string;
126
+ }
127
+ /**
128
+ * A pass-through term, which represents unrecognized options that are
129
+ * collected and passed through to an underlying tool or command.
130
+ * @since 0.8.0
131
+ */ | {
132
+ /**
133
+ * The type of the term, which is always `"passthrough"` for this term.
134
+ */
135
+ readonly type: "passthrough";
126
136
  };
127
137
  /**
128
138
  * Represents a command-line usage description, which is a sequence of
package/dist/usage.js CHANGED
@@ -330,7 +330,13 @@ function* formatUsageTermInternal(term, options) {
330
330
  text: term.value,
331
331
  width: term.value.length
332
332
  };
333
- else throw new TypeError(`Unknown usage term type: ${term["type"]}.`);
333
+ else if (term.type === "passthrough") {
334
+ const text = "[...]";
335
+ yield {
336
+ text: options?.colors ? `\x1b[2m${text}\x1b[0m` : text,
337
+ width: 5
338
+ };
339
+ } else throw new TypeError(`Unknown usage term type: ${term["type"]}.`);
334
340
  }
335
341
 
336
342
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "0.8.0-dev.164+250237ef",
3
+ "version": "0.8.0-dev.165+f4b6fb65",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",