@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.
Files changed (109) hide show
  1. package/dist/annotation-state.cjs +425 -0
  2. package/dist/annotation-state.d.cts +24 -0
  3. package/dist/annotation-state.d.ts +24 -0
  4. package/dist/annotation-state.js +414 -0
  5. package/dist/annotations.cjs +2 -248
  6. package/dist/annotations.d.cts +2 -137
  7. package/dist/annotations.d.ts +2 -137
  8. package/dist/annotations.js +2 -238
  9. package/dist/completion.cjs +611 -100
  10. package/dist/completion.d.cts +1 -1
  11. package/dist/completion.d.ts +1 -1
  12. package/dist/completion.js +611 -100
  13. package/dist/constructs.cjs +3338 -827
  14. package/dist/constructs.d.cts +48 -7
  15. package/dist/constructs.d.ts +48 -7
  16. package/dist/constructs.js +3338 -827
  17. package/dist/context.cjs +0 -23
  18. package/dist/context.d.cts +119 -53
  19. package/dist/context.d.ts +119 -53
  20. package/dist/context.js +0 -22
  21. package/dist/dependency-metadata.cjs +139 -0
  22. package/dist/dependency-metadata.d.cts +112 -0
  23. package/dist/dependency-metadata.d.ts +112 -0
  24. package/dist/dependency-metadata.js +138 -0
  25. package/dist/dependency-runtime.cjs +698 -0
  26. package/dist/dependency-runtime.d.cts +149 -0
  27. package/dist/dependency-runtime.d.ts +149 -0
  28. package/dist/dependency-runtime.js +687 -0
  29. package/dist/dependency.cjs +7 -928
  30. package/dist/dependency.d.cts +2 -794
  31. package/dist/dependency.d.ts +2 -794
  32. package/dist/dependency.js +2 -899
  33. package/dist/displaywidth.cjs +44 -0
  34. package/dist/displaywidth.js +43 -0
  35. package/dist/doc.cjs +285 -23
  36. package/dist/doc.d.cts +57 -2
  37. package/dist/doc.d.ts +57 -2
  38. package/dist/doc.js +283 -25
  39. package/dist/execution-context.cjs +56 -0
  40. package/dist/execution-context.js +53 -0
  41. package/dist/extension.cjs +87 -0
  42. package/dist/extension.d.cts +97 -0
  43. package/dist/extension.d.ts +97 -0
  44. package/dist/extension.js +76 -0
  45. package/dist/facade.cjs +718 -523
  46. package/dist/facade.d.cts +87 -18
  47. package/dist/facade.d.ts +87 -18
  48. package/dist/facade.js +718 -523
  49. package/dist/index.cjs +14 -29
  50. package/dist/index.d.cts +10 -10
  51. package/dist/index.d.ts +10 -10
  52. package/dist/index.js +7 -7
  53. package/dist/input-trace.cjs +56 -0
  54. package/dist/input-trace.d.cts +77 -0
  55. package/dist/input-trace.d.ts +77 -0
  56. package/dist/input-trace.js +55 -0
  57. package/dist/internal/annotations.cjs +316 -0
  58. package/dist/internal/annotations.d.cts +140 -0
  59. package/dist/internal/annotations.d.ts +140 -0
  60. package/dist/internal/annotations.js +306 -0
  61. package/dist/internal/dependency.cjs +984 -0
  62. package/dist/internal/dependency.d.cts +539 -0
  63. package/dist/internal/dependency.d.ts +539 -0
  64. package/dist/internal/dependency.js +964 -0
  65. package/dist/{mode-dispatch.cjs → internal/mode-dispatch.cjs} +1 -3
  66. package/dist/{mode-dispatch.d.cts → internal/mode-dispatch.d.cts} +3 -7
  67. package/dist/{mode-dispatch.d.ts → internal/mode-dispatch.d.ts} +3 -7
  68. package/dist/{mode-dispatch.js → internal/mode-dispatch.js} +1 -3
  69. package/dist/internal/parser.cjs +728 -0
  70. package/dist/internal/parser.d.cts +947 -0
  71. package/dist/internal/parser.d.ts +947 -0
  72. package/dist/internal/parser.js +711 -0
  73. package/dist/message.cjs +84 -26
  74. package/dist/message.d.cts +49 -9
  75. package/dist/message.d.ts +49 -9
  76. package/dist/message.js +84 -27
  77. package/dist/modifiers.cjs +1023 -240
  78. package/dist/modifiers.d.cts +42 -1
  79. package/dist/modifiers.d.ts +42 -1
  80. package/dist/modifiers.js +1023 -240
  81. package/dist/parser.cjs +11 -463
  82. package/dist/parser.d.cts +3 -537
  83. package/dist/parser.d.ts +3 -537
  84. package/dist/parser.js +2 -433
  85. package/dist/phase2-seed.cjs +59 -0
  86. package/dist/phase2-seed.js +56 -0
  87. package/dist/primitives.cjs +557 -208
  88. package/dist/primitives.d.cts +10 -14
  89. package/dist/primitives.d.ts +10 -14
  90. package/dist/primitives.js +557 -208
  91. package/dist/program.cjs +5 -1
  92. package/dist/program.d.cts +5 -3
  93. package/dist/program.d.ts +5 -3
  94. package/dist/program.js +6 -1
  95. package/dist/suggestion.cjs +22 -8
  96. package/dist/suggestion.js +22 -8
  97. package/dist/usage-internals.cjs +3 -2
  98. package/dist/usage-internals.js +4 -2
  99. package/dist/usage.cjs +195 -40
  100. package/dist/usage.d.cts +92 -11
  101. package/dist/usage.d.ts +92 -11
  102. package/dist/usage.js +194 -41
  103. package/dist/validate.cjs +170 -0
  104. package/dist/validate.js +164 -0
  105. package/dist/valueparser.cjs +1278 -191
  106. package/dist/valueparser.d.cts +330 -20
  107. package/dist/valueparser.d.ts +330 -20
  108. package/dist/valueparser.js +1277 -192
  109. package/package.json +9 -9
@@ -0,0 +1,687 @@
1
+ import { message } from "./message.js";
2
+ import { dependencyId, isDeferredParseState, isDependencySourceState, isPendingDependencySourceState, parseWithDependency } from "./internal/dependency.js";
3
+ import { unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
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: 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: 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[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 (isDependencySourceState(state)) {
506
+ const depId = state[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 (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 (isDeferredParseState(state)) return resolveSingleDeferred(state, runtime);
555
+ if (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 (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[parseWithDependency](deferred.rawInput, depValue));
602
+ }
603
+ if (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 (isPendingDependencySourceState(innerState)) return false;
628
+ if (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
+ export { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, createDependencyRuntimeContext, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, replayDerivedParser, replayDerivedParserAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync };