@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
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
const require_message = require('./message.cjs');
|
|
2
|
+
const require_dependency = require('./internal/dependency.cjs');
|
|
3
|
+
const require_parser = require('./internal/parser.cjs');
|
|
4
|
+
|
|
5
|
+
//#region src/dependency-runtime.ts
|
|
6
|
+
const symbolIds = /* @__PURE__ */ new WeakMap();
|
|
7
|
+
let symbolCounter = 0;
|
|
8
|
+
function stableSymbolKey(sym) {
|
|
9
|
+
const registeredKey = Symbol.keyFor(sym);
|
|
10
|
+
if (registeredKey !== void 0) return `reg:${registeredKey}`;
|
|
11
|
+
let id = symbolIds.get(sym);
|
|
12
|
+
if (id === void 0) {
|
|
13
|
+
id = `sym:${symbolCounter++}`;
|
|
14
|
+
symbolIds.set(sym, id);
|
|
15
|
+
}
|
|
16
|
+
return id;
|
|
17
|
+
}
|
|
18
|
+
var DependencyRuntimeContextImpl = class {
|
|
19
|
+
registry;
|
|
20
|
+
#replayCache = /* @__PURE__ */ new Map();
|
|
21
|
+
#failedSources = /* @__PURE__ */ new Set();
|
|
22
|
+
constructor(registry) {
|
|
23
|
+
if (registry instanceof FailedAwareRegistry) {
|
|
24
|
+
this.registry = registry.rebindFailedSources(this.#failedSources);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
this.registry = new FailedAwareRegistry(registry, this.#failedSources);
|
|
28
|
+
}
|
|
29
|
+
registerSource(sourceId, value, _origin) {
|
|
30
|
+
this.registry.set(sourceId, value);
|
|
31
|
+
}
|
|
32
|
+
hasSource(sourceId) {
|
|
33
|
+
return this.registry.has(sourceId);
|
|
34
|
+
}
|
|
35
|
+
getSource(sourceId) {
|
|
36
|
+
return this.registry.get(sourceId);
|
|
37
|
+
}
|
|
38
|
+
resolveDependencies(request) {
|
|
39
|
+
return resolveRequest(this, request);
|
|
40
|
+
}
|
|
41
|
+
getReplayResult(key) {
|
|
42
|
+
return this.#replayCache.get(serializeReplayKey(key));
|
|
43
|
+
}
|
|
44
|
+
setReplayResult(key, result) {
|
|
45
|
+
this.#replayCache.set(serializeReplayKey(key), result);
|
|
46
|
+
}
|
|
47
|
+
markSourceFailed(sourceId) {
|
|
48
|
+
this.#failedSources.add(sourceId);
|
|
49
|
+
}
|
|
50
|
+
isSourceFailed(sourceId) {
|
|
51
|
+
return this.#failedSources.has(sourceId);
|
|
52
|
+
}
|
|
53
|
+
getSuggestionDependencies(request) {
|
|
54
|
+
return resolveRequest(this, request);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Registry wrapper that hides values for sources that have failed.
|
|
59
|
+
*
|
|
60
|
+
* The wrapper lets clones share an underlying registry while maintaining
|
|
61
|
+
* an isolated failed-source view, so later lookups do not reuse stale
|
|
62
|
+
* values after extraction errors.
|
|
63
|
+
*
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
var FailedAwareRegistry = class FailedAwareRegistry {
|
|
67
|
+
#inner;
|
|
68
|
+
#failedSources;
|
|
69
|
+
constructor(inner, failedSources) {
|
|
70
|
+
this.#inner = inner;
|
|
71
|
+
this.#failedSources = failedSources;
|
|
72
|
+
}
|
|
73
|
+
set(id, value) {
|
|
74
|
+
this.#inner.set(id, value);
|
|
75
|
+
this.#failedSources.delete(id);
|
|
76
|
+
}
|
|
77
|
+
get(id) {
|
|
78
|
+
if (this.#failedSources.has(id)) return void 0;
|
|
79
|
+
return this.#inner.get(id);
|
|
80
|
+
}
|
|
81
|
+
has(id) {
|
|
82
|
+
if (this.#failedSources.has(id)) return false;
|
|
83
|
+
return this.#inner.has(id);
|
|
84
|
+
}
|
|
85
|
+
copyFailedSources(target) {
|
|
86
|
+
for (const sourceId of this.#failedSources) target.add(sourceId);
|
|
87
|
+
}
|
|
88
|
+
rebindFailedSources(target) {
|
|
89
|
+
this.copyFailedSources(target);
|
|
90
|
+
return new FailedAwareRegistry(this.#inner, target);
|
|
91
|
+
}
|
|
92
|
+
clone() {
|
|
93
|
+
const failedSources = new Set(this.#failedSources);
|
|
94
|
+
const innerClone = this.#inner.clone();
|
|
95
|
+
return innerClone instanceof FailedAwareRegistry ? innerClone.rebindFailedSources(failedSources) : new FailedAwareRegistry(innerClone, failedSources);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
function resolveRequest(ctx, request) {
|
|
99
|
+
const values = [];
|
|
100
|
+
const usedDefaults = [];
|
|
101
|
+
let resolvedCount = 0;
|
|
102
|
+
let defaultedCount = 0;
|
|
103
|
+
for (let i = 0; i < request.dependencyIds.length; i++) {
|
|
104
|
+
const id = request.dependencyIds[i];
|
|
105
|
+
if (ctx.isSourceFailed(id)) {
|
|
106
|
+
values.push(void 0);
|
|
107
|
+
usedDefaults.push(false);
|
|
108
|
+
} else if (ctx.hasSource(id)) {
|
|
109
|
+
values.push(ctx.getSource(id));
|
|
110
|
+
usedDefaults.push(false);
|
|
111
|
+
resolvedCount++;
|
|
112
|
+
} else if (request.defaultValues != null && i < request.defaultValues.length) {
|
|
113
|
+
values.push(request.defaultValues[i]);
|
|
114
|
+
usedDefaults.push(true);
|
|
115
|
+
defaultedCount++;
|
|
116
|
+
} else {
|
|
117
|
+
values.push(void 0);
|
|
118
|
+
usedDefaults.push(false);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const total = request.dependencyIds.length;
|
|
122
|
+
const foundOrDefaulted = resolvedCount + defaultedCount;
|
|
123
|
+
let kind;
|
|
124
|
+
if (foundOrDefaulted === total) kind = "resolved";
|
|
125
|
+
else if (resolvedCount === 0 && defaultedCount === 0) kind = "missing";
|
|
126
|
+
else kind = "partial";
|
|
127
|
+
return {
|
|
128
|
+
kind,
|
|
129
|
+
values,
|
|
130
|
+
usedDefaults
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Length-prefix a segment so that no delimiter escaping is needed. */
|
|
134
|
+
function lengthPrefix(s) {
|
|
135
|
+
return `${s.length}:${s}`;
|
|
136
|
+
}
|
|
137
|
+
function serializePathSegment(p) {
|
|
138
|
+
if (typeof p === "string") return lengthPrefix(`s${p}`);
|
|
139
|
+
if (typeof p === "number") return lengthPrefix(`n${p}`);
|
|
140
|
+
return lengthPrefix(`y${stableSymbolKey(p)}`);
|
|
141
|
+
}
|
|
142
|
+
function serializeReplayKey(key) {
|
|
143
|
+
const pathStr = key.path.map(serializePathSegment).join("");
|
|
144
|
+
return `${pathStr}\x01${lengthPrefix(key.rawInput)}\x01${key.dependencyFingerprint}\x01${key.parserFingerprint}`;
|
|
145
|
+
}
|
|
146
|
+
/** Minimal registry implementation for standalone use. */
|
|
147
|
+
var SimpleRegistry = class SimpleRegistry {
|
|
148
|
+
#map = /* @__PURE__ */ new Map();
|
|
149
|
+
set(id, value) {
|
|
150
|
+
this.#map.set(id, value);
|
|
151
|
+
}
|
|
152
|
+
get(id) {
|
|
153
|
+
return this.#map.get(id);
|
|
154
|
+
}
|
|
155
|
+
has(id) {
|
|
156
|
+
return this.#map.has(id);
|
|
157
|
+
}
|
|
158
|
+
clone() {
|
|
159
|
+
const copy = new SimpleRegistry();
|
|
160
|
+
for (const [k, v] of this.#map) copy.set(k, v);
|
|
161
|
+
return copy;
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Creates a new {@link DependencyRuntimeContext}.
|
|
166
|
+
*
|
|
167
|
+
* @param registry Optional existing registry to wrap for bridge interop.
|
|
168
|
+
* @returns A new runtime context.
|
|
169
|
+
* @internal
|
|
170
|
+
* @since 1.0.0
|
|
171
|
+
*/
|
|
172
|
+
function createDependencyRuntimeContext(registry) {
|
|
173
|
+
return new DependencyRuntimeContextImpl(registry ?? new SimpleRegistry());
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Creates a stable fingerprint from dependency values.
|
|
177
|
+
*
|
|
178
|
+
* @param values The dependency values to fingerprint.
|
|
179
|
+
* @returns A string fingerprint.
|
|
180
|
+
* @internal
|
|
181
|
+
* @since 1.0.0
|
|
182
|
+
*/
|
|
183
|
+
function createDependencyFingerprint(values) {
|
|
184
|
+
return values.map((v) => {
|
|
185
|
+
const raw = fingerprintValue(v);
|
|
186
|
+
return `${raw.length}:${raw}`;
|
|
187
|
+
}).join("");
|
|
188
|
+
}
|
|
189
|
+
const objectIds = /* @__PURE__ */ new WeakMap();
|
|
190
|
+
let objectIdCounter = 0;
|
|
191
|
+
function fingerprintValue(v) {
|
|
192
|
+
if (v === void 0) return "u:";
|
|
193
|
+
if (v === null) return "n:";
|
|
194
|
+
if (typeof v === "string") return `s:${v}`;
|
|
195
|
+
if (typeof v === "number") {
|
|
196
|
+
if (Object.is(v, -0)) return "d:-0";
|
|
197
|
+
return `d:${v}`;
|
|
198
|
+
}
|
|
199
|
+
if (typeof v === "boolean") return `b:${v}`;
|
|
200
|
+
if (typeof v === "symbol") return `y:${stableSymbolKey(v)}`;
|
|
201
|
+
if (typeof v === "object" || typeof v === "function") {
|
|
202
|
+
let id = objectIds.get(v);
|
|
203
|
+
if (id === void 0) {
|
|
204
|
+
id = objectIdCounter++;
|
|
205
|
+
objectIds.set(v, id);
|
|
206
|
+
}
|
|
207
|
+
return `o:${id}`;
|
|
208
|
+
}
|
|
209
|
+
return `?:${String(v)}`;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Creates a {@link ReplayKey} from a path, raw input, and dependency values.
|
|
213
|
+
*
|
|
214
|
+
* @param path The parser path.
|
|
215
|
+
* @param rawInput The raw input string.
|
|
216
|
+
* @param dependencyValues The dependency values.
|
|
217
|
+
* @returns A replay key.
|
|
218
|
+
* @internal
|
|
219
|
+
* @since 1.0.0
|
|
220
|
+
*/
|
|
221
|
+
const parserIds = /* @__PURE__ */ new WeakMap();
|
|
222
|
+
let parserIdCounter = 0;
|
|
223
|
+
/** Get a stable identity string for a replayParse function reference. */
|
|
224
|
+
function getParserFingerprint(replayParse) {
|
|
225
|
+
let id = parserIds.get(replayParse);
|
|
226
|
+
if (id === void 0) {
|
|
227
|
+
id = parserIdCounter++;
|
|
228
|
+
parserIds.set(replayParse, id);
|
|
229
|
+
}
|
|
230
|
+
return `p:${id}`;
|
|
231
|
+
}
|
|
232
|
+
function createReplayKey(path, rawInput, dependencyValues, replayParse) {
|
|
233
|
+
return {
|
|
234
|
+
path,
|
|
235
|
+
rawInput,
|
|
236
|
+
dependencyFingerprint: createDependencyFingerprint(dependencyValues),
|
|
237
|
+
parserFingerprint: replayParse != null ? getParserFingerprint(replayParse) : ""
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Collects explicit source values from parser states and registers them
|
|
242
|
+
* in the runtime context.
|
|
243
|
+
*
|
|
244
|
+
* @param nodes The runtime nodes to inspect.
|
|
245
|
+
* @param runtime The dependency runtime context.
|
|
246
|
+
* @throws Propagates synchronous errors thrown by `extractSourceValue()`.
|
|
247
|
+
* @throws {TypeError} If `extractSourceValue()` returns a promise-like result.
|
|
248
|
+
* Use {@link collectExplicitSourceValuesAsync} when async source
|
|
249
|
+
* extraction is expected.
|
|
250
|
+
* @internal
|
|
251
|
+
* @since 1.0.0
|
|
252
|
+
*/
|
|
253
|
+
function collectExplicitSourceValues(nodes, runtime) {
|
|
254
|
+
for (const node of nodes) {
|
|
255
|
+
const meta = node.parser.dependencyMetadata;
|
|
256
|
+
if (meta?.source == null) continue;
|
|
257
|
+
if (meta.source.extractSourceValue == null) continue;
|
|
258
|
+
const result = meta.source.extractSourceValue(node.state);
|
|
259
|
+
if (isPromiseLike(result)) throw new TypeError(`collectExplicitSourceValues() received an async extractSourceValue() result for ${String(meta.source.sourceId)}. Use collectExplicitSourceValuesAsync() instead.`);
|
|
260
|
+
registerExplicitSourceValue(meta.source.sourceId, result, runtime);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function registerExplicitSourceValue(sourceId, result, runtime) {
|
|
264
|
+
if (result == null) return;
|
|
265
|
+
if (result.success) runtime.registerSource(sourceId, result.value, "cli");
|
|
266
|
+
else runtime.markSourceFailed(sourceId);
|
|
267
|
+
}
|
|
268
|
+
function isPromiseLike(value) {
|
|
269
|
+
return value != null && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function";
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Async version of {@link collectExplicitSourceValues}.
|
|
273
|
+
* Awaits async `extractSourceValue` results instead of rejecting
|
|
274
|
+
* promise-like values as the synchronous variant does.
|
|
275
|
+
*
|
|
276
|
+
* @param nodes The runtime nodes to inspect.
|
|
277
|
+
* @param runtime The dependency runtime context.
|
|
278
|
+
* @throws Propagates errors thrown or rejected by `extractSourceValue()`.
|
|
279
|
+
* @internal
|
|
280
|
+
* @since 1.0.0
|
|
281
|
+
*/
|
|
282
|
+
async function collectExplicitSourceValuesAsync(nodes, runtime) {
|
|
283
|
+
for (const node of nodes) {
|
|
284
|
+
const meta = node.parser.dependencyMetadata;
|
|
285
|
+
if (meta?.source == null) continue;
|
|
286
|
+
if (meta.source.extractSourceValue == null) continue;
|
|
287
|
+
const result = await meta.source.extractSourceValue(node.state);
|
|
288
|
+
registerExplicitSourceValue(meta.source.sourceId, result, runtime);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Fills missing source defaults for source parsers whose state is
|
|
293
|
+
* unpopulated.
|
|
294
|
+
*
|
|
295
|
+
* Returns an array of failures for sources whose default evaluation
|
|
296
|
+
* failed (either threw or returned `{ success: false }`). The caller
|
|
297
|
+
* should propagate these so that dependent parsers see the real error
|
|
298
|
+
* instead of silently treating the source as absent.
|
|
299
|
+
*
|
|
300
|
+
* @param nodes The runtime nodes to inspect.
|
|
301
|
+
* @param runtime The dependency runtime context.
|
|
302
|
+
* @returns Failures from default evaluation (empty if all succeeded).
|
|
303
|
+
* @throws {TypeError} If `getMissingSourceValue()` returns a promise-like
|
|
304
|
+
* result. Use {@link fillMissingSourceDefaultsAsync} when async
|
|
305
|
+
* default extraction is expected.
|
|
306
|
+
* @internal
|
|
307
|
+
* @since 1.0.0
|
|
308
|
+
*/
|
|
309
|
+
function fillMissingSourceDefaults(nodes, runtime) {
|
|
310
|
+
const failures = [];
|
|
311
|
+
for (const node of nodes) {
|
|
312
|
+
const meta = node.parser.dependencyMetadata;
|
|
313
|
+
if (meta?.source == null) continue;
|
|
314
|
+
if (runtime.hasSource(meta.source.sourceId)) continue;
|
|
315
|
+
if (runtime.isSourceFailed(meta.source.sourceId)) continue;
|
|
316
|
+
if (node.matched === true) continue;
|
|
317
|
+
if (!meta.source.preservesSourceValue) continue;
|
|
318
|
+
if (meta.source.getMissingSourceValue == null) continue;
|
|
319
|
+
let result;
|
|
320
|
+
try {
|
|
321
|
+
result = meta.source.getMissingSourceValue();
|
|
322
|
+
} catch (e) {
|
|
323
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
324
|
+
failures.push({
|
|
325
|
+
sourceId: meta.source.sourceId,
|
|
326
|
+
path: node.path,
|
|
327
|
+
error: {
|
|
328
|
+
success: false,
|
|
329
|
+
error: require_message.message`Default value evaluation failed: ${msg}`
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
if (isPromiseLike(result)) throw new TypeError(`fillMissingSourceDefaults() received an async getMissingSourceValue() result for ${String(meta.source.sourceId)}. Use fillMissingSourceDefaultsAsync() instead.`);
|
|
335
|
+
if (result.success) runtime.registerSource(meta.source.sourceId, result.value, "default");
|
|
336
|
+
else failures.push({
|
|
337
|
+
sourceId: meta.source.sourceId,
|
|
338
|
+
path: node.path,
|
|
339
|
+
error: result
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
return failures;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Async version of {@link fillMissingSourceDefaults}.
|
|
346
|
+
* Awaits async `getMissingSourceValue` results.
|
|
347
|
+
*
|
|
348
|
+
* @param nodes The runtime nodes to inspect.
|
|
349
|
+
* @param runtime The dependency runtime context.
|
|
350
|
+
* @returns Failures from default evaluation (empty if all succeeded).
|
|
351
|
+
* @internal
|
|
352
|
+
* @since 1.0.0
|
|
353
|
+
*/
|
|
354
|
+
async function fillMissingSourceDefaultsAsync(nodes, runtime) {
|
|
355
|
+
const failures = [];
|
|
356
|
+
for (const node of nodes) {
|
|
357
|
+
const meta = node.parser.dependencyMetadata;
|
|
358
|
+
if (meta?.source == null) continue;
|
|
359
|
+
if (runtime.hasSource(meta.source.sourceId)) continue;
|
|
360
|
+
if (runtime.isSourceFailed(meta.source.sourceId)) continue;
|
|
361
|
+
if (node.matched === true) continue;
|
|
362
|
+
if (!meta.source.preservesSourceValue) continue;
|
|
363
|
+
if (meta.source.getMissingSourceValue == null) continue;
|
|
364
|
+
let result;
|
|
365
|
+
try {
|
|
366
|
+
result = await meta.source.getMissingSourceValue();
|
|
367
|
+
} catch (e) {
|
|
368
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
369
|
+
failures.push({
|
|
370
|
+
sourceId: meta.source.sourceId,
|
|
371
|
+
path: node.path,
|
|
372
|
+
error: {
|
|
373
|
+
success: false,
|
|
374
|
+
error: require_message.message`Default value evaluation failed: ${msg}`
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
if (result.success) runtime.registerSource(meta.source.sourceId, result.value, "default");
|
|
380
|
+
else failures.push({
|
|
381
|
+
sourceId: meta.source.sourceId,
|
|
382
|
+
path: node.path,
|
|
383
|
+
error: result
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
return failures;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Replays a derived parser with resolved dependency values (sync).
|
|
390
|
+
*
|
|
391
|
+
* Returns `undefined` if dependencies cannot be resolved.
|
|
392
|
+
*
|
|
393
|
+
* @param node The runtime node with derived metadata.
|
|
394
|
+
* @param rawInput The raw input to replay.
|
|
395
|
+
* @param runtime The dependency runtime context.
|
|
396
|
+
* @returns The replay result, or `undefined`.
|
|
397
|
+
* @throws {TypeError} If `replayParse()` returns a promise-like result.
|
|
398
|
+
* Use {@link replayDerivedParserAsync} for async replay.
|
|
399
|
+
* @internal
|
|
400
|
+
* @since 1.0.0
|
|
401
|
+
*/
|
|
402
|
+
function replayDerivedParser(node, rawInput, runtime) {
|
|
403
|
+
const meta = node.parser.dependencyMetadata;
|
|
404
|
+
if (meta?.derived == null) return void 0;
|
|
405
|
+
let defaults = node.defaultDependencyValues;
|
|
406
|
+
if (defaults == null && meta.derived.getDefaultDependencyValues != null) try {
|
|
407
|
+
defaults = meta.derived.getDefaultDependencyValues();
|
|
408
|
+
} catch {
|
|
409
|
+
return void 0;
|
|
410
|
+
}
|
|
411
|
+
const resolution = runtime.resolveDependencies({
|
|
412
|
+
dependencyIds: meta.derived.dependencyIds,
|
|
413
|
+
defaultValues: defaults
|
|
414
|
+
});
|
|
415
|
+
if (resolution.kind === "missing") return void 0;
|
|
416
|
+
if (resolution.kind === "partial") return void 0;
|
|
417
|
+
const key = createReplayKey(node.path, rawInput, resolution.values, meta.derived.replayParse);
|
|
418
|
+
const cached = runtime.getReplayResult(key);
|
|
419
|
+
if (cached != null) return cached;
|
|
420
|
+
const result = meta.derived.replayParse(rawInput, resolution.values);
|
|
421
|
+
if (isPromiseLike(result)) throw new TypeError("replayDerivedParser() received an async replayParse() result. Use replayDerivedParserAsync() instead.");
|
|
422
|
+
runtime.setReplayResult(key, result);
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Replays a derived parser with resolved dependency values (async).
|
|
427
|
+
*
|
|
428
|
+
* Returns `undefined` if dependencies cannot be resolved.
|
|
429
|
+
*
|
|
430
|
+
* @param node The runtime node with derived metadata.
|
|
431
|
+
* @param rawInput The raw input to replay.
|
|
432
|
+
* @param runtime The dependency runtime context.
|
|
433
|
+
* @returns The replay result, or `undefined`.
|
|
434
|
+
* @internal
|
|
435
|
+
* @since 1.0.0
|
|
436
|
+
*/
|
|
437
|
+
async function replayDerivedParserAsync(node, rawInput, runtime) {
|
|
438
|
+
const meta = node.parser.dependencyMetadata;
|
|
439
|
+
if (meta?.derived == null) return void 0;
|
|
440
|
+
let defaults = node.defaultDependencyValues;
|
|
441
|
+
if (defaults == null && meta.derived.getDefaultDependencyValues != null) try {
|
|
442
|
+
defaults = meta.derived.getDefaultDependencyValues();
|
|
443
|
+
} catch {
|
|
444
|
+
return void 0;
|
|
445
|
+
}
|
|
446
|
+
const resolution = runtime.resolveDependencies({
|
|
447
|
+
dependencyIds: meta.derived.dependencyIds,
|
|
448
|
+
defaultValues: defaults
|
|
449
|
+
});
|
|
450
|
+
if (resolution.kind === "missing") return void 0;
|
|
451
|
+
if (resolution.kind === "partial") return void 0;
|
|
452
|
+
const key = createReplayKey(node.path, rawInput, resolution.values, meta.derived.replayParse);
|
|
453
|
+
const cached = runtime.getReplayResult(key);
|
|
454
|
+
if (cached != null) return cached;
|
|
455
|
+
const result = await meta.derived.replayParse(rawInput, resolution.values);
|
|
456
|
+
runtime.setReplayResult(key, result);
|
|
457
|
+
return result;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Checks if a value is a plain object (not a class instance) for the
|
|
461
|
+
* purpose of recursive state traversal.
|
|
462
|
+
*/
|
|
463
|
+
function isPlainObject(value) {
|
|
464
|
+
if (typeof value !== "object" || value === null) return false;
|
|
465
|
+
const proto = Object.getPrototypeOf(value);
|
|
466
|
+
return proto === Object.prototype || proto === null;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Resolves a single {@link DeferredParseState} using the dependency runtime.
|
|
470
|
+
*
|
|
471
|
+
* Returns the replay result if all dependencies are available, or the
|
|
472
|
+
* preliminary result if dependencies are missing.
|
|
473
|
+
*/
|
|
474
|
+
function resolveSingleDeferred(deferred, runtime) {
|
|
475
|
+
const isMultiDep = deferred.dependencyIds != null && deferred.dependencyIds.length > 0;
|
|
476
|
+
const depIds = isMultiDep ? deferred.dependencyIds : [deferred.dependencyId];
|
|
477
|
+
const resolution = runtime.resolveDependencies({
|
|
478
|
+
dependencyIds: depIds,
|
|
479
|
+
defaultValues: deferred.defaultValues
|
|
480
|
+
});
|
|
481
|
+
if (resolution.kind !== "resolved") return deferred.preliminaryResult;
|
|
482
|
+
if (resolution.usedDefaults.every((d) => d)) return deferred.preliminaryResult;
|
|
483
|
+
const depValue = isMultiDep ? resolution.values : resolution.values[0];
|
|
484
|
+
const result = deferred.parser[require_dependency.parseWithDependency](deferred.rawInput, depValue);
|
|
485
|
+
if (isPromiseLike(result)) throw new TypeError("resolveStateWithRuntime() received an async parseWithDependency() result. Use resolveStateWithRuntimeAsync() instead.");
|
|
486
|
+
return result;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Recursively collects dependency source values from {@link DependencySourceState}
|
|
490
|
+
* objects found in the state tree and registers them in the runtime.
|
|
491
|
+
*
|
|
492
|
+
* This must run BEFORE deferred resolution so that all source values
|
|
493
|
+
* are available when replaying derived parsers.
|
|
494
|
+
*
|
|
495
|
+
* @param state The state tree to traverse.
|
|
496
|
+
* @param runtime The dependency runtime context to populate.
|
|
497
|
+
* @param visited Cycle guard for recursive traversal.
|
|
498
|
+
* @param excludedFields Optional property keys to skip at the current level.
|
|
499
|
+
* This exclusion set is not propagated recursively.
|
|
500
|
+
*/
|
|
501
|
+
function collectSourcesFromState(state, runtime, visited = /* @__PURE__ */ new WeakSet(), excludedFields) {
|
|
502
|
+
if (state == null || typeof state !== "object") return;
|
|
503
|
+
if (visited.has(state)) return;
|
|
504
|
+
visited.add(state);
|
|
505
|
+
if (require_dependency.isDependencySourceState(state)) {
|
|
506
|
+
const depId = state[require_dependency.dependencyId];
|
|
507
|
+
const result = state.result;
|
|
508
|
+
if (depId != null && result.success) runtime.registerSource(depId, result.value, "cli");
|
|
509
|
+
else if (depId != null) runtime.markSourceFailed(depId);
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
if (require_dependency.isDeferredParseState(state)) return;
|
|
513
|
+
if (Array.isArray(state)) {
|
|
514
|
+
for (const item of state) collectSourcesFromState(item, runtime, visited);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
if (typeof state === "object") for (const key of Reflect.ownKeys(state)) {
|
|
518
|
+
if (excludedFields?.has(key)) continue;
|
|
519
|
+
collectSourcesFromState(state[key], runtime, visited);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Recursively resolves all {@link DeferredParseState} objects in a state
|
|
524
|
+
* tree using the dependency runtime (sync).
|
|
525
|
+
*
|
|
526
|
+
* Performs a two-pass traversal:
|
|
527
|
+
* 1. Collect all {@link DependencySourceState} values into the runtime.
|
|
528
|
+
* 2. Resolve all {@link DeferredParseState} using the populated runtime.
|
|
529
|
+
*
|
|
530
|
+
* This replaces the old `resolveDeferredParseStates` with runtime-based
|
|
531
|
+
* resolution. Only traverses plain objects and arrays; class instances
|
|
532
|
+
* and primitives are returned as-is.
|
|
533
|
+
*
|
|
534
|
+
* @param state The state tree to resolve.
|
|
535
|
+
* @param runtime The dependency runtime context.
|
|
536
|
+
* @returns The resolved state tree.
|
|
537
|
+
* @throws {TypeError} If a deferred parser returns a promise-like result from
|
|
538
|
+
* `parseWithDependency()`. Use {@link resolveStateWithRuntimeAsync}
|
|
539
|
+
* for async resolution.
|
|
540
|
+
* @internal
|
|
541
|
+
* @since 1.0.0
|
|
542
|
+
*/
|
|
543
|
+
function resolveStateWithRuntime(state, runtime) {
|
|
544
|
+
collectSourcesFromState(state, runtime);
|
|
545
|
+
return resolveDeferredInState(state, runtime);
|
|
546
|
+
}
|
|
547
|
+
/** Pass 2 helper: recursively replace DeferredParseState with resolved values. */
|
|
548
|
+
function resolveDeferredInState(state, runtime, visited = /* @__PURE__ */ new WeakSet()) {
|
|
549
|
+
if (state == null) return state;
|
|
550
|
+
if (typeof state === "object") {
|
|
551
|
+
if (visited.has(state)) return state;
|
|
552
|
+
visited.add(state);
|
|
553
|
+
}
|
|
554
|
+
if (require_dependency.isDeferredParseState(state)) return resolveSingleDeferred(state, runtime);
|
|
555
|
+
if (require_dependency.isDependencySourceState(state)) return state;
|
|
556
|
+
if (Array.isArray(state)) {
|
|
557
|
+
const resolved = state.map((item) => resolveDeferredInState(item, runtime, visited));
|
|
558
|
+
return resolved.every((item, index) => item === state[index]) ? state : resolved;
|
|
559
|
+
}
|
|
560
|
+
if (isPlainObject(state)) {
|
|
561
|
+
const keys = Reflect.ownKeys(state);
|
|
562
|
+
const resolvedEntries = keys.map((key) => [key, resolveDeferredInState(state[key], runtime, visited)]);
|
|
563
|
+
if (resolvedEntries.every(([key, value]) => value === state[key])) return state;
|
|
564
|
+
const resolved = Object.create(Object.getPrototypeOf(state));
|
|
565
|
+
for (const [key, value] of resolvedEntries) resolved[key] = value;
|
|
566
|
+
return resolved;
|
|
567
|
+
}
|
|
568
|
+
return state;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Async version of {@link resolveStateWithRuntime}.
|
|
572
|
+
*
|
|
573
|
+
* @param state The state tree to resolve.
|
|
574
|
+
* @param runtime The dependency runtime context.
|
|
575
|
+
* @returns The resolved state tree.
|
|
576
|
+
* @internal
|
|
577
|
+
* @since 1.0.0
|
|
578
|
+
*/
|
|
579
|
+
function resolveStateWithRuntimeAsync(state, runtime) {
|
|
580
|
+
collectSourcesFromState(state, runtime);
|
|
581
|
+
return resolveDeferredInStateAsync(state, runtime);
|
|
582
|
+
}
|
|
583
|
+
/** Async pass 2 helper. */
|
|
584
|
+
async function resolveDeferredInStateAsync(state, runtime, visited = /* @__PURE__ */ new WeakSet()) {
|
|
585
|
+
if (state == null) return state;
|
|
586
|
+
if (typeof state === "object") {
|
|
587
|
+
if (visited.has(state)) return state;
|
|
588
|
+
visited.add(state);
|
|
589
|
+
}
|
|
590
|
+
if (require_dependency.isDeferredParseState(state)) {
|
|
591
|
+
const deferred = state;
|
|
592
|
+
const isMultiDep = deferred.dependencyIds != null && deferred.dependencyIds.length > 0;
|
|
593
|
+
const depIds = isMultiDep ? deferred.dependencyIds : [deferred.dependencyId];
|
|
594
|
+
const resolution = runtime.resolveDependencies({
|
|
595
|
+
dependencyIds: depIds,
|
|
596
|
+
defaultValues: deferred.defaultValues
|
|
597
|
+
});
|
|
598
|
+
if (resolution.kind !== "resolved") return deferred.preliminaryResult;
|
|
599
|
+
if (resolution.usedDefaults.every((d) => d)) return deferred.preliminaryResult;
|
|
600
|
+
const depValue = isMultiDep ? resolution.values : resolution.values[0];
|
|
601
|
+
return Promise.resolve(deferred.parser[require_dependency.parseWithDependency](deferred.rawInput, depValue));
|
|
602
|
+
}
|
|
603
|
+
if (require_dependency.isDependencySourceState(state)) return state;
|
|
604
|
+
if (Array.isArray(state)) {
|
|
605
|
+
const resolved = await Promise.all(state.map((item) => resolveDeferredInStateAsync(item, runtime, visited)));
|
|
606
|
+
return resolved.every((item, index) => item === state[index]) ? state : resolved;
|
|
607
|
+
}
|
|
608
|
+
if (isPlainObject(state)) {
|
|
609
|
+
const keys = Reflect.ownKeys(state);
|
|
610
|
+
const resolvedEntries = await Promise.all(keys.map(async (key) => {
|
|
611
|
+
return [key, await resolveDeferredInStateAsync(state[key], runtime, visited)];
|
|
612
|
+
}));
|
|
613
|
+
if (resolvedEntries.every(([key, value]) => value === state[key])) return state;
|
|
614
|
+
const resolved = Object.create(Object.getPrototypeOf(state));
|
|
615
|
+
for (const [key, value] of resolvedEntries) resolved[key] = value;
|
|
616
|
+
return resolved;
|
|
617
|
+
}
|
|
618
|
+
return state;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Determines whether a parser state represents an explicit match (the user
|
|
622
|
+
* provided input) rather than an initial/pending state.
|
|
623
|
+
*/
|
|
624
|
+
function isMatchedState(fieldState, parser) {
|
|
625
|
+
if (fieldState === void 0) return false;
|
|
626
|
+
const innerState = Array.isArray(fieldState) && fieldState.length === 1 ? fieldState[0] : fieldState;
|
|
627
|
+
if (require_dependency.isPendingDependencySourceState(innerState)) return false;
|
|
628
|
+
if (parser[require_parser.unmatchedNonCliDependencySourceStateMarker] === true && innerState != null && typeof innerState === "object" && Object.hasOwn(innerState, "hasCliValue") && innerState.hasCliValue === false) return false;
|
|
629
|
+
if (fieldState === parser.initialState) return false;
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Builds {@link RuntimeNode}s from field→parser pairs and a state record.
|
|
634
|
+
*
|
|
635
|
+
* Used by `object()` and `merge()` constructs.
|
|
636
|
+
*
|
|
637
|
+
* @param pairs Field→parser pairs.
|
|
638
|
+
* @param state The state record keyed by field name.
|
|
639
|
+
* @param parentPath Optional parent path prefix.
|
|
640
|
+
* @returns An array of runtime nodes.
|
|
641
|
+
* @internal
|
|
642
|
+
* @since 1.0.0
|
|
643
|
+
*/
|
|
644
|
+
function buildRuntimeNodesFromPairs(pairs, state, parentPath) {
|
|
645
|
+
const prefix = parentPath ?? [];
|
|
646
|
+
const nodes = [];
|
|
647
|
+
for (const [field, parser] of pairs) {
|
|
648
|
+
const fieldState = Object.hasOwn(state, field) ? state[field] : void 0;
|
|
649
|
+
nodes.push({
|
|
650
|
+
path: [...prefix, field],
|
|
651
|
+
parser,
|
|
652
|
+
state: fieldState,
|
|
653
|
+
matched: isMatchedState(fieldState, parser)
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
return nodes;
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Builds {@link RuntimeNode}s from a parser array and a state array.
|
|
660
|
+
*
|
|
661
|
+
* Used by `tuple()` and `concat()` constructs.
|
|
662
|
+
*
|
|
663
|
+
* @param parsers The child parsers.
|
|
664
|
+
* @param stateArray The state array (one element per parser).
|
|
665
|
+
* @param parentPath Optional parent path prefix.
|
|
666
|
+
* @returns An array of runtime nodes.
|
|
667
|
+
* @internal
|
|
668
|
+
* @since 1.0.0
|
|
669
|
+
*/
|
|
670
|
+
function buildRuntimeNodesFromArray(parsers, stateArray, parentPath) {
|
|
671
|
+
const prefix = parentPath ?? [];
|
|
672
|
+
const nodes = [];
|
|
673
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
674
|
+
const parser = parsers[i];
|
|
675
|
+
const elemState = i < stateArray.length ? stateArray[i] : void 0;
|
|
676
|
+
nodes.push({
|
|
677
|
+
path: [...prefix, i],
|
|
678
|
+
parser,
|
|
679
|
+
state: elemState,
|
|
680
|
+
matched: isMatchedState(elemState, parser)
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
return nodes;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
//#endregion
|
|
687
|
+
exports.buildRuntimeNodesFromArray = buildRuntimeNodesFromArray;
|
|
688
|
+
exports.buildRuntimeNodesFromPairs = buildRuntimeNodesFromPairs;
|
|
689
|
+
exports.collectExplicitSourceValues = collectExplicitSourceValues;
|
|
690
|
+
exports.collectExplicitSourceValuesAsync = collectExplicitSourceValuesAsync;
|
|
691
|
+
exports.collectSourcesFromState = collectSourcesFromState;
|
|
692
|
+
exports.createDependencyRuntimeContext = createDependencyRuntimeContext;
|
|
693
|
+
exports.fillMissingSourceDefaults = fillMissingSourceDefaults;
|
|
694
|
+
exports.fillMissingSourceDefaultsAsync = fillMissingSourceDefaultsAsync;
|
|
695
|
+
exports.replayDerivedParser = replayDerivedParser;
|
|
696
|
+
exports.replayDerivedParserAsync = replayDerivedParserAsync;
|
|
697
|
+
exports.resolveStateWithRuntime = resolveStateWithRuntime;
|
|
698
|
+
exports.resolveStateWithRuntimeAsync = resolveStateWithRuntimeAsync;
|