@optique/core 1.3.0-dev.2430 → 1.3.0-dev.2433
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/constructs.cjs +238 -88
- package/dist/constructs.js +239 -89
- package/dist/dependency-metadata.cjs +1 -0
- package/dist/dependency-metadata.d.cts +15 -0
- package/dist/dependency-metadata.d.ts +15 -0
- package/dist/dependency-metadata.js +1 -0
- package/dist/dependency-runtime.cjs +250 -33
- package/dist/dependency-runtime.d.cts +92 -1
- package/dist/dependency-runtime.d.ts +92 -1
- package/dist/dependency-runtime.js +249 -34
- package/dist/internal/parser.cjs +2 -1
- package/dist/internal/parser.d.cts +16 -0
- package/dist/internal/parser.d.ts +16 -0
- package/dist/internal/parser.js +2 -1
- package/dist/primitives.cjs +1 -1
- package/dist/primitives.js +2 -2
- package/package.json +2 -2
|
@@ -404,6 +404,17 @@ async function collectExplicitSourceValuesAsync(nodes, runtime) {
|
|
|
404
404
|
* @since 1.3.0
|
|
405
405
|
*/
|
|
406
406
|
function orderDependencyNodes(nodes) {
|
|
407
|
+
return drainDependencyGraph(buildDependencyGraph(nodes));
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Builds the provider-edge graph over runtime nodes.
|
|
411
|
+
*
|
|
412
|
+
* Scheduling barriers act as providers for the source IDs their
|
|
413
|
+
* selected subtree may expose and depend on their discriminator source
|
|
414
|
+
* as well as on outer providers of the completion dependencies their
|
|
415
|
+
* selectable subtrees aggregate.
|
|
416
|
+
*/
|
|
417
|
+
function buildDependencyGraph(nodes) {
|
|
407
418
|
const providers = /* @__PURE__ */ new Map();
|
|
408
419
|
const addProvider = (sourceId, node) => {
|
|
409
420
|
const existing = providers.get(sourceId);
|
|
@@ -418,51 +429,162 @@ function orderDependencyNodes(nodes) {
|
|
|
418
429
|
const outgoing = /* @__PURE__ */ new Map();
|
|
419
430
|
const indegree = /* @__PURE__ */ new Map();
|
|
420
431
|
for (const node of nodes) indegree.set(node, 0);
|
|
421
|
-
const addEdge = (provider, consumer) => {
|
|
422
|
-
const edges = outgoing.get(provider) ?? /* @__PURE__ */ new
|
|
423
|
-
|
|
424
|
-
|
|
432
|
+
const addEdge = (provider, consumer, advisory) => {
|
|
433
|
+
const edges = outgoing.get(provider) ?? /* @__PURE__ */ new Map();
|
|
434
|
+
const existing = edges.get(consumer);
|
|
435
|
+
if (existing != null) {
|
|
436
|
+
if (existing && !advisory) edges.set(consumer, false);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
edges.set(consumer, advisory);
|
|
425
440
|
outgoing.set(provider, edges);
|
|
426
441
|
indegree.set(consumer, (indegree.get(consumer) ?? 0) + 1);
|
|
427
442
|
};
|
|
428
443
|
for (const node of nodes) {
|
|
429
444
|
const derived = node.parser.dependencyMetadata?.derived;
|
|
430
|
-
if (derived != null) for (const dependencySourceId of derived.dependencyIds) for (const provider of providers.get(dependencySourceId) ?? []) addEdge(provider, node);
|
|
445
|
+
if (derived != null) for (const dependencySourceId of derived.dependencyIds) for (const provider of providers.get(dependencySourceId) ?? []) addEdge(provider, node, false);
|
|
431
446
|
const completion = node.parser.dependencyMetadata?.completion;
|
|
432
447
|
if (completion != null && !hasInactiveCompletion(node)) {
|
|
433
448
|
const ownSourceId = node.parser.dependencyMetadata?.source?.sourceId;
|
|
434
449
|
for (const dependencySourceId of completion.dependencyIds) {
|
|
435
450
|
if (dependencySourceId === ownSourceId) continue;
|
|
436
|
-
for (const provider of providers.get(dependencySourceId) ?? []) if (provider !== node) addEdge(provider, node);
|
|
451
|
+
for (const provider of providers.get(dependencySourceId) ?? []) if (provider !== node) addEdge(provider, node, false);
|
|
437
452
|
}
|
|
438
453
|
}
|
|
439
454
|
if (node.requiresSourceId != null) {
|
|
440
|
-
for (const provider of providers.get(node.requiresSourceId) ?? []) if (provider !== node) addEdge(provider, node);
|
|
455
|
+
for (const provider of providers.get(node.requiresSourceId) ?? []) if (provider !== node) addEdge(provider, node, false);
|
|
441
456
|
}
|
|
442
457
|
const barrierDeps = node.barrierCompletionDependencies;
|
|
443
458
|
if (barrierDeps != null) {
|
|
444
|
-
|
|
459
|
+
const advisory = node.barrierResolutionState !== "resolved";
|
|
460
|
+
for (const dependencySourceId of barrierDeps.orderingDependencyIds) for (const provider of providers.get(dependencySourceId) ?? []) if (provider !== node) addEdge(provider, node, advisory);
|
|
445
461
|
}
|
|
446
462
|
}
|
|
447
463
|
const declarationOrder = new Map(nodes.map((node, index) => [node, index]));
|
|
464
|
+
return {
|
|
465
|
+
nodes,
|
|
466
|
+
outgoing,
|
|
467
|
+
indegree,
|
|
468
|
+
declarationOrder
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Drains the graph in stable topological order.
|
|
473
|
+
*
|
|
474
|
+
* A stall—no node with indegree zero remains—normally means a genuine
|
|
475
|
+
* cycle. When the stalled region contains an unresolved barrier's
|
|
476
|
+
* advisory ordering edges within one strongly connected component, the
|
|
477
|
+
* apparent cycle aggregates edges from branches that cannot be selected
|
|
478
|
+
* together, so those advisory edges are relaxed and the drain resumes;
|
|
479
|
+
* the barrier's own resolution later replaces the estimate with
|
|
480
|
+
* concrete edges, and a cycle among those still throws.
|
|
481
|
+
*
|
|
482
|
+
* @throws {TypeError} If active provider edges contain a cycle.
|
|
483
|
+
*/
|
|
484
|
+
function drainDependencyGraph(graph) {
|
|
485
|
+
const { nodes, outgoing, declarationOrder } = graph;
|
|
486
|
+
const indegree = new Map(graph.indegree);
|
|
448
487
|
const ready = nodes.filter((node) => indegree.get(node) === 0);
|
|
449
488
|
const ordered = [];
|
|
450
|
-
while (
|
|
451
|
-
ready.
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
489
|
+
while (true) {
|
|
490
|
+
while (ready.length > 0) {
|
|
491
|
+
ready.sort((left, right) => declarationOrder.get(left) - declarationOrder.get(right));
|
|
492
|
+
const node = ready.shift();
|
|
493
|
+
ordered.push(node);
|
|
494
|
+
for (const consumer of outgoing.get(node)?.keys() ?? []) {
|
|
495
|
+
const next = (indegree.get(consumer) ?? 0) - 1;
|
|
496
|
+
indegree.set(consumer, next);
|
|
497
|
+
if (next === 0) ready.push(consumer);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
if (ordered.length === nodes.length) return ordered;
|
|
501
|
+
const residual = nodes.filter((node) => (indegree.get(node) ?? 0) > 0);
|
|
502
|
+
const sccOf = findStronglyConnected(residual, outgoing);
|
|
503
|
+
let relaxed = false;
|
|
504
|
+
for (const provider of residual) {
|
|
505
|
+
const edges = outgoing.get(provider);
|
|
506
|
+
if (edges == null) continue;
|
|
507
|
+
for (const [consumer, advisory] of edges) {
|
|
508
|
+
if (!advisory) continue;
|
|
509
|
+
const providerScc = sccOf.get(provider);
|
|
510
|
+
if (providerScc == null || providerScc !== sccOf.get(consumer)) continue;
|
|
511
|
+
edges.delete(consumer);
|
|
512
|
+
const next = (indegree.get(consumer) ?? 0) - 1;
|
|
513
|
+
indegree.set(consumer, next);
|
|
514
|
+
if (next === 0) ready.push(consumer);
|
|
515
|
+
relaxed = true;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (!relaxed) {
|
|
519
|
+
const labels = residual.map(formatDependencyNodeLabel).join(" -> ");
|
|
520
|
+
throw new TypeError(`Circular dependency detected among dependency sources: ${labels}.`);
|
|
458
521
|
}
|
|
459
522
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Assigns each node in `subset` to a strongly connected component of
|
|
526
|
+
* the induced subgraph. Only components with more than one node are
|
|
527
|
+
* recorded—an acyclic node cannot be part of an apparent cycle.
|
|
528
|
+
*/
|
|
529
|
+
function findStronglyConnected(subset, outgoing) {
|
|
530
|
+
const inSubset = new Set(subset);
|
|
531
|
+
const index = /* @__PURE__ */ new Map();
|
|
532
|
+
const lowLink = /* @__PURE__ */ new Map();
|
|
533
|
+
const onStack = /* @__PURE__ */ new Set();
|
|
534
|
+
const stack = [];
|
|
535
|
+
const sccOf = /* @__PURE__ */ new Map();
|
|
536
|
+
let nextIndex = 0;
|
|
537
|
+
let nextScc = 0;
|
|
538
|
+
const strongConnect = (root) => {
|
|
539
|
+
const frames = [{
|
|
540
|
+
node: root,
|
|
541
|
+
children: [...outgoing.get(root)?.keys() ?? []].filter((child) => inSubset.has(child)),
|
|
542
|
+
i: 0
|
|
543
|
+
}];
|
|
544
|
+
index.set(root, nextIndex);
|
|
545
|
+
lowLink.set(root, nextIndex);
|
|
546
|
+
nextIndex++;
|
|
547
|
+
stack.push(root);
|
|
548
|
+
onStack.add(root);
|
|
549
|
+
while (frames.length > 0) {
|
|
550
|
+
const frame = frames[frames.length - 1];
|
|
551
|
+
if (frame.i < frame.children.length) {
|
|
552
|
+
const child = frame.children[frame.i++];
|
|
553
|
+
if (!index.has(child)) {
|
|
554
|
+
index.set(child, nextIndex);
|
|
555
|
+
lowLink.set(child, nextIndex);
|
|
556
|
+
nextIndex++;
|
|
557
|
+
stack.push(child);
|
|
558
|
+
onStack.add(child);
|
|
559
|
+
frames.push({
|
|
560
|
+
node: child,
|
|
561
|
+
children: [...outgoing.get(child)?.keys() ?? []].filter((c) => inSubset.has(c)),
|
|
562
|
+
i: 0
|
|
563
|
+
});
|
|
564
|
+
} else if (onStack.has(child)) lowLink.set(frame.node, Math.min(lowLink.get(frame.node), index.get(child)));
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
frames.pop();
|
|
568
|
+
const node = frame.node;
|
|
569
|
+
if (lowLink.get(node) === index.get(node)) {
|
|
570
|
+
const members = [];
|
|
571
|
+
while (true) {
|
|
572
|
+
const member = stack.pop();
|
|
573
|
+
onStack.delete(member);
|
|
574
|
+
members.push(member);
|
|
575
|
+
if (member === node) break;
|
|
576
|
+
}
|
|
577
|
+
if (members.length > 1) {
|
|
578
|
+
for (const member of members) sccOf.set(member, nextScc);
|
|
579
|
+
nextScc++;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
const parent = frames[frames.length - 1];
|
|
583
|
+
if (parent != null) lowLink.set(parent.node, Math.min(lowLink.get(parent.node), lowLink.get(node)));
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
for (const node of subset) if (!index.has(node)) strongConnect(node);
|
|
587
|
+
return sccOf;
|
|
466
588
|
}
|
|
467
589
|
/** Resolves and publishes matched derived sources in stable dependency order. */
|
|
468
590
|
function resolveDerivedSourceValues(nodes, runtime, options) {
|
|
@@ -921,6 +1043,35 @@ const sourceCollectionExpansionKey = Symbol("@optique/core/dependency-runtime/so
|
|
|
921
1043
|
*/
|
|
922
1044
|
const staticSourceScopeKey = Symbol("@optique/core/dependency-runtime/staticSourceScope");
|
|
923
1045
|
/**
|
|
1046
|
+
* Static child parsers reachable only through a mutually exclusive
|
|
1047
|
+
* selection, such as `or()` alternatives, a `conditional()`'s branches,
|
|
1048
|
+
* or a `command()`'s inner parser.
|
|
1049
|
+
*
|
|
1050
|
+
* The walk unions sources and completion dependencies from this scope
|
|
1051
|
+
* exactly like {@link staticSourceScopeKey}, but a source occurrence
|
|
1052
|
+
* reached through an exclusive edge is never a *guaranteed* provider:
|
|
1053
|
+
* the run may select a sibling instead, so a scheduling barrier must not
|
|
1054
|
+
* assume the occurrence will publish. See issue #924.
|
|
1055
|
+
*
|
|
1056
|
+
* @internal
|
|
1057
|
+
* @since 1.3.0
|
|
1058
|
+
*/
|
|
1059
|
+
const exclusiveSourceScopeKey = Symbol("@optique/core/dependency-runtime/exclusiveSourceScope");
|
|
1060
|
+
/**
|
|
1061
|
+
* Source IDs a parser guarantees to provide on every successful route
|
|
1062
|
+
* through it, regardless of which internal alternative is selected.
|
|
1063
|
+
*
|
|
1064
|
+
* A `conditional()` installs the intersection of its branches' guaranteed
|
|
1065
|
+
* provides here (including the default branch when present), so an outer
|
|
1066
|
+
* scheduling barrier can treat a source that *every* selectable route
|
|
1067
|
+
* publishes as guaranteed even though each individual branch edge is
|
|
1068
|
+
* exclusive. See issue #924.
|
|
1069
|
+
*
|
|
1070
|
+
* @internal
|
|
1071
|
+
* @since 1.3.0
|
|
1072
|
+
*/
|
|
1073
|
+
const guaranteedStaticSourceIdsKey = Symbol("@optique/core/dependency-runtime/guaranteedStaticSourceIds");
|
|
1074
|
+
/**
|
|
924
1075
|
* Forwards effectful scheduling through a shape-preserving wrapper such
|
|
925
1076
|
* as `map()`, `optional()`, `withDefault()`, or `nonEmpty()`, so the
|
|
926
1077
|
* wrapped parser—a selected exclusive or command branch, or an ordinary
|
|
@@ -1098,17 +1249,54 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
|
|
|
1098
1249
|
const schedulable = nodes.filter((node) => node.parser.dependencyMetadata?.source?.completeSource != null || node.prepare != null);
|
|
1099
1250
|
if (schedulable.length === 0 && options?.includeStructural !== true) return empty;
|
|
1100
1251
|
const completed = [];
|
|
1101
|
-
|
|
1252
|
+
const barrierContext = {
|
|
1253
|
+
runtime,
|
|
1254
|
+
exec,
|
|
1255
|
+
schedule: (barrierNodes) => completeEffectfulSourcesAsync(barrierNodes, state, runtime, exec, {
|
|
1256
|
+
isReusable: () => false,
|
|
1257
|
+
isCollected: () => true,
|
|
1258
|
+
includeStructural: true
|
|
1259
|
+
}).then((result) => result.success ? void 0 : result)
|
|
1260
|
+
};
|
|
1261
|
+
const pending = [...nodes];
|
|
1262
|
+
const providesId = (node, id) => node.parser.dependencyMetadata?.source?.sourceId === id || node.providesSourceIds?.has(id) === true;
|
|
1263
|
+
const resolveBarrierAt = async (index) => {
|
|
1264
|
+
const candidate = pending[index];
|
|
1265
|
+
const resolution = await candidate.resolveBarrier(barrierContext);
|
|
1266
|
+
if (resolution != null && "success" in resolution) return resolution;
|
|
1267
|
+
pending[index] = resolution == null ? {
|
|
1268
|
+
...candidate,
|
|
1269
|
+
barrierResolutionState: "unresolvable"
|
|
1270
|
+
} : {
|
|
1271
|
+
...candidate,
|
|
1272
|
+
barrierResolutionState: "resolved",
|
|
1273
|
+
providesSourceIds: resolution.activeProvidesSourceIds,
|
|
1274
|
+
barrierCompletionDependencies: {
|
|
1275
|
+
orderingDependencyIds: resolution.orderingDependencyIds,
|
|
1276
|
+
demandEdges: []
|
|
1277
|
+
}
|
|
1278
|
+
};
|
|
1279
|
+
return void 0;
|
|
1280
|
+
};
|
|
1281
|
+
while (pending.length > 0) {
|
|
1282
|
+
for (let i = 0; i < pending.length; i++) {
|
|
1283
|
+
const candidate = pending[i];
|
|
1284
|
+
if (candidate.resolveBarrier == null || candidate.barrierResolutionState != null) continue;
|
|
1285
|
+
const requires = candidate.requiresSourceId;
|
|
1286
|
+
if (requires == null) continue;
|
|
1287
|
+
if (pending.some((other) => other !== candidate && providesId(other, requires))) continue;
|
|
1288
|
+
const failure = await resolveBarrierAt(i);
|
|
1289
|
+
if (failure != null) return failure;
|
|
1290
|
+
}
|
|
1291
|
+
const node = orderDependencyNodes(pending)[0];
|
|
1292
|
+
if (node.resolveBarrier != null && node.barrierResolutionState == null) {
|
|
1293
|
+
const failure = await resolveBarrierAt(pending.indexOf(node));
|
|
1294
|
+
if (failure != null) return failure;
|
|
1295
|
+
continue;
|
|
1296
|
+
}
|
|
1297
|
+
pending.splice(pending.indexOf(node), 1);
|
|
1102
1298
|
if (node.prepare != null) {
|
|
1103
|
-
const barrierFailure = await node.prepare(
|
|
1104
|
-
runtime,
|
|
1105
|
-
exec,
|
|
1106
|
-
schedule: (barrierNodes) => completeEffectfulSourcesAsync(barrierNodes, state, runtime, exec, {
|
|
1107
|
-
isReusable: () => false,
|
|
1108
|
-
isCollected: () => true,
|
|
1109
|
-
includeStructural: true
|
|
1110
|
-
}).then((result$1) => result$1.success ? void 0 : result$1)
|
|
1111
|
-
});
|
|
1299
|
+
const barrierFailure = await node.prepare(barrierContext);
|
|
1112
1300
|
if (barrierFailure != null) return barrierFailure;
|
|
1113
1301
|
continue;
|
|
1114
1302
|
}
|
|
@@ -1140,7 +1328,34 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
|
|
|
1140
1328
|
const collected = options?.isCollected?.(node) ?? options?.isReusable?.(node) ?? true;
|
|
1141
1329
|
if (source.extractSourceValue == null || collected === false) continue;
|
|
1142
1330
|
const extracted = await source.extractSourceValue(node.state);
|
|
1143
|
-
if (extracted?.success === true && extracted.value !== void 0)
|
|
1331
|
+
if (extracted?.success === true && extracted.value !== void 0) {
|
|
1332
|
+
runtime.registerSource(source.sourceId, extracted.value);
|
|
1333
|
+
continue;
|
|
1334
|
+
}
|
|
1335
|
+
if (options?.includeStructural === true && extracted?.success !== false && node.matched !== true && source.preservesSourceValue && source.getMissingSourceValue != null && !runtime.hasSource(source.sourceId) && !runtime.isSourceFailed(source.sourceId)) {
|
|
1336
|
+
let fallback = session?.missingDefaultsByOccurrence.get(source.getMissingSourceValue);
|
|
1337
|
+
if (fallback == null) {
|
|
1338
|
+
try {
|
|
1339
|
+
fallback = await source.getMissingSourceValue();
|
|
1340
|
+
} catch (e) {
|
|
1341
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1342
|
+
fallback = {
|
|
1343
|
+
success: false,
|
|
1344
|
+
error: message`Default value evaluation failed: ${msg}`
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
session?.missingDefaultsByOccurrence.set(source.getMissingSourceValue, fallback);
|
|
1348
|
+
}
|
|
1349
|
+
if (fallback.success) runtime.registerSource(source.sourceId, fallback.value);
|
|
1350
|
+
else {
|
|
1351
|
+
runtime.markSourceFailed(source.sourceId);
|
|
1352
|
+
propagateRuntimeSourceFailures(nodes, runtime);
|
|
1353
|
+
return {
|
|
1354
|
+
success: false,
|
|
1355
|
+
error: includeSourceFailureChain(fallback.error, source.sourceId, runtime)
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1144
1359
|
continue;
|
|
1145
1360
|
}
|
|
1146
1361
|
const pathKey = serializeSchedulingPath(node.path);
|
|
@@ -1466,4 +1681,4 @@ function getDefaultDependencySnapshotInner(state, visited) {
|
|
|
1466
1681
|
}
|
|
1467
1682
|
|
|
1468
1683
|
//#endregion
|
|
1469
|
-
export { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
|
|
1684
|
+
export { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
|
package/dist/internal/parser.cjs
CHANGED
|
@@ -26,7 +26,8 @@ function createEffectfulCompletionSession(policy = "eager") {
|
|
|
26
26
|
demanded: /* @__PURE__ */ new Set(),
|
|
27
27
|
effectfulSources: /* @__PURE__ */ new Set(),
|
|
28
28
|
completedByPath: /* @__PURE__ */ new Map(),
|
|
29
|
-
preparedByPath: /* @__PURE__ */ new Map()
|
|
29
|
+
preparedByPath: /* @__PURE__ */ new Map(),
|
|
30
|
+
missingDefaultsByOccurrence: /* @__PURE__ */ new WeakMap()
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
33
|
/**
|
|
@@ -480,6 +480,22 @@ interface EffectfulCompletionSession {
|
|
|
480
480
|
* re-completing the discriminator or re-selecting a branch.
|
|
481
481
|
*/
|
|
482
482
|
readonly preparedByPath: Map<string, unknown>;
|
|
483
|
+
/**
|
|
484
|
+
* Missing-value default results published for structural source
|
|
485
|
+
* occurrences inside a scheduling barrier's nested pass, keyed by the
|
|
486
|
+
* occurrence's composed `getMissingSourceValue` function. The
|
|
487
|
+
* function identifies the exact wrapper instance, so two branches of
|
|
488
|
+
* a `conditional()` sharing a node path never observe each other's
|
|
489
|
+
* defaults even when a phase-two binding changes the selection
|
|
490
|
+
* between passes. Unlike {@link completedByPath} this cache is
|
|
491
|
+
* shared across the passes of a run: a default does not depend on
|
|
492
|
+
* pass-specific state, so caching it keeps a non-idempotent
|
|
493
|
+
* `withDefault()` thunk at one evaluation per run even when the
|
|
494
|
+
* nested pass repeats.
|
|
495
|
+
*
|
|
496
|
+
* @since 1.3.0
|
|
497
|
+
*/
|
|
498
|
+
readonly missingDefaultsByOccurrence: WeakMap<object, ValueParserResult<unknown>>;
|
|
483
499
|
}
|
|
484
500
|
/**
|
|
485
501
|
* Creates a fresh {@link EffectfulCompletionSession}.
|
|
@@ -480,6 +480,22 @@ interface EffectfulCompletionSession {
|
|
|
480
480
|
* re-completing the discriminator or re-selecting a branch.
|
|
481
481
|
*/
|
|
482
482
|
readonly preparedByPath: Map<string, unknown>;
|
|
483
|
+
/**
|
|
484
|
+
* Missing-value default results published for structural source
|
|
485
|
+
* occurrences inside a scheduling barrier's nested pass, keyed by the
|
|
486
|
+
* occurrence's composed `getMissingSourceValue` function. The
|
|
487
|
+
* function identifies the exact wrapper instance, so two branches of
|
|
488
|
+
* a `conditional()` sharing a node path never observe each other's
|
|
489
|
+
* defaults even when a phase-two binding changes the selection
|
|
490
|
+
* between passes. Unlike {@link completedByPath} this cache is
|
|
491
|
+
* shared across the passes of a run: a default does not depend on
|
|
492
|
+
* pass-specific state, so caching it keeps a non-idempotent
|
|
493
|
+
* `withDefault()` thunk at one evaluation per run even when the
|
|
494
|
+
* nested pass repeats.
|
|
495
|
+
*
|
|
496
|
+
* @since 1.3.0
|
|
497
|
+
*/
|
|
498
|
+
readonly missingDefaultsByOccurrence: WeakMap<object, ValueParserResult<unknown>>;
|
|
483
499
|
}
|
|
484
500
|
/**
|
|
485
501
|
* Creates a fresh {@link EffectfulCompletionSession}.
|
package/dist/internal/parser.js
CHANGED
|
@@ -26,7 +26,8 @@ function createEffectfulCompletionSession(policy = "eager") {
|
|
|
26
26
|
demanded: /* @__PURE__ */ new Set(),
|
|
27
27
|
effectfulSources: /* @__PURE__ */ new Set(),
|
|
28
28
|
completedByPath: /* @__PURE__ */ new Map(),
|
|
29
|
-
preparedByPath: /* @__PURE__ */ new Map()
|
|
29
|
+
preparedByPath: /* @__PURE__ */ new Map(),
|
|
30
|
+
missingDefaultsByOccurrence: /* @__PURE__ */ new WeakMap()
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
33
|
/**
|
package/dist/primitives.cjs
CHANGED
|
@@ -1731,7 +1731,7 @@ function command(name, parser, options = {}) {
|
|
|
1731
1731
|
configurable: true,
|
|
1732
1732
|
enumerable: false
|
|
1733
1733
|
});
|
|
1734
|
-
Object.defineProperty(result, require_dependency_runtime.
|
|
1734
|
+
Object.defineProperty(result, require_dependency_runtime.exclusiveSourceScopeKey, {
|
|
1735
1735
|
value: [parser],
|
|
1736
1736
|
configurable: true,
|
|
1737
1737
|
enumerable: false
|
package/dist/primitives.js
CHANGED
|
@@ -4,7 +4,7 @@ import { validateCommandNames, validateOptionNames } from "./validate.js";
|
|
|
4
4
|
import { extractOptionNames, isDocHidden, isSuggestionHidden } from "./usage.js";
|
|
5
5
|
import { dispatchByMode, dispatchIterableByMode, wrapForMode } from "./internal/mode-dispatch.js";
|
|
6
6
|
import { getDefaultValuesFunction, getDependencyIds, getSnapshottedDefaultDependencyValues, isDerivedValueParser, suggestWithDependency } from "./internal/dependency.js";
|
|
7
|
-
import { effectfulSchedulingNodesKey, includeSourceFailureChain, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, sourceCollectionExpansionKey
|
|
7
|
+
import { effectfulSchedulingNodesKey, exclusiveSourceScopeKey, includeSourceFailureChain, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, sourceCollectionExpansionKey } from "./dependency-runtime.js";
|
|
8
8
|
import { getWrappedChildParseState, getWrappedChildState, isAnnotationWrappedInitialState, normalizeInjectedAnnotationState } from "./annotation-state.js";
|
|
9
9
|
import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
|
|
10
10
|
import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
|
|
@@ -1731,7 +1731,7 @@ function command(name, parser, options = {}) {
|
|
|
1731
1731
|
configurable: true,
|
|
1732
1732
|
enumerable: false
|
|
1733
1733
|
});
|
|
1734
|
-
Object.defineProperty(result,
|
|
1734
|
+
Object.defineProperty(result, exclusiveSourceScopeKey, {
|
|
1735
1735
|
value: [parser],
|
|
1736
1736
|
configurable: true,
|
|
1737
1737
|
enumerable: false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/core",
|
|
3
|
-
"version": "1.3.0-dev.
|
|
3
|
+
"version": "1.3.0-dev.2433",
|
|
4
4
|
"description": "Type-safe combinatorial command-line interface parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -221,7 +221,7 @@
|
|
|
221
221
|
},
|
|
222
222
|
"sideEffects": false,
|
|
223
223
|
"devDependencies": {
|
|
224
|
-
"@optique/env": "1.3.0-dev.
|
|
224
|
+
"@optique/env": "1.3.0-dev.2433+82919fcb",
|
|
225
225
|
"@types/node": "^24.0.0",
|
|
226
226
|
"fast-check": "^4.7.0",
|
|
227
227
|
"tsdown": "^0.13.0",
|