@optique/core 1.0.0-dev.908 → 1.0.0
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/annotation-state.cjs +425 -0
- package/dist/annotation-state.d.cts +24 -0
- package/dist/annotation-state.d.ts +24 -0
- package/dist/annotation-state.js +414 -0
- package/dist/annotations.cjs +2 -248
- package/dist/annotations.d.cts +2 -137
- package/dist/annotations.d.ts +2 -137
- package/dist/annotations.js +2 -238
- package/dist/completion.cjs +611 -100
- package/dist/completion.d.cts +1 -1
- package/dist/completion.d.ts +1 -1
- package/dist/completion.js +611 -100
- package/dist/constructs.cjs +3338 -827
- package/dist/constructs.d.cts +48 -7
- package/dist/constructs.d.ts +48 -7
- package/dist/constructs.js +3338 -827
- package/dist/context.cjs +0 -23
- package/dist/context.d.cts +119 -53
- package/dist/context.d.ts +119 -53
- package/dist/context.js +0 -22
- package/dist/dependency-metadata.cjs +139 -0
- package/dist/dependency-metadata.d.cts +112 -0
- package/dist/dependency-metadata.d.ts +112 -0
- package/dist/dependency-metadata.js +138 -0
- package/dist/dependency-runtime.cjs +698 -0
- package/dist/dependency-runtime.d.cts +149 -0
- package/dist/dependency-runtime.d.ts +149 -0
- package/dist/dependency-runtime.js +687 -0
- package/dist/dependency.cjs +7 -928
- package/dist/dependency.d.cts +2 -794
- package/dist/dependency.d.ts +2 -794
- package/dist/dependency.js +2 -899
- package/dist/displaywidth.cjs +44 -0
- package/dist/displaywidth.js +43 -0
- package/dist/doc.cjs +285 -23
- package/dist/doc.d.cts +57 -2
- package/dist/doc.d.ts +57 -2
- package/dist/doc.js +283 -25
- package/dist/execution-context.cjs +56 -0
- package/dist/execution-context.js +53 -0
- package/dist/extension.cjs +87 -0
- package/dist/extension.d.cts +97 -0
- package/dist/extension.d.ts +97 -0
- package/dist/extension.js +76 -0
- package/dist/facade.cjs +718 -523
- package/dist/facade.d.cts +87 -18
- package/dist/facade.d.ts +87 -18
- package/dist/facade.js +718 -523
- package/dist/index.cjs +14 -29
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +7 -7
- package/dist/input-trace.cjs +56 -0
- package/dist/input-trace.d.cts +77 -0
- package/dist/input-trace.d.ts +77 -0
- package/dist/input-trace.js +55 -0
- package/dist/internal/annotations.cjs +316 -0
- package/dist/internal/annotations.d.cts +140 -0
- package/dist/internal/annotations.d.ts +140 -0
- package/dist/internal/annotations.js +306 -0
- package/dist/internal/dependency.cjs +984 -0
- package/dist/internal/dependency.d.cts +539 -0
- package/dist/internal/dependency.d.ts +539 -0
- package/dist/internal/dependency.js +964 -0
- package/dist/{mode-dispatch.cjs → internal/mode-dispatch.cjs} +1 -3
- package/dist/{mode-dispatch.d.cts → internal/mode-dispatch.d.cts} +3 -7
- package/dist/{mode-dispatch.d.ts → internal/mode-dispatch.d.ts} +3 -7
- package/dist/{mode-dispatch.js → internal/mode-dispatch.js} +1 -3
- package/dist/internal/parser.cjs +728 -0
- package/dist/internal/parser.d.cts +947 -0
- package/dist/internal/parser.d.ts +947 -0
- package/dist/internal/parser.js +711 -0
- package/dist/message.cjs +84 -26
- package/dist/message.d.cts +49 -9
- package/dist/message.d.ts +49 -9
- package/dist/message.js +84 -27
- package/dist/modifiers.cjs +1023 -240
- package/dist/modifiers.d.cts +42 -1
- package/dist/modifiers.d.ts +42 -1
- package/dist/modifiers.js +1023 -240
- package/dist/parser.cjs +11 -463
- package/dist/parser.d.cts +3 -537
- package/dist/parser.d.ts +3 -537
- package/dist/parser.js +2 -433
- package/dist/phase2-seed.cjs +59 -0
- package/dist/phase2-seed.js +56 -0
- package/dist/primitives.cjs +557 -208
- package/dist/primitives.d.cts +10 -14
- package/dist/primitives.d.ts +10 -14
- package/dist/primitives.js +557 -208
- package/dist/program.cjs +5 -1
- package/dist/program.d.cts +5 -3
- package/dist/program.d.ts +5 -3
- package/dist/program.js +6 -1
- package/dist/suggestion.cjs +22 -8
- package/dist/suggestion.js +22 -8
- package/dist/usage-internals.cjs +3 -2
- package/dist/usage-internals.js +4 -2
- package/dist/usage.cjs +195 -40
- package/dist/usage.d.cts +92 -11
- package/dist/usage.d.ts +92 -11
- package/dist/usage.js +194 -41
- package/dist/validate.cjs +170 -0
- package/dist/validate.js +164 -0
- package/dist/valueparser.cjs +1278 -191
- package/dist/valueparser.d.cts +330 -20
- package/dist/valueparser.d.ts +330 -20
- package/dist/valueparser.js +1277 -192
- package/package.json +9 -9
package/dist/facade.js
CHANGED
|
@@ -1,295 +1,282 @@
|
|
|
1
|
-
import { injectAnnotations } from "./annotations.js";
|
|
1
|
+
import { injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper } from "./internal/annotations.js";
|
|
2
2
|
import { commandLine, formatMessage, lineBreak, message, optionName, text, value } from "./message.js";
|
|
3
3
|
import { bash, fish, nu, pwsh, zsh } from "./completion.js";
|
|
4
|
-
import {
|
|
4
|
+
import { validateCommandNames, validateContextIds, validateMetaNameCollisions, validateOptionNames, validateProgramName } from "./validate.js";
|
|
5
5
|
import { formatUsage } from "./usage.js";
|
|
6
|
-
import { group, longestMatch, object } from "./constructs.js";
|
|
7
6
|
import { formatDocPage } from "./doc.js";
|
|
7
|
+
import { dispatchByMode } from "./internal/mode-dispatch.js";
|
|
8
|
+
import { createDependencyRuntimeContext } from "./dependency-runtime.js";
|
|
9
|
+
import { createInputTrace } from "./input-trace.js";
|
|
10
|
+
import { createParserContext, getDocPage, suggest, suggestAsync } from "./internal/parser.js";
|
|
11
|
+
import { completeOrExtractPhase2Seed } from "./phase2-seed.js";
|
|
12
|
+
import { group, longestMatch, object } from "./constructs.js";
|
|
8
13
|
import { multiple, optional, withDefault } from "./modifiers.js";
|
|
9
14
|
import { string } from "./valueparser.js";
|
|
10
15
|
import { argument, command, constant, flag, option } from "./primitives.js";
|
|
11
|
-
import { getDocPage, parseAsync, parseSync, suggest, suggestAsync } from "./parser.js";
|
|
12
16
|
|
|
13
17
|
//#region src/facade.ts
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const SuppressedErrorCtor = typeof SuppressedError === "function" ? SuppressedError : (() => {
|
|
19
|
+
class SuppressedErrorPolyfill extends Error {
|
|
20
|
+
error;
|
|
21
|
+
suppressed;
|
|
22
|
+
constructor(error, suppressed, message$1) {
|
|
23
|
+
super(message$1);
|
|
24
|
+
this.name = "SuppressedError";
|
|
25
|
+
this.error = error;
|
|
26
|
+
this.suppressed = suppressed;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return SuppressedErrorPolyfill;
|
|
30
|
+
})();
|
|
20
31
|
function isPlainObject(value$1) {
|
|
21
32
|
const proto = Object.getPrototypeOf(value$1);
|
|
22
33
|
return proto === Object.prototype || proto === null;
|
|
23
34
|
}
|
|
24
|
-
function
|
|
25
|
-
if (
|
|
26
|
-
return
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
35
|
+
function prepareParsedForContexts(parsed, deferred, deferredKeys) {
|
|
36
|
+
if (!deferred) return parsed;
|
|
37
|
+
if (deferredKeys != null && deferredKeys.size === 0 && parsed != null && typeof parsed === "object") return void 0;
|
|
38
|
+
if (deferredKeys != null && deferredKeys.size > 0 && parsed != null && typeof parsed === "object" && !isPlainObject(parsed) && !Array.isArray(parsed)) return void 0;
|
|
39
|
+
if (deferredKeys != null && deferredKeys.size > 0 && parsed != null && typeof parsed === "object" && (isPlainObject(parsed) || Array.isArray(parsed))) {
|
|
40
|
+
const getDeferredEntry = (key) => {
|
|
41
|
+
const entry = deferredKeys.get(key);
|
|
42
|
+
if (entry !== void 0) return entry;
|
|
43
|
+
if (typeof key === "string") {
|
|
44
|
+
const num = Number(key);
|
|
45
|
+
if (Number.isInteger(num)) return deferredKeys.get(num);
|
|
46
|
+
} else if (typeof key === "number") return deferredKeys.get(String(key));
|
|
47
|
+
return void 0;
|
|
48
|
+
};
|
|
49
|
+
const ownKeys = Reflect.ownKeys(parsed);
|
|
50
|
+
let hasMatchingKey = false;
|
|
51
|
+
for (const key of ownKeys) if (getDeferredEntry(key) !== void 0) {
|
|
52
|
+
hasMatchingKey = true;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
if (hasMatchingKey) {
|
|
56
|
+
const isArray = Array.isArray(parsed);
|
|
57
|
+
let allDeferred = true;
|
|
58
|
+
for (const key of ownKeys) {
|
|
59
|
+
if (isArray && key === "length") continue;
|
|
60
|
+
const desc = Object.getOwnPropertyDescriptor(parsed, key);
|
|
61
|
+
if (desc != null && "value" in desc && getDeferredEntry(key) === void 0) {
|
|
62
|
+
allDeferred = false;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (allDeferred) return void 0;
|
|
67
|
+
const clone = isArray ? new Array(parsed.length) : Object.create(Object.getPrototypeOf(parsed));
|
|
68
|
+
for (const key of ownKeys) {
|
|
69
|
+
const desc = Object.getOwnPropertyDescriptor(parsed, key);
|
|
70
|
+
if (desc == null) continue;
|
|
71
|
+
const entry = getDeferredEntry(key);
|
|
72
|
+
if ("value" in desc && entry !== void 0) if (entry === null) Object.defineProperty(clone, key, {
|
|
73
|
+
...desc,
|
|
74
|
+
value: void 0
|
|
75
|
+
});
|
|
76
|
+
else Object.defineProperty(clone, key, {
|
|
77
|
+
...desc,
|
|
78
|
+
value: prepareParsedForContexts(desc.value, true, entry)
|
|
79
|
+
});
|
|
80
|
+
else Object.defineProperty(clone, key, desc);
|
|
81
|
+
}
|
|
82
|
+
return clone;
|
|
83
|
+
}
|
|
84
|
+
return void 0;
|
|
51
85
|
}
|
|
86
|
+
if (parsed == null || typeof parsed !== "object") return void 0;
|
|
87
|
+
return parsed;
|
|
52
88
|
}
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
const setCtor = value$1.constructor;
|
|
56
|
-
return Reflect.construct(Set, [], setCtor);
|
|
57
|
-
} catch {
|
|
58
|
-
return /* @__PURE__ */ new Set();
|
|
59
|
-
}
|
|
89
|
+
function isBufferUnchanged(previous, current) {
|
|
90
|
+
return current.length > 0 && current.length === previous.length && current.every((item, i) => item === previous[i]);
|
|
60
91
|
}
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
return /* @__PURE__ */ new Map();
|
|
67
|
-
}
|
|
92
|
+
function getFailureProgress(args, buffer, consumedInStep) {
|
|
93
|
+
return {
|
|
94
|
+
remainingArgs: buffer.slice(consumedInStep),
|
|
95
|
+
consumedCount: args.length - buffer.length + consumedInStep
|
|
96
|
+
};
|
|
68
97
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
if (value$1 instanceof Set) {
|
|
79
|
-
for (const entryValue of value$1) if (containsDeferredPromptValuesForContexts(entryValue, seen)) return true;
|
|
80
|
-
return containsDeferredPromptValuesInOwnProperties(value$1, seen);
|
|
81
|
-
}
|
|
82
|
-
if (value$1 instanceof Map) {
|
|
83
|
-
for (const [key, entryValue] of value$1) if (containsDeferredPromptValuesForContexts(key, seen) || containsDeferredPromptValuesForContexts(entryValue, seen)) return true;
|
|
84
|
-
return containsDeferredPromptValuesInOwnProperties(value$1, seen);
|
|
85
|
-
}
|
|
86
|
-
return containsDeferredPromptValuesInOwnProperties(value$1, seen);
|
|
98
|
+
function createParseExec(parser) {
|
|
99
|
+
return {
|
|
100
|
+
usage: parser.usage,
|
|
101
|
+
phase: "parse",
|
|
102
|
+
path: [],
|
|
103
|
+
commandPath: [],
|
|
104
|
+
trace: createInputTrace()
|
|
105
|
+
};
|
|
87
106
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
90
|
-
if (value$1 == null || typeof value$1 !== "object") return value$1;
|
|
91
|
-
const cached = seen.get(value$1);
|
|
92
|
-
if (cached !== void 0) return cached;
|
|
93
|
-
if (Array.isArray(value$1)) {
|
|
94
|
-
if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
|
|
95
|
-
const clone$1 = createArrayCloneLike(value$1);
|
|
96
|
-
seen.set(value$1, clone$1);
|
|
97
|
-
for (let i = 0; i < value$1.length; i++) clone$1[i] = stripDeferredPromptValuesForContexts(value$1[i], seen);
|
|
98
|
-
copySanitizedOwnProperties(value$1, clone$1, seen);
|
|
99
|
-
return clone$1;
|
|
100
|
-
}
|
|
101
|
-
if (value$1 instanceof Set) {
|
|
102
|
-
if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
|
|
103
|
-
const clone$1 = createSetCloneLike(value$1);
|
|
104
|
-
seen.set(value$1, clone$1);
|
|
105
|
-
for (const entryValue of value$1) clone$1.add(stripDeferredPromptValuesForContexts(entryValue, seen));
|
|
106
|
-
copySanitizedOwnProperties(value$1, clone$1, seen);
|
|
107
|
-
return clone$1;
|
|
108
|
-
}
|
|
109
|
-
if (value$1 instanceof Map) {
|
|
110
|
-
if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
|
|
111
|
-
const clone$1 = createMapCloneLike(value$1);
|
|
112
|
-
seen.set(value$1, clone$1);
|
|
113
|
-
for (const [key, entryValue] of value$1) clone$1.set(stripDeferredPromptValuesForContexts(key, seen), stripDeferredPromptValuesForContexts(entryValue, seen));
|
|
114
|
-
copySanitizedOwnProperties(value$1, clone$1, seen);
|
|
115
|
-
return clone$1;
|
|
116
|
-
}
|
|
117
|
-
if (!isPlainObject(value$1)) {
|
|
118
|
-
if (!containsDeferredPromptValuesForContexts(value$1)) return value$1;
|
|
119
|
-
return createSanitizedNonPlainContextView(value$1, seen);
|
|
120
|
-
}
|
|
121
|
-
const clone = Object.create(Object.getPrototypeOf(value$1));
|
|
122
|
-
seen.set(value$1, clone);
|
|
123
|
-
for (const key of Reflect.ownKeys(value$1)) {
|
|
124
|
-
const descriptor = Object.getOwnPropertyDescriptor(value$1, key);
|
|
125
|
-
if (descriptor == null) continue;
|
|
126
|
-
if ("value" in descriptor) descriptor.value = stripDeferredPromptValuesForContexts(descriptor.value, seen);
|
|
127
|
-
Object.defineProperty(clone, key, descriptor);
|
|
128
|
-
}
|
|
129
|
-
return clone;
|
|
107
|
+
function getCommandPath(exec) {
|
|
108
|
+
return exec?.commandPath ?? [];
|
|
130
109
|
}
|
|
131
|
-
function
|
|
132
|
-
|
|
133
|
-
return {
|
|
110
|
+
function createCompleteExec(exec, context) {
|
|
111
|
+
const runtime = createDependencyRuntimeContext();
|
|
112
|
+
return {
|
|
113
|
+
...exec,
|
|
114
|
+
phase: "complete",
|
|
115
|
+
dependencyRuntime: runtime,
|
|
116
|
+
dependencyRegistry: runtime.registry,
|
|
117
|
+
commandPath: getCommandPath(context.exec) ?? exec.commandPath,
|
|
118
|
+
trace: context.exec?.trace ?? context.trace ?? exec.trace
|
|
119
|
+
};
|
|
134
120
|
}
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
let
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (stripped !== desc.value) try {
|
|
156
|
-
Object.defineProperty(target, key, {
|
|
157
|
-
...desc,
|
|
158
|
-
value: stripped
|
|
159
|
-
});
|
|
160
|
-
saved.set(key, desc);
|
|
161
|
-
sanitizedValues.set(key, stripped);
|
|
162
|
-
} catch {
|
|
163
|
-
for (const [k, d] of saved) try {
|
|
164
|
-
Object.defineProperty(target, k, d);
|
|
165
|
-
} catch {}
|
|
166
|
-
return SANITIZE_FAILED;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
121
|
+
function attemptParseSync(parser, args, mode = "complete") {
|
|
122
|
+
const shouldUnwrapAnnotatedValue = isInjectedAnnotationWrapper(parser.initialState);
|
|
123
|
+
const exec = createParseExec(parser);
|
|
124
|
+
let context = createParserContext({
|
|
125
|
+
buffer: args,
|
|
126
|
+
state: parser.initialState,
|
|
127
|
+
optionsTerminated: false
|
|
128
|
+
}, exec);
|
|
129
|
+
do {
|
|
130
|
+
const result = parser.parse(context);
|
|
131
|
+
if (!result.success) {
|
|
132
|
+
const progress = getFailureProgress(args, context.buffer, result.consumed);
|
|
133
|
+
return {
|
|
134
|
+
kind: "failure",
|
|
135
|
+
error: result.error,
|
|
136
|
+
remainingArgs: progress.remainingArgs,
|
|
137
|
+
consumedCount: progress.consumedCount,
|
|
138
|
+
optionsTerminated: context.optionsTerminated,
|
|
139
|
+
commandPath: getCommandPath(context.exec)
|
|
140
|
+
};
|
|
169
141
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const current = Object.getOwnPropertyDescriptor(target, key);
|
|
183
|
-
if (current == null) continue;
|
|
184
|
-
if ("value" in current && current.value !== active.sanitizedValues.get(key)) continue;
|
|
185
|
-
Object.defineProperty(target, key, desc);
|
|
186
|
-
} catch {}
|
|
142
|
+
const previousBuffer = context.buffer;
|
|
143
|
+
context = result.next;
|
|
144
|
+
if (isBufferUnchanged(previousBuffer, context.buffer)) {
|
|
145
|
+
const progress = getFailureProgress(args, previousBuffer, result.consumed.length);
|
|
146
|
+
return {
|
|
147
|
+
kind: "failure",
|
|
148
|
+
error: message`Unexpected option or argument: ${context.buffer[0]}.`,
|
|
149
|
+
remainingArgs: progress.remainingArgs,
|
|
150
|
+
consumedCount: progress.consumedCount,
|
|
151
|
+
optionsTerminated: context.optionsTerminated,
|
|
152
|
+
commandPath: getCommandPath(context.exec)
|
|
153
|
+
};
|
|
187
154
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
function callMethodOnSanitizedTarget(fn, proxy, target, args, strip, seen) {
|
|
207
|
-
const result = callWithSanitizedOwnProperties(target, fn, args, strip, seen);
|
|
208
|
-
if (result !== SANITIZE_FAILED) return result;
|
|
209
|
-
const fallback = fn.apply(proxy, args);
|
|
210
|
-
if (fallback instanceof Promise) return fallback.then((v) => strip(v, seen));
|
|
211
|
-
return strip(fallback, seen);
|
|
155
|
+
} while (context.buffer.length > 0);
|
|
156
|
+
if (mode === "parse-only") return {
|
|
157
|
+
kind: "success",
|
|
158
|
+
value: void 0
|
|
159
|
+
};
|
|
160
|
+
const endResult = parser.complete(context.state, createCompleteExec(exec, context));
|
|
161
|
+
if (!endResult.success) return {
|
|
162
|
+
kind: "failure",
|
|
163
|
+
error: endResult.error,
|
|
164
|
+
remainingArgs: [],
|
|
165
|
+
consumedCount: args.length,
|
|
166
|
+
optionsTerminated: context.optionsTerminated,
|
|
167
|
+
commandPath: getCommandPath(context.exec)
|
|
168
|
+
};
|
|
169
|
+
return {
|
|
170
|
+
kind: "success",
|
|
171
|
+
value: shouldUnwrapAnnotatedValue ? unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value
|
|
172
|
+
};
|
|
212
173
|
}
|
|
213
|
-
function
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const wrapper = function(...args) {
|
|
226
|
-
if (this !== proxy) return stripDeferredPromptValuesForContexts(val.apply(this, args), seen);
|
|
227
|
-
return callMethodOnSanitizedTarget(val, proxy, target, args, stripDeferredPromptValuesForContexts, seen);
|
|
228
|
-
};
|
|
229
|
-
methodCache.set(key, {
|
|
230
|
-
fn: val,
|
|
231
|
-
wrapper
|
|
232
|
-
});
|
|
233
|
-
return wrapper;
|
|
234
|
-
}
|
|
235
|
-
return val;
|
|
236
|
-
}
|
|
237
|
-
let isAccessor = false;
|
|
238
|
-
for (let proto = target; proto != null; proto = Object.getPrototypeOf(proto)) {
|
|
239
|
-
const d = Object.getOwnPropertyDescriptor(proto, key);
|
|
240
|
-
if (d != null) {
|
|
241
|
-
isAccessor = "get" in d;
|
|
242
|
-
break;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
const result = Reflect.get(target, key, receiver);
|
|
246
|
-
if (typeof result === "function") {
|
|
247
|
-
if (/^class[\s{]/.test(Function.prototype.toString.call(result))) return result;
|
|
248
|
-
if (!isAccessor) {
|
|
249
|
-
const cached = methodCache.get(key);
|
|
250
|
-
if (cached != null && cached.fn === result) return cached.wrapper;
|
|
251
|
-
const wrapper = function(...args) {
|
|
252
|
-
if (this !== proxy) return stripDeferredPromptValuesForContexts(result.apply(this, args), seen);
|
|
253
|
-
return callMethodOnSanitizedTarget(result, proxy, target, args, stripDeferredPromptValuesForContexts, seen);
|
|
254
|
-
};
|
|
255
|
-
methodCache.set(key, {
|
|
256
|
-
fn: result,
|
|
257
|
-
wrapper
|
|
258
|
-
});
|
|
259
|
-
return wrapper;
|
|
260
|
-
}
|
|
261
|
-
return function(...args) {
|
|
262
|
-
if (this !== proxy) return stripDeferredPromptValuesForContexts(result.apply(this, args), seen);
|
|
263
|
-
return callMethodOnSanitizedTarget(result, proxy, target, args, stripDeferredPromptValuesForContexts, seen);
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
return stripDeferredPromptValuesForContexts(result, seen);
|
|
267
|
-
},
|
|
268
|
-
getOwnPropertyDescriptor(target, key) {
|
|
269
|
-
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
270
|
-
if (descriptor == null || !("value" in descriptor)) return descriptor;
|
|
271
|
-
if (!descriptor.configurable && !descriptor.writable) return descriptor;
|
|
174
|
+
async function attemptParseAsync(parser, args, mode = "complete") {
|
|
175
|
+
const shouldUnwrapAnnotatedValue = isInjectedAnnotationWrapper(parser.initialState);
|
|
176
|
+
const exec = createParseExec(parser);
|
|
177
|
+
let context = createParserContext({
|
|
178
|
+
buffer: args,
|
|
179
|
+
state: parser.initialState,
|
|
180
|
+
optionsTerminated: false
|
|
181
|
+
}, exec);
|
|
182
|
+
do {
|
|
183
|
+
const result = await parser.parse(context);
|
|
184
|
+
if (!result.success) {
|
|
185
|
+
const progress = getFailureProgress(args, context.buffer, result.consumed);
|
|
272
186
|
return {
|
|
273
|
-
|
|
274
|
-
|
|
187
|
+
kind: "failure",
|
|
188
|
+
error: result.error,
|
|
189
|
+
remainingArgs: progress.remainingArgs,
|
|
190
|
+
consumedCount: progress.consumedCount,
|
|
191
|
+
optionsTerminated: context.optionsTerminated,
|
|
192
|
+
commandPath: getCommandPath(context.exec)
|
|
275
193
|
};
|
|
276
194
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
195
|
+
const previousBuffer = context.buffer;
|
|
196
|
+
context = result.next;
|
|
197
|
+
if (isBufferUnchanged(previousBuffer, context.buffer)) {
|
|
198
|
+
const progress = getFailureProgress(args, previousBuffer, result.consumed.length);
|
|
199
|
+
return {
|
|
200
|
+
kind: "failure",
|
|
201
|
+
error: message`Unexpected option or argument: ${context.buffer[0]}.`,
|
|
202
|
+
remainingArgs: progress.remainingArgs,
|
|
203
|
+
consumedCount: progress.consumedCount,
|
|
204
|
+
optionsTerminated: context.optionsTerminated,
|
|
205
|
+
commandPath: getCommandPath(context.exec)
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
} while (context.buffer.length > 0);
|
|
209
|
+
if (mode === "parse-only") return {
|
|
210
|
+
kind: "success",
|
|
211
|
+
value: void 0
|
|
212
|
+
};
|
|
213
|
+
const endResult = await parser.complete(context.state, createCompleteExec(exec, context));
|
|
214
|
+
if (!endResult.success) return {
|
|
215
|
+
kind: "failure",
|
|
216
|
+
error: endResult.error,
|
|
217
|
+
remainingArgs: [],
|
|
218
|
+
consumedCount: args.length,
|
|
219
|
+
optionsTerminated: context.optionsTerminated,
|
|
220
|
+
commandPath: getCommandPath(context.exec)
|
|
221
|
+
};
|
|
222
|
+
return {
|
|
223
|
+
kind: "success",
|
|
224
|
+
value: shouldUnwrapAnnotatedValue ? unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value
|
|
225
|
+
};
|
|
280
226
|
}
|
|
281
|
-
function
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
227
|
+
function createPhase2SeedExec(parser, context) {
|
|
228
|
+
const exec = {
|
|
229
|
+
usage: parser.usage,
|
|
230
|
+
phase: "parse",
|
|
231
|
+
path: [],
|
|
232
|
+
commandPath: [],
|
|
233
|
+
trace: createInputTrace()
|
|
234
|
+
};
|
|
235
|
+
const runtime = createDependencyRuntimeContext();
|
|
236
|
+
return {
|
|
237
|
+
...exec,
|
|
238
|
+
phase: "complete",
|
|
239
|
+
dependencyRuntime: runtime,
|
|
240
|
+
dependencyRegistry: runtime.registry,
|
|
241
|
+
commandPath: getCommandPath(context.exec),
|
|
242
|
+
trace: context.exec?.trace ?? context.trace ?? exec.trace
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function createPhase2SeedContext(parser, args) {
|
|
246
|
+
const exec = {
|
|
247
|
+
usage: parser.usage,
|
|
248
|
+
phase: "parse",
|
|
249
|
+
path: [],
|
|
250
|
+
commandPath: [],
|
|
251
|
+
trace: createInputTrace()
|
|
252
|
+
};
|
|
253
|
+
return createParserContext({
|
|
254
|
+
buffer: args,
|
|
255
|
+
state: parser.initialState,
|
|
256
|
+
optionsTerminated: false
|
|
257
|
+
}, exec);
|
|
258
|
+
}
|
|
259
|
+
function extractPhase2SeedSync(parser, args) {
|
|
260
|
+
let context = createPhase2SeedContext(parser, args);
|
|
261
|
+
do {
|
|
262
|
+
const result = parser.parse(context);
|
|
263
|
+
if (!result.success) return completeOrExtractPhase2Seed(parser, context.state, createPhase2SeedExec(parser, context));
|
|
264
|
+
const previousBuffer = context.buffer;
|
|
265
|
+
context = result.next;
|
|
266
|
+
if (isBufferUnchanged(previousBuffer, context.buffer)) return completeOrExtractPhase2Seed(parser, context.state, createPhase2SeedExec(parser, context));
|
|
267
|
+
} while (context.buffer.length > 0);
|
|
268
|
+
return completeOrExtractPhase2Seed(parser, context.state, createPhase2SeedExec(parser, context));
|
|
290
269
|
}
|
|
291
|
-
function
|
|
292
|
-
|
|
270
|
+
async function extractPhase2SeedAsync(parser, args) {
|
|
271
|
+
let context = createPhase2SeedContext(parser, args);
|
|
272
|
+
do {
|
|
273
|
+
const result = await parser.parse(context);
|
|
274
|
+
if (!result.success) return await completeOrExtractPhase2Seed(parser, context.state, createPhase2SeedExec(parser, context));
|
|
275
|
+
const previousBuffer = context.buffer;
|
|
276
|
+
context = result.next;
|
|
277
|
+
if (isBufferUnchanged(previousBuffer, context.buffer)) return await completeOrExtractPhase2Seed(parser, context.state, createPhase2SeedExec(parser, context));
|
|
278
|
+
} while (context.buffer.length > 0);
|
|
279
|
+
return await completeOrExtractPhase2Seed(parser, context.state, createPhase2SeedExec(parser, context));
|
|
293
280
|
}
|
|
294
281
|
/**
|
|
295
282
|
* Creates help parsers based on the sub-config.
|
|
@@ -348,9 +335,6 @@ function createVersionParser(commandConfig, optionConfig) {
|
|
|
348
335
|
};
|
|
349
336
|
}
|
|
350
337
|
const metaResultBrand = Symbol("@optique/core/facade/meta");
|
|
351
|
-
function isMetaParseResult(value$1) {
|
|
352
|
-
return typeof value$1 === "object" && value$1 != null && metaResultBrand in value$1;
|
|
353
|
-
}
|
|
354
338
|
/**
|
|
355
339
|
* Creates completion parsers based on the sub-config.
|
|
356
340
|
*/
|
|
@@ -406,11 +390,13 @@ function combineWithHelpVersion(originalParser, helpParsers, versionParsers, com
|
|
|
406
390
|
const effectiveVersionOptionNames = versionOptionNames ?? ["--version"];
|
|
407
391
|
if (helpParsers.helpOption) {
|
|
408
392
|
const lenientHelpParser = {
|
|
409
|
-
|
|
393
|
+
mode: "sync",
|
|
410
394
|
$valueType: [],
|
|
411
395
|
$stateType: [],
|
|
412
396
|
priority: 200,
|
|
413
397
|
usage: helpParsers.helpOption.usage,
|
|
398
|
+
leadingNames: helpParsers.helpOption.leadingNames,
|
|
399
|
+
acceptingAnyToken: false,
|
|
414
400
|
initialState: null,
|
|
415
401
|
parse(context) {
|
|
416
402
|
const { buffer, optionsTerminated } = context;
|
|
@@ -485,11 +471,13 @@ function combineWithHelpVersion(originalParser, helpParsers, versionParsers, com
|
|
|
485
471
|
}
|
|
486
472
|
if (versionParsers.versionOption) {
|
|
487
473
|
const lenientVersionParser = {
|
|
488
|
-
|
|
474
|
+
mode: "sync",
|
|
489
475
|
$valueType: [],
|
|
490
476
|
$stateType: [],
|
|
491
477
|
priority: 200,
|
|
492
478
|
usage: versionParsers.versionOption.usage,
|
|
479
|
+
leadingNames: versionParsers.versionOption.leadingNames,
|
|
480
|
+
acceptingAnyToken: false,
|
|
493
481
|
initialState: null,
|
|
494
482
|
parse(context) {
|
|
495
483
|
const { buffer, optionsTerminated } = context;
|
|
@@ -614,54 +602,115 @@ function combineWithHelpVersion(originalParser, helpParsers, versionParsers, com
|
|
|
614
602
|
}
|
|
615
603
|
return combined;
|
|
616
604
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
error: result.error
|
|
625
|
-
};
|
|
626
|
-
const value$1 = result.value;
|
|
627
|
-
if (isMetaParseResult(value$1)) {
|
|
628
|
-
const parsedValue = value$1;
|
|
629
|
-
const hasVersionOption = versionOptionNames.some((n) => args.includes(n));
|
|
630
|
-
const hasVersionCommand = args.length > 0 && versionCommandNames.includes(args[0]);
|
|
631
|
-
const hasHelpOption = helpOptionNames.some((n) => args.includes(n));
|
|
632
|
-
const hasHelpCommand = args.length > 0 && helpCommandNames.includes(args[0]);
|
|
633
|
-
const hasCompletionCommand = args.length > 0 && completionCommandNames.includes(args[0]);
|
|
634
|
-
if (hasVersionCommand && hasHelpOption && parsedValue.helpFlag) return {
|
|
635
|
-
type: "help",
|
|
636
|
-
commands: [args[0]]
|
|
605
|
+
function classifyOptionMeta(scanArgs, fullArgs, helpOptionNames, versionOptionNames, completionOptionNames) {
|
|
606
|
+
let lastHelpVersion;
|
|
607
|
+
for (let i = 0; i < scanArgs.length; i++) {
|
|
608
|
+
const arg = scanArgs[i];
|
|
609
|
+
if (helpOptionNames.includes(arg)) lastHelpVersion = {
|
|
610
|
+
index: i,
|
|
611
|
+
kind: "help"
|
|
637
612
|
};
|
|
638
|
-
if (
|
|
639
|
-
|
|
640
|
-
|
|
613
|
+
else if (versionOptionNames.includes(arg)) lastHelpVersion = {
|
|
614
|
+
index: i,
|
|
615
|
+
kind: "version"
|
|
616
|
+
};
|
|
617
|
+
const equalsMatch = completionOptionNames.find((name) => arg.startsWith(name + "="));
|
|
618
|
+
if (equalsMatch != null) return {
|
|
619
|
+
lastHelpVersion,
|
|
620
|
+
completion: {
|
|
621
|
+
index: i,
|
|
622
|
+
shell: arg.slice(equalsMatch.length + 1),
|
|
623
|
+
args: fullArgs.slice(i + 1)
|
|
624
|
+
}
|
|
641
625
|
};
|
|
642
|
-
if (
|
|
643
|
-
|
|
644
|
-
if (Array.isArray(parsedValue.commands)) commandContext = parsedValue.commands;
|
|
645
|
-
else if (typeof parsedValue.commands === "object" && parsedValue.commands != null && "length" in parsedValue.commands) commandContext = parsedValue.commands;
|
|
626
|
+
if (completionOptionNames.includes(arg)) {
|
|
627
|
+
const shell = scanArgs[i + 1] ?? "";
|
|
646
628
|
return {
|
|
647
|
-
|
|
648
|
-
|
|
629
|
+
lastHelpVersion,
|
|
630
|
+
completion: {
|
|
631
|
+
index: i,
|
|
632
|
+
shell,
|
|
633
|
+
args: shell === "" ? [] : fullArgs.slice(i + 2)
|
|
634
|
+
}
|
|
649
635
|
};
|
|
650
636
|
}
|
|
651
|
-
|
|
652
|
-
|
|
637
|
+
}
|
|
638
|
+
return { lastHelpVersion };
|
|
639
|
+
}
|
|
640
|
+
function getHelpCommandContext(commandPath, args, helpIndex) {
|
|
641
|
+
const commands = [...commandPath];
|
|
642
|
+
for (let i = 0; i < helpIndex; i++) {
|
|
643
|
+
const arg = args[i];
|
|
644
|
+
if (!arg.startsWith("-")) commands.push(arg);
|
|
645
|
+
}
|
|
646
|
+
return commands;
|
|
647
|
+
}
|
|
648
|
+
function classifyParseFailure(failure, helpOptionNames, helpCommandNames, versionOptionNames, versionCommandNames, completionOptionNames, completionCommandNames) {
|
|
649
|
+
if (failure.remainingArgs.length < 1) return {
|
|
650
|
+
type: "error",
|
|
651
|
+
error: failure.error
|
|
652
|
+
};
|
|
653
|
+
const hasConsumedPrefix = failure.consumedCount > 0;
|
|
654
|
+
const firstArg = failure.remainingArgs[0];
|
|
655
|
+
if (!hasConsumedPrefix && completionCommandNames.includes(firstArg)) {
|
|
656
|
+
const secondArg = failure.remainingArgs[1];
|
|
657
|
+
if (helpOptionNames.includes(secondArg)) return {
|
|
658
|
+
type: "help",
|
|
659
|
+
commands: [firstArg]
|
|
660
|
+
};
|
|
661
|
+
return {
|
|
653
662
|
type: "completion",
|
|
654
|
-
|
|
655
|
-
|
|
663
|
+
source: "command",
|
|
664
|
+
shell: secondArg ?? "",
|
|
665
|
+
args: failure.remainingArgs.slice(2)
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
const optionArgs = failure.optionsTerminated ? [] : (() => {
|
|
669
|
+
const terminatorIndex = failure.remainingArgs.indexOf("--");
|
|
670
|
+
return terminatorIndex >= 0 ? failure.remainingArgs.slice(0, terminatorIndex) : failure.remainingArgs;
|
|
671
|
+
})();
|
|
672
|
+
const { lastHelpVersion, completion } = classifyOptionMeta(optionArgs, failure.remainingArgs, helpOptionNames, versionOptionNames, completionOptionNames);
|
|
673
|
+
if (!hasConsumedPrefix && versionCommandNames.includes(firstArg)) {
|
|
674
|
+
const secondArg = failure.remainingArgs[1];
|
|
675
|
+
if (helpOptionNames.includes(secondArg)) return {
|
|
676
|
+
type: "help",
|
|
677
|
+
commands: [firstArg]
|
|
656
678
|
};
|
|
679
|
+
const isCompletionImmediatelyAfter = completion?.index === 1;
|
|
680
|
+
if (secondArg == null || isCompletionImmediatelyAfter || lastHelpVersion?.index === 1 && lastHelpVersion.kind === "version") return { type: "version" };
|
|
657
681
|
return {
|
|
658
|
-
type: "
|
|
659
|
-
|
|
682
|
+
type: "error",
|
|
683
|
+
error: failure.error
|
|
660
684
|
};
|
|
661
685
|
}
|
|
686
|
+
let commandAction;
|
|
687
|
+
if (!hasConsumedPrefix && helpCommandNames.includes(firstArg)) commandAction = {
|
|
688
|
+
index: 0,
|
|
689
|
+
kind: "help"
|
|
690
|
+
};
|
|
691
|
+
const winner = lastHelpVersion == null ? commandAction : commandAction == null || lastHelpVersion.index >= commandAction.index ? lastHelpVersion : commandAction;
|
|
692
|
+
if (winner?.kind === "help") {
|
|
693
|
+
if (winner === commandAction) return {
|
|
694
|
+
type: "help",
|
|
695
|
+
commands: failure.remainingArgs.slice(1)
|
|
696
|
+
};
|
|
697
|
+
return {
|
|
698
|
+
type: "help",
|
|
699
|
+
commands: getHelpCommandContext(failure.commandPath, failure.remainingArgs, winner.index),
|
|
700
|
+
preferUserCommandDocs: failure.commandPath.length > 0
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
if (winner?.kind === "version") return { type: "version" };
|
|
704
|
+
if (completion != null) return {
|
|
705
|
+
type: "completion",
|
|
706
|
+
source: "option",
|
|
707
|
+
shell: completion.shell,
|
|
708
|
+
commandPath: failure.commandPath,
|
|
709
|
+
args: completion.args
|
|
710
|
+
};
|
|
662
711
|
return {
|
|
663
|
-
type: "
|
|
664
|
-
|
|
712
|
+
type: "error",
|
|
713
|
+
error: failure.error
|
|
665
714
|
};
|
|
666
715
|
}
|
|
667
716
|
/**
|
|
@@ -676,7 +725,7 @@ function handleCompletion(completionArgs, programName, parser, completionParser,
|
|
|
676
725
|
if (!shellName) {
|
|
677
726
|
stderr("Error: Missing shell name for completion.\n");
|
|
678
727
|
if (completionParser) {
|
|
679
|
-
const displayName = completionCommandDisplayName ?? "completion";
|
|
728
|
+
const displayName = isOptionMode ? completionOptionDisplayName ?? "--completion" : completionCommandDisplayName ?? "completion";
|
|
680
729
|
const doc = getDocPage(completionParser, [displayName]);
|
|
681
730
|
if (doc) stderr(formatDocPage(programName, doc, {
|
|
682
731
|
colors,
|
|
@@ -684,7 +733,11 @@ function handleCompletion(completionArgs, programName, parser, completionParser,
|
|
|
684
733
|
sectionOrder
|
|
685
734
|
}));
|
|
686
735
|
}
|
|
687
|
-
return dispatchByMode(parser
|
|
736
|
+
return dispatchByMode(parser.mode, () => {
|
|
737
|
+
const result = callOnError(1);
|
|
738
|
+
if (result instanceof Promise) throw new RunParserError("Synchronous parser returned async result.");
|
|
739
|
+
return result;
|
|
740
|
+
}, async () => callOnError(1));
|
|
688
741
|
}
|
|
689
742
|
const shell = availableShells[shellName];
|
|
690
743
|
if (!shell) {
|
|
@@ -697,25 +750,52 @@ function handleCompletion(completionArgs, programName, parser, completionParser,
|
|
|
697
750
|
colors,
|
|
698
751
|
quotes: !colors
|
|
699
752
|
}));
|
|
700
|
-
return dispatchByMode(parser
|
|
753
|
+
return dispatchByMode(parser.mode, () => {
|
|
754
|
+
const result = callOnError(1);
|
|
755
|
+
if (result instanceof Promise) throw new RunParserError("Synchronous parser returned async result.");
|
|
756
|
+
return result;
|
|
757
|
+
}, async () => callOnError(1));
|
|
701
758
|
}
|
|
702
759
|
if (args.length === 0) {
|
|
703
760
|
const completionArg = isOptionMode ? completionOptionDisplayName ?? "--completion" : completionCommandDisplayName ?? "completion";
|
|
704
761
|
const script = shell.generateScript(programName, [completionArg, shellName]);
|
|
705
762
|
stdout(script);
|
|
706
|
-
return dispatchByMode(parser
|
|
763
|
+
return dispatchByMode(parser.mode, () => {
|
|
764
|
+
const result = callOnCompletion(0);
|
|
765
|
+
if (result instanceof Promise) throw new RunParserError("Synchronous parser returned async result.");
|
|
766
|
+
return result;
|
|
767
|
+
}, async () => callOnCompletion(0));
|
|
707
768
|
}
|
|
708
|
-
return dispatchByMode(parser
|
|
769
|
+
return dispatchByMode(parser.mode, () => {
|
|
709
770
|
const syncParser = parser;
|
|
710
771
|
const suggestions = suggest(syncParser, args);
|
|
711
772
|
for (const chunk of shell.encodeSuggestions(suggestions)) stdout(chunk);
|
|
712
|
-
|
|
773
|
+
const result = callOnCompletion(0);
|
|
774
|
+
if (result instanceof Promise) throw new RunParserError("Synchronous parser returned async result.");
|
|
775
|
+
return result;
|
|
713
776
|
}, async () => {
|
|
714
777
|
const suggestions = await suggestAsync(parser, args);
|
|
715
778
|
for (const chunk of shell.encodeSuggestions(suggestions)) stdout(chunk);
|
|
716
779
|
return callOnCompletion(0);
|
|
717
780
|
});
|
|
718
781
|
}
|
|
782
|
+
/**
|
|
783
|
+
* Validates the configured version value.
|
|
784
|
+
*
|
|
785
|
+
* @param value Runtime version value from configuration.
|
|
786
|
+
* @returns The validated version string.
|
|
787
|
+
* @throws {TypeError} If the value is not a string, is empty, or contains
|
|
788
|
+
* ASCII control characters.
|
|
789
|
+
*/
|
|
790
|
+
function validateVersionValue(value$1) {
|
|
791
|
+
if (typeof value$1 !== "string") {
|
|
792
|
+
const type = Array.isArray(value$1) ? "array" : typeof value$1;
|
|
793
|
+
throw new TypeError(`Expected version value to be a string, but got ${type}.`);
|
|
794
|
+
}
|
|
795
|
+
if (value$1 === "") throw new TypeError("Version value must not be empty.");
|
|
796
|
+
if (/[\x00-\x1f\x7f]/.test(value$1)) throw new TypeError("Version value must not contain control characters.");
|
|
797
|
+
return value$1;
|
|
798
|
+
}
|
|
719
799
|
function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsParam) {
|
|
720
800
|
const isProgram = typeof programNameOrArgs !== "string";
|
|
721
801
|
let parser;
|
|
@@ -743,6 +823,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
743
823
|
args = argsOrOptions;
|
|
744
824
|
options = optionsParam ?? {};
|
|
745
825
|
}
|
|
826
|
+
validateProgramName(programName);
|
|
746
827
|
const { colors, maxWidth, showDefault, showChoices, sectionOrder, aboveError = "usage", onError = () => {
|
|
747
828
|
throw new RunParserError("Failed to parse command line arguments.");
|
|
748
829
|
}, stderr = console.error, stdout = console.log, brief, description, examples, author, bugs, footer } = options;
|
|
@@ -752,19 +833,58 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
752
833
|
const onHelp = options.help?.onShow ?? (() => ({}));
|
|
753
834
|
const versionCommandConfig = norm(options.version?.command);
|
|
754
835
|
const versionOptionConfig = norm(options.version?.option);
|
|
755
|
-
const versionValue = options.version
|
|
836
|
+
const versionValue = options.version ? validateVersionValue(options.version.value) : void 0;
|
|
756
837
|
const onVersion = options.version?.onShow ?? (() => ({}));
|
|
757
838
|
const completionCommandConfig = norm(options.completion?.command);
|
|
758
839
|
const completionOptionConfig = norm(options.completion?.option);
|
|
759
840
|
const onCompletion = options.completion?.onShow ?? (() => ({}));
|
|
760
841
|
const onCompletionResult = (code) => onCompletion(code);
|
|
761
842
|
const onErrorResult = (code) => onError(code);
|
|
843
|
+
if (helpOptionConfig?.names) validateOptionNames(helpOptionConfig.names, "Help option");
|
|
844
|
+
if (helpCommandConfig?.names) validateCommandNames(helpCommandConfig.names, "Help command");
|
|
845
|
+
if (versionOptionConfig?.names) validateOptionNames(versionOptionConfig.names, "Version option");
|
|
846
|
+
if (versionCommandConfig?.names) validateCommandNames(versionCommandConfig.names, "Version command");
|
|
847
|
+
if (completionOptionConfig?.names) validateOptionNames(completionOptionConfig.names, "Completion option");
|
|
848
|
+
if (completionCommandConfig?.names) validateCommandNames(completionCommandConfig.names, "Completion command");
|
|
762
849
|
const helpOptionNames = helpOptionConfig?.names ?? ["--help"];
|
|
763
850
|
const helpCommandNames = helpCommandConfig?.names ?? ["help"];
|
|
764
851
|
const versionOptionNames = versionOptionConfig?.names ?? ["--version"];
|
|
765
852
|
const versionCommandNames = versionCommandConfig?.names ?? ["version"];
|
|
766
853
|
const completionCommandNames = completionCommandConfig?.names ?? ["completion"];
|
|
767
854
|
const completionOptionNames = completionOptionConfig?.names ?? ["--completion"];
|
|
855
|
+
const activeMetaEntries = [];
|
|
856
|
+
if (options.help && helpOptionConfig) activeMetaEntries.push([
|
|
857
|
+
"option",
|
|
858
|
+
"help option",
|
|
859
|
+
helpOptionNames
|
|
860
|
+
]);
|
|
861
|
+
if (options.help && helpCommandConfig) activeMetaEntries.push([
|
|
862
|
+
"command",
|
|
863
|
+
"help command",
|
|
864
|
+
helpCommandNames
|
|
865
|
+
]);
|
|
866
|
+
if (options.version && versionOptionConfig) activeMetaEntries.push([
|
|
867
|
+
"option",
|
|
868
|
+
"version option",
|
|
869
|
+
versionOptionNames
|
|
870
|
+
]);
|
|
871
|
+
if (options.version && versionCommandConfig) activeMetaEntries.push([
|
|
872
|
+
"command",
|
|
873
|
+
"version command",
|
|
874
|
+
versionCommandNames
|
|
875
|
+
]);
|
|
876
|
+
if (options.completion && completionOptionConfig) activeMetaEntries.push([
|
|
877
|
+
"option",
|
|
878
|
+
"completion option",
|
|
879
|
+
completionOptionNames,
|
|
880
|
+
true
|
|
881
|
+
]);
|
|
882
|
+
if (options.completion && completionCommandConfig) activeMetaEntries.push([
|
|
883
|
+
"command",
|
|
884
|
+
"completion command",
|
|
885
|
+
completionCommandNames
|
|
886
|
+
]);
|
|
887
|
+
validateMetaNameCollisions(activeMetaEntries);
|
|
768
888
|
const defaultShells = {
|
|
769
889
|
bash,
|
|
770
890
|
fish,
|
|
@@ -788,25 +908,6 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
788
908
|
completionCommand: null,
|
|
789
909
|
completionOption: null
|
|
790
910
|
};
|
|
791
|
-
if (options.completion) {
|
|
792
|
-
const hasHelpOption = helpOptionConfig ? helpOptionNames.some((n) => args.includes(n)) : false;
|
|
793
|
-
if (completionCommandConfig && args.length >= 1 && completionCommandNames.includes(args[0]) && !hasHelpOption) return handleCompletion(args.slice(1), programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletionResult, onErrorResult, availableShells, colors, maxWidth, completionCommandNames[0], completionOptionNames[0], false, sectionOrder);
|
|
794
|
-
if (completionOptionConfig) for (let i = 0; i < args.length; i++) {
|
|
795
|
-
const arg = args[i];
|
|
796
|
-
const equalsMatch = completionOptionNames.find((n) => arg.startsWith(n + "="));
|
|
797
|
-
if (equalsMatch) {
|
|
798
|
-
const shell = arg.slice(equalsMatch.length + 1);
|
|
799
|
-
const completionArgs = args.slice(i + 1);
|
|
800
|
-
return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletionResult, onErrorResult, availableShells, colors, maxWidth, completionCommandNames[0], completionOptionNames[0], true, sectionOrder);
|
|
801
|
-
}
|
|
802
|
-
const exactMatch = completionOptionNames.includes(arg);
|
|
803
|
-
if (exactMatch) {
|
|
804
|
-
const shell = i + 1 < args.length ? args[i + 1] : "";
|
|
805
|
-
const completionArgs = i + 1 < args.length ? args.slice(i + 2) : [];
|
|
806
|
-
return handleCompletion([shell, ...completionArgs], programName, parser, completionParsers.completionCommand, stdout, stderr, onCompletionResult, onErrorResult, availableShells, colors, maxWidth, completionCommandNames[0], completionOptionNames[0], true, sectionOrder);
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
911
|
const augmentedParser = !options.help && !options.version && !options.completion ? parser : combineWithHelpVersion(parser, helpParsers, versionParsers, completionParsers, {
|
|
811
912
|
helpCommandGroup: helpCommandConfig?.group,
|
|
812
913
|
helpOptionGroup: helpOptionConfig?.group,
|
|
@@ -815,14 +916,17 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
815
916
|
completionCommandGroup: completionCommandConfig?.group,
|
|
816
917
|
completionOptionGroup: completionOptionConfig?.group
|
|
817
918
|
}, helpOptionConfig ? [...helpOptionNames] : void 0, versionOptionConfig ? [...versionOptionNames] : void 0);
|
|
818
|
-
const handleResult = (
|
|
819
|
-
const classified = classifyResult(result, args, helpOptionConfig ? [...helpOptionNames] : [], helpCommandConfig ? [...helpCommandNames] : [], versionOptionConfig ? [...versionOptionNames] : [], versionCommandConfig ? [...versionCommandNames] : [], completionCommandConfig ? [...completionCommandNames] : []);
|
|
919
|
+
const handleResult = (classified) => {
|
|
820
920
|
switch (classified.type) {
|
|
821
921
|
case "success": return classified.value;
|
|
822
922
|
case "version":
|
|
823
923
|
stdout(versionValue);
|
|
824
924
|
return onVersion(0);
|
|
825
|
-
case "completion":
|
|
925
|
+
case "completion": return handleCompletion([
|
|
926
|
+
classified.shell,
|
|
927
|
+
...classified.commandPath ?? [],
|
|
928
|
+
...classified.args
|
|
929
|
+
], programName, parser, classified.source === "command" ? completionParsers.completionCommand : completionParsers.completionOption, stdout, stderr, onCompletionResult, onErrorResult, availableShells, colors, maxWidth, completionCommandNames[0], completionOptionNames[0], classified.source === "option", sectionOrder);
|
|
826
930
|
case "help": {
|
|
827
931
|
let helpGeneratorParser;
|
|
828
932
|
const helpAsCommand = helpCommandConfig != null;
|
|
@@ -832,9 +936,9 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
832
936
|
const versionAsOption = versionOptionConfig != null;
|
|
833
937
|
const completionAsOption = completionOptionConfig != null;
|
|
834
938
|
const requestedCommand = classified.commands[0];
|
|
835
|
-
if (requestedCommand != null && completionCommandNames.includes(requestedCommand) && completionAsCommand && completionParsers.completionCommand) helpGeneratorParser = completionParsers.completionCommand;
|
|
836
|
-
else if (requestedCommand != null && helpCommandNames.includes(requestedCommand) && helpAsCommand && helpParsers.helpCommand) helpGeneratorParser = helpParsers.helpCommand;
|
|
837
|
-
else if (requestedCommand != null && versionCommandNames.includes(requestedCommand) && versionAsCommand && versionParsers.versionCommand) helpGeneratorParser = versionParsers.versionCommand;
|
|
939
|
+
if (requestedCommand != null && !classified.preferUserCommandDocs && completionCommandNames.includes(requestedCommand) && completionAsCommand && completionParsers.completionCommand) helpGeneratorParser = completionParsers.completionCommand;
|
|
940
|
+
else if (requestedCommand != null && !classified.preferUserCommandDocs && helpCommandNames.includes(requestedCommand) && helpAsCommand && helpParsers.helpCommand) helpGeneratorParser = helpParsers.helpCommand;
|
|
941
|
+
else if (requestedCommand != null && !classified.preferUserCommandDocs && versionCommandNames.includes(requestedCommand) && versionAsCommand && versionParsers.versionCommand) helpGeneratorParser = versionParsers.versionCommand;
|
|
838
942
|
else {
|
|
839
943
|
const commandParsers = [parser];
|
|
840
944
|
const groupedMeta = {};
|
|
@@ -926,8 +1030,8 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
926
1030
|
while (validationResult === "continue") {
|
|
927
1031
|
const stepResult = helpGeneratorParser.parse(validationContext);
|
|
928
1032
|
if (stepResult instanceof Promise) {
|
|
929
|
-
const asyncValidate = async (result
|
|
930
|
-
let res = processStep(result
|
|
1033
|
+
const asyncValidate = async (result) => {
|
|
1034
|
+
let res = processStep(result);
|
|
931
1035
|
while (res === "continue") {
|
|
932
1036
|
const next = helpGeneratorParser.parse(validationContext);
|
|
933
1037
|
const resolved = next instanceof Promise ? await next : next;
|
|
@@ -991,15 +1095,23 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
991
1095
|
default: throw new RunParserError("Unexpected parse result type");
|
|
992
1096
|
}
|
|
993
1097
|
};
|
|
994
|
-
const parserMode = parser
|
|
1098
|
+
const parserMode = parser.mode;
|
|
995
1099
|
return dispatchByMode(parserMode, () => {
|
|
996
|
-
const
|
|
997
|
-
const
|
|
1100
|
+
const attempted = attemptParseSync(parser, args);
|
|
1101
|
+
const classified = attempted.kind === "success" ? {
|
|
1102
|
+
type: "success",
|
|
1103
|
+
value: attempted.value
|
|
1104
|
+
} : classifyParseFailure(attempted, helpOptionConfig ? [...helpOptionNames] : [], helpCommandConfig ? [...helpCommandNames] : [], versionOptionConfig ? [...versionOptionNames] : [], versionCommandConfig ? [...versionCommandNames] : [], completionOptionConfig ? [...completionOptionNames] : [], completionCommandConfig ? [...completionCommandNames] : []);
|
|
1105
|
+
const handled = handleResult(classified);
|
|
998
1106
|
if (handled instanceof Promise) throw new RunParserError("Synchronous parser returned async result.");
|
|
999
1107
|
return handled;
|
|
1000
1108
|
}, async () => {
|
|
1001
|
-
const
|
|
1002
|
-
const
|
|
1109
|
+
const attempted = await attemptParseAsync(parser, args);
|
|
1110
|
+
const classified = attempted.kind === "success" ? {
|
|
1111
|
+
type: "success",
|
|
1112
|
+
value: attempted.value
|
|
1113
|
+
} : classifyParseFailure(attempted, helpOptionConfig ? [...helpOptionNames] : [], helpCommandConfig ? [...helpCommandNames] : [], versionOptionConfig ? [...versionOptionNames] : [], versionCommandConfig ? [...versionCommandNames] : [], completionOptionConfig ? [...completionOptionNames] : [], completionCommandConfig ? [...completionCommandNames] : []);
|
|
1114
|
+
const handled = handleResult(classified);
|
|
1003
1115
|
return handled instanceof Promise ? await handled : handled;
|
|
1004
1116
|
});
|
|
1005
1117
|
}
|
|
@@ -1018,9 +1130,12 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
|
|
|
1018
1130
|
* @param args The command-line arguments to parse.
|
|
1019
1131
|
* @param options Configuration options for customizing behavior.
|
|
1020
1132
|
* @returns The parsed result if successful.
|
|
1133
|
+
* @throws {TypeError} If an async parser is passed at runtime. Use
|
|
1134
|
+
* {@link runParser} or {@link runParserAsync} for async parsers.
|
|
1021
1135
|
* @since 0.9.0
|
|
1022
1136
|
*/
|
|
1023
1137
|
function runParserSync(parser, programName, args, options) {
|
|
1138
|
+
if (parser.mode !== "sync") throw new TypeError("Cannot use an async parser with runParserSync(). Use runParser() or runParserAsync() instead.");
|
|
1024
1139
|
return runParser(parser, programName, args, options);
|
|
1025
1140
|
}
|
|
1026
1141
|
/**
|
|
@@ -1057,47 +1172,38 @@ var RunParserError = class extends Error {
|
|
|
1057
1172
|
function indentLines(text$1, indent) {
|
|
1058
1173
|
return text$1.split("\n").join("\n" + " ".repeat(indent));
|
|
1059
1174
|
}
|
|
1175
|
+
function isMetaEarlyExit(classified) {
|
|
1176
|
+
return classified.type === "help" || classified.type === "version" || classified.type === "completion";
|
|
1177
|
+
}
|
|
1178
|
+
function classifyEarlyExitFailure(failure, options) {
|
|
1179
|
+
const norm = (c) => c === true ? {} : c;
|
|
1180
|
+
const helpOptionConfig = norm(options.help?.option);
|
|
1181
|
+
const helpCommandConfig = norm(options.help?.command);
|
|
1182
|
+
const versionOptionConfig = norm(options.version?.option);
|
|
1183
|
+
const versionCommandConfig = norm(options.version?.command);
|
|
1184
|
+
const completionOptionConfig = norm(options.completion?.option);
|
|
1185
|
+
const completionCommandConfig = norm(options.completion?.command);
|
|
1186
|
+
return classifyParseFailure(failure, helpOptionConfig ? [...helpOptionConfig.names ?? ["--help"]] : [], helpCommandConfig ? [...helpCommandConfig.names ?? ["help"]] : [], versionOptionConfig ? [...versionOptionConfig.names ?? ["--version"]] : [], versionCommandConfig ? [...versionCommandConfig.names ?? ["version"]] : [], completionOptionConfig ? [...completionOptionConfig.names ?? ["--completion"]] : [], completionCommandConfig ? [...completionCommandConfig.names ?? ["completion"]] : []);
|
|
1187
|
+
}
|
|
1188
|
+
function shouldProbeEarlyExit(options, needsTwoPhase) {
|
|
1189
|
+
return needsTwoPhase && (options.help != null || options.version != null || options.completion != null);
|
|
1190
|
+
}
|
|
1060
1191
|
/**
|
|
1061
|
-
* Checks if the arguments contain
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
* This enables early exit optimization: when users request help, version,
|
|
1065
|
-
* or completion, we skip annotation collection and context processing
|
|
1066
|
-
* entirely, delegating directly to runParser().
|
|
1067
|
-
*
|
|
1068
|
-
* @param args Command-line arguments to check.
|
|
1069
|
-
* @param options Run options containing help/version/completion configuration.
|
|
1070
|
-
* @returns `true` if early exit should be performed, `false` otherwise.
|
|
1192
|
+
* Checks if the arguments contain parser-visible meta requests that can be
|
|
1193
|
+
* handled without collecting source-context annotations first.
|
|
1071
1194
|
*/
|
|
1072
|
-
function
|
|
1073
|
-
const
|
|
1074
|
-
if (
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
if (
|
|
1083
|
-
|
|
1084
|
-
const versionCommandConfig = norm(options.version.command);
|
|
1085
|
-
const versionOptionNames = versionOptionConfig?.names ?? ["--version"];
|
|
1086
|
-
const versionCommandNames = versionCommandConfig?.names ?? ["version"];
|
|
1087
|
-
if (versionOptionConfig && versionOptionNames.some((n) => args.includes(n))) return true;
|
|
1088
|
-
if (versionCommandConfig && versionCommandNames.includes(args[0])) return true;
|
|
1089
|
-
}
|
|
1090
|
-
if (options.completion) {
|
|
1091
|
-
const completionCommandConfig = norm(options.completion.command);
|
|
1092
|
-
const completionOptionConfig = norm(options.completion.option);
|
|
1093
|
-
const completionCommandNames = completionCommandConfig?.names ?? ["completion"];
|
|
1094
|
-
const completionOptionNames = completionOptionConfig?.names ?? ["--completion"];
|
|
1095
|
-
if (completionCommandConfig && completionCommandNames.includes(args[0])) return true;
|
|
1096
|
-
if (completionOptionConfig) {
|
|
1097
|
-
for (const arg of args) for (const name of completionOptionNames) if (arg === name || arg.startsWith(name + "=")) return true;
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
return false;
|
|
1195
|
+
function needsEarlyExitSync(parser, args, options) {
|
|
1196
|
+
const attempted = attemptParseSync(parser, args, "parse-only");
|
|
1197
|
+
if (attempted.kind === "success") return false;
|
|
1198
|
+
return isMetaEarlyExit(classifyEarlyExitFailure(attempted, options));
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Async variant of {@link needsEarlyExitSync}.
|
|
1202
|
+
*/
|
|
1203
|
+
async function needsEarlyExitAsync(parser, args, options) {
|
|
1204
|
+
const attempted = await attemptParseAsync(parser, args, "parse-only");
|
|
1205
|
+
if (attempted.kind === "success") return false;
|
|
1206
|
+
return isMetaEarlyExit(classifyEarlyExitFailure(attempted, options));
|
|
1101
1207
|
}
|
|
1102
1208
|
/**
|
|
1103
1209
|
* Merges multiple annotation objects, with earlier contexts having priority.
|
|
@@ -1116,56 +1222,73 @@ function mergeAnnotations(annotationsList) {
|
|
|
1116
1222
|
}
|
|
1117
1223
|
return result;
|
|
1118
1224
|
}
|
|
1225
|
+
function validateContextPhases(contexts) {
|
|
1226
|
+
for (const context of contexts) {
|
|
1227
|
+
const phase = context.phase;
|
|
1228
|
+
if (phase !== "single-pass" && phase !== "two-pass") throw new TypeError(`Context ${String(context.id)} must declare phase as "single-pass" or "two-pass".`);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1119
1231
|
/**
|
|
1120
1232
|
* Collects phase 1 annotations from all contexts and determines whether
|
|
1121
1233
|
* two-phase parsing is needed.
|
|
1122
1234
|
*
|
|
1123
1235
|
* @param contexts Source contexts to collect annotations from.
|
|
1124
1236
|
* @param options Optional context-required options to pass to each context.
|
|
1125
|
-
* @returns Promise with merged annotations
|
|
1237
|
+
* @returns Promise with merged annotations, per-context snapshots, and a
|
|
1238
|
+
* two-phase hint.
|
|
1126
1239
|
*/
|
|
1127
1240
|
async function collectPhase1Annotations(contexts, options) {
|
|
1128
1241
|
const annotationsList = [];
|
|
1129
|
-
let
|
|
1242
|
+
let snapshots;
|
|
1130
1243
|
for (const context of contexts) {
|
|
1131
|
-
const
|
|
1132
|
-
|
|
1244
|
+
const request = { phase: "phase1" };
|
|
1245
|
+
const result = context.getAnnotations(request, options);
|
|
1133
1246
|
const annotations = result instanceof Promise ? await result : result;
|
|
1134
|
-
const
|
|
1135
|
-
const
|
|
1136
|
-
annotationsList.push(
|
|
1247
|
+
const internalAnnotations = context.getInternalAnnotations?.(request, annotations);
|
|
1248
|
+
const snapshot = internalAnnotations == null ? annotations : mergeAnnotations([annotations, internalAnnotations]);
|
|
1249
|
+
annotationsList.push(snapshot);
|
|
1250
|
+
if (snapshots != null) snapshots.push(snapshot);
|
|
1251
|
+
else if (context.phase === "two-pass") snapshots = [...annotationsList];
|
|
1137
1252
|
}
|
|
1138
1253
|
return {
|
|
1139
1254
|
annotations: mergeAnnotations(annotationsList),
|
|
1140
|
-
|
|
1141
|
-
|
|
1255
|
+
needsTwoPhase: snapshots != null,
|
|
1256
|
+
snapshots: snapshots ?? []
|
|
1142
1257
|
};
|
|
1143
1258
|
}
|
|
1144
1259
|
/**
|
|
1145
|
-
* Collects annotations from all contexts.
|
|
1260
|
+
* Collects final annotations from all contexts.
|
|
1261
|
+
*
|
|
1262
|
+
* `single-pass` contexts reuse their phase-1 snapshot. `two-pass` contexts
|
|
1263
|
+
* are recollected with the parsed value and replace their own phase-1
|
|
1264
|
+
* snapshot in the final merge.
|
|
1146
1265
|
*
|
|
1147
1266
|
* @param contexts Source contexts to collect annotations from.
|
|
1267
|
+
* @param phase1Snapshots Per-context snapshots collected during phase 1.
|
|
1148
1268
|
* @param parsed Optional parsed result from a previous parse pass.
|
|
1149
1269
|
* @param options Optional context-required options to pass to each context.
|
|
1150
1270
|
* @returns Promise that resolves to merged annotations.
|
|
1151
1271
|
*/
|
|
1152
|
-
async function
|
|
1272
|
+
async function collectFinalAnnotations(contexts, phase1Snapshots, parsed, options, deferred, deferredKeys) {
|
|
1153
1273
|
const annotationsList = [];
|
|
1154
|
-
const preparedParsed = prepareParsedForContexts(parsed);
|
|
1155
|
-
for (
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1274
|
+
const preparedParsed = prepareParsedForContexts(parsed, deferred, deferredKeys);
|
|
1275
|
+
for (let index = 0; index < contexts.length; index++) {
|
|
1276
|
+
const context = contexts[index];
|
|
1277
|
+
if (context.phase === "single-pass") {
|
|
1278
|
+
annotationsList.push(phase1Snapshots[index]);
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
const request = {
|
|
1282
|
+
phase: "phase2",
|
|
1283
|
+
parsed: preparedParsed
|
|
1284
|
+
};
|
|
1285
|
+
const result = context.getAnnotations(request, options);
|
|
1286
|
+
const annotations = result instanceof Promise ? await result : result;
|
|
1287
|
+
const internalAnnotations = context.getInternalAnnotations?.(request, annotations);
|
|
1288
|
+
const mergedAnnotations = internalAnnotations == null ? annotations : mergeAnnotations([annotations, internalAnnotations]);
|
|
1163
1289
|
annotationsList.push(mergedAnnotations);
|
|
1164
1290
|
}
|
|
1165
|
-
return {
|
|
1166
|
-
annotations: mergeAnnotations(annotationsList),
|
|
1167
|
-
annotationsList
|
|
1168
|
-
};
|
|
1291
|
+
return { annotations: mergeAnnotations(annotationsList) };
|
|
1169
1292
|
}
|
|
1170
1293
|
/**
|
|
1171
1294
|
* Collects phase 1 annotations from all contexts synchronously and determines
|
|
@@ -1173,70 +1296,62 @@ async function collectAnnotations(contexts, parsed, options) {
|
|
|
1173
1296
|
*
|
|
1174
1297
|
* @param contexts Source contexts to collect annotations from.
|
|
1175
1298
|
* @param options Optional context-required options to pass to each context.
|
|
1176
|
-
* @returns Merged annotations
|
|
1177
|
-
* @throws
|
|
1299
|
+
* @returns Merged annotations, per-context snapshots, and a two-phase hint.
|
|
1300
|
+
* @throws {TypeError} If any context returns a Promise.
|
|
1178
1301
|
*/
|
|
1179
1302
|
function collectPhase1AnnotationsSync(contexts, options) {
|
|
1180
1303
|
const annotationsList = [];
|
|
1181
|
-
let
|
|
1304
|
+
let snapshots;
|
|
1182
1305
|
for (const context of contexts) {
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
const
|
|
1187
|
-
const
|
|
1188
|
-
annotationsList.push(
|
|
1306
|
+
const request = { phase: "phase1" };
|
|
1307
|
+
const result = context.getAnnotations(request, options);
|
|
1308
|
+
if (result instanceof Promise) throw new TypeError(`Context ${String(context.id)} returned a Promise in sync mode. Use runWith() or runWithAsync() for async contexts.`);
|
|
1309
|
+
const internalAnnotations = context.getInternalAnnotations?.(request, result);
|
|
1310
|
+
const snapshot = internalAnnotations == null ? result : mergeAnnotations([result, internalAnnotations]);
|
|
1311
|
+
annotationsList.push(snapshot);
|
|
1312
|
+
if (snapshots != null) snapshots.push(snapshot);
|
|
1313
|
+
else if (context.phase === "two-pass") snapshots = [...annotationsList];
|
|
1189
1314
|
}
|
|
1190
1315
|
return {
|
|
1191
1316
|
annotations: mergeAnnotations(annotationsList),
|
|
1192
|
-
|
|
1193
|
-
|
|
1317
|
+
needsTwoPhase: snapshots != null,
|
|
1318
|
+
snapshots: snapshots ?? []
|
|
1194
1319
|
};
|
|
1195
1320
|
}
|
|
1196
1321
|
/**
|
|
1197
|
-
*
|
|
1322
|
+
* Collects final annotations from all contexts synchronously.
|
|
1198
1323
|
*
|
|
1199
|
-
*
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
1202
|
-
*/
|
|
1203
|
-
function needsTwoPhaseContext(context, result) {
|
|
1204
|
-
if (context.mode !== void 0) return context.mode === "dynamic";
|
|
1205
|
-
if (result instanceof Promise) return true;
|
|
1206
|
-
return Object.getOwnPropertySymbols(result).length === 0;
|
|
1207
|
-
}
|
|
1208
|
-
/**
|
|
1209
|
-
* Collects annotations from all contexts synchronously.
|
|
1324
|
+
* `single-pass` contexts reuse their phase-1 snapshot. `two-pass` contexts
|
|
1325
|
+
* are recollected with the parsed value and replace their own phase-1
|
|
1326
|
+
* snapshot in the final merge.
|
|
1210
1327
|
*
|
|
1211
1328
|
* @param contexts Source contexts to collect annotations from.
|
|
1329
|
+
* @param phase1Snapshots Per-context snapshots collected during phase 1.
|
|
1212
1330
|
* @param parsed Optional parsed result from a previous parse pass.
|
|
1213
1331
|
* @param options Optional context-required options to pass to each context.
|
|
1214
1332
|
* @returns Merged annotations.
|
|
1215
|
-
* @throws
|
|
1333
|
+
* @throws {TypeError} If any context returns a Promise.
|
|
1216
1334
|
*/
|
|
1217
|
-
function
|
|
1335
|
+
function collectFinalAnnotationsSync(contexts, phase1Snapshots, parsed, options, deferred, deferredKeys) {
|
|
1218
1336
|
const annotationsList = [];
|
|
1219
|
-
const preparedParsed = prepareParsedForContexts(parsed);
|
|
1220
|
-
for (
|
|
1221
|
-
const
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1337
|
+
const preparedParsed = prepareParsedForContexts(parsed, deferred, deferredKeys);
|
|
1338
|
+
for (let index = 0; index < contexts.length; index++) {
|
|
1339
|
+
const context = contexts[index];
|
|
1340
|
+
if (context.phase === "single-pass") {
|
|
1341
|
+
annotationsList.push(phase1Snapshots[index]);
|
|
1342
|
+
continue;
|
|
1343
|
+
}
|
|
1344
|
+
const request = {
|
|
1345
|
+
phase: "phase2",
|
|
1346
|
+
parsed: preparedParsed
|
|
1347
|
+
};
|
|
1348
|
+
const result = context.getAnnotations(request, options);
|
|
1349
|
+
if (result instanceof Promise) throw new TypeError(`Context ${String(context.id)} returned a Promise in sync mode. Use runWith() or runWithAsync() for async contexts.`);
|
|
1350
|
+
const internalAnnotations = context.getInternalAnnotations?.(request, result);
|
|
1351
|
+
const mergedAnnotations = internalAnnotations == null ? result : mergeAnnotations([result, internalAnnotations]);
|
|
1228
1352
|
annotationsList.push(mergedAnnotations);
|
|
1229
1353
|
}
|
|
1230
|
-
return {
|
|
1231
|
-
annotations: mergeAnnotations(annotationsList),
|
|
1232
|
-
annotationsList
|
|
1233
|
-
};
|
|
1234
|
-
}
|
|
1235
|
-
function mergeTwoPhaseAnnotations(phase1AnnotationsList, phase2AnnotationsList) {
|
|
1236
|
-
const mergedPerContext = [];
|
|
1237
|
-
const length = Math.max(phase1AnnotationsList.length, phase2AnnotationsList.length);
|
|
1238
|
-
for (let i = 0; i < length; i++) mergedPerContext.push(mergeAnnotations([phase2AnnotationsList[i] ?? {}, phase1AnnotationsList[i] ?? {}]));
|
|
1239
|
-
return mergeAnnotations(mergedPerContext);
|
|
1354
|
+
return { annotations: mergeAnnotations(annotationsList) };
|
|
1240
1355
|
}
|
|
1241
1356
|
/**
|
|
1242
1357
|
* Disposes all contexts that implement `AsyncDisposable` or `Disposable`.
|
|
@@ -1276,22 +1391,63 @@ function disposeContextsSync(contexts) {
|
|
|
1276
1391
|
if (errors.length > 1) throw new AggregateError(errors, "Failed to dispose one or more source contexts.");
|
|
1277
1392
|
}
|
|
1278
1393
|
/**
|
|
1394
|
+
* Body of {@link runWith}, extracted so that the caller can handle
|
|
1395
|
+
* disposal outside a `finally` block (avoiding `no-unsafe-finally` lint).
|
|
1396
|
+
*/
|
|
1397
|
+
async function runWithBody(parser, programName, contexts, args, options) {
|
|
1398
|
+
validateContextIds(contexts);
|
|
1399
|
+
validateContextPhases(contexts);
|
|
1400
|
+
const ctxOptions = options.contextOptions;
|
|
1401
|
+
const { annotations: phase1Annotations, needsTwoPhase, snapshots: phase1Snapshots } = await collectPhase1Annotations(contexts, ctxOptions);
|
|
1402
|
+
if (shouldProbeEarlyExit(options, needsTwoPhase)) {
|
|
1403
|
+
const earlyExitParser = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1404
|
+
if (await needsEarlyExitAsync(earlyExitParser, args, options)) {
|
|
1405
|
+
if (parser.mode === "async") return runParser(earlyExitParser, programName, args, options);
|
|
1406
|
+
return Promise.resolve(runParser(earlyExitParser, programName, args, options));
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
const augmentedParser1 = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1410
|
+
if (!needsTwoPhase) {
|
|
1411
|
+
if (parser.mode === "async") return runParser(augmentedParser1, programName, args, options);
|
|
1412
|
+
return Promise.resolve(runParser(augmentedParser1, programName, args, options));
|
|
1413
|
+
}
|
|
1414
|
+
const firstPassSeed = await dispatchByMode(parser.mode, () => extractPhase2SeedSync(augmentedParser1, args), () => extractPhase2SeedAsync(augmentedParser1, args));
|
|
1415
|
+
if (firstPassSeed == null) {
|
|
1416
|
+
const fallbackParser = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1417
|
+
if (parser.mode === "async") return runParser(fallbackParser, programName, args, options);
|
|
1418
|
+
return Promise.resolve(runParser(fallbackParser, programName, args, options));
|
|
1419
|
+
}
|
|
1420
|
+
const { annotations: finalAnnotations } = await collectFinalAnnotations(contexts, phase1Snapshots, firstPassSeed.value, ctxOptions, firstPassSeed.deferred, firstPassSeed.deferredKeys);
|
|
1421
|
+
const augmentedParser2 = injectAnnotationsIntoParser(parser, finalAnnotations);
|
|
1422
|
+
if (parser.mode === "async") return runParser(augmentedParser2, programName, args, options);
|
|
1423
|
+
return Promise.resolve(runParser(augmentedParser2, programName, args, options));
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1279
1426
|
* Runs a parser with multiple source contexts.
|
|
1280
1427
|
*
|
|
1281
|
-
* This function automatically handles
|
|
1282
|
-
* priority. Earlier contexts in the array override later ones.
|
|
1428
|
+
* This function automatically handles single-pass and two-pass contexts with
|
|
1429
|
+
* proper priority. Earlier contexts in the array override later ones.
|
|
1283
1430
|
*
|
|
1284
1431
|
* The function uses a smart two-phase approach:
|
|
1285
1432
|
*
|
|
1286
|
-
* 1. *Phase 1*: Collect annotations from all contexts
|
|
1287
|
-
*
|
|
1288
|
-
*
|
|
1289
|
-
*
|
|
1290
|
-
*
|
|
1291
|
-
*
|
|
1433
|
+
* 1. *Phase 1*: Collect annotations from all contexts.
|
|
1434
|
+
* 2. *First parse*: Parse with Phase 1 annotations. If that pass finishes
|
|
1435
|
+
* successfully, its value becomes the phase-two input. If the parser
|
|
1436
|
+
* reaches a usable intermediate state but still does not complete
|
|
1437
|
+
* successfully, the runner extracts a best-effort seed from that state
|
|
1438
|
+
* instead.
|
|
1439
|
+
* 3. *Phase 2*: Call `getAnnotations({ phase: "phase2", parsed })` on all
|
|
1440
|
+
* two-pass contexts with the first pass value. Deferred or otherwise
|
|
1441
|
+
* unresolved fields in `parsed` may be `undefined`. Each two-pass
|
|
1442
|
+
* context's phase-two return
|
|
1443
|
+
* value replaces its own phase-one contribution for the final parse, so
|
|
1444
|
+
* returning `{}` clears any annotations that context provided during
|
|
1445
|
+
* phase 1. Single-pass contexts reuse their phase-one snapshot.
|
|
1446
|
+
* 4. *Second parse*: Parse again with the merged phase-two annotations.
|
|
1292
1447
|
*
|
|
1293
|
-
* If all contexts are
|
|
1294
|
-
*
|
|
1448
|
+
* If all contexts are single-pass, the second parse is skipped for
|
|
1449
|
+
* optimization. Phase 2 is also skipped when the first pass does not yield
|
|
1450
|
+
* any usable seed at all.
|
|
1295
1451
|
*
|
|
1296
1452
|
* @template TParser The parser type.
|
|
1297
1453
|
* @template THelp Return type when help is shown.
|
|
@@ -1301,6 +1457,13 @@ function disposeContextsSync(contexts) {
|
|
|
1301
1457
|
* @param contexts Source contexts to use (priority: earlier overrides later).
|
|
1302
1458
|
* @param options Run options including args, help, version, etc.
|
|
1303
1459
|
* @returns Promise that resolves to the parsed result.
|
|
1460
|
+
* @throws {TypeError} If two or more contexts share the same
|
|
1461
|
+
* {@link SourceContext.id}.
|
|
1462
|
+
* @throws {TypeError} If any context omits `phase` or declares an invalid
|
|
1463
|
+
* phase value.
|
|
1464
|
+
* @throws {SuppressedError} If the runner throws and a context's disposal
|
|
1465
|
+
* also throws. The original error is available via `.suppressed` and the
|
|
1466
|
+
* disposal error via `.error`.
|
|
1304
1467
|
* @since 0.10.0
|
|
1305
1468
|
*
|
|
1306
1469
|
* @example
|
|
@@ -1310,6 +1473,7 @@ function disposeContextsSync(contexts) {
|
|
|
1310
1473
|
*
|
|
1311
1474
|
* const envContext: SourceContext = {
|
|
1312
1475
|
* id: Symbol.for("@myapp/env"),
|
|
1476
|
+
* phase: "single-pass",
|
|
1313
1477
|
* getAnnotations() {
|
|
1314
1478
|
* return { [Symbol.for("@myapp/env")]: process.env };
|
|
1315
1479
|
* }
|
|
@@ -1325,54 +1489,61 @@ function disposeContextsSync(contexts) {
|
|
|
1325
1489
|
*/
|
|
1326
1490
|
async function runWith(parser, programName, contexts, options) {
|
|
1327
1491
|
const args = options?.args ?? [];
|
|
1328
|
-
if (needsEarlyExit(args, options)) {
|
|
1329
|
-
if (parser.$mode === "async") return runParser(parser, programName, args, options);
|
|
1330
|
-
return Promise.resolve(runParser(parser, programName, args, options));
|
|
1331
|
-
}
|
|
1332
1492
|
if (contexts.length === 0) {
|
|
1333
|
-
if (parser
|
|
1493
|
+
if (parser.mode === "async") return runParser(parser, programName, args, options);
|
|
1334
1494
|
return Promise.resolve(runParser(parser, programName, args, options));
|
|
1335
1495
|
}
|
|
1496
|
+
let result;
|
|
1497
|
+
let primaryError;
|
|
1498
|
+
let hasPrimaryError = false;
|
|
1499
|
+
try {
|
|
1500
|
+
result = await runWithBody(parser, programName, contexts, args, options);
|
|
1501
|
+
} catch (error) {
|
|
1502
|
+
hasPrimaryError = true;
|
|
1503
|
+
primaryError = error;
|
|
1504
|
+
}
|
|
1336
1505
|
try {
|
|
1337
|
-
const { annotations: phase1Annotations, annotationsList: phase1AnnotationsList, hasDynamic: needsTwoPhase } = await collectPhase1Annotations(contexts, options);
|
|
1338
|
-
if (!needsTwoPhase) {
|
|
1339
|
-
const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1340
|
-
if (parser.$mode === "async") return runParser(augmentedParser, programName, args, options);
|
|
1341
|
-
return Promise.resolve(runParser(augmentedParser, programName, args, options));
|
|
1342
|
-
}
|
|
1343
|
-
const augmentedParser1 = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1344
|
-
let firstPassResult;
|
|
1345
|
-
let firstPassFailed = false;
|
|
1346
|
-
try {
|
|
1347
|
-
if (parser.$mode === "async") firstPassResult = await parseAsync(augmentedParser1, args);
|
|
1348
|
-
else firstPassResult = parseSync(augmentedParser1, args);
|
|
1349
|
-
if (typeof firstPassResult === "object" && firstPassResult !== null && "success" in firstPassResult) {
|
|
1350
|
-
const result = firstPassResult;
|
|
1351
|
-
if (result.success) firstPassResult = result.value;
|
|
1352
|
-
else firstPassFailed = true;
|
|
1353
|
-
}
|
|
1354
|
-
} catch {
|
|
1355
|
-
firstPassFailed = true;
|
|
1356
|
-
}
|
|
1357
|
-
if (firstPassFailed) {
|
|
1358
|
-
const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1359
|
-
if (parser.$mode === "async") return runParser(augmentedParser, programName, args, options);
|
|
1360
|
-
return Promise.resolve(runParser(augmentedParser, programName, args, options));
|
|
1361
|
-
}
|
|
1362
|
-
const { annotationsList: phase2AnnotationsList } = await collectAnnotations(contexts, firstPassResult, options);
|
|
1363
|
-
const finalAnnotations = mergeTwoPhaseAnnotations(phase1AnnotationsList, phase2AnnotationsList);
|
|
1364
|
-
const augmentedParser2 = injectAnnotationsIntoParser(parser, finalAnnotations);
|
|
1365
|
-
if (parser.$mode === "async") return runParser(augmentedParser2, programName, args, options);
|
|
1366
|
-
return Promise.resolve(runParser(augmentedParser2, programName, args, options));
|
|
1367
|
-
} finally {
|
|
1368
1506
|
await disposeContexts(contexts);
|
|
1507
|
+
} catch (disposeError) {
|
|
1508
|
+
if (hasPrimaryError) throw new SuppressedErrorCtor(disposeError, primaryError, "An error was suppressed during context disposal.");
|
|
1509
|
+
throw disposeError;
|
|
1369
1510
|
}
|
|
1511
|
+
if (hasPrimaryError) throw primaryError;
|
|
1512
|
+
return result;
|
|
1513
|
+
}
|
|
1514
|
+
/**
|
|
1515
|
+
* Body of {@link runWithSync}, extracted so that the caller can handle
|
|
1516
|
+
* disposal outside a `finally` block (avoiding `no-unsafe-finally` lint).
|
|
1517
|
+
*/
|
|
1518
|
+
function runWithSyncBody(parser, programName, contexts, args, options) {
|
|
1519
|
+
validateContextIds(contexts);
|
|
1520
|
+
validateContextPhases(contexts);
|
|
1521
|
+
const ctxOptions = options.contextOptions;
|
|
1522
|
+
const { annotations: phase1Annotations, needsTwoPhase, snapshots: phase1Snapshots } = collectPhase1AnnotationsSync(contexts, ctxOptions);
|
|
1523
|
+
if (shouldProbeEarlyExit(options, needsTwoPhase)) {
|
|
1524
|
+
const earlyExitParser = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1525
|
+
if (needsEarlyExitSync(earlyExitParser, args, options)) return runParser(earlyExitParser, programName, args, options);
|
|
1526
|
+
}
|
|
1527
|
+
const augmentedParser1 = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1528
|
+
if (!needsTwoPhase) return runParser(augmentedParser1, programName, args, options);
|
|
1529
|
+
const firstPassSeed = extractPhase2SeedSync(augmentedParser1, args);
|
|
1530
|
+
if (firstPassSeed == null) {
|
|
1531
|
+
const fallbackParser = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1532
|
+
return runParser(fallbackParser, programName, args, options);
|
|
1533
|
+
}
|
|
1534
|
+
const { annotations: finalAnnotations } = collectFinalAnnotationsSync(contexts, phase1Snapshots, firstPassSeed.value, ctxOptions, firstPassSeed.deferred, firstPassSeed.deferredKeys);
|
|
1535
|
+
const augmentedParser2 = injectAnnotationsIntoParser(parser, finalAnnotations);
|
|
1536
|
+
return runParser(augmentedParser2, programName, args, options);
|
|
1370
1537
|
}
|
|
1371
1538
|
/**
|
|
1372
1539
|
* Runs a synchronous parser with multiple source contexts.
|
|
1373
1540
|
*
|
|
1374
1541
|
* This is the sync-only variant of {@link runWith}. All contexts must return
|
|
1375
|
-
* annotations synchronously (not Promises).
|
|
1542
|
+
* annotations synchronously (not Promises). It uses the same two-phase
|
|
1543
|
+
* best-effort seed extraction as {@link runWith} when two-pass contexts are
|
|
1544
|
+
* present. In two-phase runs, each two-pass context's phase-two return value
|
|
1545
|
+
* replaces that context's phase-one contribution for the final parse, so
|
|
1546
|
+
* returning `{}` clears any annotations that context provided during phase 1.
|
|
1376
1547
|
*
|
|
1377
1548
|
* @template TParser The sync parser type.
|
|
1378
1549
|
* @template THelp Return type when help is shown.
|
|
@@ -1382,36 +1553,40 @@ async function runWith(parser, programName, contexts, options) {
|
|
|
1382
1553
|
* @param contexts Source contexts to use (priority: earlier overrides later).
|
|
1383
1554
|
* @param options Run options including args, help, version, etc.
|
|
1384
1555
|
* @returns The parsed result.
|
|
1385
|
-
* @throws
|
|
1556
|
+
* @throws {TypeError} If an async parser is passed at runtime. Use
|
|
1557
|
+
* {@link runWith} or {@link runWithAsync} for async parsers.
|
|
1558
|
+
* @throws {TypeError} If two or more contexts share the same
|
|
1559
|
+
* {@link SourceContext.id}.
|
|
1560
|
+
* @throws {TypeError} If any context omits `phase` or declares an invalid
|
|
1561
|
+
* phase value.
|
|
1562
|
+
* @throws {TypeError} If any context returns a Promise or if a context's
|
|
1386
1563
|
* `[Symbol.asyncDispose]` returns a Promise.
|
|
1564
|
+
* @throws {SuppressedError} If the runner throws and a context's disposal
|
|
1565
|
+
* also throws. The original error is available via `.suppressed` and the
|
|
1566
|
+
* disposal error via `.error`.
|
|
1387
1567
|
* @since 0.10.0
|
|
1388
1568
|
*/
|
|
1389
1569
|
function runWithSync(parser, programName, contexts, options) {
|
|
1570
|
+
if (parser.mode !== "sync") throw new TypeError("Cannot use an async parser with runWithSync(). Use runWith() or runWithAsync() instead.");
|
|
1390
1571
|
const args = options?.args ?? [];
|
|
1391
|
-
if (needsEarlyExit(args, options)) return runParser(parser, programName, args, options);
|
|
1392
1572
|
if (contexts.length === 0) return runParser(parser, programName, args, options);
|
|
1573
|
+
let result;
|
|
1574
|
+
let primaryError;
|
|
1575
|
+
let hasPrimaryError = false;
|
|
1576
|
+
try {
|
|
1577
|
+
result = runWithSyncBody(parser, programName, contexts, args, options);
|
|
1578
|
+
} catch (error) {
|
|
1579
|
+
hasPrimaryError = true;
|
|
1580
|
+
primaryError = error;
|
|
1581
|
+
}
|
|
1393
1582
|
try {
|
|
1394
|
-
const { annotations: phase1Annotations, annotationsList: phase1AnnotationsList, hasDynamic: needsTwoPhase } = collectPhase1AnnotationsSync(contexts, options);
|
|
1395
|
-
if (!needsTwoPhase) {
|
|
1396
|
-
const augmentedParser = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1397
|
-
return runParser(augmentedParser, programName, args, options);
|
|
1398
|
-
}
|
|
1399
|
-
const augmentedParser1 = injectAnnotationsIntoParser(parser, phase1Annotations);
|
|
1400
|
-
let firstPassResult;
|
|
1401
|
-
try {
|
|
1402
|
-
const result = parseSync(augmentedParser1, args);
|
|
1403
|
-
if (result.success) firstPassResult = result.value;
|
|
1404
|
-
else return runParser(augmentedParser1, programName, args, options);
|
|
1405
|
-
} catch {
|
|
1406
|
-
return runParser(augmentedParser1, programName, args, options);
|
|
1407
|
-
}
|
|
1408
|
-
const { annotationsList: phase2AnnotationsList } = collectAnnotationsSync(contexts, firstPassResult, options);
|
|
1409
|
-
const finalAnnotations = mergeTwoPhaseAnnotations(phase1AnnotationsList, phase2AnnotationsList);
|
|
1410
|
-
const augmentedParser2 = injectAnnotationsIntoParser(parser, finalAnnotations);
|
|
1411
|
-
return runParser(augmentedParser2, programName, args, options);
|
|
1412
|
-
} finally {
|
|
1413
1583
|
disposeContextsSync(contexts);
|
|
1584
|
+
} catch (disposeError) {
|
|
1585
|
+
if (hasPrimaryError) throw new SuppressedErrorCtor(disposeError, primaryError, "An error was suppressed during context disposal.");
|
|
1586
|
+
throw disposeError;
|
|
1414
1587
|
}
|
|
1588
|
+
if (hasPrimaryError) throw primaryError;
|
|
1589
|
+
return result;
|
|
1415
1590
|
}
|
|
1416
1591
|
/**
|
|
1417
1592
|
* Runs any parser asynchronously with multiple source contexts.
|
|
@@ -1427,6 +1602,11 @@ function runWithSync(parser, programName, contexts, options) {
|
|
|
1427
1602
|
* @param contexts Source contexts to use (priority: earlier overrides later).
|
|
1428
1603
|
* @param options Run options including args, help, version, etc.
|
|
1429
1604
|
* @returns Promise that resolves to the parsed result.
|
|
1605
|
+
* @throws {TypeError} If two or more contexts share the same
|
|
1606
|
+
* {@link SourceContext.id}.
|
|
1607
|
+
* @throws {SuppressedError} If the runner throws and a context's disposal
|
|
1608
|
+
* also throws. The original error is available via `.suppressed` and the
|
|
1609
|
+
* disposal error via `.error`.
|
|
1430
1610
|
* @since 0.10.0
|
|
1431
1611
|
*/
|
|
1432
1612
|
function runWithAsync(parser, programName, contexts, options) {
|
|
@@ -1441,10 +1621,25 @@ function runWithAsync(parser, programName, contexts, options) {
|
|
|
1441
1621
|
*/
|
|
1442
1622
|
function injectAnnotationsIntoParser(parser, annotations) {
|
|
1443
1623
|
const newInitialState = injectAnnotations(parser.initialState, annotations);
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1624
|
+
const descriptors = { ...Object.getOwnPropertyDescriptors(parser) };
|
|
1625
|
+
const initialState = descriptors.initialState;
|
|
1626
|
+
descriptors.initialState = initialState == null ? {
|
|
1627
|
+
value: newInitialState,
|
|
1628
|
+
writable: true,
|
|
1629
|
+
enumerable: true,
|
|
1630
|
+
configurable: true
|
|
1631
|
+
} : "get" in initialState || "set" in initialState ? {
|
|
1632
|
+
value: newInitialState,
|
|
1633
|
+
writable: true,
|
|
1634
|
+
enumerable: initialState.enumerable ?? true,
|
|
1635
|
+
configurable: initialState.configurable ?? true
|
|
1636
|
+
} : {
|
|
1637
|
+
value: newInitialState,
|
|
1638
|
+
writable: initialState.writable ?? true,
|
|
1639
|
+
enumerable: initialState.enumerable ?? true,
|
|
1640
|
+
configurable: initialState.configurable ?? true
|
|
1447
1641
|
};
|
|
1642
|
+
return Object.create(Object.getPrototypeOf(parser), descriptors);
|
|
1448
1643
|
}
|
|
1449
1644
|
|
|
1450
1645
|
//#endregion
|