@optique/core 0.10.0-dev.331 → 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.
- package/dist/context.cjs +21 -0
- package/dist/context.d.cts +87 -0
- package/dist/context.d.ts +87 -0
- package/dist/context.js +20 -0
- package/dist/facade.cjs +237 -1
- package/dist/facade.d.cts +101 -1
- package/dist/facade.d.ts +101 -1
- package/dist/facade.js +234 -1
- package/dist/index.cjs +3 -0
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -2
- package/package.json +9 -1
package/dist/context.cjs
ADDED
|
@@ -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 };
|
package/dist/context.js
ADDED
|
@@ -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;
|
package/dist/facade.d.cts
CHANGED
|
@@ -2,6 +2,7 @@ import { Message } from "./message.cjs";
|
|
|
2
2
|
import { ShowDefaultOptions } from "./doc.cjs";
|
|
3
3
|
import { InferMode, InferValue, Mode, ModeValue, Parser } from "./parser.cjs";
|
|
4
4
|
import { ShellCompletion } from "./completion.cjs";
|
|
5
|
+
import { SourceContext } from "./context.cjs";
|
|
5
6
|
import { Program } from "./program.cjs";
|
|
6
7
|
|
|
7
8
|
//#region src/facade.d.ts
|
|
@@ -282,5 +283,104 @@ declare function runParserAsync<TParser extends Parser<Mode, unknown, unknown>,
|
|
|
282
283
|
declare class RunParserError extends Error {
|
|
283
284
|
constructor(message: string);
|
|
284
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Options for runWith functions.
|
|
288
|
+
* Extends RunOptions with additional context-related settings.
|
|
289
|
+
*
|
|
290
|
+
* @template THelp The return type when help is shown.
|
|
291
|
+
* @template TError The return type when an error occurs.
|
|
292
|
+
* @since 0.10.0
|
|
293
|
+
*/
|
|
294
|
+
interface RunWithOptions<THelp, TError> extends RunOptions<THelp, TError> {
|
|
295
|
+
/**
|
|
296
|
+
* Command-line arguments to parse. If not provided, defaults to
|
|
297
|
+
* `process.argv.slice(2)` on Node.js/Bun or `Deno.args` on Deno.
|
|
298
|
+
*/
|
|
299
|
+
readonly args?: readonly string[];
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Runs a parser with multiple source contexts.
|
|
303
|
+
*
|
|
304
|
+
* This function automatically handles static and dynamic contexts with proper
|
|
305
|
+
* priority. Earlier contexts in the array override later ones.
|
|
306
|
+
*
|
|
307
|
+
* The function uses a smart two-phase approach:
|
|
308
|
+
*
|
|
309
|
+
* 1. *Phase 1*: Collect annotations from all contexts (static contexts return
|
|
310
|
+
* their data, dynamic contexts may return empty).
|
|
311
|
+
* 2. *First parse*: Parse with Phase 1 annotations.
|
|
312
|
+
* 3. *Phase 2*: Call `getAnnotations(parsed)` on all contexts with the first
|
|
313
|
+
* parse result.
|
|
314
|
+
* 4. *Second parse*: Parse again with merged annotations from both phases.
|
|
315
|
+
*
|
|
316
|
+
* If all contexts are static (no dynamic contexts), the second parse is skipped
|
|
317
|
+
* for optimization.
|
|
318
|
+
*
|
|
319
|
+
* @template TParser The parser type.
|
|
320
|
+
* @template THelp Return type when help is shown.
|
|
321
|
+
* @template TError Return type when an error occurs.
|
|
322
|
+
* @param parser The parser to execute.
|
|
323
|
+
* @param programName Name of the program for help/error output.
|
|
324
|
+
* @param contexts Source contexts to use (priority: earlier overrides later).
|
|
325
|
+
* @param options Run options including args, help, version, etc.
|
|
326
|
+
* @returns Promise that resolves to the parsed result.
|
|
327
|
+
* @since 0.10.0
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```typescript
|
|
331
|
+
* import { runWith } from "@optique/core/facade";
|
|
332
|
+
* import type { SourceContext } from "@optique/core/context";
|
|
333
|
+
*
|
|
334
|
+
* const envContext: SourceContext = {
|
|
335
|
+
* id: Symbol.for("@myapp/env"),
|
|
336
|
+
* getAnnotations() {
|
|
337
|
+
* return { [Symbol.for("@myapp/env")]: process.env };
|
|
338
|
+
* }
|
|
339
|
+
* };
|
|
340
|
+
*
|
|
341
|
+
* const result = await runWith(
|
|
342
|
+
* parser,
|
|
343
|
+
* "myapp",
|
|
344
|
+
* [envContext],
|
|
345
|
+
* { args: process.argv.slice(2) }
|
|
346
|
+
* );
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
declare function runWith<TParser extends Parser<Mode, unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, contexts: readonly SourceContext[], options?: RunWithOptions<THelp, TError>): Promise<InferValue<TParser>>;
|
|
350
|
+
/**
|
|
351
|
+
* Runs a synchronous parser with multiple source contexts.
|
|
352
|
+
*
|
|
353
|
+
* This is the sync-only variant of {@link runWith}. All contexts must return
|
|
354
|
+
* annotations synchronously (not Promises).
|
|
355
|
+
*
|
|
356
|
+
* @template TParser The sync parser type.
|
|
357
|
+
* @template THelp Return type when help is shown.
|
|
358
|
+
* @template TError Return type when an error occurs.
|
|
359
|
+
* @param parser The synchronous parser to execute.
|
|
360
|
+
* @param programName Name of the program for help/error output.
|
|
361
|
+
* @param contexts Source contexts to use (priority: earlier overrides later).
|
|
362
|
+
* @param options Run options including args, help, version, etc.
|
|
363
|
+
* @returns The parsed result.
|
|
364
|
+
* @throws Error if any context returns a Promise.
|
|
365
|
+
* @since 0.10.0
|
|
366
|
+
*/
|
|
367
|
+
declare function runWithSync<TParser extends Parser<"sync", unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, contexts: readonly SourceContext[], options?: RunWithOptions<THelp, TError>): InferValue<TParser>;
|
|
368
|
+
/**
|
|
369
|
+
* Runs any parser asynchronously with multiple source contexts.
|
|
370
|
+
*
|
|
371
|
+
* This function accepts parsers of any mode (sync or async) and always
|
|
372
|
+
* returns a Promise. Use this when working with async contexts or parsers.
|
|
373
|
+
*
|
|
374
|
+
* @template TParser The parser type.
|
|
375
|
+
* @template THelp Return type when help is shown.
|
|
376
|
+
* @template TError Return type when an error occurs.
|
|
377
|
+
* @param parser The parser to execute.
|
|
378
|
+
* @param programName Name of the program for help/error output.
|
|
379
|
+
* @param contexts Source contexts to use (priority: earlier overrides later).
|
|
380
|
+
* @param options Run options including args, help, version, etc.
|
|
381
|
+
* @returns Promise that resolves to the parsed result.
|
|
382
|
+
* @since 0.10.0
|
|
383
|
+
*/
|
|
384
|
+
declare function runWithAsync<TParser extends Parser<Mode, unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, contexts: readonly SourceContext[], options?: RunWithOptions<THelp, TError>): Promise<InferValue<TParser>>;
|
|
285
385
|
//#endregion
|
|
286
|
-
export { RunOptions, RunParserError, runParser, runParserAsync, runParserSync };
|
|
386
|
+
export { RunOptions, RunParserError, RunWithOptions, type SourceContext, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync };
|
package/dist/facade.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Message } from "./message.js";
|
|
|
2
2
|
import { ShowDefaultOptions } from "./doc.js";
|
|
3
3
|
import { InferMode, InferValue, Mode, ModeValue, Parser } from "./parser.js";
|
|
4
4
|
import { ShellCompletion } from "./completion.js";
|
|
5
|
+
import { SourceContext } from "./context.js";
|
|
5
6
|
import { Program } from "./program.js";
|
|
6
7
|
|
|
7
8
|
//#region src/facade.d.ts
|
|
@@ -282,5 +283,104 @@ declare function runParserAsync<TParser extends Parser<Mode, unknown, unknown>,
|
|
|
282
283
|
declare class RunParserError extends Error {
|
|
283
284
|
constructor(message: string);
|
|
284
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Options for runWith functions.
|
|
288
|
+
* Extends RunOptions with additional context-related settings.
|
|
289
|
+
*
|
|
290
|
+
* @template THelp The return type when help is shown.
|
|
291
|
+
* @template TError The return type when an error occurs.
|
|
292
|
+
* @since 0.10.0
|
|
293
|
+
*/
|
|
294
|
+
interface RunWithOptions<THelp, TError> extends RunOptions<THelp, TError> {
|
|
295
|
+
/**
|
|
296
|
+
* Command-line arguments to parse. If not provided, defaults to
|
|
297
|
+
* `process.argv.slice(2)` on Node.js/Bun or `Deno.args` on Deno.
|
|
298
|
+
*/
|
|
299
|
+
readonly args?: readonly string[];
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Runs a parser with multiple source contexts.
|
|
303
|
+
*
|
|
304
|
+
* This function automatically handles static and dynamic contexts with proper
|
|
305
|
+
* priority. Earlier contexts in the array override later ones.
|
|
306
|
+
*
|
|
307
|
+
* The function uses a smart two-phase approach:
|
|
308
|
+
*
|
|
309
|
+
* 1. *Phase 1*: Collect annotations from all contexts (static contexts return
|
|
310
|
+
* their data, dynamic contexts may return empty).
|
|
311
|
+
* 2. *First parse*: Parse with Phase 1 annotations.
|
|
312
|
+
* 3. *Phase 2*: Call `getAnnotations(parsed)` on all contexts with the first
|
|
313
|
+
* parse result.
|
|
314
|
+
* 4. *Second parse*: Parse again with merged annotations from both phases.
|
|
315
|
+
*
|
|
316
|
+
* If all contexts are static (no dynamic contexts), the second parse is skipped
|
|
317
|
+
* for optimization.
|
|
318
|
+
*
|
|
319
|
+
* @template TParser The parser type.
|
|
320
|
+
* @template THelp Return type when help is shown.
|
|
321
|
+
* @template TError Return type when an error occurs.
|
|
322
|
+
* @param parser The parser to execute.
|
|
323
|
+
* @param programName Name of the program for help/error output.
|
|
324
|
+
* @param contexts Source contexts to use (priority: earlier overrides later).
|
|
325
|
+
* @param options Run options including args, help, version, etc.
|
|
326
|
+
* @returns Promise that resolves to the parsed result.
|
|
327
|
+
* @since 0.10.0
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```typescript
|
|
331
|
+
* import { runWith } from "@optique/core/facade";
|
|
332
|
+
* import type { SourceContext } from "@optique/core/context";
|
|
333
|
+
*
|
|
334
|
+
* const envContext: SourceContext = {
|
|
335
|
+
* id: Symbol.for("@myapp/env"),
|
|
336
|
+
* getAnnotations() {
|
|
337
|
+
* return { [Symbol.for("@myapp/env")]: process.env };
|
|
338
|
+
* }
|
|
339
|
+
* };
|
|
340
|
+
*
|
|
341
|
+
* const result = await runWith(
|
|
342
|
+
* parser,
|
|
343
|
+
* "myapp",
|
|
344
|
+
* [envContext],
|
|
345
|
+
* { args: process.argv.slice(2) }
|
|
346
|
+
* );
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
declare function runWith<TParser extends Parser<Mode, unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, contexts: readonly SourceContext[], options?: RunWithOptions<THelp, TError>): Promise<InferValue<TParser>>;
|
|
350
|
+
/**
|
|
351
|
+
* Runs a synchronous parser with multiple source contexts.
|
|
352
|
+
*
|
|
353
|
+
* This is the sync-only variant of {@link runWith}. All contexts must return
|
|
354
|
+
* annotations synchronously (not Promises).
|
|
355
|
+
*
|
|
356
|
+
* @template TParser The sync parser type.
|
|
357
|
+
* @template THelp Return type when help is shown.
|
|
358
|
+
* @template TError Return type when an error occurs.
|
|
359
|
+
* @param parser The synchronous parser to execute.
|
|
360
|
+
* @param programName Name of the program for help/error output.
|
|
361
|
+
* @param contexts Source contexts to use (priority: earlier overrides later).
|
|
362
|
+
* @param options Run options including args, help, version, etc.
|
|
363
|
+
* @returns The parsed result.
|
|
364
|
+
* @throws Error if any context returns a Promise.
|
|
365
|
+
* @since 0.10.0
|
|
366
|
+
*/
|
|
367
|
+
declare function runWithSync<TParser extends Parser<"sync", unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, contexts: readonly SourceContext[], options?: RunWithOptions<THelp, TError>): InferValue<TParser>;
|
|
368
|
+
/**
|
|
369
|
+
* Runs any parser asynchronously with multiple source contexts.
|
|
370
|
+
*
|
|
371
|
+
* This function accepts parsers of any mode (sync or async) and always
|
|
372
|
+
* returns a Promise. Use this when working with async contexts or parsers.
|
|
373
|
+
*
|
|
374
|
+
* @template TParser The parser type.
|
|
375
|
+
* @template THelp Return type when help is shown.
|
|
376
|
+
* @template TError Return type when an error occurs.
|
|
377
|
+
* @param parser The parser to execute.
|
|
378
|
+
* @param programName Name of the program for help/error output.
|
|
379
|
+
* @param contexts Source contexts to use (priority: earlier overrides later).
|
|
380
|
+
* @param options Run options including args, help, version, etc.
|
|
381
|
+
* @returns Promise that resolves to the parsed result.
|
|
382
|
+
* @since 0.10.0
|
|
383
|
+
*/
|
|
384
|
+
declare function runWithAsync<TParser extends Parser<Mode, unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, contexts: readonly SourceContext[], options?: RunWithOptions<THelp, TError>): Promise<InferValue<TParser>>;
|
|
285
385
|
//#endregion
|
|
286
|
-
export { RunOptions, RunParserError, runParser, runParserAsync, runParserSync };
|
|
386
|
+
export { RunOptions, RunParserError, RunWithOptions, type SourceContext, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync };
|
package/dist/facade.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { annotationKey } from "./annotations.js";
|
|
1
2
|
import { commandLine, formatMessage, message, optionName, text, value } from "./message.js";
|
|
2
3
|
import { bash, fish, nu, pwsh, zsh } from "./completion.js";
|
|
3
4
|
import { formatUsage } from "./usage.js";
|
|
@@ -658,6 +659,238 @@ 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 parseAsync(augmentedParser1, args);
|
|
797
|
+
else firstPassResult = 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 = 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
|
+
[annotationKey]: annotations
|
|
888
|
+
};
|
|
889
|
+
return {
|
|
890
|
+
...parser,
|
|
891
|
+
initialState: newInitialState
|
|
892
|
+
};
|
|
893
|
+
}
|
|
661
894
|
|
|
662
895
|
//#endregion
|
|
663
|
-
export { RunParserError, runParser, runParserAsync, runParserSync };
|
|
896
|
+
export { RunParserError, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync };
|
package/dist/index.cjs
CHANGED
|
@@ -95,6 +95,9 @@ exports.pwsh = require_completion.pwsh;
|
|
|
95
95
|
exports.runParser = require_facade.runParser;
|
|
96
96
|
exports.runParserAsync = require_facade.runParserAsync;
|
|
97
97
|
exports.runParserSync = require_facade.runParserSync;
|
|
98
|
+
exports.runWith = require_facade.runWith;
|
|
99
|
+
exports.runWithAsync = require_facade.runWithAsync;
|
|
100
|
+
exports.runWithSync = require_facade.runWithSync;
|
|
98
101
|
exports.string = require_valueparser.string;
|
|
99
102
|
exports.suggest = require_parser.suggest;
|
|
100
103
|
exports.suggestAsync = require_parser.suggestAsync;
|
package/dist/index.d.cts
CHANGED
|
@@ -10,5 +10,6 @@ import { AnyDependencySource, CombineMode, CombinedDependencyMode, DeferredParse
|
|
|
10
10
|
import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.cjs";
|
|
11
11
|
import { CombineModes, DocState, InferMode, InferValue, Mode, ModeIterable, ModeValue, Parser, ParserContext, ParserResult, Result, Suggestion, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./parser.cjs";
|
|
12
12
|
import { ShellCompletion, bash, fish, nu, pwsh, zsh } from "./completion.cjs";
|
|
13
|
-
import {
|
|
14
|
-
|
|
13
|
+
import { SourceContext } from "./context.cjs";
|
|
14
|
+
import { RunOptions, RunParserError, RunWithOptions, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync } from "./facade.cjs";
|
|
15
|
+
export { type Annotations, AnyDependencySource, ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CombineMode, CombineModes, CombinedDependencyMode, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DeferredParseState, DependencyError, DependencyMode, DependencyRegistry, DependencySource, DependencySourceState, DependencyValue, DependencyValues, DeriveAsyncOptions, DeriveFromAsyncOptions, DeriveFromOptions, DeriveFromSyncOptions, DeriveOptions, DeriveSyncOptions, DerivedValueParser, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, DuplicateOptionError, FlagErrorOptions, FlagOptions, FloatOptions, InferMode, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, type Message, type MessageFormatOptions, type MessageTerm, Mode, ModeIterable, ModeValue, MultipleErrorOptions, MultipleOptions, NoMatchContext, NonEmptyString, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OptionState, OrErrorOptions, OrOptions, type ParseOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, PendingDependencySourceState, ResolvedDependency, Result, RunOptions, RunParserError, RunWithOptions, ShellCompletion, ShowDefaultOptions, SourceContext, StringOptions, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, type ValueSetOptions, WithDefaultError, WithDefaultOptions, annotationKey, argument, bash, choice, command, commandLine, concat, conditional, constant, createDeferredParseState, createDependencySourceState, createPendingDependencySourceState, defaultValues, deferredParseMarker, dependency, dependencyId, dependencyIds, dependencySourceMarker, dependencySourceStateMarker, deriveFrom, deriveFromAsync, deriveFromSync, derivedValueParserMarker, ensureNonEmptyString, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDependencyError, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getAnnotations, getDefaultValuesFunction, getDependencyIds, getDocPage, getDocPageAsync, getDocPageSync, group, integer, isDeferredParseState, isDependencySource, isDependencySourceState, isDerivedValueParser, isNonEmptyString, isPendingDependencySourceState, isValueParser, isWrappedDependencySource, link, locale, longestMatch, map, merge, message, metavar, multiple, nonEmpty, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, parseAsync, parseSync, parseWithDependency, passThrough, pendingDependencySourceStateMarker, pwsh, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync, string, suggest, suggestAsync, suggestSync, suggestWithDependency, text, transformsDependencyValue, transformsDependencyValueMarker, tuple, url, uuid, value, valueSet, values, withDefault, wrappedDependencySourceMarker, zsh };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,6 @@ import { AnyDependencySource, CombineMode, CombinedDependencyMode, DeferredParse
|
|
|
10
10
|
import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, flag, option, passThrough } from "./primitives.js";
|
|
11
11
|
import { CombineModes, DocState, InferMode, InferValue, Mode, ModeIterable, ModeValue, Parser, ParserContext, ParserResult, Result, Suggestion, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./parser.js";
|
|
12
12
|
import { ShellCompletion, bash, fish, nu, pwsh, zsh } from "./completion.js";
|
|
13
|
-
import {
|
|
14
|
-
|
|
13
|
+
import { SourceContext } from "./context.js";
|
|
14
|
+
import { RunOptions, RunParserError, RunWithOptions, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync } from "./facade.js";
|
|
15
|
+
export { type Annotations, AnyDependencySource, ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CombineMode, CombineModes, CombinedDependencyMode, CommandErrorOptions, CommandOptions, ConditionalErrorOptions, ConditionalOptions, DeferredParseState, DependencyError, DependencyMode, DependencyRegistry, DependencySource, DependencySourceState, DependencyValue, DependencyValues, DeriveAsyncOptions, DeriveFromAsyncOptions, DeriveFromOptions, DeriveFromSyncOptions, DeriveOptions, DeriveSyncOptions, DerivedValueParser, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, DuplicateOptionError, FlagErrorOptions, FlagOptions, FloatOptions, InferMode, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, type Message, type MessageFormatOptions, type MessageTerm, Mode, ModeIterable, ModeValue, MultipleErrorOptions, MultipleOptions, NoMatchContext, NonEmptyString, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OptionState, OrErrorOptions, OrOptions, type ParseOptions, Parser, ParserContext, ParserResult, PassThroughFormat, PassThroughOptions, PendingDependencySourceState, ResolvedDependency, Result, RunOptions, RunParserError, RunWithOptions, ShellCompletion, ShowDefaultOptions, SourceContext, StringOptions, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, type ValueSetOptions, WithDefaultError, WithDefaultOptions, annotationKey, argument, bash, choice, command, commandLine, concat, conditional, constant, createDeferredParseState, createDependencySourceState, createPendingDependencySourceState, defaultValues, deferredParseMarker, dependency, dependencyId, dependencyIds, dependencySourceMarker, dependencySourceStateMarker, deriveFrom, deriveFromAsync, deriveFromSync, derivedValueParserMarker, ensureNonEmptyString, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDependencyError, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getAnnotations, getDefaultValuesFunction, getDependencyIds, getDocPage, getDocPageAsync, getDocPageSync, group, integer, isDeferredParseState, isDependencySource, isDependencySourceState, isDerivedValueParser, isNonEmptyString, isPendingDependencySourceState, isValueParser, isWrappedDependencySource, link, locale, longestMatch, map, merge, message, metavar, multiple, nonEmpty, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, parseAsync, parseSync, parseWithDependency, passThrough, pendingDependencySourceStateMarker, pwsh, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync, string, suggest, suggestAsync, suggestSync, suggestWithDependency, text, transformsDependencyValue, transformsDependencyValueMarker, tuple, url, uuid, value, valueSet, values, withDefault, wrappedDependencySourceMarker, zsh };
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,6 @@ import { ensureNonEmptyString, isNonEmptyString } from "./nonempty.js";
|
|
|
10
10
|
import { choice, float, integer, isValueParser, locale, string, url, uuid } from "./valueparser.js";
|
|
11
11
|
import { argument, command, constant, flag, option, passThrough } from "./primitives.js";
|
|
12
12
|
import { getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./parser.js";
|
|
13
|
-
import { RunParserError, runParser, runParserAsync, runParserSync } from "./facade.js";
|
|
13
|
+
import { RunParserError, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync } from "./facade.js";
|
|
14
14
|
|
|
15
|
-
export { DependencyRegistry, DuplicateOptionError, RunParserError, WithDefaultError, annotationKey, argument, bash, choice, command, commandLine, concat, conditional, constant, createDeferredParseState, createDependencySourceState, createPendingDependencySourceState, defaultValues, deferredParseMarker, dependency, dependencyId, dependencyIds, dependencySourceMarker, dependencySourceStateMarker, deriveFrom, deriveFromAsync, deriveFromSync, derivedValueParserMarker, ensureNonEmptyString, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDependencyError, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getAnnotations, getDefaultValuesFunction, getDependencyIds, getDocPage, getDocPageAsync, getDocPageSync, group, integer, isDeferredParseState, isDependencySource, isDependencySourceState, isDerivedValueParser, isNonEmptyString, isPendingDependencySourceState, isValueParser, isWrappedDependencySource, link, locale, longestMatch, map, merge, message, metavar, multiple, nonEmpty, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, parseAsync, parseSync, parseWithDependency, passThrough, pendingDependencySourceStateMarker, pwsh, runParser, runParserAsync, runParserSync, string, suggest, suggestAsync, suggestSync, suggestWithDependency, text, transformsDependencyValue, transformsDependencyValueMarker, tuple, url, uuid, value, valueSet, values, withDefault, wrappedDependencySourceMarker, zsh };
|
|
15
|
+
export { DependencyRegistry, DuplicateOptionError, RunParserError, WithDefaultError, annotationKey, argument, bash, choice, command, commandLine, concat, conditional, constant, createDeferredParseState, createDependencySourceState, createPendingDependencySourceState, defaultValues, deferredParseMarker, dependency, dependencyId, dependencyIds, dependencySourceMarker, dependencySourceStateMarker, deriveFrom, deriveFromAsync, deriveFromSync, derivedValueParserMarker, ensureNonEmptyString, envVar, extractArgumentMetavars, extractCommandNames, extractOptionNames, fish, flag, float, formatDependencyError, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getAnnotations, getDefaultValuesFunction, getDependencyIds, getDocPage, getDocPageAsync, getDocPageSync, group, integer, isDeferredParseState, isDependencySource, isDependencySourceState, isDerivedValueParser, isNonEmptyString, isPendingDependencySourceState, isValueParser, isWrappedDependencySource, link, locale, longestMatch, map, merge, message, metavar, multiple, nonEmpty, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, parseAsync, parseSync, parseWithDependency, passThrough, pendingDependencySourceStateMarker, pwsh, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync, string, suggest, suggestAsync, suggestSync, suggestWithDependency, text, transformsDependencyValue, transformsDependencyValueMarker, tuple, url, uuid, value, valueSet, values, withDefault, wrappedDependencySourceMarker, zsh };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/core",
|
|
3
|
-
"version": "0.10.0-dev.
|
|
3
|
+
"version": "0.10.0-dev.332+be2882ab",
|
|
4
4
|
"description": "Type-safe combinatorial command-line interface parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -67,6 +67,14 @@
|
|
|
67
67
|
"import": "./dist/completion.js",
|
|
68
68
|
"require": "./dist/completion.cjs"
|
|
69
69
|
},
|
|
70
|
+
"./context": {
|
|
71
|
+
"types": {
|
|
72
|
+
"import": "./dist/context.d.ts",
|
|
73
|
+
"require": "./dist/context.d.cts"
|
|
74
|
+
},
|
|
75
|
+
"import": "./dist/context.js",
|
|
76
|
+
"require": "./dist/context.cjs"
|
|
77
|
+
},
|
|
70
78
|
"./constructs": {
|
|
71
79
|
"types": {
|
|
72
80
|
"import": "./dist/constructs.d.ts",
|