@optique/core 0.8.0-dev.164 → 0.8.0-dev.166
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/constructs.cjs +108 -184
- package/dist/constructs.d.cts +10 -1
- package/dist/constructs.d.ts +10 -1
- package/dist/constructs.js +109 -186
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/modifiers.cjs +41 -58
- package/dist/modifiers.js +41 -58
- package/dist/parser.cjs +15 -9
- package/dist/parser.d.cts +3 -3
- package/dist/parser.d.ts +3 -3
- package/dist/parser.js +16 -12
- package/dist/primitives.cjs +167 -1
- package/dist/primitives.d.cts +78 -1
- package/dist/primitives.d.ts +78 -1
- package/dist/primitives.js +166 -1
- package/dist/suggestion.cjs +50 -0
- package/dist/suggestion.js +50 -1
- package/dist/usage.cjs +7 -1
- package/dist/usage.d.cts +10 -0
- package/dist/usage.d.ts +10 -0
- package/dist/usage.js +7 -1
- package/dist/valueparser.cjs +1 -1
- package/dist/valueparser.js +1 -1
- package/package.json +1 -1
package/dist/modifiers.js
CHANGED
|
@@ -2,6 +2,45 @@ import { formatMessage, message, text } from "./message.js";
|
|
|
2
2
|
|
|
3
3
|
//#region src/modifiers.ts
|
|
4
4
|
/**
|
|
5
|
+
* Internal helper for optional-style parsing logic shared by optional()
|
|
6
|
+
* and withDefault(). Handles the common pattern of:
|
|
7
|
+
* - Unwrapping optional state to inner parser state
|
|
8
|
+
* - Detecting if inner parser actually matched (state changed or no consumption)
|
|
9
|
+
* - Returning success with undefined state when inner parser fails without consuming
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
function parseOptionalStyle(context, parser) {
|
|
13
|
+
const innerState = typeof context.state === "undefined" ? parser.initialState : context.state[0];
|
|
14
|
+
const result = parser.parse({
|
|
15
|
+
...context,
|
|
16
|
+
state: innerState
|
|
17
|
+
});
|
|
18
|
+
if (result.success) {
|
|
19
|
+
if (result.next.state !== innerState || result.consumed.length === 0) return {
|
|
20
|
+
success: true,
|
|
21
|
+
next: {
|
|
22
|
+
...result.next,
|
|
23
|
+
state: [result.next.state]
|
|
24
|
+
},
|
|
25
|
+
consumed: result.consumed
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
success: true,
|
|
29
|
+
next: {
|
|
30
|
+
...result.next,
|
|
31
|
+
state: context.state
|
|
32
|
+
},
|
|
33
|
+
consumed: result.consumed
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (result.consumed === 0) return {
|
|
37
|
+
success: true,
|
|
38
|
+
next: context,
|
|
39
|
+
consumed: []
|
|
40
|
+
};
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
5
44
|
* Creates a parser that makes another parser optional, allowing it to succeed
|
|
6
45
|
* without consuming input if the wrapped parser fails to match.
|
|
7
46
|
* If the wrapped parser succeeds, this returns its value.
|
|
@@ -23,35 +62,7 @@ function optional(parser) {
|
|
|
23
62
|
}],
|
|
24
63
|
initialState: void 0,
|
|
25
64
|
parse(context) {
|
|
26
|
-
|
|
27
|
-
const result = parser.parse({
|
|
28
|
-
...context,
|
|
29
|
-
state: innerState
|
|
30
|
-
});
|
|
31
|
-
if (result.success) {
|
|
32
|
-
if (result.next.state !== innerState || result.consumed.length === 0) return {
|
|
33
|
-
success: true,
|
|
34
|
-
next: {
|
|
35
|
-
...result.next,
|
|
36
|
-
state: [result.next.state]
|
|
37
|
-
},
|
|
38
|
-
consumed: result.consumed
|
|
39
|
-
};
|
|
40
|
-
return {
|
|
41
|
-
success: true,
|
|
42
|
-
next: {
|
|
43
|
-
...result.next,
|
|
44
|
-
state: context.state
|
|
45
|
-
},
|
|
46
|
-
consumed: result.consumed
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
if (result.consumed === 0) return {
|
|
50
|
-
success: true,
|
|
51
|
-
next: context,
|
|
52
|
-
consumed: []
|
|
53
|
-
};
|
|
54
|
-
return result;
|
|
65
|
+
return parseOptionalStyle(context, parser);
|
|
55
66
|
},
|
|
56
67
|
complete(state) {
|
|
57
68
|
if (typeof state === "undefined") return {
|
|
@@ -121,35 +132,7 @@ function withDefault(parser, defaultValue, options) {
|
|
|
121
132
|
}],
|
|
122
133
|
initialState: void 0,
|
|
123
134
|
parse(context) {
|
|
124
|
-
|
|
125
|
-
const result = parser.parse({
|
|
126
|
-
...context,
|
|
127
|
-
state: innerState
|
|
128
|
-
});
|
|
129
|
-
if (result.success) {
|
|
130
|
-
if (result.next.state !== innerState || result.consumed.length === 0) return {
|
|
131
|
-
success: true,
|
|
132
|
-
next: {
|
|
133
|
-
...result.next,
|
|
134
|
-
state: [result.next.state]
|
|
135
|
-
},
|
|
136
|
-
consumed: result.consumed
|
|
137
|
-
};
|
|
138
|
-
return {
|
|
139
|
-
success: true,
|
|
140
|
-
next: {
|
|
141
|
-
...result.next,
|
|
142
|
-
state: context.state
|
|
143
|
-
},
|
|
144
|
-
consumed: result.consumed
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
if (result.consumed === 0) return {
|
|
148
|
-
success: true,
|
|
149
|
-
next: context,
|
|
150
|
-
consumed: []
|
|
151
|
-
};
|
|
152
|
-
return result;
|
|
135
|
+
return parseOptionalStyle(context, parser);
|
|
153
136
|
},
|
|
154
137
|
complete(state) {
|
|
155
138
|
if (typeof state === "undefined") try {
|
package/dist/parser.cjs
CHANGED
|
@@ -34,7 +34,7 @@ function parse(parser, args) {
|
|
|
34
34
|
};
|
|
35
35
|
const previousBuffer = context.buffer;
|
|
36
36
|
context = result.next;
|
|
37
|
-
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer
|
|
37
|
+
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer.every((item, i) => item === previousBuffer[i])) return {
|
|
38
38
|
success: false,
|
|
39
39
|
error: require_message.message`Unexpected option or argument: ${context.buffer[0]}.`
|
|
40
40
|
};
|
|
@@ -90,7 +90,7 @@ function suggest(parser, args) {
|
|
|
90
90
|
if (!result.success) return Array.from(parser.suggest(context, prefix));
|
|
91
91
|
const previousBuffer = context.buffer;
|
|
92
92
|
context = result.next;
|
|
93
|
-
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer
|
|
93
|
+
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer.every((item, i) => item === previousBuffer[i])) return [];
|
|
94
94
|
}
|
|
95
95
|
return Array.from(parser.suggest(context, prefix));
|
|
96
96
|
}
|
|
@@ -154,14 +154,18 @@ function getDocPage(parser, args = []) {
|
|
|
154
154
|
const usage = [...require_usage.normalizeUsage(parser.usage)];
|
|
155
155
|
let i = 0;
|
|
156
156
|
for (const arg of args) {
|
|
157
|
+
if (i >= usage.length) break;
|
|
157
158
|
const term = usage[i];
|
|
158
|
-
if (
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
if (term.type === "exclusive") {
|
|
160
|
+
for (const termGroup of term.terms) {
|
|
161
|
+
const firstTerm = termGroup[0];
|
|
162
|
+
if (firstTerm?.type !== "command" || firstTerm.name !== arg) continue;
|
|
163
|
+
usage.splice(i, 1, ...termGroup);
|
|
164
|
+
i += termGroup.length;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
if (usage[i] === term) i++;
|
|
168
|
+
} else i++;
|
|
165
169
|
}
|
|
166
170
|
return {
|
|
167
171
|
usage,
|
|
@@ -172,6 +176,7 @@ function getDocPage(parser, args = []) {
|
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
//#endregion
|
|
179
|
+
exports.DuplicateOptionError = require_constructs.DuplicateOptionError;
|
|
175
180
|
exports.WithDefaultError = require_modifiers.WithDefaultError;
|
|
176
181
|
exports.argument = require_primitives.argument;
|
|
177
182
|
exports.command = require_primitives.command;
|
|
@@ -190,6 +195,7 @@ exports.option = require_primitives.option;
|
|
|
190
195
|
exports.optional = require_modifiers.optional;
|
|
191
196
|
exports.or = require_constructs.or;
|
|
192
197
|
exports.parse = parse;
|
|
198
|
+
exports.passThrough = require_primitives.passThrough;
|
|
193
199
|
exports.suggest = suggest;
|
|
194
200
|
exports.tuple = require_constructs.tuple;
|
|
195
201
|
exports.withDefault = require_modifiers.withDefault;
|
package/dist/parser.d.cts
CHANGED
|
@@ -3,8 +3,8 @@ 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";
|
|
7
|
-
import { ConditionalErrorOptions, ConditionalOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
|
|
6
|
+
import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.cjs";
|
|
7
|
+
import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, 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
|
|
10
10
|
|
|
@@ -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, DuplicateOptionError, 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,8 +3,8 @@ 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";
|
|
7
|
-
import { ConditionalErrorOptions, ConditionalOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
6
|
+
import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.js";
|
|
7
|
+
import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, 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
|
|
10
10
|
|
|
@@ -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, DuplicateOptionError, 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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { message } from "./message.js";
|
|
2
2
|
import { normalizeUsage } from "./usage.js";
|
|
3
|
-
import { concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
|
|
3
|
+
import { DuplicateOptionError, 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
|
/**
|
|
@@ -34,7 +34,7 @@ function parse(parser, args) {
|
|
|
34
34
|
};
|
|
35
35
|
const previousBuffer = context.buffer;
|
|
36
36
|
context = result.next;
|
|
37
|
-
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer
|
|
37
|
+
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer.every((item, i) => item === previousBuffer[i])) return {
|
|
38
38
|
success: false,
|
|
39
39
|
error: message`Unexpected option or argument: ${context.buffer[0]}.`
|
|
40
40
|
};
|
|
@@ -90,7 +90,7 @@ function suggest(parser, args) {
|
|
|
90
90
|
if (!result.success) return Array.from(parser.suggest(context, prefix));
|
|
91
91
|
const previousBuffer = context.buffer;
|
|
92
92
|
context = result.next;
|
|
93
|
-
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer
|
|
93
|
+
if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer.every((item, i) => item === previousBuffer[i])) return [];
|
|
94
94
|
}
|
|
95
95
|
return Array.from(parser.suggest(context, prefix));
|
|
96
96
|
}
|
|
@@ -154,14 +154,18 @@ function getDocPage(parser, args = []) {
|
|
|
154
154
|
const usage = [...normalizeUsage(parser.usage)];
|
|
155
155
|
let i = 0;
|
|
156
156
|
for (const arg of args) {
|
|
157
|
+
if (i >= usage.length) break;
|
|
157
158
|
const term = usage[i];
|
|
158
|
-
if (
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
if (term.type === "exclusive") {
|
|
160
|
+
for (const termGroup of term.terms) {
|
|
161
|
+
const firstTerm = termGroup[0];
|
|
162
|
+
if (firstTerm?.type !== "command" || firstTerm.name !== arg) continue;
|
|
163
|
+
usage.splice(i, 1, ...termGroup);
|
|
164
|
+
i += termGroup.length;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
if (usage[i] === term) i++;
|
|
168
|
+
} else i++;
|
|
165
169
|
}
|
|
166
170
|
return {
|
|
167
171
|
usage,
|
|
@@ -172,4 +176,4 @@ function getDocPage(parser, args = []) {
|
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
//#endregion
|
|
175
|
-
export { WithDefaultError, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, suggest, tuple, withDefault };
|
|
179
|
+
export { DuplicateOptionError, WithDefaultError, argument, command, concat, conditional, constant, flag, getDocPage, group, longestMatch, map, merge, multiple, object, option, optional, or, parse, passThrough, suggest, tuple, withDefault };
|
package/dist/primitives.cjs
CHANGED
|
@@ -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;
|
package/dist/primitives.d.cts
CHANGED
|
@@ -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 };
|
package/dist/primitives.d.ts
CHANGED
|
@@ -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 };
|