@optique/core 0.5.0-dev.79 → 0.5.0-dev.82
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 +754 -0
- package/dist/constructs.d.cts +1100 -0
- package/dist/constructs.d.ts +1100 -0
- package/dist/constructs.js +748 -0
- package/dist/facade.cjs +56 -46
- package/dist/facade.js +32 -22
- package/dist/index.cjs +20 -17
- package/dist/index.d.cts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/modifiers.cjs +300 -0
- package/dist/modifiers.d.cts +192 -0
- package/dist/modifiers.d.ts +192 -0
- package/dist/modifiers.js +296 -0
- package/dist/parser.cjs +20 -1581
- package/dist/parser.d.cts +6 -1279
- package/dist/parser.d.ts +6 -1279
- package/dist/parser.js +4 -1565
- package/dist/primitives.cjs +595 -0
- package/dist/primitives.d.cts +274 -0
- package/dist/primitives.d.ts +274 -0
- package/dist/primitives.js +591 -0
- package/dist/valueparser.cjs +28 -28
- package/dist/valueparser.d.cts +144 -0
- package/dist/valueparser.d.ts +144 -0
- package/dist/valueparser.js +28 -28
- package/package.json +25 -1
package/dist/parser.cjs
CHANGED
|
@@ -1,1497 +1,11 @@
|
|
|
1
1
|
const require_message = require('./message.cjs');
|
|
2
|
+
const require_constructs = require('./constructs.cjs');
|
|
2
3
|
const require_usage = require('./usage.cjs');
|
|
3
|
-
const
|
|
4
|
+
const require_modifiers = require('./modifiers.cjs');
|
|
5
|
+
const require_primitives = require('./primitives.cjs');
|
|
4
6
|
|
|
5
7
|
//#region src/parser.ts
|
|
6
8
|
/**
|
|
7
|
-
* Creates a parser that always succeeds without consuming any input and
|
|
8
|
-
* produces a constant value of the type {@link T}.
|
|
9
|
-
* @template T The type of the constant value produced by the parser.
|
|
10
|
-
*/
|
|
11
|
-
function constant(value) {
|
|
12
|
-
return {
|
|
13
|
-
$valueType: [],
|
|
14
|
-
$stateType: [],
|
|
15
|
-
priority: 0,
|
|
16
|
-
usage: [],
|
|
17
|
-
initialState: value,
|
|
18
|
-
parse(context) {
|
|
19
|
-
return {
|
|
20
|
-
success: true,
|
|
21
|
-
next: context,
|
|
22
|
-
consumed: []
|
|
23
|
-
};
|
|
24
|
-
},
|
|
25
|
-
complete(state) {
|
|
26
|
-
return {
|
|
27
|
-
success: true,
|
|
28
|
-
value: state
|
|
29
|
-
};
|
|
30
|
-
},
|
|
31
|
-
getDocFragments(_state, _defaultValue) {
|
|
32
|
-
return { fragments: [] };
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
function option(...args) {
|
|
37
|
-
const lastArg = args.at(-1);
|
|
38
|
-
const secondLastArg = args.at(-2);
|
|
39
|
-
let valueParser;
|
|
40
|
-
let optionNames$1;
|
|
41
|
-
let options = {};
|
|
42
|
-
if (require_valueparser.isValueParser(lastArg)) {
|
|
43
|
-
valueParser = lastArg;
|
|
44
|
-
optionNames$1 = args.slice(0, -1);
|
|
45
|
-
} else if (typeof lastArg === "object" && lastArg != null) {
|
|
46
|
-
options = lastArg;
|
|
47
|
-
if (require_valueparser.isValueParser(secondLastArg)) {
|
|
48
|
-
valueParser = secondLastArg;
|
|
49
|
-
optionNames$1 = args.slice(0, -2);
|
|
50
|
-
} else {
|
|
51
|
-
valueParser = void 0;
|
|
52
|
-
optionNames$1 = args.slice(0, -1);
|
|
53
|
-
}
|
|
54
|
-
} else {
|
|
55
|
-
optionNames$1 = args;
|
|
56
|
-
valueParser = void 0;
|
|
57
|
-
}
|
|
58
|
-
return {
|
|
59
|
-
$valueType: [],
|
|
60
|
-
$stateType: [],
|
|
61
|
-
priority: 10,
|
|
62
|
-
usage: [valueParser == null ? {
|
|
63
|
-
type: "optional",
|
|
64
|
-
terms: [{
|
|
65
|
-
type: "option",
|
|
66
|
-
names: optionNames$1
|
|
67
|
-
}]
|
|
68
|
-
} : {
|
|
69
|
-
type: "option",
|
|
70
|
-
names: optionNames$1,
|
|
71
|
-
metavar: valueParser.metavar
|
|
72
|
-
}],
|
|
73
|
-
initialState: valueParser == null ? {
|
|
74
|
-
success: true,
|
|
75
|
-
value: false
|
|
76
|
-
} : {
|
|
77
|
-
success: false,
|
|
78
|
-
error: require_message.message`Missing option ${require_message.optionNames(optionNames$1)}.`
|
|
79
|
-
},
|
|
80
|
-
parse(context) {
|
|
81
|
-
if (context.optionsTerminated) return {
|
|
82
|
-
success: false,
|
|
83
|
-
consumed: 0,
|
|
84
|
-
error: require_message.message`No more options can be parsed.`
|
|
85
|
-
};
|
|
86
|
-
else if (context.buffer.length < 1) return {
|
|
87
|
-
success: false,
|
|
88
|
-
consumed: 0,
|
|
89
|
-
error: require_message.message`Expected an option, but got end of input.`
|
|
90
|
-
};
|
|
91
|
-
if (context.buffer[0] === "--") return {
|
|
92
|
-
success: true,
|
|
93
|
-
next: {
|
|
94
|
-
...context,
|
|
95
|
-
buffer: context.buffer.slice(1),
|
|
96
|
-
state: context.state,
|
|
97
|
-
optionsTerminated: true
|
|
98
|
-
},
|
|
99
|
-
consumed: context.buffer.slice(0, 1)
|
|
100
|
-
};
|
|
101
|
-
if (optionNames$1.includes(context.buffer[0])) {
|
|
102
|
-
if (context.state.success && (valueParser != null || context.state.value)) return {
|
|
103
|
-
success: false,
|
|
104
|
-
consumed: 1,
|
|
105
|
-
error: require_message.message`${context.buffer[0]} cannot be used multiple times.`
|
|
106
|
-
};
|
|
107
|
-
if (valueParser == null) return {
|
|
108
|
-
success: true,
|
|
109
|
-
next: {
|
|
110
|
-
...context,
|
|
111
|
-
state: {
|
|
112
|
-
success: true,
|
|
113
|
-
value: true
|
|
114
|
-
},
|
|
115
|
-
buffer: context.buffer.slice(1)
|
|
116
|
-
},
|
|
117
|
-
consumed: context.buffer.slice(0, 1)
|
|
118
|
-
};
|
|
119
|
-
if (context.buffer.length < 2) return {
|
|
120
|
-
success: false,
|
|
121
|
-
consumed: 1,
|
|
122
|
-
error: require_message.message`Option ${require_message.optionName(context.buffer[0])} requires a value, but got no value.`
|
|
123
|
-
};
|
|
124
|
-
const result = valueParser.parse(context.buffer[1]);
|
|
125
|
-
return {
|
|
126
|
-
success: true,
|
|
127
|
-
next: {
|
|
128
|
-
...context,
|
|
129
|
-
state: result,
|
|
130
|
-
buffer: context.buffer.slice(2)
|
|
131
|
-
},
|
|
132
|
-
consumed: context.buffer.slice(0, 2)
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/")).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
|
|
136
|
-
for (const prefix of prefixes) {
|
|
137
|
-
if (!context.buffer[0].startsWith(prefix)) continue;
|
|
138
|
-
if (context.state.success && (valueParser != null || context.state.value)) return {
|
|
139
|
-
success: false,
|
|
140
|
-
consumed: 1,
|
|
141
|
-
error: require_message.message`${require_message.optionName(prefix)} cannot be used multiple times.`
|
|
142
|
-
};
|
|
143
|
-
const value = context.buffer[0].slice(prefix.length);
|
|
144
|
-
if (valueParser == null) return {
|
|
145
|
-
success: false,
|
|
146
|
-
consumed: 1,
|
|
147
|
-
error: require_message.message`Option ${require_message.optionName(prefix)} is a Boolean flag, but got a value: ${value}.`
|
|
148
|
-
};
|
|
149
|
-
const result = valueParser.parse(value);
|
|
150
|
-
return {
|
|
151
|
-
success: true,
|
|
152
|
-
next: {
|
|
153
|
-
...context,
|
|
154
|
-
state: result,
|
|
155
|
-
buffer: context.buffer.slice(1)
|
|
156
|
-
},
|
|
157
|
-
consumed: context.buffer.slice(0, 1)
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
if (valueParser == null) {
|
|
161
|
-
const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
|
|
162
|
-
for (const shortOption of shortOptions) {
|
|
163
|
-
if (!context.buffer[0].startsWith(shortOption)) continue;
|
|
164
|
-
if (context.state.success && (valueParser != null || context.state.value)) return {
|
|
165
|
-
success: false,
|
|
166
|
-
consumed: 1,
|
|
167
|
-
error: require_message.message`${require_message.optionName(shortOption)} cannot be used multiple times.`
|
|
168
|
-
};
|
|
169
|
-
return {
|
|
170
|
-
success: true,
|
|
171
|
-
next: {
|
|
172
|
-
...context,
|
|
173
|
-
state: {
|
|
174
|
-
success: true,
|
|
175
|
-
value: true
|
|
176
|
-
},
|
|
177
|
-
buffer: [`-${context.buffer[0].slice(2)}`, ...context.buffer.slice(1)]
|
|
178
|
-
},
|
|
179
|
-
consumed: [context.buffer[0].slice(0, 2)]
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
success: false,
|
|
185
|
-
consumed: 0,
|
|
186
|
-
error: require_message.message`No matched option for ${require_message.optionName(context.buffer[0])}.`
|
|
187
|
-
};
|
|
188
|
-
},
|
|
189
|
-
complete(state) {
|
|
190
|
-
if (state == null) return valueParser == null ? {
|
|
191
|
-
success: true,
|
|
192
|
-
value: false
|
|
193
|
-
} : {
|
|
194
|
-
success: false,
|
|
195
|
-
error: require_message.message`Missing option ${require_message.optionNames(optionNames$1)}.`
|
|
196
|
-
};
|
|
197
|
-
if (state.success) return state;
|
|
198
|
-
return {
|
|
199
|
-
success: false,
|
|
200
|
-
error: require_message.message`${require_message.optionNames(optionNames$1)}: ${state.error}`
|
|
201
|
-
};
|
|
202
|
-
},
|
|
203
|
-
getDocFragments(_state, defaultValue) {
|
|
204
|
-
const fragments = [{
|
|
205
|
-
type: "entry",
|
|
206
|
-
term: {
|
|
207
|
-
type: "option",
|
|
208
|
-
names: optionNames$1,
|
|
209
|
-
metavar: valueParser?.metavar
|
|
210
|
-
},
|
|
211
|
-
description: options.description,
|
|
212
|
-
default: defaultValue != null && valueParser != null ? require_message.message`${valueParser.format(defaultValue)}` : void 0
|
|
213
|
-
}];
|
|
214
|
-
return {
|
|
215
|
-
fragments,
|
|
216
|
-
description: options.description
|
|
217
|
-
};
|
|
218
|
-
},
|
|
219
|
-
[Symbol.for("Deno.customInspect")]() {
|
|
220
|
-
return `option(${optionNames$1.map((o) => JSON.stringify(o)).join(", ")})`;
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Creates a parser for command-line flags that must be explicitly provided.
|
|
226
|
-
* Unlike {@link option}, this parser fails if the flag is not present, making
|
|
227
|
-
* it suitable for required boolean flags that don't have a meaningful default.
|
|
228
|
-
*
|
|
229
|
-
* The key difference from {@link option} is:
|
|
230
|
-
* - {@link option} without a value parser: Returns `false` when not present
|
|
231
|
-
* - {@link flag}: Fails parsing when not present, only produces `true`
|
|
232
|
-
*
|
|
233
|
-
* This is useful for dependent options where the presence of a flag changes
|
|
234
|
-
* the shape of the result type.
|
|
235
|
-
*
|
|
236
|
-
* @param args The {@link OptionName}s to parse, followed by an optional
|
|
237
|
-
* {@link FlagOptions} object that allows you to specify
|
|
238
|
-
* a description or other metadata.
|
|
239
|
-
* @returns A {@link Parser} that produces `true` when the flag is present
|
|
240
|
-
* and fails when it is not present.
|
|
241
|
-
*
|
|
242
|
-
* @example
|
|
243
|
-
* ```typescript
|
|
244
|
-
* // Basic flag usage
|
|
245
|
-
* const parser = flag("-f", "--force");
|
|
246
|
-
* // Succeeds with true: parse(parser, ["-f"])
|
|
247
|
-
* // Fails: parse(parser, [])
|
|
248
|
-
*
|
|
249
|
-
* // With description
|
|
250
|
-
* const verboseFlag = flag("-v", "--verbose", {
|
|
251
|
-
* description: "Enable verbose output"
|
|
252
|
-
* });
|
|
253
|
-
* ```
|
|
254
|
-
*/
|
|
255
|
-
function flag(...args) {
|
|
256
|
-
const lastArg = args.at(-1);
|
|
257
|
-
let optionNames$1;
|
|
258
|
-
let options = {};
|
|
259
|
-
if (typeof lastArg === "object" && lastArg != null && !Array.isArray(lastArg)) {
|
|
260
|
-
options = lastArg;
|
|
261
|
-
optionNames$1 = args.slice(0, -1);
|
|
262
|
-
} else optionNames$1 = args;
|
|
263
|
-
return {
|
|
264
|
-
$valueType: [],
|
|
265
|
-
$stateType: [],
|
|
266
|
-
priority: 10,
|
|
267
|
-
usage: [{
|
|
268
|
-
type: "option",
|
|
269
|
-
names: optionNames$1
|
|
270
|
-
}],
|
|
271
|
-
initialState: void 0,
|
|
272
|
-
parse(context) {
|
|
273
|
-
if (context.optionsTerminated) return {
|
|
274
|
-
success: false,
|
|
275
|
-
consumed: 0,
|
|
276
|
-
error: require_message.message`No more options can be parsed.`
|
|
277
|
-
};
|
|
278
|
-
else if (context.buffer.length < 1) return {
|
|
279
|
-
success: false,
|
|
280
|
-
consumed: 0,
|
|
281
|
-
error: require_message.message`Expected an option, but got end of input.`
|
|
282
|
-
};
|
|
283
|
-
if (context.buffer[0] === "--") return {
|
|
284
|
-
success: true,
|
|
285
|
-
next: {
|
|
286
|
-
...context,
|
|
287
|
-
buffer: context.buffer.slice(1),
|
|
288
|
-
state: context.state,
|
|
289
|
-
optionsTerminated: true
|
|
290
|
-
},
|
|
291
|
-
consumed: context.buffer.slice(0, 1)
|
|
292
|
-
};
|
|
293
|
-
if (optionNames$1.includes(context.buffer[0])) {
|
|
294
|
-
if (context.state?.success) return {
|
|
295
|
-
success: false,
|
|
296
|
-
consumed: 1,
|
|
297
|
-
error: require_message.message`${require_message.optionName(context.buffer[0])} cannot be used multiple times.`
|
|
298
|
-
};
|
|
299
|
-
return {
|
|
300
|
-
success: true,
|
|
301
|
-
next: {
|
|
302
|
-
...context,
|
|
303
|
-
state: {
|
|
304
|
-
success: true,
|
|
305
|
-
value: true
|
|
306
|
-
},
|
|
307
|
-
buffer: context.buffer.slice(1)
|
|
308
|
-
},
|
|
309
|
-
consumed: context.buffer.slice(0, 1)
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/")).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
|
|
313
|
-
for (const prefix of prefixes) if (context.buffer[0].startsWith(prefix)) {
|
|
314
|
-
const value = context.buffer[0].slice(prefix.length);
|
|
315
|
-
return {
|
|
316
|
-
success: false,
|
|
317
|
-
consumed: 1,
|
|
318
|
-
error: require_message.message`Flag ${require_message.optionName(prefix.slice(0, -1))} does not accept a value, but got: ${value}.`
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
|
|
322
|
-
for (const shortOption of shortOptions) {
|
|
323
|
-
if (!context.buffer[0].startsWith(shortOption)) continue;
|
|
324
|
-
if (context.state?.success) return {
|
|
325
|
-
success: false,
|
|
326
|
-
consumed: 1,
|
|
327
|
-
error: require_message.message`${require_message.optionName(shortOption)} cannot be used multiple times.`
|
|
328
|
-
};
|
|
329
|
-
return {
|
|
330
|
-
success: true,
|
|
331
|
-
next: {
|
|
332
|
-
...context,
|
|
333
|
-
state: {
|
|
334
|
-
success: true,
|
|
335
|
-
value: true
|
|
336
|
-
},
|
|
337
|
-
buffer: [`-${context.buffer[0].slice(2)}`, ...context.buffer.slice(1)]
|
|
338
|
-
},
|
|
339
|
-
consumed: [context.buffer[0].slice(0, 2)]
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
return {
|
|
343
|
-
success: false,
|
|
344
|
-
consumed: 0,
|
|
345
|
-
error: require_message.message`No matched option for ${require_message.optionName(context.buffer[0])}.`
|
|
346
|
-
};
|
|
347
|
-
},
|
|
348
|
-
complete(state) {
|
|
349
|
-
if (state == null) return {
|
|
350
|
-
success: false,
|
|
351
|
-
error: require_message.message`Required flag ${require_message.optionNames(optionNames$1)} is missing.`
|
|
352
|
-
};
|
|
353
|
-
if (state.success) return {
|
|
354
|
-
success: true,
|
|
355
|
-
value: true
|
|
356
|
-
};
|
|
357
|
-
return {
|
|
358
|
-
success: false,
|
|
359
|
-
error: require_message.message`${require_message.optionNames(optionNames$1)}: ${state.error}`
|
|
360
|
-
};
|
|
361
|
-
},
|
|
362
|
-
getDocFragments(_state, _defaultValue) {
|
|
363
|
-
const fragments = [{
|
|
364
|
-
type: "entry",
|
|
365
|
-
term: {
|
|
366
|
-
type: "option",
|
|
367
|
-
names: optionNames$1
|
|
368
|
-
},
|
|
369
|
-
description: options.description
|
|
370
|
-
}];
|
|
371
|
-
return {
|
|
372
|
-
fragments,
|
|
373
|
-
description: options.description
|
|
374
|
-
};
|
|
375
|
-
},
|
|
376
|
-
[Symbol.for("Deno.customInspect")]() {
|
|
377
|
-
return `flag(${optionNames$1.map((o) => JSON.stringify(o)).join(", ")})`;
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
/**
|
|
382
|
-
* Creates a parser that expects a single argument value.
|
|
383
|
-
* This parser is typically used for positional arguments
|
|
384
|
-
* that are not options or flags.
|
|
385
|
-
* @template T The type of the value produced by the parser.
|
|
386
|
-
* @param valueParser The {@link ValueParser} that defines how to parse
|
|
387
|
-
* the argument value.
|
|
388
|
-
* @param options Optional configuration for the argument parser,
|
|
389
|
-
* allowing you to specify a description or other metadata.
|
|
390
|
-
* @returns A {@link Parser} that expects a single argument value and produces
|
|
391
|
-
* the parsed value of type {@link T}.
|
|
392
|
-
*/
|
|
393
|
-
function argument(valueParser, options = {}) {
|
|
394
|
-
const optionPattern = /^--?[a-z0-9-]+$/i;
|
|
395
|
-
const term = {
|
|
396
|
-
type: "argument",
|
|
397
|
-
metavar: valueParser.metavar
|
|
398
|
-
};
|
|
399
|
-
return {
|
|
400
|
-
$valueType: [],
|
|
401
|
-
$stateType: [],
|
|
402
|
-
priority: 5,
|
|
403
|
-
usage: [term],
|
|
404
|
-
initialState: void 0,
|
|
405
|
-
parse(context) {
|
|
406
|
-
if (context.buffer.length < 1) return {
|
|
407
|
-
success: false,
|
|
408
|
-
consumed: 0,
|
|
409
|
-
error: require_message.message`Expected an argument, but got end of input.`
|
|
410
|
-
};
|
|
411
|
-
let i = 0;
|
|
412
|
-
let optionsTerminated = context.optionsTerminated;
|
|
413
|
-
if (!optionsTerminated) {
|
|
414
|
-
if (context.buffer[i] === "--") {
|
|
415
|
-
optionsTerminated = true;
|
|
416
|
-
i++;
|
|
417
|
-
} else if (context.buffer[i].match(optionPattern)) return {
|
|
418
|
-
success: false,
|
|
419
|
-
consumed: i,
|
|
420
|
-
error: require_message.message`Expected an argument, but got an option: ${require_message.optionName(context.buffer[i])}.`
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
if (context.buffer.length < i + 1) return {
|
|
424
|
-
success: false,
|
|
425
|
-
consumed: i,
|
|
426
|
-
error: require_message.message`Expected an argument, but got end of input.`
|
|
427
|
-
};
|
|
428
|
-
if (context.state != null) return {
|
|
429
|
-
success: false,
|
|
430
|
-
consumed: i,
|
|
431
|
-
error: require_message.message`The argument ${require_message.metavar(valueParser.metavar)} cannot be used multiple times.`
|
|
432
|
-
};
|
|
433
|
-
const result = valueParser.parse(context.buffer[i]);
|
|
434
|
-
return {
|
|
435
|
-
success: true,
|
|
436
|
-
next: {
|
|
437
|
-
...context,
|
|
438
|
-
buffer: context.buffer.slice(i + 1),
|
|
439
|
-
state: result,
|
|
440
|
-
optionsTerminated
|
|
441
|
-
},
|
|
442
|
-
consumed: context.buffer.slice(0, i + 1)
|
|
443
|
-
};
|
|
444
|
-
},
|
|
445
|
-
complete(state) {
|
|
446
|
-
if (state == null) return {
|
|
447
|
-
success: false,
|
|
448
|
-
error: require_message.message`Expected a ${require_message.metavar(valueParser.metavar)}, but too few arguments.`
|
|
449
|
-
};
|
|
450
|
-
else if (state.success) return state;
|
|
451
|
-
return {
|
|
452
|
-
success: false,
|
|
453
|
-
error: require_message.message`${require_message.metavar(valueParser.metavar)}: ${state.error}`
|
|
454
|
-
};
|
|
455
|
-
},
|
|
456
|
-
getDocFragments(_state, defaultValue) {
|
|
457
|
-
const fragments = [{
|
|
458
|
-
type: "entry",
|
|
459
|
-
term,
|
|
460
|
-
description: options.description,
|
|
461
|
-
default: defaultValue == null ? void 0 : require_message.message`${valueParser.format(defaultValue)}`
|
|
462
|
-
}];
|
|
463
|
-
return {
|
|
464
|
-
fragments,
|
|
465
|
-
description: options.description
|
|
466
|
-
};
|
|
467
|
-
},
|
|
468
|
-
[Symbol.for("Deno.customInspect")]() {
|
|
469
|
-
return `argument()`;
|
|
470
|
-
}
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
/**
|
|
474
|
-
* Creates a parser that makes another parser optional, allowing it to succeed
|
|
475
|
-
* without consuming input if the wrapped parser fails to match.
|
|
476
|
-
* If the wrapped parser succeeds, this returns its value.
|
|
477
|
-
* If the wrapped parser fails, this returns `undefined` without consuming input.
|
|
478
|
-
* @template TValue The type of the value returned by the wrapped parser.
|
|
479
|
-
* @template TState The type of the state used by the wrapped parser.
|
|
480
|
-
* @param parser The {@link Parser} to make optional.
|
|
481
|
-
* @returns A {@link Parser} that produces either the result of the wrapped parser
|
|
482
|
-
* or `undefined` if the wrapped parser fails to match.
|
|
483
|
-
*/
|
|
484
|
-
function optional(parser) {
|
|
485
|
-
return {
|
|
486
|
-
$valueType: [],
|
|
487
|
-
$stateType: [],
|
|
488
|
-
priority: parser.priority,
|
|
489
|
-
usage: [{
|
|
490
|
-
type: "optional",
|
|
491
|
-
terms: parser.usage
|
|
492
|
-
}],
|
|
493
|
-
initialState: void 0,
|
|
494
|
-
parse(context) {
|
|
495
|
-
const result = parser.parse({
|
|
496
|
-
...context,
|
|
497
|
-
state: typeof context.state === "undefined" ? parser.initialState : context.state[0]
|
|
498
|
-
});
|
|
499
|
-
if (result.success) return {
|
|
500
|
-
success: true,
|
|
501
|
-
next: {
|
|
502
|
-
...result.next,
|
|
503
|
-
state: [result.next.state]
|
|
504
|
-
},
|
|
505
|
-
consumed: result.consumed
|
|
506
|
-
};
|
|
507
|
-
return result;
|
|
508
|
-
},
|
|
509
|
-
complete(state) {
|
|
510
|
-
if (typeof state === "undefined") return {
|
|
511
|
-
success: true,
|
|
512
|
-
value: void 0
|
|
513
|
-
};
|
|
514
|
-
return parser.complete(state[0]);
|
|
515
|
-
},
|
|
516
|
-
getDocFragments(state, defaultValue) {
|
|
517
|
-
const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state === void 0 ? { kind: "unavailable" } : {
|
|
518
|
-
kind: "available",
|
|
519
|
-
state: state.state[0]
|
|
520
|
-
};
|
|
521
|
-
return parser.getDocFragments(innerState, defaultValue);
|
|
522
|
-
}
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* Error type for structured error messages in {@link withDefault} default value callbacks.
|
|
527
|
-
* Unlike regular errors that only support string messages, this error type accepts
|
|
528
|
-
* a {@link Message} object that supports rich formatting, colors, and structured content.
|
|
529
|
-
*
|
|
530
|
-
* @example
|
|
531
|
-
* ```typescript
|
|
532
|
-
* withDefault(option("--url", url()), () => {
|
|
533
|
-
* if (!process.env.INSTANCE_URL) {
|
|
534
|
-
* throw new WithDefaultError(
|
|
535
|
-
* message`Environment variable ${envVar("INSTANCE_URL")} is not set.`
|
|
536
|
-
* );
|
|
537
|
-
* }
|
|
538
|
-
* return new URL(process.env.INSTANCE_URL);
|
|
539
|
-
* })
|
|
540
|
-
* ```
|
|
541
|
-
*
|
|
542
|
-
* @since 0.5.0
|
|
543
|
-
*/
|
|
544
|
-
var WithDefaultError = class extends Error {
|
|
545
|
-
/**
|
|
546
|
-
* The structured message associated with this error.
|
|
547
|
-
*/
|
|
548
|
-
errorMessage;
|
|
549
|
-
/**
|
|
550
|
-
* Creates a new WithDefaultError with a structured message.
|
|
551
|
-
* @param message The structured {@link Message} describing the error.
|
|
552
|
-
*/
|
|
553
|
-
constructor(message$1) {
|
|
554
|
-
super(require_message.formatMessage(message$1));
|
|
555
|
-
this.errorMessage = message$1;
|
|
556
|
-
this.name = "WithDefaultError";
|
|
557
|
-
}
|
|
558
|
-
};
|
|
559
|
-
function withDefault(parser, defaultValue, options) {
|
|
560
|
-
return {
|
|
561
|
-
$valueType: [],
|
|
562
|
-
$stateType: [],
|
|
563
|
-
priority: parser.priority,
|
|
564
|
-
usage: [{
|
|
565
|
-
type: "optional",
|
|
566
|
-
terms: parser.usage
|
|
567
|
-
}],
|
|
568
|
-
initialState: void 0,
|
|
569
|
-
parse(context) {
|
|
570
|
-
const result = parser.parse({
|
|
571
|
-
...context,
|
|
572
|
-
state: typeof context.state === "undefined" ? parser.initialState : context.state[0]
|
|
573
|
-
});
|
|
574
|
-
if (result.success) return {
|
|
575
|
-
success: true,
|
|
576
|
-
next: {
|
|
577
|
-
...result.next,
|
|
578
|
-
state: [result.next.state]
|
|
579
|
-
},
|
|
580
|
-
consumed: result.consumed
|
|
581
|
-
};
|
|
582
|
-
return result;
|
|
583
|
-
},
|
|
584
|
-
complete(state) {
|
|
585
|
-
if (typeof state === "undefined") try {
|
|
586
|
-
const value = typeof defaultValue === "function" ? defaultValue() : defaultValue;
|
|
587
|
-
return {
|
|
588
|
-
success: true,
|
|
589
|
-
value
|
|
590
|
-
};
|
|
591
|
-
} catch (error) {
|
|
592
|
-
return {
|
|
593
|
-
success: false,
|
|
594
|
-
error: error instanceof WithDefaultError ? error.errorMessage : require_message.message`${require_message.text(String(error))}`
|
|
595
|
-
};
|
|
596
|
-
}
|
|
597
|
-
return parser.complete(state[0]);
|
|
598
|
-
},
|
|
599
|
-
getDocFragments(state, upperDefaultValue) {
|
|
600
|
-
const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state === void 0 ? { kind: "unavailable" } : {
|
|
601
|
-
kind: "available",
|
|
602
|
-
state: state.state[0]
|
|
603
|
-
};
|
|
604
|
-
const actualDefaultValue = upperDefaultValue != null ? upperDefaultValue : typeof defaultValue === "function" ? defaultValue() : defaultValue;
|
|
605
|
-
const fragments = parser.getDocFragments(innerState, actualDefaultValue);
|
|
606
|
-
if (options?.message) {
|
|
607
|
-
const modifiedFragments = fragments.fragments.map((fragment) => {
|
|
608
|
-
if (fragment.type === "entry") return {
|
|
609
|
-
...fragment,
|
|
610
|
-
default: options.message
|
|
611
|
-
};
|
|
612
|
-
return fragment;
|
|
613
|
-
});
|
|
614
|
-
return {
|
|
615
|
-
...fragments,
|
|
616
|
-
fragments: modifiedFragments
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
return fragments;
|
|
620
|
-
}
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
/**
|
|
624
|
-
* Creates a parser that transforms the result value of another parser using
|
|
625
|
-
* a mapping function. This enables value transformation while preserving
|
|
626
|
-
* the original parser's parsing logic and state management.
|
|
627
|
-
*
|
|
628
|
-
* The `map()` function is useful for:
|
|
629
|
-
* - Converting parsed values to different types
|
|
630
|
-
* - Applying transformations like string formatting or boolean inversion
|
|
631
|
-
* - Computing derived values from parsed input
|
|
632
|
-
* - Creating reusable transformations that can be applied to any parser
|
|
633
|
-
*
|
|
634
|
-
* @template T The type of the value produced by the original parser.
|
|
635
|
-
* @template U The type of the value produced by the mapping function.
|
|
636
|
-
* @template TState The type of the state used by the original parser.
|
|
637
|
-
* @param parser The {@link Parser} whose result will be transformed.
|
|
638
|
-
* @param transform A function that transforms the parsed value from type T to type U.
|
|
639
|
-
* @returns A {@link Parser} that produces the transformed value of type U
|
|
640
|
-
* while preserving the original parser's state type and parsing behavior.
|
|
641
|
-
*
|
|
642
|
-
* @example
|
|
643
|
-
* ```typescript
|
|
644
|
-
* // Transform boolean flag to its inverse
|
|
645
|
-
* const parser = object({
|
|
646
|
-
* disallow: map(option("--allow"), b => !b)
|
|
647
|
-
* });
|
|
648
|
-
*
|
|
649
|
-
* // Transform string to uppercase
|
|
650
|
-
* const upperParser = map(argument(string()), s => s.toUpperCase());
|
|
651
|
-
*
|
|
652
|
-
* // Transform number to formatted string
|
|
653
|
-
* const prefixedParser = map(option("-n", integer()), n => `value: ${n}`);
|
|
654
|
-
* ```
|
|
655
|
-
*/
|
|
656
|
-
function map(parser, transform) {
|
|
657
|
-
return {
|
|
658
|
-
$valueType: [],
|
|
659
|
-
$stateType: parser.$stateType,
|
|
660
|
-
priority: parser.priority,
|
|
661
|
-
usage: parser.usage,
|
|
662
|
-
initialState: parser.initialState,
|
|
663
|
-
parse: parser.parse.bind(parser),
|
|
664
|
-
complete(state) {
|
|
665
|
-
const result = parser.complete(state);
|
|
666
|
-
if (result.success) return {
|
|
667
|
-
success: true,
|
|
668
|
-
value: transform(result.value)
|
|
669
|
-
};
|
|
670
|
-
return result;
|
|
671
|
-
},
|
|
672
|
-
getDocFragments(state, _defaultValue) {
|
|
673
|
-
return parser.getDocFragments(state, void 0);
|
|
674
|
-
}
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
/**
|
|
678
|
-
* Creates a parser that allows multiple occurrences of a given parser.
|
|
679
|
-
* This parser can be used to parse multiple values of the same type,
|
|
680
|
-
* such as multiple command-line arguments or options.
|
|
681
|
-
* @template TValue The type of the value that the parser produces.
|
|
682
|
-
* @template TState The type of the state used by the parser.
|
|
683
|
-
* @param parser The {@link Parser} to apply multiple times.
|
|
684
|
-
* @param options Optional configuration for the parser,
|
|
685
|
-
* allowing you to specify the minimum and maximum number of
|
|
686
|
-
* occurrences allowed.
|
|
687
|
-
* @returns A {@link Parser} that produces an array of values
|
|
688
|
-
* of type {@link TValue} and an array of states
|
|
689
|
-
* of type {@link TState}.
|
|
690
|
-
*/
|
|
691
|
-
function multiple(parser, options = {}) {
|
|
692
|
-
const { min = 0, max = Infinity } = options;
|
|
693
|
-
return {
|
|
694
|
-
$valueType: [],
|
|
695
|
-
$stateType: [],
|
|
696
|
-
priority: parser.priority,
|
|
697
|
-
usage: [{
|
|
698
|
-
type: "multiple",
|
|
699
|
-
terms: parser.usage,
|
|
700
|
-
min
|
|
701
|
-
}],
|
|
702
|
-
initialState: [],
|
|
703
|
-
parse(context) {
|
|
704
|
-
let added = context.state.length < 1;
|
|
705
|
-
let result = parser.parse({
|
|
706
|
-
...context,
|
|
707
|
-
state: context.state.at(-1) ?? parser.initialState
|
|
708
|
-
});
|
|
709
|
-
if (!result.success) if (!added) {
|
|
710
|
-
result = parser.parse({
|
|
711
|
-
...context,
|
|
712
|
-
state: parser.initialState
|
|
713
|
-
});
|
|
714
|
-
if (!result.success) return result;
|
|
715
|
-
added = true;
|
|
716
|
-
} else return result;
|
|
717
|
-
return {
|
|
718
|
-
success: true,
|
|
719
|
-
next: {
|
|
720
|
-
...result.next,
|
|
721
|
-
state: [...added ? context.state : context.state.slice(0, -1), result.next.state]
|
|
722
|
-
},
|
|
723
|
-
consumed: result.consumed
|
|
724
|
-
};
|
|
725
|
-
},
|
|
726
|
-
complete(state) {
|
|
727
|
-
const result = [];
|
|
728
|
-
for (const s of state) {
|
|
729
|
-
const valueResult = parser.complete(s);
|
|
730
|
-
if (valueResult.success) result.push(valueResult.value);
|
|
731
|
-
else return {
|
|
732
|
-
success: false,
|
|
733
|
-
error: valueResult.error
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
if (result.length < min) return {
|
|
737
|
-
success: false,
|
|
738
|
-
error: require_message.message`Expected at least ${require_message.text(min.toLocaleString("en"))} values, but got only ${require_message.text(result.length.toLocaleString("en"))}.`
|
|
739
|
-
};
|
|
740
|
-
else if (result.length > max) return {
|
|
741
|
-
success: false,
|
|
742
|
-
error: require_message.message`Expected at most ${require_message.text(max.toLocaleString("en"))} values, but got ${require_message.text(result.length.toLocaleString("en"))}.`
|
|
743
|
-
};
|
|
744
|
-
return {
|
|
745
|
-
success: true,
|
|
746
|
-
value: result
|
|
747
|
-
};
|
|
748
|
-
},
|
|
749
|
-
getDocFragments(state, defaultValue) {
|
|
750
|
-
const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state.length > 0 ? {
|
|
751
|
-
kind: "available",
|
|
752
|
-
state: state.state.at(-1)
|
|
753
|
-
} : { kind: "unavailable" };
|
|
754
|
-
return parser.getDocFragments(innerState, defaultValue != null && defaultValue.length > 0 ? defaultValue[0] : void 0);
|
|
755
|
-
}
|
|
756
|
-
};
|
|
757
|
-
}
|
|
758
|
-
function object(labelOrParsers, maybeParsers) {
|
|
759
|
-
const label = typeof labelOrParsers === "string" ? labelOrParsers : void 0;
|
|
760
|
-
const parsers = typeof labelOrParsers === "string" ? maybeParsers : labelOrParsers;
|
|
761
|
-
const parserPairs = Object.entries(parsers);
|
|
762
|
-
parserPairs.sort(([_, parserA], [__, parserB]) => parserB.priority - parserA.priority);
|
|
763
|
-
return {
|
|
764
|
-
$valueType: [],
|
|
765
|
-
$stateType: [],
|
|
766
|
-
priority: Math.max(...Object.values(parsers).map((p) => p.priority)),
|
|
767
|
-
usage: parserPairs.flatMap(([_, p]) => p.usage),
|
|
768
|
-
initialState: Object.fromEntries(Object.entries(parsers).map(([key, parser]) => [key, parser.initialState])),
|
|
769
|
-
parse(context) {
|
|
770
|
-
let error = {
|
|
771
|
-
consumed: 0,
|
|
772
|
-
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.`
|
|
773
|
-
};
|
|
774
|
-
let currentContext = context;
|
|
775
|
-
let anySuccess = false;
|
|
776
|
-
const allConsumed = [];
|
|
777
|
-
let madeProgress = true;
|
|
778
|
-
while (madeProgress && currentContext.buffer.length > 0) {
|
|
779
|
-
madeProgress = false;
|
|
780
|
-
for (const [field, parser] of parserPairs) {
|
|
781
|
-
const result = parser.parse({
|
|
782
|
-
...currentContext,
|
|
783
|
-
state: currentContext.state && typeof currentContext.state === "object" && field in currentContext.state ? currentContext.state[field] : parser.initialState
|
|
784
|
-
});
|
|
785
|
-
if (result.success && result.consumed.length > 0) {
|
|
786
|
-
currentContext = {
|
|
787
|
-
...currentContext,
|
|
788
|
-
buffer: result.next.buffer,
|
|
789
|
-
optionsTerminated: result.next.optionsTerminated,
|
|
790
|
-
state: {
|
|
791
|
-
...currentContext.state,
|
|
792
|
-
[field]: result.next.state
|
|
793
|
-
}
|
|
794
|
-
};
|
|
795
|
-
allConsumed.push(...result.consumed);
|
|
796
|
-
anySuccess = true;
|
|
797
|
-
madeProgress = true;
|
|
798
|
-
break;
|
|
799
|
-
} else if (!result.success && error.consumed < result.consumed) error = result;
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
if (anySuccess) return {
|
|
803
|
-
success: true,
|
|
804
|
-
next: currentContext,
|
|
805
|
-
consumed: allConsumed
|
|
806
|
-
};
|
|
807
|
-
if (context.buffer.length === 0) {
|
|
808
|
-
let allCanComplete = true;
|
|
809
|
-
for (const [field, parser] of parserPairs) {
|
|
810
|
-
const fieldState = context.state && typeof context.state === "object" && field in context.state ? context.state[field] : parser.initialState;
|
|
811
|
-
const completeResult = parser.complete(fieldState);
|
|
812
|
-
if (!completeResult.success) {
|
|
813
|
-
allCanComplete = false;
|
|
814
|
-
break;
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
if (allCanComplete) return {
|
|
818
|
-
success: true,
|
|
819
|
-
next: context,
|
|
820
|
-
consumed: []
|
|
821
|
-
};
|
|
822
|
-
}
|
|
823
|
-
return {
|
|
824
|
-
...error,
|
|
825
|
-
success: false
|
|
826
|
-
};
|
|
827
|
-
},
|
|
828
|
-
complete(state) {
|
|
829
|
-
const result = {};
|
|
830
|
-
for (const field in state) {
|
|
831
|
-
if (!(field in parsers)) continue;
|
|
832
|
-
const valueResult = parsers[field].complete(state[field]);
|
|
833
|
-
if (valueResult.success) result[field] = valueResult.value;
|
|
834
|
-
else return {
|
|
835
|
-
success: false,
|
|
836
|
-
error: valueResult.error
|
|
837
|
-
};
|
|
838
|
-
}
|
|
839
|
-
return {
|
|
840
|
-
success: true,
|
|
841
|
-
value: result
|
|
842
|
-
};
|
|
843
|
-
},
|
|
844
|
-
getDocFragments(state, defaultValue) {
|
|
845
|
-
const fragments = parserPairs.flatMap(([field, p]) => {
|
|
846
|
-
const fieldState = state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
847
|
-
kind: "available",
|
|
848
|
-
state: state.state[field]
|
|
849
|
-
};
|
|
850
|
-
return p.getDocFragments(fieldState, defaultValue?.[field]).fragments;
|
|
851
|
-
});
|
|
852
|
-
const entries = fragments.filter((d) => d.type === "entry");
|
|
853
|
-
const sections = [];
|
|
854
|
-
for (const fragment of fragments) {
|
|
855
|
-
if (fragment.type !== "section") continue;
|
|
856
|
-
if (fragment.title == null) entries.push(...fragment.entries);
|
|
857
|
-
else sections.push(fragment);
|
|
858
|
-
}
|
|
859
|
-
const section = {
|
|
860
|
-
title: label,
|
|
861
|
-
entries
|
|
862
|
-
};
|
|
863
|
-
sections.push(section);
|
|
864
|
-
return { fragments: sections.map((s) => ({
|
|
865
|
-
...s,
|
|
866
|
-
type: "section"
|
|
867
|
-
})) };
|
|
868
|
-
}
|
|
869
|
-
};
|
|
870
|
-
}
|
|
871
|
-
function tuple(labelOrParsers, maybeParsers) {
|
|
872
|
-
const label = typeof labelOrParsers === "string" ? labelOrParsers : void 0;
|
|
873
|
-
const parsers = typeof labelOrParsers === "string" ? maybeParsers : labelOrParsers;
|
|
874
|
-
return {
|
|
875
|
-
$valueType: [],
|
|
876
|
-
$stateType: [],
|
|
877
|
-
usage: parsers.toSorted((a, b) => b.priority - a.priority).flatMap((p) => p.usage),
|
|
878
|
-
priority: parsers.length > 0 ? Math.max(...parsers.map((p) => p.priority)) : 0,
|
|
879
|
-
initialState: parsers.map((parser) => parser.initialState),
|
|
880
|
-
parse(context) {
|
|
881
|
-
let currentContext = context;
|
|
882
|
-
const allConsumed = [];
|
|
883
|
-
const matchedParsers = /* @__PURE__ */ new Set();
|
|
884
|
-
while (matchedParsers.size < parsers.length) {
|
|
885
|
-
let foundMatch = false;
|
|
886
|
-
let error = {
|
|
887
|
-
consumed: 0,
|
|
888
|
-
error: require_message.message`No remaining parsers could match the input.`
|
|
889
|
-
};
|
|
890
|
-
const remainingParsers = parsers.map((parser, index) => [parser, index]).filter(([_, index]) => !matchedParsers.has(index)).sort(([parserA], [parserB]) => parserB.priority - parserA.priority);
|
|
891
|
-
for (const [parser, index] of remainingParsers) {
|
|
892
|
-
const result = parser.parse({
|
|
893
|
-
...currentContext,
|
|
894
|
-
state: currentContext.state[index]
|
|
895
|
-
});
|
|
896
|
-
if (result.success && result.consumed.length > 0) {
|
|
897
|
-
currentContext = {
|
|
898
|
-
...currentContext,
|
|
899
|
-
buffer: result.next.buffer,
|
|
900
|
-
optionsTerminated: result.next.optionsTerminated,
|
|
901
|
-
state: currentContext.state.map((s, idx) => idx === index ? result.next.state : s)
|
|
902
|
-
};
|
|
903
|
-
allConsumed.push(...result.consumed);
|
|
904
|
-
matchedParsers.add(index);
|
|
905
|
-
foundMatch = true;
|
|
906
|
-
break;
|
|
907
|
-
} else if (!result.success && error.consumed < result.consumed) error = result;
|
|
908
|
-
}
|
|
909
|
-
if (!foundMatch) for (const [parser, index] of remainingParsers) {
|
|
910
|
-
const result = parser.parse({
|
|
911
|
-
...currentContext,
|
|
912
|
-
state: currentContext.state[index]
|
|
913
|
-
});
|
|
914
|
-
if (result.success && result.consumed.length < 1) {
|
|
915
|
-
currentContext = {
|
|
916
|
-
...currentContext,
|
|
917
|
-
state: currentContext.state.map((s, idx) => idx === index ? result.next.state : s)
|
|
918
|
-
};
|
|
919
|
-
matchedParsers.add(index);
|
|
920
|
-
foundMatch = true;
|
|
921
|
-
break;
|
|
922
|
-
} else if (!result.success && result.consumed < 1) {
|
|
923
|
-
matchedParsers.add(index);
|
|
924
|
-
foundMatch = true;
|
|
925
|
-
break;
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
if (!foundMatch) return {
|
|
929
|
-
...error,
|
|
930
|
-
success: false
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
return {
|
|
934
|
-
success: true,
|
|
935
|
-
next: currentContext,
|
|
936
|
-
consumed: allConsumed
|
|
937
|
-
};
|
|
938
|
-
},
|
|
939
|
-
complete(state) {
|
|
940
|
-
const result = [];
|
|
941
|
-
for (let i = 0; i < parsers.length; i++) {
|
|
942
|
-
const valueResult = parsers[i].complete(state[i]);
|
|
943
|
-
if (valueResult.success) result[i] = valueResult.value;
|
|
944
|
-
else return {
|
|
945
|
-
success: false,
|
|
946
|
-
error: valueResult.error
|
|
947
|
-
};
|
|
948
|
-
}
|
|
949
|
-
return {
|
|
950
|
-
success: true,
|
|
951
|
-
value: result
|
|
952
|
-
};
|
|
953
|
-
},
|
|
954
|
-
getDocFragments(state, defaultValue) {
|
|
955
|
-
const fragments = parsers.flatMap((p, i) => {
|
|
956
|
-
const indexState = state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
957
|
-
kind: "available",
|
|
958
|
-
state: state.state[i]
|
|
959
|
-
};
|
|
960
|
-
return p.getDocFragments(indexState, defaultValue?.[i]).fragments;
|
|
961
|
-
});
|
|
962
|
-
const entries = fragments.filter((d) => d.type === "entry");
|
|
963
|
-
const sections = [];
|
|
964
|
-
for (const fragment of fragments) {
|
|
965
|
-
if (fragment.type !== "section") continue;
|
|
966
|
-
if (fragment.title == null) entries.push(...fragment.entries);
|
|
967
|
-
else sections.push(fragment);
|
|
968
|
-
}
|
|
969
|
-
const section = {
|
|
970
|
-
title: label,
|
|
971
|
-
entries
|
|
972
|
-
};
|
|
973
|
-
sections.push(section);
|
|
974
|
-
return { fragments: sections.map((s) => ({
|
|
975
|
-
...s,
|
|
976
|
-
type: "section"
|
|
977
|
-
})) };
|
|
978
|
-
},
|
|
979
|
-
[Symbol.for("Deno.customInspect")]() {
|
|
980
|
-
const parsersStr = parsers.length === 1 ? `[1 parser]` : `[${parsers.length} parsers]`;
|
|
981
|
-
return label ? `tuple(${JSON.stringify(label)}, ${parsersStr})` : `tuple(${parsersStr})`;
|
|
982
|
-
}
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
function or(...parsers) {
|
|
986
|
-
return {
|
|
987
|
-
$valueType: [],
|
|
988
|
-
$stateType: [],
|
|
989
|
-
priority: Math.max(...parsers.map((p) => p.priority)),
|
|
990
|
-
usage: [{
|
|
991
|
-
type: "exclusive",
|
|
992
|
-
terms: parsers.map((p) => p.usage)
|
|
993
|
-
}],
|
|
994
|
-
initialState: void 0,
|
|
995
|
-
complete(state) {
|
|
996
|
-
if (state == null) return {
|
|
997
|
-
success: false,
|
|
998
|
-
error: require_message.message`No parser matched.`
|
|
999
|
-
};
|
|
1000
|
-
const [i, result] = state;
|
|
1001
|
-
if (result.success) return parsers[i].complete(result.next.state);
|
|
1002
|
-
return {
|
|
1003
|
-
success: false,
|
|
1004
|
-
error: result.error
|
|
1005
|
-
};
|
|
1006
|
-
},
|
|
1007
|
-
parse(context) {
|
|
1008
|
-
let error = {
|
|
1009
|
-
consumed: 0,
|
|
1010
|
-
error: context.buffer.length < 1 ? require_message.message`No parser matched.` : require_message.message`Unexpected option or subcommand: ${require_message.optionName(context.buffer[0])}.`
|
|
1011
|
-
};
|
|
1012
|
-
const orderedParsers = parsers.map((p, i) => [p, i]);
|
|
1013
|
-
orderedParsers.sort(([_, a], [__, b]) => context.state?.[0] === a ? -1 : context.state?.[0] === b ? 1 : a - b);
|
|
1014
|
-
for (const [parser, i] of orderedParsers) {
|
|
1015
|
-
const result = parser.parse({
|
|
1016
|
-
...context,
|
|
1017
|
-
state: context.state == null || context.state[0] !== i || !context.state[1].success ? parser.initialState : context.state[1].next.state
|
|
1018
|
-
});
|
|
1019
|
-
if (result.success && result.consumed.length > 0) {
|
|
1020
|
-
if (context.state?.[0] !== i && context.state?.[1].success) return {
|
|
1021
|
-
success: false,
|
|
1022
|
-
consumed: context.buffer.length - result.next.buffer.length,
|
|
1023
|
-
error: require_message.message`${require_message.values(context.state[1].consumed)} and ${require_message.values(result.consumed)} cannot be used together.`
|
|
1024
|
-
};
|
|
1025
|
-
return {
|
|
1026
|
-
success: true,
|
|
1027
|
-
next: {
|
|
1028
|
-
...context,
|
|
1029
|
-
buffer: result.next.buffer,
|
|
1030
|
-
optionsTerminated: result.next.optionsTerminated,
|
|
1031
|
-
state: [i, result]
|
|
1032
|
-
},
|
|
1033
|
-
consumed: result.consumed
|
|
1034
|
-
};
|
|
1035
|
-
} else if (!result.success && error.consumed < result.consumed) error = result;
|
|
1036
|
-
}
|
|
1037
|
-
return {
|
|
1038
|
-
...error,
|
|
1039
|
-
success: false
|
|
1040
|
-
};
|
|
1041
|
-
},
|
|
1042
|
-
getDocFragments(state, _defaultValue) {
|
|
1043
|
-
let description;
|
|
1044
|
-
let fragments;
|
|
1045
|
-
if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }, void 0).fragments);
|
|
1046
|
-
else {
|
|
1047
|
-
const [index, parserResult] = state.state;
|
|
1048
|
-
const innerState = parserResult.success ? {
|
|
1049
|
-
kind: "available",
|
|
1050
|
-
state: parserResult.next.state
|
|
1051
|
-
} : { kind: "unavailable" };
|
|
1052
|
-
const docFragments = parsers[index].getDocFragments(innerState, void 0);
|
|
1053
|
-
description = docFragments.description;
|
|
1054
|
-
fragments = docFragments.fragments;
|
|
1055
|
-
}
|
|
1056
|
-
const entries = fragments.filter((f) => f.type === "entry");
|
|
1057
|
-
const sections = [];
|
|
1058
|
-
for (const fragment of fragments) {
|
|
1059
|
-
if (fragment.type !== "section") continue;
|
|
1060
|
-
if (fragment.title == null) entries.push(...fragment.entries);
|
|
1061
|
-
else sections.push(fragment);
|
|
1062
|
-
}
|
|
1063
|
-
return {
|
|
1064
|
-
description,
|
|
1065
|
-
fragments: [...sections.map((s) => ({
|
|
1066
|
-
...s,
|
|
1067
|
-
type: "section"
|
|
1068
|
-
})), {
|
|
1069
|
-
type: "section",
|
|
1070
|
-
entries
|
|
1071
|
-
}]
|
|
1072
|
-
};
|
|
1073
|
-
}
|
|
1074
|
-
};
|
|
1075
|
-
}
|
|
1076
|
-
function longestMatch(...parsers) {
|
|
1077
|
-
return {
|
|
1078
|
-
$valueType: [],
|
|
1079
|
-
$stateType: [],
|
|
1080
|
-
priority: Math.max(...parsers.map((p) => p.priority)),
|
|
1081
|
-
usage: [{
|
|
1082
|
-
type: "exclusive",
|
|
1083
|
-
terms: parsers.map((p) => p.usage)
|
|
1084
|
-
}],
|
|
1085
|
-
initialState: void 0,
|
|
1086
|
-
complete(state) {
|
|
1087
|
-
if (state == null) return {
|
|
1088
|
-
success: false,
|
|
1089
|
-
error: require_message.message`No parser matched.`
|
|
1090
|
-
};
|
|
1091
|
-
const [i, result] = state;
|
|
1092
|
-
if (result.success) return parsers[i].complete(result.next.state);
|
|
1093
|
-
return {
|
|
1094
|
-
success: false,
|
|
1095
|
-
error: result.error
|
|
1096
|
-
};
|
|
1097
|
-
},
|
|
1098
|
-
parse(context) {
|
|
1099
|
-
let bestMatch = null;
|
|
1100
|
-
let error = {
|
|
1101
|
-
consumed: 0,
|
|
1102
|
-
error: context.buffer.length < 1 ? require_message.message`No parser matched.` : require_message.message`Unexpected option or subcommand: ${require_message.optionName(context.buffer[0])}.`
|
|
1103
|
-
};
|
|
1104
|
-
for (let i = 0; i < parsers.length; i++) {
|
|
1105
|
-
const parser = parsers[i];
|
|
1106
|
-
const result = parser.parse({
|
|
1107
|
-
...context,
|
|
1108
|
-
state: context.state == null || context.state[0] !== i || !context.state[1].success ? parser.initialState : context.state[1].next.state
|
|
1109
|
-
});
|
|
1110
|
-
if (result.success) {
|
|
1111
|
-
const consumed = context.buffer.length - result.next.buffer.length;
|
|
1112
|
-
if (bestMatch === null || consumed > bestMatch.consumed) bestMatch = {
|
|
1113
|
-
index: i,
|
|
1114
|
-
result,
|
|
1115
|
-
consumed
|
|
1116
|
-
};
|
|
1117
|
-
} else if (error.consumed < result.consumed) error = result;
|
|
1118
|
-
}
|
|
1119
|
-
if (bestMatch && bestMatch.result.success) return {
|
|
1120
|
-
success: true,
|
|
1121
|
-
next: {
|
|
1122
|
-
...context,
|
|
1123
|
-
buffer: bestMatch.result.next.buffer,
|
|
1124
|
-
optionsTerminated: bestMatch.result.next.optionsTerminated,
|
|
1125
|
-
state: [bestMatch.index, bestMatch.result]
|
|
1126
|
-
},
|
|
1127
|
-
consumed: bestMatch.result.consumed
|
|
1128
|
-
};
|
|
1129
|
-
return {
|
|
1130
|
-
...error,
|
|
1131
|
-
success: false
|
|
1132
|
-
};
|
|
1133
|
-
},
|
|
1134
|
-
getDocFragments(state, _defaultValue) {
|
|
1135
|
-
let description;
|
|
1136
|
-
let fragments;
|
|
1137
|
-
if (state.kind === "unavailable" || state.state == null) fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
1138
|
-
else {
|
|
1139
|
-
const [i, result] = state.state;
|
|
1140
|
-
if (result.success) {
|
|
1141
|
-
const docResult = parsers[i].getDocFragments({
|
|
1142
|
-
kind: "available",
|
|
1143
|
-
state: result.next.state
|
|
1144
|
-
});
|
|
1145
|
-
description = docResult.description;
|
|
1146
|
-
fragments = docResult.fragments;
|
|
1147
|
-
} else fragments = parsers.flatMap((p) => p.getDocFragments({ kind: "unavailable" }).fragments);
|
|
1148
|
-
}
|
|
1149
|
-
return {
|
|
1150
|
-
description,
|
|
1151
|
-
fragments
|
|
1152
|
-
};
|
|
1153
|
-
}
|
|
1154
|
-
};
|
|
1155
|
-
}
|
|
1156
|
-
function merge(...args) {
|
|
1157
|
-
const label = typeof args[0] === "string" ? args[0] : void 0;
|
|
1158
|
-
let parsers = typeof args[0] === "string" ? args.slice(1) : args;
|
|
1159
|
-
parsers = parsers.toSorted((a, b) => b.priority - a.priority);
|
|
1160
|
-
const initialState = {};
|
|
1161
|
-
for (const parser of parsers) if (parser.initialState && typeof parser.initialState === "object") for (const field in parser.initialState) initialState[field] = parser.initialState[field];
|
|
1162
|
-
return {
|
|
1163
|
-
$valueType: [],
|
|
1164
|
-
$stateType: [],
|
|
1165
|
-
priority: Math.max(...parsers.map((p) => p.priority)),
|
|
1166
|
-
usage: parsers.flatMap((p) => p.usage),
|
|
1167
|
-
initialState,
|
|
1168
|
-
parse(context) {
|
|
1169
|
-
for (let i = 0; i < parsers.length; i++) {
|
|
1170
|
-
const parser = parsers[i];
|
|
1171
|
-
let parserState;
|
|
1172
|
-
if (parser.initialState === void 0) parserState = void 0;
|
|
1173
|
-
else if (parser.initialState && typeof parser.initialState === "object") if (context.state && typeof context.state === "object") {
|
|
1174
|
-
const extractedState = {};
|
|
1175
|
-
for (const field in parser.initialState) extractedState[field] = field in context.state ? context.state[field] : parser.initialState[field];
|
|
1176
|
-
parserState = extractedState;
|
|
1177
|
-
} else parserState = parser.initialState;
|
|
1178
|
-
else parserState = parser.initialState;
|
|
1179
|
-
const result = parser.parse({
|
|
1180
|
-
...context,
|
|
1181
|
-
state: parserState
|
|
1182
|
-
});
|
|
1183
|
-
if (result.success) {
|
|
1184
|
-
let newState;
|
|
1185
|
-
if (parser.initialState === void 0) newState = {
|
|
1186
|
-
...context.state,
|
|
1187
|
-
[`__parser_${i}`]: result.next.state
|
|
1188
|
-
};
|
|
1189
|
-
else newState = {
|
|
1190
|
-
...context.state,
|
|
1191
|
-
...result.next.state
|
|
1192
|
-
};
|
|
1193
|
-
return {
|
|
1194
|
-
success: true,
|
|
1195
|
-
next: {
|
|
1196
|
-
...context,
|
|
1197
|
-
buffer: result.next.buffer,
|
|
1198
|
-
optionsTerminated: result.next.optionsTerminated,
|
|
1199
|
-
state: newState
|
|
1200
|
-
},
|
|
1201
|
-
consumed: result.consumed
|
|
1202
|
-
};
|
|
1203
|
-
} else if (result.consumed < 1) continue;
|
|
1204
|
-
else return result;
|
|
1205
|
-
}
|
|
1206
|
-
return {
|
|
1207
|
-
success: false,
|
|
1208
|
-
consumed: 0,
|
|
1209
|
-
error: require_message.message`No parser matched the input.`
|
|
1210
|
-
};
|
|
1211
|
-
},
|
|
1212
|
-
complete(state) {
|
|
1213
|
-
const object$1 = {};
|
|
1214
|
-
for (let i = 0; i < parsers.length; i++) {
|
|
1215
|
-
const parser = parsers[i];
|
|
1216
|
-
let parserState;
|
|
1217
|
-
if (parser.initialState === void 0) {
|
|
1218
|
-
const key = `__parser_${i}`;
|
|
1219
|
-
if (state && typeof state === "object" && key in state) parserState = state[key];
|
|
1220
|
-
else parserState = void 0;
|
|
1221
|
-
} else if (parser.initialState && typeof parser.initialState === "object") if (state && typeof state === "object") {
|
|
1222
|
-
const extractedState = {};
|
|
1223
|
-
for (const field in parser.initialState) extractedState[field] = field in state ? state[field] : parser.initialState[field];
|
|
1224
|
-
parserState = extractedState;
|
|
1225
|
-
} else parserState = parser.initialState;
|
|
1226
|
-
else parserState = parser.initialState;
|
|
1227
|
-
const result = parser.complete(parserState);
|
|
1228
|
-
if (!result.success) return result;
|
|
1229
|
-
for (const field in result.value) object$1[field] = result.value[field];
|
|
1230
|
-
}
|
|
1231
|
-
return {
|
|
1232
|
-
success: true,
|
|
1233
|
-
value: object$1
|
|
1234
|
-
};
|
|
1235
|
-
},
|
|
1236
|
-
getDocFragments(state, _defaultValue) {
|
|
1237
|
-
const fragments = parsers.flatMap((p) => {
|
|
1238
|
-
const parserState = p.initialState === void 0 ? { kind: "unavailable" } : state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
1239
|
-
kind: "available",
|
|
1240
|
-
state: state.state
|
|
1241
|
-
};
|
|
1242
|
-
return p.getDocFragments(parserState, void 0).fragments;
|
|
1243
|
-
});
|
|
1244
|
-
const entries = fragments.filter((f) => f.type === "entry");
|
|
1245
|
-
const sections = [];
|
|
1246
|
-
for (const fragment of fragments) {
|
|
1247
|
-
if (fragment.type !== "section") continue;
|
|
1248
|
-
if (fragment.title == null) entries.push(...fragment.entries);
|
|
1249
|
-
else sections.push(fragment);
|
|
1250
|
-
}
|
|
1251
|
-
if (label) {
|
|
1252
|
-
const labeledSection = {
|
|
1253
|
-
title: label,
|
|
1254
|
-
entries
|
|
1255
|
-
};
|
|
1256
|
-
sections.push(labeledSection);
|
|
1257
|
-
return { fragments: sections.map((s) => ({
|
|
1258
|
-
...s,
|
|
1259
|
-
type: "section"
|
|
1260
|
-
})) };
|
|
1261
|
-
}
|
|
1262
|
-
return { fragments: [...sections.map((s) => ({
|
|
1263
|
-
...s,
|
|
1264
|
-
type: "section"
|
|
1265
|
-
})), {
|
|
1266
|
-
type: "section",
|
|
1267
|
-
entries
|
|
1268
|
-
}] };
|
|
1269
|
-
}
|
|
1270
|
-
};
|
|
1271
|
-
}
|
|
1272
|
-
function concat(...parsers) {
|
|
1273
|
-
const initialState = parsers.map((parser) => parser.initialState);
|
|
1274
|
-
return {
|
|
1275
|
-
$valueType: [],
|
|
1276
|
-
$stateType: [],
|
|
1277
|
-
priority: parsers.length > 0 ? Math.max(...parsers.map((p) => p.priority)) : 0,
|
|
1278
|
-
usage: parsers.flatMap((p) => p.usage),
|
|
1279
|
-
initialState,
|
|
1280
|
-
parse(context) {
|
|
1281
|
-
let currentContext = context;
|
|
1282
|
-
const allConsumed = [];
|
|
1283
|
-
const matchedParsers = /* @__PURE__ */ new Set();
|
|
1284
|
-
while (matchedParsers.size < parsers.length) {
|
|
1285
|
-
let foundMatch = false;
|
|
1286
|
-
let error = {
|
|
1287
|
-
consumed: 0,
|
|
1288
|
-
error: require_message.message`No remaining parsers could match the input.`
|
|
1289
|
-
};
|
|
1290
|
-
const remainingParsers = parsers.map((parser, index) => [parser, index]).filter(([_, index]) => !matchedParsers.has(index)).sort(([parserA], [parserB]) => parserB.priority - parserA.priority);
|
|
1291
|
-
for (const [parser, index] of remainingParsers) {
|
|
1292
|
-
const result = parser.parse({
|
|
1293
|
-
...currentContext,
|
|
1294
|
-
state: currentContext.state[index]
|
|
1295
|
-
});
|
|
1296
|
-
if (result.success && result.consumed.length > 0) {
|
|
1297
|
-
currentContext = {
|
|
1298
|
-
...currentContext,
|
|
1299
|
-
buffer: result.next.buffer,
|
|
1300
|
-
optionsTerminated: result.next.optionsTerminated,
|
|
1301
|
-
state: currentContext.state.map((s, idx) => idx === index ? result.next.state : s)
|
|
1302
|
-
};
|
|
1303
|
-
allConsumed.push(...result.consumed);
|
|
1304
|
-
matchedParsers.add(index);
|
|
1305
|
-
foundMatch = true;
|
|
1306
|
-
break;
|
|
1307
|
-
} else if (!result.success && error.consumed < result.consumed) error = result;
|
|
1308
|
-
}
|
|
1309
|
-
if (!foundMatch) for (const [parser, index] of remainingParsers) {
|
|
1310
|
-
const result = parser.parse({
|
|
1311
|
-
...currentContext,
|
|
1312
|
-
state: currentContext.state[index]
|
|
1313
|
-
});
|
|
1314
|
-
if (result.success && result.consumed.length < 1) {
|
|
1315
|
-
currentContext = {
|
|
1316
|
-
...currentContext,
|
|
1317
|
-
state: currentContext.state.map((s, idx) => idx === index ? result.next.state : s)
|
|
1318
|
-
};
|
|
1319
|
-
matchedParsers.add(index);
|
|
1320
|
-
foundMatch = true;
|
|
1321
|
-
break;
|
|
1322
|
-
} else if (!result.success && result.consumed < 1) {
|
|
1323
|
-
matchedParsers.add(index);
|
|
1324
|
-
foundMatch = true;
|
|
1325
|
-
break;
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
1328
|
-
if (!foundMatch) return {
|
|
1329
|
-
...error,
|
|
1330
|
-
success: false
|
|
1331
|
-
};
|
|
1332
|
-
}
|
|
1333
|
-
return {
|
|
1334
|
-
success: true,
|
|
1335
|
-
next: currentContext,
|
|
1336
|
-
consumed: allConsumed
|
|
1337
|
-
};
|
|
1338
|
-
},
|
|
1339
|
-
complete(state) {
|
|
1340
|
-
const results = [];
|
|
1341
|
-
for (let i = 0; i < parsers.length; i++) {
|
|
1342
|
-
const parser = parsers[i];
|
|
1343
|
-
const parserState = state[i];
|
|
1344
|
-
const result = parser.complete(parserState);
|
|
1345
|
-
if (!result.success) return result;
|
|
1346
|
-
if (Array.isArray(result.value)) results.push(...result.value);
|
|
1347
|
-
else results.push(result.value);
|
|
1348
|
-
}
|
|
1349
|
-
return {
|
|
1350
|
-
success: true,
|
|
1351
|
-
value: results
|
|
1352
|
-
};
|
|
1353
|
-
},
|
|
1354
|
-
getDocFragments(state, _defaultValue) {
|
|
1355
|
-
const fragments = parsers.flatMap((p, index) => {
|
|
1356
|
-
const indexState = state.kind === "unavailable" ? { kind: "unavailable" } : {
|
|
1357
|
-
kind: "available",
|
|
1358
|
-
state: state.state[index]
|
|
1359
|
-
};
|
|
1360
|
-
return p.getDocFragments(indexState, void 0).fragments;
|
|
1361
|
-
});
|
|
1362
|
-
const entries = fragments.filter((f) => f.type === "entry");
|
|
1363
|
-
const sections = [];
|
|
1364
|
-
for (const fragment of fragments) {
|
|
1365
|
-
if (fragment.type !== "section") continue;
|
|
1366
|
-
if (fragment.title == null) entries.push(...fragment.entries);
|
|
1367
|
-
else sections.push(fragment);
|
|
1368
|
-
}
|
|
1369
|
-
const result = [...sections.map((s) => ({
|
|
1370
|
-
...s,
|
|
1371
|
-
type: "section"
|
|
1372
|
-
}))];
|
|
1373
|
-
if (entries.length > 0) result.push({
|
|
1374
|
-
type: "section",
|
|
1375
|
-
entries
|
|
1376
|
-
});
|
|
1377
|
-
return { fragments: result };
|
|
1378
|
-
}
|
|
1379
|
-
};
|
|
1380
|
-
}
|
|
1381
|
-
/**
|
|
1382
|
-
* Creates a parser that matches a specific subcommand name and then applies
|
|
1383
|
-
* an inner parser to the remaining arguments.
|
|
1384
|
-
* This is useful for building CLI tools with subcommands like git, npm, etc.
|
|
1385
|
-
* @template T The type of the value returned by the inner parser.
|
|
1386
|
-
* @template TState The type of the state used by the inner parser.
|
|
1387
|
-
* @param name The subcommand name to match (e.g., `"show"`, `"edit"`).
|
|
1388
|
-
* @param parser The {@link Parser} to apply after the command is matched.
|
|
1389
|
-
* @param options Optional configuration for the command parser, such as
|
|
1390
|
-
* a description for documentation.
|
|
1391
|
-
* @returns A {@link Parser} that matches the command name and delegates
|
|
1392
|
-
* to the inner parser for the remaining arguments.
|
|
1393
|
-
*/
|
|
1394
|
-
function command(name, parser, options = {}) {
|
|
1395
|
-
return {
|
|
1396
|
-
$valueType: [],
|
|
1397
|
-
$stateType: [],
|
|
1398
|
-
priority: 15,
|
|
1399
|
-
usage: [{
|
|
1400
|
-
type: "command",
|
|
1401
|
-
name
|
|
1402
|
-
}, ...parser.usage],
|
|
1403
|
-
initialState: void 0,
|
|
1404
|
-
parse(context) {
|
|
1405
|
-
if (context.state === void 0) {
|
|
1406
|
-
if (context.buffer.length < 1 || context.buffer[0] !== name) return {
|
|
1407
|
-
success: false,
|
|
1408
|
-
consumed: 0,
|
|
1409
|
-
error: require_message.message`Expected command ${require_message.optionName(name)}, but got ${context.buffer.length > 0 ? context.buffer[0] : "end of input"}.`
|
|
1410
|
-
};
|
|
1411
|
-
return {
|
|
1412
|
-
success: true,
|
|
1413
|
-
next: {
|
|
1414
|
-
...context,
|
|
1415
|
-
buffer: context.buffer.slice(1),
|
|
1416
|
-
state: ["matched", name]
|
|
1417
|
-
},
|
|
1418
|
-
consumed: context.buffer.slice(0, 1)
|
|
1419
|
-
};
|
|
1420
|
-
} else if (context.state[0] === "matched") {
|
|
1421
|
-
const result = parser.parse({
|
|
1422
|
-
...context,
|
|
1423
|
-
state: parser.initialState
|
|
1424
|
-
});
|
|
1425
|
-
if (result.success) return {
|
|
1426
|
-
success: true,
|
|
1427
|
-
next: {
|
|
1428
|
-
...result.next,
|
|
1429
|
-
state: ["parsing", result.next.state]
|
|
1430
|
-
},
|
|
1431
|
-
consumed: result.consumed
|
|
1432
|
-
};
|
|
1433
|
-
return result;
|
|
1434
|
-
} else if (context.state[0] === "parsing") {
|
|
1435
|
-
const result = parser.parse({
|
|
1436
|
-
...context,
|
|
1437
|
-
state: context.state[1]
|
|
1438
|
-
});
|
|
1439
|
-
if (result.success) return {
|
|
1440
|
-
success: true,
|
|
1441
|
-
next: {
|
|
1442
|
-
...result.next,
|
|
1443
|
-
state: ["parsing", result.next.state]
|
|
1444
|
-
},
|
|
1445
|
-
consumed: result.consumed
|
|
1446
|
-
};
|
|
1447
|
-
return result;
|
|
1448
|
-
}
|
|
1449
|
-
return {
|
|
1450
|
-
success: false,
|
|
1451
|
-
consumed: 0,
|
|
1452
|
-
error: require_message.message`Invalid command state.`
|
|
1453
|
-
};
|
|
1454
|
-
},
|
|
1455
|
-
complete(state) {
|
|
1456
|
-
if (typeof state === "undefined") return {
|
|
1457
|
-
success: false,
|
|
1458
|
-
error: require_message.message`Command ${require_message.optionName(name)} was not matched.`
|
|
1459
|
-
};
|
|
1460
|
-
else if (state[0] === "matched") return parser.complete(parser.initialState);
|
|
1461
|
-
else if (state[0] === "parsing") return parser.complete(state[1]);
|
|
1462
|
-
return {
|
|
1463
|
-
success: false,
|
|
1464
|
-
error: require_message.message`Invalid command state during completion.`
|
|
1465
|
-
};
|
|
1466
|
-
},
|
|
1467
|
-
getDocFragments(state, defaultValue) {
|
|
1468
|
-
if (state.kind === "unavailable" || typeof state.state === "undefined") return {
|
|
1469
|
-
description: options.description,
|
|
1470
|
-
fragments: [{
|
|
1471
|
-
type: "entry",
|
|
1472
|
-
term: {
|
|
1473
|
-
type: "command",
|
|
1474
|
-
name
|
|
1475
|
-
},
|
|
1476
|
-
description: options.description
|
|
1477
|
-
}]
|
|
1478
|
-
};
|
|
1479
|
-
const innerState = state.state[0] === "parsing" ? {
|
|
1480
|
-
kind: "available",
|
|
1481
|
-
state: state.state[1]
|
|
1482
|
-
} : { kind: "unavailable" };
|
|
1483
|
-
const innerFragments = parser.getDocFragments(innerState, defaultValue);
|
|
1484
|
-
return {
|
|
1485
|
-
...innerFragments,
|
|
1486
|
-
description: innerFragments.description ?? options.description
|
|
1487
|
-
};
|
|
1488
|
-
},
|
|
1489
|
-
[Symbol.for("Deno.customInspect")]() {
|
|
1490
|
-
return `command(${JSON.stringify(name)})`;
|
|
1491
|
-
}
|
|
1492
|
-
};
|
|
1493
|
-
}
|
|
1494
|
-
/**
|
|
1495
9
|
* Parses an array of command-line arguments using the provided combined parser.
|
|
1496
10
|
* This function processes the input arguments, applying the parser to each
|
|
1497
11
|
* argument until all arguments are consumed or an error occurs.
|
|
@@ -1534,81 +48,6 @@ function parse(parser, args) {
|
|
|
1534
48
|
};
|
|
1535
49
|
}
|
|
1536
50
|
/**
|
|
1537
|
-
* Wraps a parser with a group label for documentation purposes.
|
|
1538
|
-
*
|
|
1539
|
-
* The `group()` function is a documentation-only wrapper that applies a label
|
|
1540
|
-
* to any parser for help text organization. This allows you to use clean code
|
|
1541
|
-
* structure with combinators like {@link merge} while maintaining well-organized
|
|
1542
|
-
* help text through group labeling.
|
|
1543
|
-
*
|
|
1544
|
-
* The wrapped parser has identical parsing behavior but generates documentation
|
|
1545
|
-
* fragments wrapped in a labeled section. This is particularly useful when
|
|
1546
|
-
* combining parsers using {@link merge}—you can wrap the merged result with
|
|
1547
|
-
* `group()` to add a section header in help output.
|
|
1548
|
-
*
|
|
1549
|
-
* @example
|
|
1550
|
-
* ```typescript
|
|
1551
|
-
* const apiOptions = merge(
|
|
1552
|
-
* object({ endpoint: option("--endpoint", string()) }),
|
|
1553
|
-
* object({ timeout: option("--timeout", integer()) })
|
|
1554
|
-
* );
|
|
1555
|
-
*
|
|
1556
|
-
* const groupedApiOptions = group("API Options", apiOptions);
|
|
1557
|
-
* // Now produces a labeled "API Options" section in help text
|
|
1558
|
-
* ```
|
|
1559
|
-
*
|
|
1560
|
-
* @example
|
|
1561
|
-
* ```typescript
|
|
1562
|
-
* // Can be used with any parser, not just merge()
|
|
1563
|
-
* const verboseGroup = group("Verbosity", object({
|
|
1564
|
-
* verbose: option("-v", "--verbose"),
|
|
1565
|
-
* quiet: option("-q", "--quiet")
|
|
1566
|
-
* }));
|
|
1567
|
-
* ```
|
|
1568
|
-
*
|
|
1569
|
-
* @template TValue The value type of the wrapped parser.
|
|
1570
|
-
* @template TState The state type of the wrapped parser.
|
|
1571
|
-
* @param label A descriptive label for this parser group, used for
|
|
1572
|
-
* documentation and help text organization.
|
|
1573
|
-
* @param parser The parser to wrap with a group label.
|
|
1574
|
-
* @returns A new parser that behaves identically to the input parser
|
|
1575
|
-
* but generates documentation within a labeled section.
|
|
1576
|
-
* @since 0.4.0
|
|
1577
|
-
*/
|
|
1578
|
-
function group(label, parser) {
|
|
1579
|
-
return {
|
|
1580
|
-
$valueType: parser.$valueType,
|
|
1581
|
-
$stateType: parser.$stateType,
|
|
1582
|
-
priority: parser.priority,
|
|
1583
|
-
usage: parser.usage,
|
|
1584
|
-
initialState: parser.initialState,
|
|
1585
|
-
parse: (context) => parser.parse(context),
|
|
1586
|
-
complete: (state) => parser.complete(state),
|
|
1587
|
-
getDocFragments: (state, defaultValue) => {
|
|
1588
|
-
const { description, fragments } = parser.getDocFragments(state, defaultValue);
|
|
1589
|
-
const allEntries = [];
|
|
1590
|
-
const titledSections = [];
|
|
1591
|
-
for (const fragment of fragments) if (fragment.type === "entry") allEntries.push(fragment);
|
|
1592
|
-
else if (fragment.type === "section") if (fragment.title) titledSections.push(fragment);
|
|
1593
|
-
else allEntries.push(...fragment.entries);
|
|
1594
|
-
const labeledSection = {
|
|
1595
|
-
title: label,
|
|
1596
|
-
entries: allEntries
|
|
1597
|
-
};
|
|
1598
|
-
return {
|
|
1599
|
-
description,
|
|
1600
|
-
fragments: [...titledSections.map((s) => ({
|
|
1601
|
-
...s,
|
|
1602
|
-
type: "section"
|
|
1603
|
-
})), {
|
|
1604
|
-
type: "section",
|
|
1605
|
-
...labeledSection
|
|
1606
|
-
}]
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
1609
|
-
};
|
|
1610
|
-
}
|
|
1611
|
-
/**
|
|
1612
51
|
* Generates a documentation page for a parser based on its current state after
|
|
1613
52
|
* attempting to parse the provided arguments. This function is useful for
|
|
1614
53
|
* creating help documentation that reflects the current parsing context.
|
|
@@ -1687,22 +126,22 @@ function getDocPage(parser, args = []) {
|
|
|
1687
126
|
}
|
|
1688
127
|
|
|
1689
128
|
//#endregion
|
|
1690
|
-
exports.WithDefaultError = WithDefaultError;
|
|
1691
|
-
exports.argument = argument;
|
|
1692
|
-
exports.command = command;
|
|
1693
|
-
exports.concat = concat;
|
|
1694
|
-
exports.constant = constant;
|
|
1695
|
-
exports.flag = flag;
|
|
129
|
+
exports.WithDefaultError = require_modifiers.WithDefaultError;
|
|
130
|
+
exports.argument = require_primitives.argument;
|
|
131
|
+
exports.command = require_primitives.command;
|
|
132
|
+
exports.concat = require_constructs.concat;
|
|
133
|
+
exports.constant = require_primitives.constant;
|
|
134
|
+
exports.flag = require_primitives.flag;
|
|
1696
135
|
exports.getDocPage = getDocPage;
|
|
1697
|
-
exports.group = group;
|
|
1698
|
-
exports.longestMatch = longestMatch;
|
|
1699
|
-
exports.map = map;
|
|
1700
|
-
exports.merge = merge;
|
|
1701
|
-
exports.multiple = multiple;
|
|
1702
|
-
exports.object = object;
|
|
1703
|
-
exports.option = option;
|
|
1704
|
-
exports.optional = optional;
|
|
1705
|
-
exports.or = or;
|
|
136
|
+
exports.group = require_constructs.group;
|
|
137
|
+
exports.longestMatch = require_constructs.longestMatch;
|
|
138
|
+
exports.map = require_modifiers.map;
|
|
139
|
+
exports.merge = require_constructs.merge;
|
|
140
|
+
exports.multiple = require_modifiers.multiple;
|
|
141
|
+
exports.object = require_constructs.object;
|
|
142
|
+
exports.option = require_primitives.option;
|
|
143
|
+
exports.optional = require_modifiers.optional;
|
|
144
|
+
exports.or = require_constructs.or;
|
|
1706
145
|
exports.parse = parse;
|
|
1707
|
-
exports.tuple = tuple;
|
|
1708
|
-
exports.withDefault = withDefault;
|
|
146
|
+
exports.tuple = require_constructs.tuple;
|
|
147
|
+
exports.withDefault = require_modifiers.withDefault;
|