@optique/core 0.10.7-dev.485 → 1.0.0-dev.1109

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.
Files changed (56) hide show
  1. package/README.md +4 -6
  2. package/dist/annotations.cjs +209 -1
  3. package/dist/annotations.d.cts +78 -1
  4. package/dist/annotations.d.ts +78 -1
  5. package/dist/annotations.js +201 -1
  6. package/dist/completion.cjs +186 -50
  7. package/dist/completion.js +186 -50
  8. package/dist/constructs.cjs +310 -78
  9. package/dist/constructs.d.cts +525 -644
  10. package/dist/constructs.d.ts +525 -644
  11. package/dist/constructs.js +311 -79
  12. package/dist/context.cjs +43 -3
  13. package/dist/context.d.cts +113 -5
  14. package/dist/context.d.ts +113 -5
  15. package/dist/context.js +41 -3
  16. package/dist/dependency.cjs +172 -66
  17. package/dist/dependency.d.cts +22 -2
  18. package/dist/dependency.d.ts +22 -2
  19. package/dist/dependency.js +172 -66
  20. package/dist/doc.cjs +46 -1
  21. package/dist/doc.d.cts +24 -0
  22. package/dist/doc.d.ts +24 -0
  23. package/dist/doc.js +46 -1
  24. package/dist/facade.cjs +702 -322
  25. package/dist/facade.d.cts +124 -190
  26. package/dist/facade.d.ts +124 -190
  27. package/dist/facade.js +703 -323
  28. package/dist/index.cjs +5 -0
  29. package/dist/index.d.cts +5 -5
  30. package/dist/index.d.ts +5 -5
  31. package/dist/index.js +3 -3
  32. package/dist/message.cjs +7 -4
  33. package/dist/message.js +7 -4
  34. package/dist/mode-dispatch.cjs +23 -1
  35. package/dist/mode-dispatch.d.cts +55 -0
  36. package/dist/mode-dispatch.d.ts +55 -0
  37. package/dist/mode-dispatch.js +21 -1
  38. package/dist/modifiers.cjs +210 -55
  39. package/dist/modifiers.js +211 -56
  40. package/dist/parser.cjs +80 -47
  41. package/dist/parser.d.cts +18 -3
  42. package/dist/parser.d.ts +18 -3
  43. package/dist/parser.js +82 -50
  44. package/dist/primitives.cjs +102 -37
  45. package/dist/primitives.d.cts +81 -24
  46. package/dist/primitives.d.ts +81 -24
  47. package/dist/primitives.js +103 -39
  48. package/dist/usage.cjs +88 -6
  49. package/dist/usage.d.cts +51 -13
  50. package/dist/usage.d.ts +51 -13
  51. package/dist/usage.js +85 -7
  52. package/dist/valueparser.cjs +371 -99
  53. package/dist/valueparser.d.cts +56 -7
  54. package/dist/valueparser.d.ts +56 -7
  55. package/dist/valueparser.js +371 -99
  56. package/package.json +10 -1
package/dist/parser.cjs CHANGED
@@ -1,11 +1,17 @@
1
1
  const require_annotations = require('./annotations.cjs');
2
2
  const require_message = require('./message.cjs');
3
+ const require_mode_dispatch = require('./mode-dispatch.cjs');
3
4
  const require_usage = require('./usage.cjs');
4
5
  const require_constructs = require('./constructs.cjs');
5
6
  const require_modifiers = require('./modifiers.cjs');
6
7
  const require_primitives = require('./primitives.cjs');
7
8
 
8
9
  //#region src/parser.ts
10
+ function injectAnnotationsIntoState(state, options) {
11
+ const annotations = options?.annotations;
12
+ if (annotations == null) return state;
13
+ return require_annotations.injectAnnotations(state, annotations);
14
+ }
9
15
  /**
10
16
  * Parses an array of command-line arguments using the provided combined parser.
11
17
  * This function processes the input arguments, applying the parser to each
@@ -29,11 +35,8 @@ const require_primitives = require('./primitives.cjs');
29
35
  * @since 0.10.0 Added optional `options` parameter for annotations support.
30
36
  */
31
37
  function parseSync(parser, args, options) {
32
- let initialState = parser.initialState;
33
- if (options?.annotations && initialState != null) initialState = {
34
- ...typeof initialState === "object" ? initialState : {},
35
- [require_annotations.annotationKey]: options.annotations
36
- };
38
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
39
+ const shouldUnwrapAnnotatedValue = options?.annotations != null || require_annotations.isInjectedAnnotationWrapper(parser.initialState);
37
40
  let context = {
38
41
  buffer: args,
39
42
  optionsTerminated: false,
@@ -56,7 +59,7 @@ function parseSync(parser, args, options) {
56
59
  const endResult = parser.complete(context.state);
57
60
  return endResult.success ? {
58
61
  success: true,
59
- value: endResult.value
62
+ value: shouldUnwrapAnnotatedValue ? require_annotations.unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value
60
63
  } : {
61
64
  success: false,
62
65
  error: endResult.error
@@ -82,11 +85,8 @@ function parseSync(parser, args, options) {
82
85
  * @since 0.10.0 Added optional `options` parameter for annotations support.
83
86
  */
84
87
  async function parseAsync(parser, args, options) {
85
- let initialState = parser.initialState;
86
- if (options?.annotations && initialState != null) initialState = {
87
- ...typeof initialState === "object" ? initialState : {},
88
- [require_annotations.annotationKey]: options.annotations
89
- };
88
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
89
+ const shouldUnwrapAnnotatedValue = options?.annotations != null || require_annotations.isInjectedAnnotationWrapper(parser.initialState);
90
90
  let context = {
91
91
  buffer: args,
92
92
  optionsTerminated: false,
@@ -109,7 +109,7 @@ async function parseAsync(parser, args, options) {
109
109
  const endResult = await parser.complete(context.state);
110
110
  return endResult.success ? {
111
111
  success: true,
112
- value: endResult.value
112
+ value: shouldUnwrapAnnotatedValue ? require_annotations.unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value
113
113
  } : {
114
114
  success: false,
115
115
  error: endResult.error
@@ -138,8 +138,7 @@ async function parseAsync(parser, args, options) {
138
138
  * @since 0.10.0 Added optional `options` parameter for annotations support.
139
139
  */
140
140
  function parse(parser, args, options) {
141
- if (parser.$mode === "async") return parseAsync(parser, args, options);
142
- return parseSync(parser, args, options);
141
+ return require_mode_dispatch.dispatchByMode(parser.$mode, () => parseSync(parser, args, options), () => parseAsync(parser, args, options));
143
142
  }
144
143
  /**
145
144
  * Generates command-line suggestions based on current parsing state.
@@ -180,11 +179,7 @@ function parse(parser, args, options) {
180
179
  function suggestSync(parser, args, options) {
181
180
  const allButLast = args.slice(0, -1);
182
181
  const prefix = args[args.length - 1];
183
- let initialState = parser.initialState;
184
- if (options?.annotations && initialState != null) initialState = {
185
- ...typeof initialState === "object" ? initialState : {},
186
- [require_annotations.annotationKey]: options.annotations
187
- };
182
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
188
183
  let context = {
189
184
  buffer: allButLast,
190
185
  optionsTerminated: false,
@@ -223,11 +218,7 @@ function suggestSync(parser, args, options) {
223
218
  async function suggestAsync(parser, args, options) {
224
219
  const allButLast = args.slice(0, -1);
225
220
  const prefix = args[args.length - 1];
226
- let initialState = parser.initialState;
227
- if (options?.annotations && initialState != null) initialState = {
228
- ...typeof initialState === "object" ? initialState : {},
229
- [require_annotations.annotationKey]: options.annotations
230
- };
221
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
231
222
  let context = {
232
223
  buffer: allButLast,
233
224
  optionsTerminated: false,
@@ -273,8 +264,7 @@ async function suggestAsync(parser, args, options) {
273
264
  * @since 0.10.0 Added optional `options` parameter for annotations support.
274
265
  */
275
266
  function suggest(parser, args, options) {
276
- if (parser.$mode === "async") return suggestAsync(parser, args, options);
277
- return suggestSync(parser, args, options);
267
+ return require_mode_dispatch.dispatchByMode(parser.$mode, () => suggestSync(parser, args, options), () => suggestAsync(parser, args, options));
278
268
  }
279
269
  /**
280
270
  * Recursively searches for a command within nested exclusive usage terms.
@@ -339,11 +329,7 @@ function getDocPage(parser, args = [], options) {
339
329
  * Internal sync implementation of getDocPage.
340
330
  */
341
331
  function getDocPageSyncImpl(parser, args, options) {
342
- let initialState = parser.initialState;
343
- if (options?.annotations && initialState != null) initialState = {
344
- ...typeof initialState === "object" ? initialState : {},
345
- [require_annotations.annotationKey]: options.annotations
346
- };
332
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
347
333
  let context = {
348
334
  buffer: args,
349
335
  optionsTerminated: false,
@@ -361,11 +347,7 @@ function getDocPageSyncImpl(parser, args, options) {
361
347
  * Internal async implementation of getDocPage.
362
348
  */
363
349
  async function getDocPageAsyncImpl(parser, args, options) {
364
- let initialState = parser.initialState;
365
- if (options?.annotations && initialState != null) initialState = {
366
- ...typeof initialState === "object" ? initialState : {},
367
- [require_annotations.annotationKey]: options.annotations
368
- };
350
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
369
351
  let context = {
370
352
  buffer: args,
371
353
  optionsTerminated: false,
@@ -384,29 +366,79 @@ async function getDocPageAsyncImpl(parser, args, options) {
384
366
  * Shared by both sync and async implementations.
385
367
  */
386
368
  function buildDocPage(parser, context, args) {
387
- const { brief, description, fragments, footer } = parser.getDocFragments({
369
+ let effectiveArgs = args;
370
+ let { brief, description, fragments, footer } = parser.getDocFragments({
388
371
  kind: "available",
389
372
  state: context.state
390
373
  }, void 0);
391
- const entries = fragments.filter((f) => f.type === "entry");
392
- const sections = [];
393
- for (const fragment of fragments) {
394
- if (fragment.type !== "section") continue;
395
- if (fragment.title == null) entries.push(...fragment.entries);
396
- else sections.push(fragment);
374
+ if (args.length === 0 && Reflect.get(parser, Symbol.for("@optique/core/commandParser")) === true && fragments.length === 1 && fragments[0].type === "entry" && fragments[0].term.type === "command") {
375
+ const cmdName = fragments[0].term.name;
376
+ const matched = parser.getDocFragments({
377
+ kind: "available",
378
+ state: ["matched", cmdName]
379
+ }, void 0);
380
+ ({brief, description, fragments, footer} = matched);
381
+ effectiveArgs = [cmdName];
397
382
  }
398
- if (entries.length > 0) sections.push({ entries });
383
+ const buildingSections = [];
384
+ let untitledSection = null;
385
+ const titledSectionMap = /* @__PURE__ */ new Map();
386
+ for (const fragment of fragments) if (fragment.type === "entry") {
387
+ if (untitledSection == null) {
388
+ untitledSection = { entries: [] };
389
+ buildingSections.push(untitledSection);
390
+ }
391
+ untitledSection.entries.push(fragment);
392
+ } else if (fragment.type === "section") if (fragment.title == null) {
393
+ if (untitledSection == null) {
394
+ untitledSection = { entries: [] };
395
+ buildingSections.push(untitledSection);
396
+ }
397
+ untitledSection.entries.push(...fragment.entries);
398
+ } else {
399
+ let section = titledSectionMap.get(fragment.title);
400
+ if (section == null) {
401
+ section = {
402
+ title: fragment.title,
403
+ entries: []
404
+ };
405
+ titledSectionMap.set(fragment.title, section);
406
+ buildingSections.push(section);
407
+ }
408
+ section.entries.push(...fragment.entries);
409
+ }
410
+ const sections = buildingSections;
399
411
  const usage = [...require_usage.normalizeUsage(parser.usage)];
412
+ const maybeApplyCommandUsageLine = (term, arg, isLastArg, usageIndex) => {
413
+ if (term?.type !== "command" || term.name !== arg || !isLastArg || term.usageLine == null) return;
414
+ const defaultUsageLine = usage.slice(usageIndex + 1);
415
+ const customUsageLine = typeof term.usageLine === "function" ? term.usageLine(defaultUsageLine) : term.usageLine;
416
+ const normalizedCustomUsageLine = require_usage.normalizeUsage(customUsageLine);
417
+ usage.splice(usageIndex + 1, usage.length - (usageIndex + 1), ...normalizedCustomUsageLine);
418
+ };
400
419
  let i = 0;
401
- for (const arg of args) {
420
+ for (let argIndex = 0; argIndex < effectiveArgs.length; argIndex++) {
421
+ const arg = effectiveArgs[argIndex];
402
422
  if (i >= usage.length) break;
403
- const term = usage[i];
423
+ let term = usage[i];
404
424
  if (term.type === "exclusive") {
405
425
  const found = findCommandInExclusive(term, arg);
406
- if (found) usage.splice(i, 1, ...found);
426
+ if (found) {
427
+ usage.splice(i, 1, ...found);
428
+ term = usage[i];
429
+ }
407
430
  }
431
+ maybeApplyCommandUsageLine(term, arg, argIndex === effectiveArgs.length - 1, i);
408
432
  i++;
409
433
  }
434
+ if (effectiveArgs.length === 0 && usage.length > 0) {
435
+ const first = usage[0];
436
+ if (first.type === "command" && first.usageLine != null) {
437
+ const defaultUsageLine = usage.slice(1);
438
+ const customUsageLine = typeof first.usageLine === "function" ? first.usageLine(defaultUsageLine) : first.usageLine;
439
+ usage.splice(1, usage.length - 1, ...require_usage.normalizeUsage(customUsageLine));
440
+ }
441
+ }
410
442
  return {
411
443
  usage,
412
444
  sections,
@@ -424,6 +456,7 @@ exports.command = require_primitives.command;
424
456
  exports.concat = require_constructs.concat;
425
457
  exports.conditional = require_constructs.conditional;
426
458
  exports.constant = require_primitives.constant;
459
+ exports.fail = require_primitives.fail;
427
460
  exports.flag = require_primitives.flag;
428
461
  exports.getDocPage = getDocPage;
429
462
  exports.getDocPageAsync = getDocPageAsync;
package/dist/parser.d.cts CHANGED
@@ -4,9 +4,9 @@ import { Usage } from "./usage.cjs";
4
4
  import { DocFragments, DocPage } from "./doc.cjs";
5
5
  import { DependencyRegistryLike } from "./registry-types.cjs";
6
6
  import { ValueParserResult } from "./valueparser.cjs";
7
- import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
7
+ import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, GroupOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
8
8
  import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, nonEmpty, optional, withDefault } from "./modifiers.cjs";
9
- import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.cjs";
9
+ import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, fail, flag, option, passThrough } from "./primitives.cjs";
10
10
 
11
11
  //#region src/parser.d.ts
12
12
 
@@ -158,6 +158,21 @@ interface Parser<M extends Mode = "sync", TValue = unknown, TState = unknown> {
158
158
  * fragments for this parser.
159
159
  */
160
160
  getDocFragments(state: DocState<TState>, defaultValue?: TValue): DocFragments;
161
+ /**
162
+ * Optional predicate that determines whether completion should be
163
+ * deferred for the given parser state.
164
+ *
165
+ * When present, combinator wrappers ({@link optional}, {@link withDefault},
166
+ * {@link group}) forward this field to the outer parser. This enables
167
+ * packages like *\@optique/inquirer* to detect when interactive prompting
168
+ * should be deferred until an outer context (like a configuration file
169
+ * source) has resolved.
170
+ *
171
+ * @param state The current parser state.
172
+ * @returns `true` if completion should be deferred.
173
+ * @since 1.0.0
174
+ */
175
+ shouldDeferCompletion?(state: TState): boolean;
161
176
  }
162
177
  /**
163
178
  * The context of the parser, which includes the input buffer and the state.
@@ -534,4 +549,4 @@ declare function getDocPage(parser: Parser<"sync", unknown, unknown>, args?: rea
534
549
  declare function getDocPage(parser: Parser<"async", unknown, unknown>, args?: readonly string[], options?: ParseOptions): Promise<DocPage | undefined>;
535
550
  declare function getDocPage<M extends Mode>(parser: Parser<M, unknown, unknown>, args?: readonly string[], options?: ParseOptions): ModeValue<M, DocPage | undefined>;
536
551
  //#endregion
537
- export { ArgumentErrorOptions, ArgumentOptions, CombineModes, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, DuplicateOptionError, FlagErrorOptions, FlagOptions, InferMode, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Mode, ModeIterable, ModeValue, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OptionState, OrErrorOptions, OrOptions, type ParseOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, flag, getDocPage, getDocPageAsync, getDocPageSync, group, longestMatch, map, merge, multiple, nonEmpty, object, option, optional, or, parse, parseAsync, parseSync, passThrough, suggest, suggestAsync, suggestSync, tuple, withDefault };
552
+ export { ArgumentErrorOptions, ArgumentOptions, CombineModes, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, DuplicateOptionError, FlagErrorOptions, FlagOptions, GroupOptions, InferMode, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Mode, ModeIterable, ModeValue, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OptionState, OrErrorOptions, OrOptions, type ParseOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, fail, flag, getDocPage, getDocPageAsync, getDocPageSync, group, longestMatch, map, merge, multiple, nonEmpty, object, option, optional, or, parse, parseAsync, parseSync, passThrough, suggest, suggestAsync, suggestSync, tuple, withDefault };
package/dist/parser.d.ts CHANGED
@@ -4,9 +4,9 @@ import { Usage } from "./usage.js";
4
4
  import { DocFragments, DocPage } from "./doc.js";
5
5
  import { DependencyRegistryLike } from "./registry-types.js";
6
6
  import { ValueParserResult } from "./valueparser.js";
7
- import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
7
+ import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, GroupOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
8
8
  import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, nonEmpty, optional, withDefault } from "./modifiers.js";
9
- import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.js";
9
+ import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, fail, flag, option, passThrough } from "./primitives.js";
10
10
 
11
11
  //#region src/parser.d.ts
12
12
 
@@ -158,6 +158,21 @@ interface Parser<M extends Mode = "sync", TValue = unknown, TState = unknown> {
158
158
  * fragments for this parser.
159
159
  */
160
160
  getDocFragments(state: DocState<TState>, defaultValue?: TValue): DocFragments;
161
+ /**
162
+ * Optional predicate that determines whether completion should be
163
+ * deferred for the given parser state.
164
+ *
165
+ * When present, combinator wrappers ({@link optional}, {@link withDefault},
166
+ * {@link group}) forward this field to the outer parser. This enables
167
+ * packages like *\@optique/inquirer* to detect when interactive prompting
168
+ * should be deferred until an outer context (like a configuration file
169
+ * source) has resolved.
170
+ *
171
+ * @param state The current parser state.
172
+ * @returns `true` if completion should be deferred.
173
+ * @since 1.0.0
174
+ */
175
+ shouldDeferCompletion?(state: TState): boolean;
161
176
  }
162
177
  /**
163
178
  * The context of the parser, which includes the input buffer and the state.
@@ -534,4 +549,4 @@ declare function getDocPage(parser: Parser<"sync", unknown, unknown>, args?: rea
534
549
  declare function getDocPage(parser: Parser<"async", unknown, unknown>, args?: readonly string[], options?: ParseOptions): Promise<DocPage | undefined>;
535
550
  declare function getDocPage<M extends Mode>(parser: Parser<M, unknown, unknown>, args?: readonly string[], options?: ParseOptions): ModeValue<M, DocPage | undefined>;
536
551
  //#endregion
537
- export { ArgumentErrorOptions, ArgumentOptions, CombineModes, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, DuplicateOptionError, FlagErrorOptions, FlagOptions, InferMode, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Mode, ModeIterable, ModeValue, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OptionState, OrErrorOptions, OrOptions, type ParseOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, flag, getDocPage, getDocPageAsync, getDocPageSync, group, longestMatch, map, merge, multiple, nonEmpty, object, option, optional, or, parse, parseAsync, parseSync, passThrough, suggest, suggestAsync, suggestSync, tuple, withDefault };
552
+ export { ArgumentErrorOptions, ArgumentOptions, CombineModes, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DocState, DuplicateOptionError, FlagErrorOptions, FlagOptions, GroupOptions, InferMode, InferValue, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, Mode, ModeIterable, ModeValue, MultipleErrorOptions, MultipleOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionOptions, OptionState, OrErrorOptions, OrOptions, type ParseOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, Result, Suggestion, TupleOptions, WithDefaultError, WithDefaultOptions, argument, command, concat, conditional, constant, fail, flag, getDocPage, getDocPageAsync, getDocPageSync, group, longestMatch, map, merge, multiple, nonEmpty, object, option, optional, or, parse, parseAsync, parseSync, passThrough, suggest, suggestAsync, suggestSync, tuple, withDefault };
package/dist/parser.js CHANGED
@@ -1,11 +1,17 @@
1
- import { annotationKey } from "./annotations.js";
1
+ import { injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper } from "./annotations.js";
2
2
  import { message } from "./message.js";
3
+ import { dispatchByMode } from "./mode-dispatch.js";
3
4
  import { normalizeUsage } from "./usage.js";
4
5
  import { DuplicateOptionError, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
5
6
  import { WithDefaultError, map, multiple, nonEmpty, optional, withDefault } from "./modifiers.js";
6
- import { argument, command, constant, flag, option, passThrough } from "./primitives.js";
7
+ import { argument, command, constant, fail, flag, option, passThrough } from "./primitives.js";
7
8
 
8
9
  //#region src/parser.ts
10
+ function injectAnnotationsIntoState(state, options) {
11
+ const annotations = options?.annotations;
12
+ if (annotations == null) return state;
13
+ return injectAnnotations(state, annotations);
14
+ }
9
15
  /**
10
16
  * Parses an array of command-line arguments using the provided combined parser.
11
17
  * This function processes the input arguments, applying the parser to each
@@ -29,11 +35,8 @@ import { argument, command, constant, flag, option, passThrough } from "./primit
29
35
  * @since 0.10.0 Added optional `options` parameter for annotations support.
30
36
  */
31
37
  function parseSync(parser, args, options) {
32
- let initialState = parser.initialState;
33
- if (options?.annotations && initialState != null) initialState = {
34
- ...typeof initialState === "object" ? initialState : {},
35
- [annotationKey]: options.annotations
36
- };
38
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
39
+ const shouldUnwrapAnnotatedValue = options?.annotations != null || isInjectedAnnotationWrapper(parser.initialState);
37
40
  let context = {
38
41
  buffer: args,
39
42
  optionsTerminated: false,
@@ -56,7 +59,7 @@ function parseSync(parser, args, options) {
56
59
  const endResult = parser.complete(context.state);
57
60
  return endResult.success ? {
58
61
  success: true,
59
- value: endResult.value
62
+ value: shouldUnwrapAnnotatedValue ? unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value
60
63
  } : {
61
64
  success: false,
62
65
  error: endResult.error
@@ -82,11 +85,8 @@ function parseSync(parser, args, options) {
82
85
  * @since 0.10.0 Added optional `options` parameter for annotations support.
83
86
  */
84
87
  async function parseAsync(parser, args, options) {
85
- let initialState = parser.initialState;
86
- if (options?.annotations && initialState != null) initialState = {
87
- ...typeof initialState === "object" ? initialState : {},
88
- [annotationKey]: options.annotations
89
- };
88
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
89
+ const shouldUnwrapAnnotatedValue = options?.annotations != null || isInjectedAnnotationWrapper(parser.initialState);
90
90
  let context = {
91
91
  buffer: args,
92
92
  optionsTerminated: false,
@@ -109,7 +109,7 @@ async function parseAsync(parser, args, options) {
109
109
  const endResult = await parser.complete(context.state);
110
110
  return endResult.success ? {
111
111
  success: true,
112
- value: endResult.value
112
+ value: shouldUnwrapAnnotatedValue ? unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value
113
113
  } : {
114
114
  success: false,
115
115
  error: endResult.error
@@ -138,8 +138,7 @@ async function parseAsync(parser, args, options) {
138
138
  * @since 0.10.0 Added optional `options` parameter for annotations support.
139
139
  */
140
140
  function parse(parser, args, options) {
141
- if (parser.$mode === "async") return parseAsync(parser, args, options);
142
- return parseSync(parser, args, options);
141
+ return dispatchByMode(parser.$mode, () => parseSync(parser, args, options), () => parseAsync(parser, args, options));
143
142
  }
144
143
  /**
145
144
  * Generates command-line suggestions based on current parsing state.
@@ -180,11 +179,7 @@ function parse(parser, args, options) {
180
179
  function suggestSync(parser, args, options) {
181
180
  const allButLast = args.slice(0, -1);
182
181
  const prefix = args[args.length - 1];
183
- let initialState = parser.initialState;
184
- if (options?.annotations && initialState != null) initialState = {
185
- ...typeof initialState === "object" ? initialState : {},
186
- [annotationKey]: options.annotations
187
- };
182
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
188
183
  let context = {
189
184
  buffer: allButLast,
190
185
  optionsTerminated: false,
@@ -223,11 +218,7 @@ function suggestSync(parser, args, options) {
223
218
  async function suggestAsync(parser, args, options) {
224
219
  const allButLast = args.slice(0, -1);
225
220
  const prefix = args[args.length - 1];
226
- let initialState = parser.initialState;
227
- if (options?.annotations && initialState != null) initialState = {
228
- ...typeof initialState === "object" ? initialState : {},
229
- [annotationKey]: options.annotations
230
- };
221
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
231
222
  let context = {
232
223
  buffer: allButLast,
233
224
  optionsTerminated: false,
@@ -273,8 +264,7 @@ async function suggestAsync(parser, args, options) {
273
264
  * @since 0.10.0 Added optional `options` parameter for annotations support.
274
265
  */
275
266
  function suggest(parser, args, options) {
276
- if (parser.$mode === "async") return suggestAsync(parser, args, options);
277
- return suggestSync(parser, args, options);
267
+ return dispatchByMode(parser.$mode, () => suggestSync(parser, args, options), () => suggestAsync(parser, args, options));
278
268
  }
279
269
  /**
280
270
  * Recursively searches for a command within nested exclusive usage terms.
@@ -339,11 +329,7 @@ function getDocPage(parser, args = [], options) {
339
329
  * Internal sync implementation of getDocPage.
340
330
  */
341
331
  function getDocPageSyncImpl(parser, args, options) {
342
- let initialState = parser.initialState;
343
- if (options?.annotations && initialState != null) initialState = {
344
- ...typeof initialState === "object" ? initialState : {},
345
- [annotationKey]: options.annotations
346
- };
332
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
347
333
  let context = {
348
334
  buffer: args,
349
335
  optionsTerminated: false,
@@ -361,11 +347,7 @@ function getDocPageSyncImpl(parser, args, options) {
361
347
  * Internal async implementation of getDocPage.
362
348
  */
363
349
  async function getDocPageAsyncImpl(parser, args, options) {
364
- let initialState = parser.initialState;
365
- if (options?.annotations && initialState != null) initialState = {
366
- ...typeof initialState === "object" ? initialState : {},
367
- [annotationKey]: options.annotations
368
- };
350
+ const initialState = injectAnnotationsIntoState(parser.initialState, options);
369
351
  let context = {
370
352
  buffer: args,
371
353
  optionsTerminated: false,
@@ -384,29 +366,79 @@ async function getDocPageAsyncImpl(parser, args, options) {
384
366
  * Shared by both sync and async implementations.
385
367
  */
386
368
  function buildDocPage(parser, context, args) {
387
- const { brief, description, fragments, footer } = parser.getDocFragments({
369
+ let effectiveArgs = args;
370
+ let { brief, description, fragments, footer } = parser.getDocFragments({
388
371
  kind: "available",
389
372
  state: context.state
390
373
  }, void 0);
391
- const entries = fragments.filter((f) => f.type === "entry");
392
- const sections = [];
393
- for (const fragment of fragments) {
394
- if (fragment.type !== "section") continue;
395
- if (fragment.title == null) entries.push(...fragment.entries);
396
- else sections.push(fragment);
374
+ if (args.length === 0 && Reflect.get(parser, Symbol.for("@optique/core/commandParser")) === true && fragments.length === 1 && fragments[0].type === "entry" && fragments[0].term.type === "command") {
375
+ const cmdName = fragments[0].term.name;
376
+ const matched = parser.getDocFragments({
377
+ kind: "available",
378
+ state: ["matched", cmdName]
379
+ }, void 0);
380
+ ({brief, description, fragments, footer} = matched);
381
+ effectiveArgs = [cmdName];
397
382
  }
398
- if (entries.length > 0) sections.push({ entries });
383
+ const buildingSections = [];
384
+ let untitledSection = null;
385
+ const titledSectionMap = /* @__PURE__ */ new Map();
386
+ for (const fragment of fragments) if (fragment.type === "entry") {
387
+ if (untitledSection == null) {
388
+ untitledSection = { entries: [] };
389
+ buildingSections.push(untitledSection);
390
+ }
391
+ untitledSection.entries.push(fragment);
392
+ } else if (fragment.type === "section") if (fragment.title == null) {
393
+ if (untitledSection == null) {
394
+ untitledSection = { entries: [] };
395
+ buildingSections.push(untitledSection);
396
+ }
397
+ untitledSection.entries.push(...fragment.entries);
398
+ } else {
399
+ let section = titledSectionMap.get(fragment.title);
400
+ if (section == null) {
401
+ section = {
402
+ title: fragment.title,
403
+ entries: []
404
+ };
405
+ titledSectionMap.set(fragment.title, section);
406
+ buildingSections.push(section);
407
+ }
408
+ section.entries.push(...fragment.entries);
409
+ }
410
+ const sections = buildingSections;
399
411
  const usage = [...normalizeUsage(parser.usage)];
412
+ const maybeApplyCommandUsageLine = (term, arg, isLastArg, usageIndex) => {
413
+ if (term?.type !== "command" || term.name !== arg || !isLastArg || term.usageLine == null) return;
414
+ const defaultUsageLine = usage.slice(usageIndex + 1);
415
+ const customUsageLine = typeof term.usageLine === "function" ? term.usageLine(defaultUsageLine) : term.usageLine;
416
+ const normalizedCustomUsageLine = normalizeUsage(customUsageLine);
417
+ usage.splice(usageIndex + 1, usage.length - (usageIndex + 1), ...normalizedCustomUsageLine);
418
+ };
400
419
  let i = 0;
401
- for (const arg of args) {
420
+ for (let argIndex = 0; argIndex < effectiveArgs.length; argIndex++) {
421
+ const arg = effectiveArgs[argIndex];
402
422
  if (i >= usage.length) break;
403
- const term = usage[i];
423
+ let term = usage[i];
404
424
  if (term.type === "exclusive") {
405
425
  const found = findCommandInExclusive(term, arg);
406
- if (found) usage.splice(i, 1, ...found);
426
+ if (found) {
427
+ usage.splice(i, 1, ...found);
428
+ term = usage[i];
429
+ }
407
430
  }
431
+ maybeApplyCommandUsageLine(term, arg, argIndex === effectiveArgs.length - 1, i);
408
432
  i++;
409
433
  }
434
+ if (effectiveArgs.length === 0 && usage.length > 0) {
435
+ const first = usage[0];
436
+ if (first.type === "command" && first.usageLine != null) {
437
+ const defaultUsageLine = usage.slice(1);
438
+ const customUsageLine = typeof first.usageLine === "function" ? first.usageLine(defaultUsageLine) : first.usageLine;
439
+ usage.splice(1, usage.length - 1, ...normalizeUsage(customUsageLine));
440
+ }
441
+ }
410
442
  return {
411
443
  usage,
412
444
  sections,
@@ -417,4 +449,4 @@ function buildDocPage(parser, context, args) {
417
449
  }
418
450
 
419
451
  //#endregion
420
- export { DuplicateOptionError, WithDefaultError, argument, command, concat, conditional, constant, flag, getDocPage, getDocPageAsync, getDocPageSync, group, longestMatch, map, merge, multiple, nonEmpty, object, option, optional, or, parse, parseAsync, parseSync, passThrough, suggest, suggestAsync, suggestSync, tuple, withDefault };
452
+ export { DuplicateOptionError, WithDefaultError, argument, command, concat, conditional, constant, fail, flag, getDocPage, getDocPageAsync, getDocPageSync, group, longestMatch, map, merge, multiple, nonEmpty, object, option, optional, or, parse, parseAsync, parseSync, passThrough, suggest, suggestAsync, suggestSync, tuple, withDefault };