@optique/core 0.9.0-dev.201 → 0.9.0-dev.202

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/modifiers.js CHANGED
@@ -9,12 +9,31 @@ import { formatMessage, message, text } from "./message.js";
9
9
  * - Returning success with undefined state when inner parser fails without consuming
10
10
  * @internal
11
11
  */
12
- function parseOptionalStyle(context, parser) {
12
+ function parseOptionalStyleSync(context, parser) {
13
13
  const innerState = typeof context.state === "undefined" ? parser.initialState : context.state[0];
14
14
  const result = parser.parse({
15
15
  ...context,
16
16
  state: innerState
17
17
  });
18
+ return processOptionalStyleResult(result, innerState, context);
19
+ }
20
+ /**
21
+ * Internal async helper for optional-style parsing logic.
22
+ * @internal
23
+ */
24
+ async function parseOptionalStyleAsync(context, parser) {
25
+ const innerState = typeof context.state === "undefined" ? parser.initialState : context.state[0];
26
+ const result = await parser.parse({
27
+ ...context,
28
+ state: innerState
29
+ });
30
+ return processOptionalStyleResult(result, innerState, context);
31
+ }
32
+ /**
33
+ * Internal helper to process optional-style parse results.
34
+ * @internal
35
+ */
36
+ function processOptionalStyleResult(result, innerState, context) {
18
37
  if (result.success) {
19
38
  if (result.next.state !== innerState || result.consumed.length === 0) return {
20
39
  success: true,
@@ -45,6 +64,7 @@ function parseOptionalStyle(context, parser) {
45
64
  * without consuming input if the wrapped parser fails to match.
46
65
  * If the wrapped parser succeeds, this returns its value.
47
66
  * If the wrapped parser fails, this returns `undefined` without consuming input.
67
+ * @template M The execution mode of the parser.
48
68
  * @template TValue The type of the value returned by the wrapped parser.
49
69
  * @template TState The type of the state used by the wrapped parser.
50
70
  * @param parser The {@link Parser} to make optional.
@@ -52,7 +72,25 @@ function parseOptionalStyle(context, parser) {
52
72
  * or `undefined` if the wrapped parser fails to match.
53
73
  */
54
74
  function optional(parser) {
75
+ const syncParser = parser;
76
+ const isAsync = parser.$mode === "async";
77
+ function* suggestSync(context, prefix) {
78
+ const innerState = typeof context.state === "undefined" ? syncParser.initialState : context.state[0];
79
+ yield* syncParser.suggest({
80
+ ...context,
81
+ state: innerState
82
+ }, prefix);
83
+ }
84
+ async function* suggestAsync(context, prefix) {
85
+ const innerState = typeof context.state === "undefined" ? syncParser.initialState : context.state[0];
86
+ const suggestions = parser.suggest({
87
+ ...context,
88
+ state: innerState
89
+ }, prefix);
90
+ for await (const s of suggestions) yield s;
91
+ }
55
92
  return {
93
+ $mode: parser.$mode,
56
94
  $valueType: [],
57
95
  $stateType: [],
58
96
  priority: parser.priority,
@@ -62,28 +100,27 @@ function optional(parser) {
62
100
  }],
63
101
  initialState: void 0,
64
102
  parse(context) {
65
- return parseOptionalStyle(context, parser);
103
+ if (isAsync) return parseOptionalStyleAsync(context, parser);
104
+ return parseOptionalStyleSync(context, syncParser);
66
105
  },
67
106
  complete(state) {
68
107
  if (typeof state === "undefined") return {
69
108
  success: true,
70
109
  value: void 0
71
110
  };
72
- return parser.complete(state[0]);
111
+ if (!isAsync) return syncParser.complete(state[0]);
112
+ return (async () => await parser.complete(state[0]))();
73
113
  },
74
114
  suggest(context, prefix) {
75
- const innerState = typeof context.state === "undefined" ? parser.initialState : context.state[0];
76
- return parser.suggest({
77
- ...context,
78
- state: innerState
79
- }, prefix);
115
+ if (isAsync) return suggestAsync(context, prefix);
116
+ return suggestSync(context, prefix);
80
117
  },
81
118
  getDocFragments(state, defaultValue) {
82
119
  const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state === void 0 ? { kind: "unavailable" } : {
83
120
  kind: "available",
84
121
  state: state.state[0]
85
122
  };
86
- return parser.getDocFragments(innerState, defaultValue);
123
+ return syncParser.getDocFragments(innerState, defaultValue);
87
124
  }
88
125
  };
89
126
  }
@@ -122,7 +159,25 @@ var WithDefaultError = class extends Error {
122
159
  }
123
160
  };
124
161
  function withDefault(parser, defaultValue, options) {
162
+ const syncParser = parser;
163
+ const isAsync = parser.$mode === "async";
164
+ function* suggestSync(context, prefix) {
165
+ const innerState = typeof context.state === "undefined" ? syncParser.initialState : context.state[0];
166
+ yield* syncParser.suggest({
167
+ ...context,
168
+ state: innerState
169
+ }, prefix);
170
+ }
171
+ async function* suggestAsync(context, prefix) {
172
+ const innerState = typeof context.state === "undefined" ? syncParser.initialState : context.state[0];
173
+ const suggestions = parser.suggest({
174
+ ...context,
175
+ state: innerState
176
+ }, prefix);
177
+ for await (const s of suggestions) yield s;
178
+ }
125
179
  return {
180
+ $mode: parser.$mode,
126
181
  $valueType: [],
127
182
  $stateType: [],
128
183
  priority: parser.priority,
@@ -132,7 +187,8 @@ function withDefault(parser, defaultValue, options) {
132
187
  }],
133
188
  initialState: void 0,
134
189
  parse(context) {
135
- return parseOptionalStyle(context, parser);
190
+ if (isAsync) return parseOptionalStyleAsync(context, parser);
191
+ return parseOptionalStyleSync(context, syncParser);
136
192
  },
137
193
  complete(state) {
138
194
  if (typeof state === "undefined") try {
@@ -147,14 +203,12 @@ function withDefault(parser, defaultValue, options) {
147
203
  error: error instanceof WithDefaultError ? error.errorMessage : message`${text(String(error))}`
148
204
  };
149
205
  }
150
- return parser.complete(state[0]);
206
+ if (!isAsync) return syncParser.complete(state[0]);
207
+ return (async () => await parser.complete(state[0]))();
151
208
  },
152
209
  suggest(context, prefix) {
153
- const innerState = typeof context.state === "undefined" ? parser.initialState : context.state[0];
154
- return parser.suggest({
155
- ...context,
156
- state: innerState
157
- }, prefix);
210
+ if (isAsync) return suggestAsync(context, prefix);
211
+ return suggestSync(context, prefix);
158
212
  },
159
213
  getDocFragments(state, upperDefaultValue) {
160
214
  const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state === void 0 ? { kind: "unavailable" } : {
@@ -162,7 +216,7 @@ function withDefault(parser, defaultValue, options) {
162
216
  state: state.state[0]
163
217
  };
164
218
  const actualDefaultValue = upperDefaultValue != null ? upperDefaultValue : typeof defaultValue === "function" ? defaultValue() : defaultValue;
165
- const fragments = parser.getDocFragments(innerState, actualDefaultValue);
219
+ const fragments = syncParser.getDocFragments(innerState, actualDefaultValue);
166
220
  if (options?.message) {
167
221
  const modifiedFragments = fragments.fragments.map((fragment) => {
168
222
  if (fragment.type === "entry") return {
@@ -191,6 +245,7 @@ function withDefault(parser, defaultValue, options) {
191
245
  * - Computing derived values from parsed input
192
246
  * - Creating reusable transformations that can be applied to any parser
193
247
  *
248
+ * @template M The execution mode of the parser.
194
249
  * @template T The type of the value produced by the original parser.
195
250
  * @template U The type of the value produced by the mapping function.
196
251
  * @template TState The type of the state used by the original parser.
@@ -214,33 +269,68 @@ function withDefault(parser, defaultValue, options) {
214
269
  * ```
215
270
  */
216
271
  function map(parser, transform) {
217
- return {
272
+ const syncParser = parser;
273
+ const isAsync = parser.$mode === "async";
274
+ function* suggestSync(context, prefix) {
275
+ yield* syncParser.suggest(context, prefix);
276
+ }
277
+ async function* suggestAsync(context, prefix) {
278
+ const suggestions = parser.suggest(context, prefix);
279
+ for await (const s of suggestions) yield s;
280
+ }
281
+ const result = {
282
+ $mode: "sync",
218
283
  $valueType: [],
219
284
  $stateType: parser.$stateType,
220
285
  priority: parser.priority,
221
286
  usage: parser.usage,
222
287
  initialState: parser.initialState,
223
- parse: parser.parse.bind(parser),
288
+ parse(context) {
289
+ if (isAsync) return parser.parse(context);
290
+ return syncParser.parse(context);
291
+ },
224
292
  complete(state) {
225
- const result = parser.complete(state);
226
- if (result.success) return {
227
- success: true,
228
- value: transform(result.value)
229
- };
230
- return result;
293
+ if (!isAsync) {
294
+ const innerResult = syncParser.complete(state);
295
+ if (innerResult.success) return {
296
+ success: true,
297
+ value: transform(innerResult.value)
298
+ };
299
+ return {
300
+ success: false,
301
+ error: innerResult.error
302
+ };
303
+ }
304
+ return (async () => {
305
+ const innerResult = await parser.complete(state);
306
+ if (innerResult.success) return {
307
+ success: true,
308
+ value: transform(innerResult.value)
309
+ };
310
+ return {
311
+ success: false,
312
+ error: innerResult.error
313
+ };
314
+ })();
231
315
  },
232
316
  suggest(context, prefix) {
233
- return parser.suggest(context, prefix);
317
+ if (isAsync) return suggestAsync(context, prefix);
318
+ return suggestSync(context, prefix);
234
319
  },
235
320
  getDocFragments(state, _defaultValue) {
236
- return parser.getDocFragments(state, void 0);
321
+ return syncParser.getDocFragments(state, void 0);
237
322
  }
238
323
  };
324
+ return {
325
+ ...result,
326
+ $mode: parser.$mode
327
+ };
239
328
  }
240
329
  /**
241
330
  * Creates a parser that allows multiple occurrences of a given parser.
242
331
  * This parser can be used to parse multiple values of the same type,
243
332
  * such as multiple command-line arguments or options.
333
+ * @template M The execution mode of the parser.
244
334
  * @template TValue The type of the value that the parser produces.
245
335
  * @template TState The type of the state used by the parser.
246
336
  * @param parser The {@link Parser} to apply multiple times.
@@ -252,8 +342,59 @@ function map(parser, transform) {
252
342
  * of type {@link TState}.
253
343
  */
254
344
  function multiple(parser, options = {}) {
345
+ const syncParser = parser;
346
+ const isAsync = parser.$mode === "async";
255
347
  const { min = 0, max = Infinity } = options;
256
- return {
348
+ const parseSync = (context) => {
349
+ let added = context.state.length < 1;
350
+ let result = syncParser.parse({
351
+ ...context,
352
+ state: context.state.at(-1) ?? syncParser.initialState
353
+ });
354
+ if (!result.success) if (!added) {
355
+ result = syncParser.parse({
356
+ ...context,
357
+ state: syncParser.initialState
358
+ });
359
+ if (!result.success) return result;
360
+ added = true;
361
+ } else return result;
362
+ return {
363
+ success: true,
364
+ next: {
365
+ ...result.next,
366
+ state: [...added ? context.state : context.state.slice(0, -1), result.next.state]
367
+ },
368
+ consumed: result.consumed
369
+ };
370
+ };
371
+ const parseAsync = async (context) => {
372
+ let added = context.state.length < 1;
373
+ let resultOrPromise = parser.parse({
374
+ ...context,
375
+ state: context.state.at(-1) ?? parser.initialState
376
+ });
377
+ let result = await resultOrPromise;
378
+ if (!result.success) if (!added) {
379
+ resultOrPromise = parser.parse({
380
+ ...context,
381
+ state: parser.initialState
382
+ });
383
+ result = await resultOrPromise;
384
+ if (!result.success) return result;
385
+ added = true;
386
+ } else return result;
387
+ return {
388
+ success: true,
389
+ next: {
390
+ ...result.next,
391
+ state: [...added ? context.state : context.state.slice(0, -1), result.next.state]
392
+ },
393
+ consumed: result.consumed
394
+ };
395
+ };
396
+ const resultParser = {
397
+ $mode: parser.$mode,
257
398
  $valueType: [],
258
399
  $stateType: [],
259
400
  priority: parser.priority,
@@ -264,71 +405,79 @@ function multiple(parser, options = {}) {
264
405
  }],
265
406
  initialState: [],
266
407
  parse(context) {
267
- let added = context.state.length < 1;
268
- let result = parser.parse({
269
- ...context,
270
- state: context.state.at(-1) ?? parser.initialState
271
- });
272
- if (!result.success) if (!added) {
273
- result = parser.parse({
274
- ...context,
275
- state: parser.initialState
276
- });
277
- if (!result.success) return result;
278
- added = true;
279
- } else return result;
280
- return {
281
- success: true,
282
- next: {
283
- ...result.next,
284
- state: [...added ? context.state : context.state.slice(0, -1), result.next.state]
285
- },
286
- consumed: result.consumed
287
- };
408
+ if (isAsync) return parseAsync(context);
409
+ return parseSync(context);
288
410
  },
289
411
  complete(state) {
290
- const result = [];
291
- for (const s of state) {
292
- const valueResult = parser.complete(s);
293
- if (valueResult.success) result.push(valueResult.value);
294
- else return {
295
- success: false,
296
- error: valueResult.error
297
- };
298
- }
299
- if (result.length < min) {
300
- const customMessage = options.errors?.tooFew;
301
- return {
302
- success: false,
303
- error: customMessage ? typeof customMessage === "function" ? customMessage(min, result.length) : customMessage : message`Expected at least ${text(min.toLocaleString("en"))} values, but got only ${text(result.length.toLocaleString("en"))}.`
304
- };
305
- } else if (result.length > max) {
306
- const customMessage = options.errors?.tooMany;
307
- return {
308
- success: false,
309
- error: customMessage ? typeof customMessage === "function" ? customMessage(max, result.length) : customMessage : message`Expected at most ${text(max.toLocaleString("en"))} values, but got ${text(result.length.toLocaleString("en"))}.`
310
- };
412
+ if (!isAsync) {
413
+ const result = [];
414
+ for (const s of state) {
415
+ const valueResult = syncParser.complete(s);
416
+ if (valueResult.success) result.push(valueResult.value);
417
+ else return {
418
+ success: false,
419
+ error: valueResult.error
420
+ };
421
+ }
422
+ return validateMultipleResult(result);
311
423
  }
312
- return {
313
- success: true,
314
- value: result
315
- };
424
+ return (async () => {
425
+ const result = [];
426
+ for (const s of state) {
427
+ const valueResult = await parser.complete(s);
428
+ if (valueResult.success) result.push(valueResult.value);
429
+ else return {
430
+ success: false,
431
+ error: valueResult.error
432
+ };
433
+ }
434
+ return validateMultipleResult(result);
435
+ })();
316
436
  },
317
437
  suggest(context, prefix) {
318
438
  const innerState = context.state.length > 0 ? context.state.at(-1) : parser.initialState;
319
- return parser.suggest({
320
- ...context,
321
- state: innerState
322
- }, prefix);
439
+ if (isAsync) return async function* () {
440
+ const suggestions = parser.suggest({
441
+ ...context,
442
+ state: innerState
443
+ }, prefix);
444
+ for await (const s of suggestions) yield s;
445
+ }();
446
+ return function* () {
447
+ yield* syncParser.suggest({
448
+ ...context,
449
+ state: innerState
450
+ }, prefix);
451
+ }();
323
452
  },
324
453
  getDocFragments(state, defaultValue) {
325
454
  const innerState = state.kind === "unavailable" ? { kind: "unavailable" } : state.state.length > 0 ? {
326
455
  kind: "available",
327
456
  state: state.state.at(-1)
328
457
  } : { kind: "unavailable" };
329
- return parser.getDocFragments(innerState, defaultValue != null && defaultValue.length > 0 ? defaultValue[0] : void 0);
458
+ return syncParser.getDocFragments(innerState, defaultValue != null && defaultValue.length > 0 ? defaultValue[0] : void 0);
330
459
  }
331
460
  };
461
+ function validateMultipleResult(result) {
462
+ if (result.length < min) {
463
+ const customMessage = options.errors?.tooFew;
464
+ return {
465
+ success: false,
466
+ error: customMessage ? typeof customMessage === "function" ? customMessage(min, result.length) : customMessage : message`Expected at least ${text(min.toLocaleString("en"))} values, but got only ${text(result.length.toLocaleString("en"))}.`
467
+ };
468
+ } else if (result.length > max) {
469
+ const customMessage = options.errors?.tooMany;
470
+ return {
471
+ success: false,
472
+ error: customMessage ? typeof customMessage === "function" ? customMessage(max, result.length) : customMessage : message`Expected at most ${text(max.toLocaleString("en"))} values, but got ${text(result.length.toLocaleString("en"))}.`
473
+ };
474
+ }
475
+ return {
476
+ success: true,
477
+ value: result
478
+ };
479
+ }
480
+ return resultParser;
332
481
  }
333
482
 
334
483
  //#endregion
package/dist/parser.cjs CHANGED
@@ -9,17 +9,23 @@ const require_primitives = require('./primitives.cjs');
9
9
  * Parses an array of command-line arguments using the provided combined parser.
10
10
  * This function processes the input arguments, applying the parser to each
11
11
  * argument until all arguments are consumed or an error occurs.
12
+ *
13
+ * This function only accepts synchronous parsers. For asynchronous parsers,
14
+ * use {@link parseAsync}.
15
+ *
12
16
  * @template T The type of the value produced by the parser.
13
17
  * @param parser The combined {@link Parser} to use for parsing the input
14
- * arguments.
18
+ * arguments. Must be a synchronous parser.
15
19
  * @param args The array of command-line arguments to parse. Usually this is
16
20
  * `process.argv.slice(2)` in Node.js or `Deno.args` in Deno.
17
21
  * @returns A {@link Result} object indicating whether the parsing was
18
22
  * successful or not. If successful, it contains the parsed value of
19
23
  * type `T`. If not, it contains an error message describing the
20
24
  * failure.
25
+ * @since 0.9.0 Renamed from the original `parse` function which now delegates
26
+ * to this for sync parsers.
21
27
  */
22
- function parse(parser, args) {
28
+ function parseSync(parser, args) {
23
29
  let context = {
24
30
  buffer: args,
25
31
  optionsTerminated: false,
@@ -49,11 +55,86 @@ function parse(parser, args) {
49
55
  };
50
56
  }
51
57
  /**
58
+ * Parses an array of command-line arguments using the provided combined parser.
59
+ * This function processes the input arguments, applying the parser to each
60
+ * argument until all arguments are consumed or an error occurs.
61
+ *
62
+ * This function accepts any parser (sync or async) and always returns a Promise.
63
+ * For synchronous parsing with sync parsers, use {@link parseSync} instead.
64
+ *
65
+ * @template T The type of the value produced by the parser.
66
+ * @param parser The combined {@link Parser} to use for parsing the input
67
+ * arguments.
68
+ * @param args The array of command-line arguments to parse. Usually this is
69
+ * `process.argv.slice(2)` in Node.js or `Deno.args` in Deno.
70
+ * @returns A Promise that resolves to a {@link Result} object indicating
71
+ * whether the parsing was successful or not.
72
+ * @since 0.9.0
73
+ */
74
+ async function parseAsync(parser, args) {
75
+ let context = {
76
+ buffer: args,
77
+ optionsTerminated: false,
78
+ state: parser.initialState,
79
+ usage: parser.usage
80
+ };
81
+ do {
82
+ const result = await parser.parse(context);
83
+ if (!result.success) return {
84
+ success: false,
85
+ error: result.error
86
+ };
87
+ const previousBuffer = context.buffer;
88
+ context = result.next;
89
+ if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer.every((item, i) => item === previousBuffer[i])) return {
90
+ success: false,
91
+ error: require_message.message`Unexpected option or argument: ${context.buffer[0]}.`
92
+ };
93
+ } while (context.buffer.length > 0);
94
+ const endResult = await parser.complete(context.state);
95
+ return endResult.success ? {
96
+ success: true,
97
+ value: endResult.value
98
+ } : {
99
+ success: false,
100
+ error: endResult.error
101
+ };
102
+ }
103
+ /**
104
+ * Parses an array of command-line arguments using the provided combined parser.
105
+ * This function processes the input arguments, applying the parser to each
106
+ * argument until all arguments are consumed or an error occurs.
107
+ *
108
+ * The return type depends on the parser's mode:
109
+ * - Sync parsers return `Result<T>` directly.
110
+ * - Async parsers return `Promise<Result<T>>`.
111
+ *
112
+ * For explicit control, use {@link parseSync} or {@link parseAsync}.
113
+ *
114
+ * @template M The execution mode of the parser.
115
+ * @template T The type of the value produced by the parser.
116
+ * @param parser The combined {@link Parser} to use for parsing the input
117
+ * arguments.
118
+ * @param args The array of command-line arguments to parse. Usually this is
119
+ * `process.argv.slice(2)` in Node.js or `Deno.args` in Deno.
120
+ * @returns A {@link Result} object (for sync) or Promise thereof (for async)
121
+ * indicating whether the parsing was successful or not.
122
+ */
123
+ function parse(parser, args) {
124
+ if (parser.$mode === "async") return parseAsync(parser, args);
125
+ return parseSync(parser, args);
126
+ }
127
+ /**
52
128
  * Generates command-line suggestions based on current parsing state.
53
129
  * This function processes the input arguments up to the last argument,
54
130
  * then calls the parser's suggest method with the remaining prefix.
131
+ *
132
+ * This function only accepts synchronous parsers. For asynchronous parsers,
133
+ * use {@link suggestAsync}.
134
+ *
55
135
  * @template T The type of the value produced by the parser.
56
136
  * @param parser The {@link Parser} to use for generating suggestions.
137
+ * Must be a synchronous parser.
57
138
  * @param args The array of command-line arguments including the partial
58
139
  * argument to complete. The last element is treated as
59
140
  * the prefix for suggestions.
@@ -67,16 +148,17 @@ function parse(parser, args) {
67
148
  * });
68
149
  *
69
150
  * // Get suggestions for options starting with "--"
70
- * const suggestions = suggest(parser, ["--"]);
151
+ * const suggestions = suggestSync(parser, ["--"]);
71
152
  * // Returns: [{ text: "--verbose" }, { text: "--format" }]
72
153
  *
73
154
  * // Get suggestions after parsing some arguments
74
- * const suggestions2 = suggest(parser, ["-v", "--format="]);
155
+ * const suggestions2 = suggestSync(parser, ["-v", "--format="]);
75
156
  * // Returns: [{ text: "--format=json" }, { text: "--format=yaml" }]
76
157
  * ```
77
158
  * @since 0.6.0
159
+ * @since 0.9.0 Renamed from the original `suggest` function.
78
160
  */
79
- function suggest(parser, args) {
161
+ function suggestSync(parser, args) {
80
162
  const allButLast = args.slice(0, -1);
81
163
  const prefix = args[args.length - 1];
82
164
  let context = {
@@ -95,6 +177,73 @@ function suggest(parser, args) {
95
177
  return Array.from(parser.suggest(context, prefix));
96
178
  }
97
179
  /**
180
+ * Generates command-line suggestions based on current parsing state.
181
+ * This function processes the input arguments up to the last argument,
182
+ * then calls the parser's suggest method with the remaining prefix.
183
+ *
184
+ * This function accepts any parser (sync or async) and always returns a Promise.
185
+ * For synchronous suggestion generation with sync parsers, use
186
+ * {@link suggestSync} instead.
187
+ *
188
+ * @template T The type of the value produced by the parser.
189
+ * @param parser The {@link Parser} to use for generating suggestions.
190
+ * @param args The array of command-line arguments including the partial
191
+ * argument to complete. The last element is treated as
192
+ * the prefix for suggestions.
193
+ * @returns A Promise that resolves to an array of {@link Suggestion} objects
194
+ * containing completion candidates.
195
+ * @since 0.9.0
196
+ */
197
+ async function suggestAsync(parser, args) {
198
+ const allButLast = args.slice(0, -1);
199
+ const prefix = args[args.length - 1];
200
+ let context = {
201
+ buffer: allButLast,
202
+ optionsTerminated: false,
203
+ state: parser.initialState,
204
+ usage: parser.usage
205
+ };
206
+ while (context.buffer.length > 0) {
207
+ const result = await parser.parse(context);
208
+ if (!result.success) {
209
+ const suggestions$1 = [];
210
+ for await (const suggestion of parser.suggest(context, prefix)) suggestions$1.push(suggestion);
211
+ return suggestions$1;
212
+ }
213
+ const previousBuffer = context.buffer;
214
+ context = result.next;
215
+ if (context.buffer.length > 0 && context.buffer.length === previousBuffer.length && context.buffer.every((item, i) => item === previousBuffer[i])) return [];
216
+ }
217
+ const suggestions = [];
218
+ for await (const suggestion of parser.suggest(context, prefix)) suggestions.push(suggestion);
219
+ return suggestions;
220
+ }
221
+ /**
222
+ * Generates command-line suggestions based on current parsing state.
223
+ * This function processes the input arguments up to the last argument,
224
+ * then calls the parser's suggest method with the remaining prefix.
225
+ *
226
+ * The return type depends on the parser's mode:
227
+ * - Sync parsers return `readonly Suggestion[]` directly.
228
+ * - Async parsers return `Promise<readonly Suggestion[]>`.
229
+ *
230
+ * For explicit control, use {@link suggestSync} or {@link suggestAsync}.
231
+ *
232
+ * @template M The execution mode of the parser.
233
+ * @template T The type of the value produced by the parser.
234
+ * @param parser The {@link Parser} to use for generating suggestions.
235
+ * @param args The array of command-line arguments including the partial
236
+ * argument to complete. The last element is treated as
237
+ * the prefix for suggestions.
238
+ * @returns An array of {@link Suggestion} objects (for sync) or Promise thereof
239
+ * (for async) containing completion candidates.
240
+ * @since 0.6.0
241
+ */
242
+ function suggest(parser, args) {
243
+ if (parser.$mode === "async") return suggestAsync(parser, args);
244
+ return suggestSync(parser, args);
245
+ }
246
+ /**
98
247
  * Recursively searches for a command within nested exclusive usage terms.
99
248
  * When the command is found, returns the expanded usage terms for that command.
100
249
  *
@@ -212,7 +361,11 @@ exports.option = require_primitives.option;
212
361
  exports.optional = require_modifiers.optional;
213
362
  exports.or = require_constructs.or;
214
363
  exports.parse = parse;
364
+ exports.parseAsync = parseAsync;
365
+ exports.parseSync = parseSync;
215
366
  exports.passThrough = require_primitives.passThrough;
216
367
  exports.suggest = suggest;
368
+ exports.suggestAsync = suggestAsync;
369
+ exports.suggestSync = suggestSync;
217
370
  exports.tuple = require_constructs.tuple;
218
371
  exports.withDefault = require_modifiers.withDefault;