@optique/core 0.10.0-dev.330 → 0.10.0-dev.332

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.
@@ -0,0 +1,41 @@
1
+
2
+ //#region src/annotations.ts
3
+ /**
4
+ * Runtime context extension system for Optique parsers.
5
+ *
6
+ * This module provides the annotations system that allows external runtime data
7
+ * to be passed to parsers during the parsing session. This enables use cases like
8
+ * config file fallbacks, environment-based validation, and shared context.
9
+ *
10
+ * @module
11
+ * @since 0.10.0
12
+ */
13
+ /**
14
+ * Annotation key symbol for storing data in parser state.
15
+ * @since 0.10.0
16
+ */
17
+ const annotationKey = Symbol.for("@optique/core/parser/annotation");
18
+ /**
19
+ * Extracts annotations from parser state.
20
+ *
21
+ * @param state Parser state that may contain annotations
22
+ * @returns Annotations object or undefined if no annotations are present
23
+ * @since 0.10.0
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const annotations = getAnnotations(state);
28
+ * const myData = annotations?.[myDataKey];
29
+ * ```
30
+ */
31
+ function getAnnotations(state) {
32
+ if (state == null || typeof state !== "object") return void 0;
33
+ const stateObj = state;
34
+ const annotations = stateObj[annotationKey];
35
+ if (annotations != null && typeof annotations === "object") return annotations;
36
+ return void 0;
37
+ }
38
+
39
+ //#endregion
40
+ exports.annotationKey = annotationKey;
41
+ exports.getAnnotations = getAnnotations;
@@ -0,0 +1,60 @@
1
+ //#region src/annotations.d.ts
2
+ /**
3
+ * Runtime context extension system for Optique parsers.
4
+ *
5
+ * This module provides the annotations system that allows external runtime data
6
+ * to be passed to parsers during the parsing session. This enables use cases like
7
+ * config file fallbacks, environment-based validation, and shared context.
8
+ *
9
+ * @module
10
+ * @since 0.10.0
11
+ */
12
+ /**
13
+ * Annotation key symbol for storing data in parser state.
14
+ * @since 0.10.0
15
+ */
16
+ declare const annotationKey: unique symbol;
17
+ /**
18
+ * Annotations that can be passed to parsers during execution.
19
+ * Allows external packages to provide additional data that parsers can access
20
+ * during complete() or parse() phases.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const myDataKey = Symbol.for("@my-package/data");
25
+ * const result = parse(parser, args, {
26
+ * annotations: {
27
+ * [myDataKey]: { foo: "bar" }
28
+ * }
29
+ * });
30
+ * ```
31
+ * @since 0.10.0
32
+ */
33
+ type Annotations = Record<symbol, unknown>;
34
+ /**
35
+ * Options for parse functions.
36
+ * @since 0.10.0
37
+ */
38
+ interface ParseOptions {
39
+ /**
40
+ * Annotations to attach to the parsing session.
41
+ * Parsers can access these annotations via getAnnotations(state).
42
+ */
43
+ annotations?: Annotations;
44
+ }
45
+ /**
46
+ * Extracts annotations from parser state.
47
+ *
48
+ * @param state Parser state that may contain annotations
49
+ * @returns Annotations object or undefined if no annotations are present
50
+ * @since 0.10.0
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const annotations = getAnnotations(state);
55
+ * const myData = annotations?.[myDataKey];
56
+ * ```
57
+ */
58
+ declare function getAnnotations(state: unknown): Annotations | undefined;
59
+ //#endregion
60
+ export { Annotations, ParseOptions, annotationKey, getAnnotations };
@@ -0,0 +1,60 @@
1
+ //#region src/annotations.d.ts
2
+ /**
3
+ * Runtime context extension system for Optique parsers.
4
+ *
5
+ * This module provides the annotations system that allows external runtime data
6
+ * to be passed to parsers during the parsing session. This enables use cases like
7
+ * config file fallbacks, environment-based validation, and shared context.
8
+ *
9
+ * @module
10
+ * @since 0.10.0
11
+ */
12
+ /**
13
+ * Annotation key symbol for storing data in parser state.
14
+ * @since 0.10.0
15
+ */
16
+ declare const annotationKey: unique symbol;
17
+ /**
18
+ * Annotations that can be passed to parsers during execution.
19
+ * Allows external packages to provide additional data that parsers can access
20
+ * during complete() or parse() phases.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const myDataKey = Symbol.for("@my-package/data");
25
+ * const result = parse(parser, args, {
26
+ * annotations: {
27
+ * [myDataKey]: { foo: "bar" }
28
+ * }
29
+ * });
30
+ * ```
31
+ * @since 0.10.0
32
+ */
33
+ type Annotations = Record<symbol, unknown>;
34
+ /**
35
+ * Options for parse functions.
36
+ * @since 0.10.0
37
+ */
38
+ interface ParseOptions {
39
+ /**
40
+ * Annotations to attach to the parsing session.
41
+ * Parsers can access these annotations via getAnnotations(state).
42
+ */
43
+ annotations?: Annotations;
44
+ }
45
+ /**
46
+ * Extracts annotations from parser state.
47
+ *
48
+ * @param state Parser state that may contain annotations
49
+ * @returns Annotations object or undefined if no annotations are present
50
+ * @since 0.10.0
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const annotations = getAnnotations(state);
55
+ * const myData = annotations?.[myDataKey];
56
+ * ```
57
+ */
58
+ declare function getAnnotations(state: unknown): Annotations | undefined;
59
+ //#endregion
60
+ export { Annotations, ParseOptions, annotationKey, getAnnotations };
@@ -0,0 +1,39 @@
1
+ //#region src/annotations.ts
2
+ /**
3
+ * Runtime context extension system for Optique parsers.
4
+ *
5
+ * This module provides the annotations system that allows external runtime data
6
+ * to be passed to parsers during the parsing session. This enables use cases like
7
+ * config file fallbacks, environment-based validation, and shared context.
8
+ *
9
+ * @module
10
+ * @since 0.10.0
11
+ */
12
+ /**
13
+ * Annotation key symbol for storing data in parser state.
14
+ * @since 0.10.0
15
+ */
16
+ const annotationKey = Symbol.for("@optique/core/parser/annotation");
17
+ /**
18
+ * Extracts annotations from parser state.
19
+ *
20
+ * @param state Parser state that may contain annotations
21
+ * @returns Annotations object or undefined if no annotations are present
22
+ * @since 0.10.0
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const annotations = getAnnotations(state);
27
+ * const myData = annotations?.[myDataKey];
28
+ * ```
29
+ */
30
+ function getAnnotations(state) {
31
+ if (state == null || typeof state !== "object") return void 0;
32
+ const stateObj = state;
33
+ const annotations = stateObj[annotationKey];
34
+ if (annotations != null && typeof annotations === "object") return annotations;
35
+ return void 0;
36
+ }
37
+
38
+ //#endregion
39
+ export { annotationKey, getAnnotations };
@@ -0,0 +1,21 @@
1
+
2
+ //#region src/context.ts
3
+ /**
4
+ * Checks whether a context is static (returns annotations without needing
5
+ * parsed results).
6
+ *
7
+ * A context is considered static if `getAnnotations()` called without
8
+ * arguments returns a non-empty annotations object synchronously.
9
+ *
10
+ * @param context The source context to check.
11
+ * @returns `true` if the context is static, `false` otherwise.
12
+ * @since 0.10.0
13
+ */
14
+ function isStaticContext(context) {
15
+ const result = context.getAnnotations();
16
+ if (result instanceof Promise) return false;
17
+ return Object.getOwnPropertySymbols(result).length > 0;
18
+ }
19
+
20
+ //#endregion
21
+ exports.isStaticContext = isStaticContext;
@@ -0,0 +1,87 @@
1
+ import { Annotations } from "./annotations.cjs";
2
+
3
+ //#region src/context.d.ts
4
+
5
+ /**
6
+ * A source context that can provide data to parsers via annotations.
7
+ *
8
+ * Source contexts are used to inject external data (like environment variables
9
+ * or config files) into the parsing process. They can be either:
10
+ *
11
+ * - *Static*: Data is immediately available (e.g., environment variables)
12
+ * - *Dynamic*: Data depends on parsing results (e.g., config files whose path
13
+ * is determined by a CLI option)
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // Static context example (environment variables)
18
+ * const envContext: SourceContext = {
19
+ * id: Symbol.for("@myapp/env"),
20
+ * getAnnotations() {
21
+ * return {
22
+ * [Symbol.for("@myapp/env")]: {
23
+ * HOST: process.env.HOST,
24
+ * PORT: process.env.PORT,
25
+ * }
26
+ * };
27
+ * }
28
+ * };
29
+ *
30
+ * // Dynamic context example (config file)
31
+ * const configContext: SourceContext = {
32
+ * id: Symbol.for("@myapp/config"),
33
+ * async getAnnotations(parsed?: unknown) {
34
+ * if (!parsed) return {}; // Return empty on first pass
35
+ * const result = parsed as { config?: string };
36
+ * if (!result.config) return {};
37
+ * const data = await loadConfigFile(result.config);
38
+ * return {
39
+ * [Symbol.for("@myapp/config")]: data
40
+ * };
41
+ * }
42
+ * };
43
+ * ```
44
+ *
45
+ * @since 0.10.0
46
+ */
47
+ interface SourceContext {
48
+ /**
49
+ * Unique identifier for this context.
50
+ *
51
+ * This symbol is typically the same as the annotation key used by parsers
52
+ * that consume this context's data.
53
+ */
54
+ readonly id: symbol;
55
+ /**
56
+ * Get annotations to inject into parsing.
57
+ *
58
+ * This method is called twice during `runWith()` execution:
59
+ *
60
+ * 1. *First call*: `parsed` is `undefined`. Static contexts should return
61
+ * their annotations, while dynamic contexts should return an empty object.
62
+ * 2. *Second call*: `parsed` contains the result from the first parse pass.
63
+ * Dynamic contexts can use this to load external data (e.g., reading
64
+ * a config file whose path was determined in the first pass).
65
+ *
66
+ * @param parsed Optional parsed result from a previous parse pass.
67
+ * Static contexts can ignore this parameter.
68
+ * Dynamic contexts use this to extract necessary data.
69
+ * @returns Annotations to merge into the parsing session. Can be a Promise
70
+ * for async operations (e.g., loading config files).
71
+ */
72
+ getAnnotations(parsed?: unknown): Promise<Annotations> | Annotations;
73
+ }
74
+ /**
75
+ * Checks whether a context is static (returns annotations without needing
76
+ * parsed results).
77
+ *
78
+ * A context is considered static if `getAnnotations()` called without
79
+ * arguments returns a non-empty annotations object synchronously.
80
+ *
81
+ * @param context The source context to check.
82
+ * @returns `true` if the context is static, `false` otherwise.
83
+ * @since 0.10.0
84
+ */
85
+ declare function isStaticContext(context: SourceContext): boolean;
86
+ //#endregion
87
+ export { type Annotations, SourceContext, isStaticContext };
@@ -0,0 +1,87 @@
1
+ import { Annotations } from "./annotations.js";
2
+
3
+ //#region src/context.d.ts
4
+
5
+ /**
6
+ * A source context that can provide data to parsers via annotations.
7
+ *
8
+ * Source contexts are used to inject external data (like environment variables
9
+ * or config files) into the parsing process. They can be either:
10
+ *
11
+ * - *Static*: Data is immediately available (e.g., environment variables)
12
+ * - *Dynamic*: Data depends on parsing results (e.g., config files whose path
13
+ * is determined by a CLI option)
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // Static context example (environment variables)
18
+ * const envContext: SourceContext = {
19
+ * id: Symbol.for("@myapp/env"),
20
+ * getAnnotations() {
21
+ * return {
22
+ * [Symbol.for("@myapp/env")]: {
23
+ * HOST: process.env.HOST,
24
+ * PORT: process.env.PORT,
25
+ * }
26
+ * };
27
+ * }
28
+ * };
29
+ *
30
+ * // Dynamic context example (config file)
31
+ * const configContext: SourceContext = {
32
+ * id: Symbol.for("@myapp/config"),
33
+ * async getAnnotations(parsed?: unknown) {
34
+ * if (!parsed) return {}; // Return empty on first pass
35
+ * const result = parsed as { config?: string };
36
+ * if (!result.config) return {};
37
+ * const data = await loadConfigFile(result.config);
38
+ * return {
39
+ * [Symbol.for("@myapp/config")]: data
40
+ * };
41
+ * }
42
+ * };
43
+ * ```
44
+ *
45
+ * @since 0.10.0
46
+ */
47
+ interface SourceContext {
48
+ /**
49
+ * Unique identifier for this context.
50
+ *
51
+ * This symbol is typically the same as the annotation key used by parsers
52
+ * that consume this context's data.
53
+ */
54
+ readonly id: symbol;
55
+ /**
56
+ * Get annotations to inject into parsing.
57
+ *
58
+ * This method is called twice during `runWith()` execution:
59
+ *
60
+ * 1. *First call*: `parsed` is `undefined`. Static contexts should return
61
+ * their annotations, while dynamic contexts should return an empty object.
62
+ * 2. *Second call*: `parsed` contains the result from the first parse pass.
63
+ * Dynamic contexts can use this to load external data (e.g., reading
64
+ * a config file whose path was determined in the first pass).
65
+ *
66
+ * @param parsed Optional parsed result from a previous parse pass.
67
+ * Static contexts can ignore this parameter.
68
+ * Dynamic contexts use this to extract necessary data.
69
+ * @returns Annotations to merge into the parsing session. Can be a Promise
70
+ * for async operations (e.g., loading config files).
71
+ */
72
+ getAnnotations(parsed?: unknown): Promise<Annotations> | Annotations;
73
+ }
74
+ /**
75
+ * Checks whether a context is static (returns annotations without needing
76
+ * parsed results).
77
+ *
78
+ * A context is considered static if `getAnnotations()` called without
79
+ * arguments returns a non-empty annotations object synchronously.
80
+ *
81
+ * @param context The source context to check.
82
+ * @returns `true` if the context is static, `false` otherwise.
83
+ * @since 0.10.0
84
+ */
85
+ declare function isStaticContext(context: SourceContext): boolean;
86
+ //#endregion
87
+ export { type Annotations, SourceContext, isStaticContext };
@@ -0,0 +1,20 @@
1
+ //#region src/context.ts
2
+ /**
3
+ * Checks whether a context is static (returns annotations without needing
4
+ * parsed results).
5
+ *
6
+ * A context is considered static if `getAnnotations()` called without
7
+ * arguments returns a non-empty annotations object synchronously.
8
+ *
9
+ * @param context The source context to check.
10
+ * @returns `true` if the context is static, `false` otherwise.
11
+ * @since 0.10.0
12
+ */
13
+ function isStaticContext(context) {
14
+ const result = context.getAnnotations();
15
+ if (result instanceof Promise) return false;
16
+ return Object.getOwnPropertySymbols(result).length > 0;
17
+ }
18
+
19
+ //#endregion
20
+ export { isStaticContext };
package/dist/facade.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ const require_annotations = require('./annotations.cjs');
1
2
  const require_message = require('./message.cjs');
2
3
  const require_completion = require('./completion.cjs');
3
4
  const require_usage = require('./usage.cjs');
@@ -658,9 +659,244 @@ var RunParserError = class extends Error {
658
659
  function indentLines(text$1, indent) {
659
660
  return text$1.split("\n").join("\n" + " ".repeat(indent));
660
661
  }
662
+ /**
663
+ * Merges multiple annotation objects, with earlier contexts having priority.
664
+ *
665
+ * When the same symbol key exists in multiple annotations, the value from
666
+ * the earlier context (lower index in the array) takes precedence.
667
+ *
668
+ * @param annotationsList Array of annotations to merge.
669
+ * @returns Merged annotations object.
670
+ */
671
+ function mergeAnnotations(annotationsList) {
672
+ const result = {};
673
+ for (let i = annotationsList.length - 1; i >= 0; i--) {
674
+ const annotations = annotationsList[i];
675
+ for (const key of Object.getOwnPropertySymbols(annotations)) result[key] = annotations[key];
676
+ }
677
+ return result;
678
+ }
679
+ /**
680
+ * Collects annotations from all contexts.
681
+ *
682
+ * @param contexts Source contexts to collect annotations from.
683
+ * @param parsed Optional parsed result from a previous parse pass.
684
+ * @returns Promise that resolves to merged annotations.
685
+ */
686
+ async function collectAnnotations(contexts, parsed) {
687
+ const annotationsList = [];
688
+ for (const context of contexts) {
689
+ const result = context.getAnnotations(parsed);
690
+ if (result instanceof Promise) annotationsList.push(await result);
691
+ else annotationsList.push(result);
692
+ }
693
+ return mergeAnnotations(annotationsList);
694
+ }
695
+ /**
696
+ * Collects annotations from all contexts synchronously.
697
+ *
698
+ * @param contexts Source contexts to collect annotations from.
699
+ * @param parsed Optional parsed result from a previous parse pass.
700
+ * @returns Merged annotations.
701
+ * @throws Error if any context returns a Promise.
702
+ */
703
+ function collectAnnotationsSync(contexts, parsed) {
704
+ const annotationsList = [];
705
+ for (const context of contexts) {
706
+ const result = context.getAnnotations(parsed);
707
+ if (result instanceof Promise) throw new Error(`Context ${String(context.id)} returned a Promise in sync mode. Use runWith() or runWithAsync() for async contexts.`);
708
+ annotationsList.push(result);
709
+ }
710
+ return mergeAnnotations(annotationsList);
711
+ }
712
+ /**
713
+ * Checks if any context has dynamic behavior (returns different annotations
714
+ * when called with parsed results).
715
+ *
716
+ * A context is considered dynamic if:
717
+ * - It returns a Promise
718
+ * - It returns empty annotations without parsed results but may return
719
+ * non-empty annotations with parsed results
720
+ *
721
+ * @param contexts Source contexts to check.
722
+ * @returns `true` if any context appears to be dynamic.
723
+ */
724
+ function hasDynamicContexts(contexts) {
725
+ for (const context of contexts) {
726
+ const result = context.getAnnotations();
727
+ if (result instanceof Promise) return true;
728
+ if (Object.getOwnPropertySymbols(result).length === 0) return true;
729
+ }
730
+ return false;
731
+ }
732
+ /**
733
+ * Runs a parser with multiple source contexts.
734
+ *
735
+ * This function automatically handles static and dynamic contexts with proper
736
+ * priority. Earlier contexts in the array override later ones.
737
+ *
738
+ * The function uses a smart two-phase approach:
739
+ *
740
+ * 1. *Phase 1*: Collect annotations from all contexts (static contexts return
741
+ * their data, dynamic contexts may return empty).
742
+ * 2. *First parse*: Parse with Phase 1 annotations.
743
+ * 3. *Phase 2*: Call `getAnnotations(parsed)` on all contexts with the first
744
+ * parse result.
745
+ * 4. *Second parse*: Parse again with merged annotations from both phases.
746
+ *
747
+ * If all contexts are static (no dynamic contexts), the second parse is skipped
748
+ * for optimization.
749
+ *
750
+ * @template TParser The parser type.
751
+ * @template THelp Return type when help is shown.
752
+ * @template TError Return type when an error occurs.
753
+ * @param parser The parser to execute.
754
+ * @param programName Name of the program for help/error output.
755
+ * @param contexts Source contexts to use (priority: earlier overrides later).
756
+ * @param options Run options including args, help, version, etc.
757
+ * @returns Promise that resolves to the parsed result.
758
+ * @since 0.10.0
759
+ *
760
+ * @example
761
+ * ```typescript
762
+ * import { runWith } from "@optique/core/facade";
763
+ * import type { SourceContext } from "@optique/core/context";
764
+ *
765
+ * const envContext: SourceContext = {
766
+ * id: Symbol.for("@myapp/env"),
767
+ * getAnnotations() {
768
+ * return { [Symbol.for("@myapp/env")]: process.env };
769
+ * }
770
+ * };
771
+ *
772
+ * const result = await runWith(
773
+ * parser,
774
+ * "myapp",
775
+ * [envContext],
776
+ * { args: process.argv.slice(2) }
777
+ * );
778
+ * ```
779
+ */
780
+ async function runWith(parser, programName, contexts, options) {
781
+ const args = options?.args ?? [];
782
+ if (contexts.length === 0) {
783
+ if (parser.$mode === "async") return runParser(parser, programName, args, options);
784
+ return Promise.resolve(runParser(parser, programName, args, options));
785
+ }
786
+ const phase1Annotations = await collectAnnotations(contexts);
787
+ const needsTwoPhase = hasDynamicContexts(contexts);
788
+ if (!needsTwoPhase) {
789
+ const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
790
+ if (parser.$mode === "async") return runParser(augmentedParser, programName, args, options);
791
+ return Promise.resolve(runParser(augmentedParser, programName, args, options));
792
+ }
793
+ const augmentedParser1 = injectAnnotationsIntoParser(parser, phase1Annotations);
794
+ let firstPassResult;
795
+ try {
796
+ if (parser.$mode === "async") firstPassResult = await require_parser.parseAsync(augmentedParser1, args);
797
+ else firstPassResult = require_parser.parseSync(augmentedParser1, args);
798
+ if (typeof firstPassResult === "object" && firstPassResult !== null && "success" in firstPassResult) {
799
+ const result = firstPassResult;
800
+ if (result.success) firstPassResult = result.value;
801
+ else {
802
+ const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
803
+ if (parser.$mode === "async") return runParser(augmentedParser, programName, args, options);
804
+ return Promise.resolve(runParser(augmentedParser, programName, args, options));
805
+ }
806
+ }
807
+ } catch {
808
+ const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
809
+ if (parser.$mode === "async") return runParser(augmentedParser, programName, args, options);
810
+ return Promise.resolve(runParser(augmentedParser, programName, args, options));
811
+ }
812
+ const phase2Annotations = await collectAnnotations(contexts, firstPassResult);
813
+ const finalAnnotations = mergeAnnotations([phase1Annotations, phase2Annotations]);
814
+ const augmentedParser2 = injectAnnotationsIntoParser(parser, finalAnnotations);
815
+ if (parser.$mode === "async") return runParser(augmentedParser2, programName, args, options);
816
+ return Promise.resolve(runParser(augmentedParser2, programName, args, options));
817
+ }
818
+ /**
819
+ * Runs a synchronous parser with multiple source contexts.
820
+ *
821
+ * This is the sync-only variant of {@link runWith}. All contexts must return
822
+ * annotations synchronously (not Promises).
823
+ *
824
+ * @template TParser The sync parser type.
825
+ * @template THelp Return type when help is shown.
826
+ * @template TError Return type when an error occurs.
827
+ * @param parser The synchronous parser to execute.
828
+ * @param programName Name of the program for help/error output.
829
+ * @param contexts Source contexts to use (priority: earlier overrides later).
830
+ * @param options Run options including args, help, version, etc.
831
+ * @returns The parsed result.
832
+ * @throws Error if any context returns a Promise.
833
+ * @since 0.10.0
834
+ */
835
+ function runWithSync(parser, programName, contexts, options) {
836
+ const args = options?.args ?? [];
837
+ if (contexts.length === 0) return runParser(parser, programName, args, options);
838
+ const phase1Annotations = collectAnnotationsSync(contexts);
839
+ const needsTwoPhase = hasDynamicContexts(contexts);
840
+ if (!needsTwoPhase) {
841
+ const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
842
+ return runParser(augmentedParser, programName, args, options);
843
+ }
844
+ const augmentedParser1 = injectAnnotationsIntoParser(parser, phase1Annotations);
845
+ let firstPassResult;
846
+ try {
847
+ const result = require_parser.parseSync(augmentedParser1, args);
848
+ if (result.success) firstPassResult = result.value;
849
+ else return runParser(augmentedParser1, programName, args, options);
850
+ } catch {
851
+ return runParser(augmentedParser1, programName, args, options);
852
+ }
853
+ const phase2Annotations = collectAnnotationsSync(contexts, firstPassResult);
854
+ const finalAnnotations = mergeAnnotations([phase1Annotations, phase2Annotations]);
855
+ const augmentedParser2 = injectAnnotationsIntoParser(parser, finalAnnotations);
856
+ return runParser(augmentedParser2, programName, args, options);
857
+ }
858
+ /**
859
+ * Runs any parser asynchronously with multiple source contexts.
860
+ *
861
+ * This function accepts parsers of any mode (sync or async) and always
862
+ * returns a Promise. Use this when working with async contexts or parsers.
863
+ *
864
+ * @template TParser The parser type.
865
+ * @template THelp Return type when help is shown.
866
+ * @template TError Return type when an error occurs.
867
+ * @param parser The parser to execute.
868
+ * @param programName Name of the program for help/error output.
869
+ * @param contexts Source contexts to use (priority: earlier overrides later).
870
+ * @param options Run options including args, help, version, etc.
871
+ * @returns Promise that resolves to the parsed result.
872
+ * @since 0.10.0
873
+ */
874
+ function runWithAsync(parser, programName, contexts, options) {
875
+ return runWith(parser, programName, contexts, options);
876
+ }
877
+ /**
878
+ * Creates a new parser with annotations injected into its initial state.
879
+ *
880
+ * @param parser The original parser.
881
+ * @param annotations Annotations to inject.
882
+ * @returns A new parser with annotations in its initial state.
883
+ */
884
+ function injectAnnotationsIntoParser(parser, annotations) {
885
+ const newInitialState = {
886
+ ...parser.initialState,
887
+ [require_annotations.annotationKey]: annotations
888
+ };
889
+ return {
890
+ ...parser,
891
+ initialState: newInitialState
892
+ };
893
+ }
661
894
 
662
895
  //#endregion
663
896
  exports.RunParserError = RunParserError;
664
897
  exports.runParser = runParser;
665
898
  exports.runParserAsync = runParserAsync;
666
- exports.runParserSync = runParserSync;
899
+ exports.runParserSync = runParserSync;
900
+ exports.runWith = runWith;
901
+ exports.runWithAsync = runWithAsync;
902
+ exports.runWithSync = runWithSync;