@optique/core 1.3.0-dev.2581 → 1.3.0-dev.2582
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 +114 -9
- package/dist/constructs.js +115 -10
- package/dist/dependency-metadata.d.cts +15 -0
- package/dist/dependency-metadata.d.ts +15 -0
- package/dist/dependency-runtime.cjs +21 -0
- package/dist/dependency-runtime.d.cts +48 -3
- package/dist/dependency-runtime.d.ts +48 -3
- package/dist/dependency-runtime.js +20 -1
- package/package.json +2 -2
package/dist/constructs.cjs
CHANGED
|
@@ -115,18 +115,23 @@ const preExpandedBranchNodes = /* @__PURE__ */ new WeakSet();
|
|
|
115
115
|
* numeric path segments and record states use their field keys, matching
|
|
116
116
|
* the paths that child completion (and parse-time tracing) uses.
|
|
117
117
|
*/
|
|
118
|
-
function expandEffectfulRuntimeNodes(nodes) {
|
|
118
|
+
function expandEffectfulRuntimeNodes(nodes, options) {
|
|
119
119
|
const expanded = [];
|
|
120
120
|
const visit = (node) => {
|
|
121
121
|
const meta = node.parser.dependencyMetadata;
|
|
122
|
+
const optedIntoCollection = node.parser[require_dependency_runtime.sourceCollectionExpansionKey] === true;
|
|
123
|
+
if (options?.structuralOnly === true && !optedIntoCollection && require_dependency_runtime.exclusiveSourceScopeKey in node.parser) {
|
|
124
|
+
expanded.push(node);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
122
127
|
const schedulingNodes = node.parser[require_dependency_runtime.effectfulSchedulingNodesKey];
|
|
123
|
-
const expandsThroughHook = schedulingNodes != null && meta?.derived == null &&
|
|
128
|
+
const expandsThroughHook = schedulingNodes != null && meta?.derived == null && optedIntoCollection;
|
|
124
129
|
if (!expandsThroughHook && (meta?.source?.completeSource != null || meta?.derived != null)) {
|
|
125
130
|
expanded.push(node);
|
|
126
131
|
return;
|
|
127
132
|
}
|
|
128
133
|
if (schedulingNodes != null) {
|
|
129
|
-
const children = schedulingNodes(node.state, node.path);
|
|
134
|
+
const children = schedulingNodes(node.state, node.path, options);
|
|
130
135
|
if (children.length === 0 && meta?.source != null) {
|
|
131
136
|
expanded.push(node);
|
|
132
137
|
return;
|
|
@@ -145,10 +150,16 @@ function expandEffectfulRuntimeNodes(nodes) {
|
|
|
145
150
|
if (duplicateFieldNames.has(field)) continue;
|
|
146
151
|
const segment = Array.isArray(state) && typeof field === "string" ? Number(field) : field;
|
|
147
152
|
const childState = Array.isArray(state) ? state[segment] : state[field];
|
|
153
|
+
const annotatedChildState = require_annotation_state.getWrappedChildState(state, childState, childParser);
|
|
154
|
+
const isDerived = childParser.dependencyMetadata?.derived != null;
|
|
155
|
+
const rawInput = isDerived ? require_dependency_runtime.extractRawInputFromState(annotatedChildState) : void 0;
|
|
156
|
+
const defaultDependencyValues = isDerived ? require_dependency_runtime.getDefaultDependencySnapshot(annotatedChildState) : void 0;
|
|
148
157
|
visit({
|
|
149
158
|
path: [...node.path, segment],
|
|
150
159
|
parser: childParser,
|
|
151
|
-
state:
|
|
160
|
+
state: annotatedChildState,
|
|
161
|
+
...rawInput != null ? { rawInput } : {},
|
|
162
|
+
...defaultDependencyValues != null ? { defaultDependencyValues } : {}
|
|
152
163
|
});
|
|
153
164
|
}
|
|
154
165
|
};
|
|
@@ -173,15 +184,101 @@ function expandSourceCollectionNodes(nodes) {
|
|
|
173
184
|
for (let i = 0; i < nodes.length; i++) {
|
|
174
185
|
const node = nodes[i];
|
|
175
186
|
const optedIn = node.parser[require_dependency_runtime.sourceCollectionExpansionKey] === true;
|
|
176
|
-
if (
|
|
187
|
+
if (optedIn) {
|
|
188
|
+
if (expanded == null) expanded = nodes.slice(0, i);
|
|
189
|
+
expanded.push(...expandEffectfulRuntimeNodes([node]));
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const nested = nestedCommandLineSourceNodes(node);
|
|
193
|
+
if (nested.length < 1) {
|
|
177
194
|
expanded?.push(node);
|
|
178
195
|
continue;
|
|
179
196
|
}
|
|
180
197
|
if (expanded == null) expanded = nodes.slice(0, i);
|
|
181
|
-
expanded.push(...
|
|
198
|
+
expanded.push(node, ...nested);
|
|
182
199
|
}
|
|
183
200
|
return expanded ?? nodes;
|
|
184
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* The command-line source occurrences a structural child contributes to
|
|
204
|
+
* its enclosing construct's collection scope.
|
|
205
|
+
*
|
|
206
|
+
* A plain nested construct—an `object()`, `tuple()`, `concat()`,
|
|
207
|
+
* `merge()`, or one of those behind a transparent wrapper—is part of the
|
|
208
|
+
* enclosing declaration sequence, so a source it holds must reach a
|
|
209
|
+
* consumer declared before it, exactly as a source declared directly
|
|
210
|
+
* beside that consumer does. Only occurrences that consumed
|
|
211
|
+
* command-line input are contributed: an absent occurrence has no value
|
|
212
|
+
* to publish, and a bound or defaulted one publishes through its own
|
|
213
|
+
* construct's pre-completion, whose fallback readers and lazy defaults
|
|
214
|
+
* must keep evaluating exactly once
|
|
215
|
+
* (https://github.com/dahlia/optique/issues/958).
|
|
216
|
+
*
|
|
217
|
+
* @param node The structural child to look inside.
|
|
218
|
+
* @returns The nested command-line source occurrences, in declaration
|
|
219
|
+
* order. Empty for a child that holds none.
|
|
220
|
+
*/
|
|
221
|
+
function nestedCommandLineSourceNodes(node) {
|
|
222
|
+
const nested = [];
|
|
223
|
+
for (const descendant of expandEffectfulRuntimeNodes([node], { structuralOnly: true })) {
|
|
224
|
+
if (descendant === node) continue;
|
|
225
|
+
if (descendant.parser.dependencyMetadata?.source == null) continue;
|
|
226
|
+
if ((require_dependency_runtime.exclusiveSourceScopeKey in descendant.parser || descendant.parser.dependencyMetadata?.source?.exclusiveOccurrence === true) && descendant.parser[require_dependency_runtime.sourceCollectionExpansionKey] !== true) continue;
|
|
227
|
+
if (!hasCommandLineSourceInput(descendant)) continue;
|
|
228
|
+
nested.push({
|
|
229
|
+
...descendant,
|
|
230
|
+
matched: true
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return nested;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Whether a source occurrence's state holds no parsed input at all.
|
|
237
|
+
*
|
|
238
|
+
* State identity against `initialState` misses two shapes a wrapper
|
|
239
|
+
* produces afresh on every parse: a repetition that matched nothing,
|
|
240
|
+
* whose state is a new empty array, and a wrapper whose own initial
|
|
241
|
+
* state is `undefined`, which annotation injection turns into an object
|
|
242
|
+
* carrying nothing but annotation symbols. Both look matched by
|
|
243
|
+
* identity while holding nothing to publish, and neither forwards the
|
|
244
|
+
* binding marker that would otherwise catch them.
|
|
245
|
+
*
|
|
246
|
+
* Treating an unrecognized shape as non-empty is the safe direction: the
|
|
247
|
+
* occurrence is then subject to the remaining provenance checks.
|
|
248
|
+
*
|
|
249
|
+
* @param state The occurrence's state, already unwrapped one level.
|
|
250
|
+
* @returns `true` when the state carries no parsed input.
|
|
251
|
+
*/
|
|
252
|
+
function isEmptySourceState(state) {
|
|
253
|
+
if (state == null) return true;
|
|
254
|
+
if (Array.isArray(state)) return state.length < 1;
|
|
255
|
+
if (typeof state !== "object") return false;
|
|
256
|
+
return Object.getOwnPropertyNames(state).length < 1;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Whether a nested source occurrence holds a value the command line
|
|
260
|
+
* supplied.
|
|
261
|
+
*
|
|
262
|
+
* A source that can complete from a binding (`bindEnv()`,
|
|
263
|
+
* `bindConfig()`, and other `completesFromSource` wrappers) reaches an
|
|
264
|
+
* annotated state even when nothing on the command line matched, so an
|
|
265
|
+
* unmatched state alone does not prove provenance. Such an occurrence
|
|
266
|
+
* has to say so through its own state; otherwise extracting from it here
|
|
267
|
+
* would run the binding's fallback reader in addition to the run its
|
|
268
|
+
* owning construct's pre-completion already performs.
|
|
269
|
+
*
|
|
270
|
+
* @param node The nested source occurrence.
|
|
271
|
+
* @returns `true` when the occurrence's state came from the command
|
|
272
|
+
* line, whether or not that input passed validation.
|
|
273
|
+
*/
|
|
274
|
+
function hasCommandLineSourceInput(node) {
|
|
275
|
+
const parser = node.parser;
|
|
276
|
+
if (!require_dependency_runtime.isMatchedState(node.state, parser)) return false;
|
|
277
|
+
const innerState = Array.isArray(node.state) && node.state.length === 1 ? node.state[0] : node.state;
|
|
278
|
+
if (isEmptySourceState(innerState)) return false;
|
|
279
|
+
if (parser[require_internal_parser.unmatchedNonCliDependencySourceStateMarker] !== true) return true;
|
|
280
|
+
return innerState != null && typeof innerState === "object" && innerState.hasCliValue === true;
|
|
281
|
+
}
|
|
185
282
|
let conditionalInstanceCounter = 0;
|
|
186
283
|
/**
|
|
187
284
|
* Whether a source occurrence publishes a value even when its state
|
|
@@ -431,10 +528,11 @@ async function scheduleEffectfulSourceCompletions(nodes, state, runtime, exec, p
|
|
|
431
528
|
for (const node of nodes) {
|
|
432
529
|
const optedIn = node.parser[require_dependency_runtime.sourceCollectionExpansionKey] === true;
|
|
433
530
|
const preExpanded = preExpandedBranchNodes.has(node);
|
|
531
|
+
const nestedPaths = optedIn || preExpanded ? void 0 : new Set(nestedCommandLineSourceNodes(node).map((nested) => require_dependency_runtime.serializeSchedulingPath(nested.path)));
|
|
434
532
|
for (const expandedNode of expandEffectfulRuntimeNodes([node])) {
|
|
435
533
|
expandedNodes.push(expandedNode);
|
|
436
534
|
if (preExpanded) continue;
|
|
437
|
-
if (optedIn || expandedNode === node) collected.add(expandedNode);
|
|
535
|
+
if (optedIn || expandedNode === node || nestedPaths?.has(require_dependency_runtime.serializeSchedulingPath(expandedNode.path)) === true) collected.add(expandedNode);
|
|
438
536
|
}
|
|
439
537
|
}
|
|
440
538
|
const republish = exec?.republishCachedCompletions === true;
|
|
@@ -1245,6 +1343,7 @@ function composeExclusiveDependencyMetadata(parsers) {
|
|
|
1245
1343
|
...sharedSource,
|
|
1246
1344
|
getMissingSourceValue: void 0,
|
|
1247
1345
|
completesWhenMissing: false,
|
|
1346
|
+
exclusiveOccurrence: true,
|
|
1248
1347
|
preservesSourceValue: everyBranchPreserves,
|
|
1249
1348
|
extractSourceValue(state) {
|
|
1250
1349
|
if (!Array.isArray(state) || state.length !== 2 || typeof state[0] !== "number") return void 0;
|
|
@@ -5981,6 +6080,7 @@ function group(label, parser, options = {}) {
|
|
|
5981
6080
|
...fieldParsersKey in parser ? { [fieldParsersKey]: parser[fieldParsersKey] } : {},
|
|
5982
6081
|
...require_dependency_runtime.effectfulSchedulingNodesKey in parser ? { [require_dependency_runtime.effectfulSchedulingNodesKey]: parser[require_dependency_runtime.effectfulSchedulingNodesKey] } : {},
|
|
5983
6082
|
...require_dependency_runtime.sourceCollectionExpansionKey in parser ? { [require_dependency_runtime.sourceCollectionExpansionKey]: parser[require_dependency_runtime.sourceCollectionExpansionKey] } : {},
|
|
6083
|
+
...require_dependency_runtime.exclusiveSourceScopeKey in parser ? { [require_dependency_runtime.exclusiveSourceScopeKey]: parser[require_dependency_runtime.exclusiveSourceScopeKey] } : {},
|
|
5984
6084
|
...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: parser.shouldDeferCompletion.bind(parser) } : {},
|
|
5985
6085
|
...typeof parser.canSkip === "function" ? { canSkip: parser.canSkip.bind(parser) } : {},
|
|
5986
6086
|
getSuggestRuntimeNodes(state, path) {
|
|
@@ -6052,6 +6152,11 @@ function group(label, parser, options = {}) {
|
|
|
6052
6152
|
configurable: true,
|
|
6053
6153
|
enumerable: false
|
|
6054
6154
|
});
|
|
6155
|
+
if (parser[require_internal_parser.unmatchedNonCliDependencySourceStateMarker] === true) Object.defineProperty(groupParser, require_internal_parser.unmatchedNonCliDependencySourceStateMarker, {
|
|
6156
|
+
value: true,
|
|
6157
|
+
configurable: true,
|
|
6158
|
+
enumerable: true
|
|
6159
|
+
});
|
|
6055
6160
|
if ("placeholder" in parser) Object.defineProperty(groupParser, "placeholder", {
|
|
6056
6161
|
get() {
|
|
6057
6162
|
return parser.placeholder;
|
|
@@ -6778,7 +6883,7 @@ function conditional(discriminator, branches, defaultBranch, options) {
|
|
|
6778
6883
|
}
|
|
6779
6884
|
return ids;
|
|
6780
6885
|
};
|
|
6781
|
-
const buildConditionalSchedulingNodes = (state, parentPath) => {
|
|
6886
|
+
const buildConditionalSchedulingNodes = (state, parentPath, expandOptions) => {
|
|
6782
6887
|
if (state == null || typeof state !== "object") return [];
|
|
6783
6888
|
const conditionalState = state;
|
|
6784
6889
|
const annotatedDiscriminatorState = require_annotation_state.getWrappedChildState(conditionalState, conditionalState.discriminatorState, discriminator);
|
|
@@ -6797,7 +6902,7 @@ function conditional(discriminator, branches, defaultBranch, options) {
|
|
|
6797
6902
|
state: require_annotation_state.getWrappedChildState(conditionalState, conditionalState.branchState, branchParser)
|
|
6798
6903
|
};
|
|
6799
6904
|
const branchKey = selected.kind === "branch" ? selected.key : void 0;
|
|
6800
|
-
if (branchKey != null && options?.errors?.branchError != null) for (const expanded of wrapBranchBarrierNodes(expandEffectfulRuntimeNodes([branchNode]), branchKey)) {
|
|
6905
|
+
if (branchKey != null && options?.errors?.branchError != null) for (const expanded of wrapBranchBarrierNodes(expandEffectfulRuntimeNodes([branchNode], expandOptions), branchKey)) {
|
|
6801
6906
|
preExpandedBranchNodes.add(expanded);
|
|
6802
6907
|
nodes.push(expanded);
|
|
6803
6908
|
}
|
package/dist/constructs.js
CHANGED
|
@@ -5,7 +5,7 @@ import { message, optionName, text, values } from "./message.js";
|
|
|
5
5
|
import { deduplicateDocFragments } from "./doc.js";
|
|
6
6
|
import { dispatchByMode, dispatchIterableByMode } from "./internal/mode-dispatch.js";
|
|
7
7
|
import { createDependencySourceState, dependencyId, isDependencySourceState, isPendingDependencySourceState, isWrappedDependencySource, wrappedDependencySourceMarker } from "./internal/dependency.js";
|
|
8
|
-
import { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyRuntimeContext, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, forkRuntimeForCommittedSubtree, guaranteedStaticSourceIdsKey, hasInactiveCompletion, recordSourceScope, releaseUncollectedSourceValues, replaceCachedBarrierFailure, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey } from "./dependency-runtime.js";
|
|
8
|
+
import { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyRuntimeContext, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, forkRuntimeForCommittedSubtree, getDefaultDependencySnapshot, guaranteedStaticSourceIdsKey, hasInactiveCompletion, isMatchedState, recordSourceScope, releaseUncollectedSourceValues, replaceCachedBarrierFailure, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey } from "./dependency-runtime.js";
|
|
9
9
|
import { defineInheritedAnnotationParser, defineParseLanes, getOwnParseLanes, getParserSuggestRuntimeNodes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
|
|
10
10
|
import { annotationViewTargets, getWrappedChildParseState, getWrappedChildState, reconcileObjectChildState, unwrapAnnotationView } from "./annotation-state.js";
|
|
11
11
|
import { allowDuplicateLeadingCommandNamesKey } from "./internal/command-alias.js";
|
|
@@ -115,18 +115,23 @@ const preExpandedBranchNodes = /* @__PURE__ */ new WeakSet();
|
|
|
115
115
|
* numeric path segments and record states use their field keys, matching
|
|
116
116
|
* the paths that child completion (and parse-time tracing) uses.
|
|
117
117
|
*/
|
|
118
|
-
function expandEffectfulRuntimeNodes(nodes) {
|
|
118
|
+
function expandEffectfulRuntimeNodes(nodes, options) {
|
|
119
119
|
const expanded = [];
|
|
120
120
|
const visit = (node) => {
|
|
121
121
|
const meta = node.parser.dependencyMetadata;
|
|
122
|
+
const optedIntoCollection = node.parser[sourceCollectionExpansionKey] === true;
|
|
123
|
+
if (options?.structuralOnly === true && !optedIntoCollection && exclusiveSourceScopeKey in node.parser) {
|
|
124
|
+
expanded.push(node);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
122
127
|
const schedulingNodes = node.parser[effectfulSchedulingNodesKey];
|
|
123
|
-
const expandsThroughHook = schedulingNodes != null && meta?.derived == null &&
|
|
128
|
+
const expandsThroughHook = schedulingNodes != null && meta?.derived == null && optedIntoCollection;
|
|
124
129
|
if (!expandsThroughHook && (meta?.source?.completeSource != null || meta?.derived != null)) {
|
|
125
130
|
expanded.push(node);
|
|
126
131
|
return;
|
|
127
132
|
}
|
|
128
133
|
if (schedulingNodes != null) {
|
|
129
|
-
const children = schedulingNodes(node.state, node.path);
|
|
134
|
+
const children = schedulingNodes(node.state, node.path, options);
|
|
130
135
|
if (children.length === 0 && meta?.source != null) {
|
|
131
136
|
expanded.push(node);
|
|
132
137
|
return;
|
|
@@ -145,10 +150,16 @@ function expandEffectfulRuntimeNodes(nodes) {
|
|
|
145
150
|
if (duplicateFieldNames.has(field)) continue;
|
|
146
151
|
const segment = Array.isArray(state) && typeof field === "string" ? Number(field) : field;
|
|
147
152
|
const childState = Array.isArray(state) ? state[segment] : state[field];
|
|
153
|
+
const annotatedChildState = getWrappedChildState(state, childState, childParser);
|
|
154
|
+
const isDerived = childParser.dependencyMetadata?.derived != null;
|
|
155
|
+
const rawInput = isDerived ? extractRawInputFromState(annotatedChildState) : void 0;
|
|
156
|
+
const defaultDependencyValues = isDerived ? getDefaultDependencySnapshot(annotatedChildState) : void 0;
|
|
148
157
|
visit({
|
|
149
158
|
path: [...node.path, segment],
|
|
150
159
|
parser: childParser,
|
|
151
|
-
state:
|
|
160
|
+
state: annotatedChildState,
|
|
161
|
+
...rawInput != null ? { rawInput } : {},
|
|
162
|
+
...defaultDependencyValues != null ? { defaultDependencyValues } : {}
|
|
152
163
|
});
|
|
153
164
|
}
|
|
154
165
|
};
|
|
@@ -173,15 +184,101 @@ function expandSourceCollectionNodes(nodes) {
|
|
|
173
184
|
for (let i = 0; i < nodes.length; i++) {
|
|
174
185
|
const node = nodes[i];
|
|
175
186
|
const optedIn = node.parser[sourceCollectionExpansionKey] === true;
|
|
176
|
-
if (
|
|
187
|
+
if (optedIn) {
|
|
188
|
+
if (expanded == null) expanded = nodes.slice(0, i);
|
|
189
|
+
expanded.push(...expandEffectfulRuntimeNodes([node]));
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const nested = nestedCommandLineSourceNodes(node);
|
|
193
|
+
if (nested.length < 1) {
|
|
177
194
|
expanded?.push(node);
|
|
178
195
|
continue;
|
|
179
196
|
}
|
|
180
197
|
if (expanded == null) expanded = nodes.slice(0, i);
|
|
181
|
-
expanded.push(...
|
|
198
|
+
expanded.push(node, ...nested);
|
|
182
199
|
}
|
|
183
200
|
return expanded ?? nodes;
|
|
184
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* The command-line source occurrences a structural child contributes to
|
|
204
|
+
* its enclosing construct's collection scope.
|
|
205
|
+
*
|
|
206
|
+
* A plain nested construct—an `object()`, `tuple()`, `concat()`,
|
|
207
|
+
* `merge()`, or one of those behind a transparent wrapper—is part of the
|
|
208
|
+
* enclosing declaration sequence, so a source it holds must reach a
|
|
209
|
+
* consumer declared before it, exactly as a source declared directly
|
|
210
|
+
* beside that consumer does. Only occurrences that consumed
|
|
211
|
+
* command-line input are contributed: an absent occurrence has no value
|
|
212
|
+
* to publish, and a bound or defaulted one publishes through its own
|
|
213
|
+
* construct's pre-completion, whose fallback readers and lazy defaults
|
|
214
|
+
* must keep evaluating exactly once
|
|
215
|
+
* (https://github.com/dahlia/optique/issues/958).
|
|
216
|
+
*
|
|
217
|
+
* @param node The structural child to look inside.
|
|
218
|
+
* @returns The nested command-line source occurrences, in declaration
|
|
219
|
+
* order. Empty for a child that holds none.
|
|
220
|
+
*/
|
|
221
|
+
function nestedCommandLineSourceNodes(node) {
|
|
222
|
+
const nested = [];
|
|
223
|
+
for (const descendant of expandEffectfulRuntimeNodes([node], { structuralOnly: true })) {
|
|
224
|
+
if (descendant === node) continue;
|
|
225
|
+
if (descendant.parser.dependencyMetadata?.source == null) continue;
|
|
226
|
+
if ((exclusiveSourceScopeKey in descendant.parser || descendant.parser.dependencyMetadata?.source?.exclusiveOccurrence === true) && descendant.parser[sourceCollectionExpansionKey] !== true) continue;
|
|
227
|
+
if (!hasCommandLineSourceInput(descendant)) continue;
|
|
228
|
+
nested.push({
|
|
229
|
+
...descendant,
|
|
230
|
+
matched: true
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
return nested;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Whether a source occurrence's state holds no parsed input at all.
|
|
237
|
+
*
|
|
238
|
+
* State identity against `initialState` misses two shapes a wrapper
|
|
239
|
+
* produces afresh on every parse: a repetition that matched nothing,
|
|
240
|
+
* whose state is a new empty array, and a wrapper whose own initial
|
|
241
|
+
* state is `undefined`, which annotation injection turns into an object
|
|
242
|
+
* carrying nothing but annotation symbols. Both look matched by
|
|
243
|
+
* identity while holding nothing to publish, and neither forwards the
|
|
244
|
+
* binding marker that would otherwise catch them.
|
|
245
|
+
*
|
|
246
|
+
* Treating an unrecognized shape as non-empty is the safe direction: the
|
|
247
|
+
* occurrence is then subject to the remaining provenance checks.
|
|
248
|
+
*
|
|
249
|
+
* @param state The occurrence's state, already unwrapped one level.
|
|
250
|
+
* @returns `true` when the state carries no parsed input.
|
|
251
|
+
*/
|
|
252
|
+
function isEmptySourceState(state) {
|
|
253
|
+
if (state == null) return true;
|
|
254
|
+
if (Array.isArray(state)) return state.length < 1;
|
|
255
|
+
if (typeof state !== "object") return false;
|
|
256
|
+
return Object.getOwnPropertyNames(state).length < 1;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Whether a nested source occurrence holds a value the command line
|
|
260
|
+
* supplied.
|
|
261
|
+
*
|
|
262
|
+
* A source that can complete from a binding (`bindEnv()`,
|
|
263
|
+
* `bindConfig()`, and other `completesFromSource` wrappers) reaches an
|
|
264
|
+
* annotated state even when nothing on the command line matched, so an
|
|
265
|
+
* unmatched state alone does not prove provenance. Such an occurrence
|
|
266
|
+
* has to say so through its own state; otherwise extracting from it here
|
|
267
|
+
* would run the binding's fallback reader in addition to the run its
|
|
268
|
+
* owning construct's pre-completion already performs.
|
|
269
|
+
*
|
|
270
|
+
* @param node The nested source occurrence.
|
|
271
|
+
* @returns `true` when the occurrence's state came from the command
|
|
272
|
+
* line, whether or not that input passed validation.
|
|
273
|
+
*/
|
|
274
|
+
function hasCommandLineSourceInput(node) {
|
|
275
|
+
const parser = node.parser;
|
|
276
|
+
if (!isMatchedState(node.state, parser)) return false;
|
|
277
|
+
const innerState = Array.isArray(node.state) && node.state.length === 1 ? node.state[0] : node.state;
|
|
278
|
+
if (isEmptySourceState(innerState)) return false;
|
|
279
|
+
if (parser[unmatchedNonCliDependencySourceStateMarker] !== true) return true;
|
|
280
|
+
return innerState != null && typeof innerState === "object" && innerState.hasCliValue === true;
|
|
281
|
+
}
|
|
185
282
|
let conditionalInstanceCounter = 0;
|
|
186
283
|
/**
|
|
187
284
|
* Whether a source occurrence publishes a value even when its state
|
|
@@ -431,10 +528,11 @@ async function scheduleEffectfulSourceCompletions(nodes, state, runtime, exec, p
|
|
|
431
528
|
for (const node of nodes) {
|
|
432
529
|
const optedIn = node.parser[sourceCollectionExpansionKey] === true;
|
|
433
530
|
const preExpanded = preExpandedBranchNodes.has(node);
|
|
531
|
+
const nestedPaths = optedIn || preExpanded ? void 0 : new Set(nestedCommandLineSourceNodes(node).map((nested) => serializeSchedulingPath(nested.path)));
|
|
434
532
|
for (const expandedNode of expandEffectfulRuntimeNodes([node])) {
|
|
435
533
|
expandedNodes.push(expandedNode);
|
|
436
534
|
if (preExpanded) continue;
|
|
437
|
-
if (optedIn || expandedNode === node) collected.add(expandedNode);
|
|
535
|
+
if (optedIn || expandedNode === node || nestedPaths?.has(serializeSchedulingPath(expandedNode.path)) === true) collected.add(expandedNode);
|
|
438
536
|
}
|
|
439
537
|
}
|
|
440
538
|
const republish = exec?.republishCachedCompletions === true;
|
|
@@ -1245,6 +1343,7 @@ function composeExclusiveDependencyMetadata(parsers) {
|
|
|
1245
1343
|
...sharedSource,
|
|
1246
1344
|
getMissingSourceValue: void 0,
|
|
1247
1345
|
completesWhenMissing: false,
|
|
1346
|
+
exclusiveOccurrence: true,
|
|
1248
1347
|
preservesSourceValue: everyBranchPreserves,
|
|
1249
1348
|
extractSourceValue(state) {
|
|
1250
1349
|
if (!Array.isArray(state) || state.length !== 2 || typeof state[0] !== "number") return void 0;
|
|
@@ -5981,6 +6080,7 @@ function group(label, parser, options = {}) {
|
|
|
5981
6080
|
...fieldParsersKey in parser ? { [fieldParsersKey]: parser[fieldParsersKey] } : {},
|
|
5982
6081
|
...effectfulSchedulingNodesKey in parser ? { [effectfulSchedulingNodesKey]: parser[effectfulSchedulingNodesKey] } : {},
|
|
5983
6082
|
...sourceCollectionExpansionKey in parser ? { [sourceCollectionExpansionKey]: parser[sourceCollectionExpansionKey] } : {},
|
|
6083
|
+
...exclusiveSourceScopeKey in parser ? { [exclusiveSourceScopeKey]: parser[exclusiveSourceScopeKey] } : {},
|
|
5984
6084
|
...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: parser.shouldDeferCompletion.bind(parser) } : {},
|
|
5985
6085
|
...typeof parser.canSkip === "function" ? { canSkip: parser.canSkip.bind(parser) } : {},
|
|
5986
6086
|
getSuggestRuntimeNodes(state, path) {
|
|
@@ -6052,6 +6152,11 @@ function group(label, parser, options = {}) {
|
|
|
6052
6152
|
configurable: true,
|
|
6053
6153
|
enumerable: false
|
|
6054
6154
|
});
|
|
6155
|
+
if (parser[unmatchedNonCliDependencySourceStateMarker] === true) Object.defineProperty(groupParser, unmatchedNonCliDependencySourceStateMarker, {
|
|
6156
|
+
value: true,
|
|
6157
|
+
configurable: true,
|
|
6158
|
+
enumerable: true
|
|
6159
|
+
});
|
|
6055
6160
|
if ("placeholder" in parser) Object.defineProperty(groupParser, "placeholder", {
|
|
6056
6161
|
get() {
|
|
6057
6162
|
return parser.placeholder;
|
|
@@ -6778,7 +6883,7 @@ function conditional(discriminator, branches, defaultBranch, options) {
|
|
|
6778
6883
|
}
|
|
6779
6884
|
return ids;
|
|
6780
6885
|
};
|
|
6781
|
-
const buildConditionalSchedulingNodes = (state, parentPath) => {
|
|
6886
|
+
const buildConditionalSchedulingNodes = (state, parentPath, expandOptions) => {
|
|
6782
6887
|
if (state == null || typeof state !== "object") return [];
|
|
6783
6888
|
const conditionalState = state;
|
|
6784
6889
|
const annotatedDiscriminatorState = getWrappedChildState(conditionalState, conditionalState.discriminatorState, discriminator);
|
|
@@ -6797,7 +6902,7 @@ function conditional(discriminator, branches, defaultBranch, options) {
|
|
|
6797
6902
|
state: getWrappedChildState(conditionalState, conditionalState.branchState, branchParser)
|
|
6798
6903
|
};
|
|
6799
6904
|
const branchKey = selected.kind === "branch" ? selected.key : void 0;
|
|
6800
|
-
if (branchKey != null && options?.errors?.branchError != null) for (const expanded of wrapBranchBarrierNodes(expandEffectfulRuntimeNodes([branchNode]), branchKey)) {
|
|
6905
|
+
if (branchKey != null && options?.errors?.branchError != null) for (const expanded of wrapBranchBarrierNodes(expandEffectfulRuntimeNodes([branchNode], expandOptions), branchKey)) {
|
|
6801
6906
|
preExpandedBranchNodes.add(expanded);
|
|
6802
6907
|
nodes.push(expanded);
|
|
6803
6908
|
}
|
|
@@ -73,6 +73,21 @@ interface DependencySourceCapability {
|
|
|
73
73
|
* @since 1.3.0
|
|
74
74
|
*/
|
|
75
75
|
readonly completesWhenMissing?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Whether this capability publishes whichever mutually exclusive
|
|
78
|
+
* alternative the run selected, rather than an occurrence of its own.
|
|
79
|
+
*
|
|
80
|
+
* An `or()`/`longestMatch()` whose alternatives share one source
|
|
81
|
+
* composes such a capability. The alternative is a scope of its own,
|
|
82
|
+
* so an enclosing construct's explicit source collection leaves it
|
|
83
|
+
* alone unless the exclusive parser opted into collection. Wrappers
|
|
84
|
+
* compose source capabilities by spreading them, so the flag travels
|
|
85
|
+
* through `optional()`, `withDefault()`, `map()`, and `multiple()`
|
|
86
|
+
* without each having to forward it.
|
|
87
|
+
*
|
|
88
|
+
* @since 1.3.0
|
|
89
|
+
*/
|
|
90
|
+
readonly exclusiveOccurrence?: boolean;
|
|
76
91
|
/**
|
|
77
92
|
* Whether the parser's output value is the actual dependency source value.
|
|
78
93
|
* `false` when a transform like `map()` has been applied.
|
|
@@ -73,6 +73,21 @@ interface DependencySourceCapability {
|
|
|
73
73
|
* @since 1.3.0
|
|
74
74
|
*/
|
|
75
75
|
readonly completesWhenMissing?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Whether this capability publishes whichever mutually exclusive
|
|
78
|
+
* alternative the run selected, rather than an occurrence of its own.
|
|
79
|
+
*
|
|
80
|
+
* An `or()`/`longestMatch()` whose alternatives share one source
|
|
81
|
+
* composes such a capability. The alternative is a scope of its own,
|
|
82
|
+
* so an enclosing construct's explicit source collection leaves it
|
|
83
|
+
* alone unless the exclusive parser opted into collection. Wrappers
|
|
84
|
+
* compose source capabilities by spreading them, so the flag travels
|
|
85
|
+
* through `optional()`, `withDefault()`, `map()`, and `multiple()`
|
|
86
|
+
* without each having to forward it.
|
|
87
|
+
*
|
|
88
|
+
* @since 1.3.0
|
|
89
|
+
*/
|
|
90
|
+
readonly exclusiveOccurrence?: boolean;
|
|
76
91
|
/**
|
|
77
92
|
* Whether the parser's output value is the actual dependency source value.
|
|
78
93
|
* `false` when a transform like `map()` has been applied.
|
|
@@ -1850,6 +1850,13 @@ async function resolveDeferredInStateAsync(state, runtime, visited = /* @__PURE_
|
|
|
1850
1850
|
/**
|
|
1851
1851
|
* Determines whether a parser state represents an explicit match (the user
|
|
1852
1852
|
* provided input) rather than an initial/pending state.
|
|
1853
|
+
*
|
|
1854
|
+
* @param fieldState The parser's state.
|
|
1855
|
+
* @param parser The parser owning that state.
|
|
1856
|
+
* @returns `true` when the state reflects command-line input, whether or
|
|
1857
|
+
* not that input passed validation.
|
|
1858
|
+
* @internal
|
|
1859
|
+
* @since 1.3.0
|
|
1853
1860
|
*/
|
|
1854
1861
|
function isMatchedState(fieldState, parser) {
|
|
1855
1862
|
if (fieldState === void 0) return false;
|
|
@@ -1922,6 +1929,18 @@ function buildRuntimeNodesFromArray(parsers, stateArray, parentPath) {
|
|
|
1922
1929
|
}
|
|
1923
1930
|
return nodes;
|
|
1924
1931
|
}
|
|
1932
|
+
/**
|
|
1933
|
+
* Reads a derived parser state's snapshotted default dependency values.
|
|
1934
|
+
*
|
|
1935
|
+
* Nodes must carry the parse-time snapshot so replay never re-evaluates a
|
|
1936
|
+
* dynamic `getDefaultDependencyValues()` thunk.
|
|
1937
|
+
*
|
|
1938
|
+
* @param state The derived parser's state.
|
|
1939
|
+
* @returns The snapshotted values, or `undefined` when the state carries
|
|
1940
|
+
* none.
|
|
1941
|
+
* @internal
|
|
1942
|
+
* @since 1.3.0
|
|
1943
|
+
*/
|
|
1925
1944
|
function getDefaultDependencySnapshot(state) {
|
|
1926
1945
|
return getDefaultDependencySnapshotInner(state, /* @__PURE__ */ new Set());
|
|
1927
1946
|
}
|
|
@@ -1965,9 +1984,11 @@ exports.extractRawInputFromState = extractRawInputFromState;
|
|
|
1965
1984
|
exports.fillMissingSourceDefaults = fillMissingSourceDefaults;
|
|
1966
1985
|
exports.fillMissingSourceDefaultsAsync = fillMissingSourceDefaultsAsync;
|
|
1967
1986
|
exports.forkRuntimeForCommittedSubtree = forkRuntimeForCommittedSubtree;
|
|
1987
|
+
exports.getDefaultDependencySnapshot = getDefaultDependencySnapshot;
|
|
1968
1988
|
exports.guaranteedStaticSourceIdsKey = guaranteedStaticSourceIdsKey;
|
|
1969
1989
|
exports.hasInactiveCompletion = hasInactiveCompletion;
|
|
1970
1990
|
exports.includeSourceFailureChain = includeSourceFailureChain;
|
|
1991
|
+
exports.isMatchedState = isMatchedState;
|
|
1971
1992
|
exports.orderDependencyNodes = orderDependencyNodes;
|
|
1972
1993
|
exports.recordDerivedRawInput = recordDerivedRawInput;
|
|
1973
1994
|
exports.recordSourceScope = recordSourceScope;
|
|
@@ -3,7 +3,7 @@ import { DependencyRegistryLike } from "./registry-types.cjs";
|
|
|
3
3
|
import { ValueParserResult } from "./valueparser.cjs";
|
|
4
4
|
import { ParserDependencyMetadata } from "./dependency-metadata.cjs";
|
|
5
5
|
import { InputTrace } from "./input-trace.cjs";
|
|
6
|
-
import { EffectfulCompletionSession, ExecutionContext } from "./internal/parser.cjs";
|
|
6
|
+
import { EffectfulCompletionSession, ExecutionContext, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.cjs";
|
|
7
7
|
|
|
8
8
|
//#region src/dependency-runtime.d.ts
|
|
9
9
|
|
|
@@ -612,13 +612,29 @@ declare function extractRawInputFromState(state: unknown): string | undefined;
|
|
|
612
612
|
* @since 1.3.0
|
|
613
613
|
*/
|
|
614
614
|
declare const effectfulSchedulingNodesKey: unique symbol;
|
|
615
|
+
/**
|
|
616
|
+
* Options that steer how far a runtime-node expansion walks.
|
|
617
|
+
*
|
|
618
|
+
* @internal
|
|
619
|
+
* @since 1.3.0
|
|
620
|
+
*/
|
|
621
|
+
interface ExpandRuntimeNodesOptions {
|
|
622
|
+
/**
|
|
623
|
+
* Stops the walk at an exclusive parser—an `or()`, `longestMatch()`, or
|
|
624
|
+
* `conditional()` alternative—that has not opted into source
|
|
625
|
+
* collection, so a scope of its own is not folded into the enclosing
|
|
626
|
+
* one. A hook that expands descendants itself must forward this to
|
|
627
|
+
* its own expansion.
|
|
628
|
+
*/
|
|
629
|
+
readonly structuralOnly?: boolean;
|
|
630
|
+
}
|
|
615
631
|
/**
|
|
616
632
|
* The shape of the {@link effectfulSchedulingNodesKey} hook.
|
|
617
633
|
*
|
|
618
634
|
* @internal
|
|
619
635
|
* @since 1.3.0
|
|
620
636
|
*/
|
|
621
|
-
type EffectfulSchedulingNodesFn = (state: unknown, parentPath: readonly PropertyKey[] | undefined) => readonly RuntimeNode[];
|
|
637
|
+
type EffectfulSchedulingNodesFn = (state: unknown, parentPath: readonly PropertyKey[] | undefined, options?: ExpandRuntimeNodesOptions) => readonly RuntimeNode[];
|
|
622
638
|
/**
|
|
623
639
|
* Opt-in marker for parsers whose {@link effectfulSchedulingNodesKey}
|
|
624
640
|
* hook also defines their explicit-source *collection* scope.
|
|
@@ -929,6 +945,22 @@ declare function resolveStateWithRuntime(state: unknown, runtime: DependencyRunt
|
|
|
929
945
|
* @since 1.0.0
|
|
930
946
|
*/
|
|
931
947
|
declare function resolveStateWithRuntimeAsync(state: unknown, runtime: DependencyRuntimeContext): Promise<unknown>;
|
|
948
|
+
/**
|
|
949
|
+
* Determines whether a parser state represents an explicit match (the user
|
|
950
|
+
* provided input) rather than an initial/pending state.
|
|
951
|
+
*
|
|
952
|
+
* @param fieldState The parser's state.
|
|
953
|
+
* @param parser The parser owning that state.
|
|
954
|
+
* @returns `true` when the state reflects command-line input, whether or
|
|
955
|
+
* not that input passed validation.
|
|
956
|
+
* @internal
|
|
957
|
+
* @since 1.3.0
|
|
958
|
+
*/
|
|
959
|
+
declare function isMatchedState(fieldState: unknown, parser: {
|
|
960
|
+
readonly dependencyMetadata?: ParserDependencyMetadata;
|
|
961
|
+
readonly initialState?: unknown;
|
|
962
|
+
readonly [unmatchedNonCliDependencySourceStateMarker]?: true;
|
|
963
|
+
}): boolean;
|
|
932
964
|
/**
|
|
933
965
|
* Builds {@link RuntimeNode}s from field→parser pairs and a state record.
|
|
934
966
|
*
|
|
@@ -961,5 +993,18 @@ declare function buildRuntimeNodesFromArray(parsers: ReadonlyArray<{
|
|
|
961
993
|
readonly dependencyMetadata?: ParserDependencyMetadata;
|
|
962
994
|
readonly initialState?: unknown;
|
|
963
995
|
}>, stateArray: readonly unknown[], parentPath?: readonly PropertyKey[]): readonly RuntimeNode[];
|
|
996
|
+
/**
|
|
997
|
+
* Reads a derived parser state's snapshotted default dependency values.
|
|
998
|
+
*
|
|
999
|
+
* Nodes must carry the parse-time snapshot so replay never re-evaluates a
|
|
1000
|
+
* dynamic `getDefaultDependencyValues()` thunk.
|
|
1001
|
+
*
|
|
1002
|
+
* @param state The derived parser's state.
|
|
1003
|
+
* @returns The snapshotted values, or `undefined` when the state carries
|
|
1004
|
+
* none.
|
|
1005
|
+
* @internal
|
|
1006
|
+
* @since 1.3.0
|
|
1007
|
+
*/
|
|
1008
|
+
declare function getDefaultDependencySnapshot(state: unknown): readonly unknown[] | undefined;
|
|
964
1009
|
//#endregion
|
|
965
|
-
export { BarrierCompletionDemandEdge, BarrierCompletionDependencies, BarrierResolution, CompleteEffectfulSourcesOptions, DependencyRequest, DependencyResolution, DependencyRuntimeContext, EffectfulSchedulingNodesFn, EffectfulSourceCompletion, EffectfulSourceCompletionResult, ReplayKey, ResolveDerivedSourceValuesOptions, RuntimeNode, SchedulingBarrierContext, SourceDefaultFailure, buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, forkRuntimeForCommittedSubtree, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, recordSourceScope, releaseUncollectedSourceValues, replaceCachedBarrierFailure, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
|
|
1010
|
+
export { BarrierCompletionDemandEdge, BarrierCompletionDependencies, BarrierResolution, CompleteEffectfulSourcesOptions, DependencyRequest, DependencyResolution, DependencyRuntimeContext, EffectfulSchedulingNodesFn, EffectfulSourceCompletion, EffectfulSourceCompletionResult, ExpandRuntimeNodesOptions, ReplayKey, ResolveDerivedSourceValuesOptions, RuntimeNode, SchedulingBarrierContext, SourceDefaultFailure, buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, forkRuntimeForCommittedSubtree, getDefaultDependencySnapshot, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, isMatchedState, orderDependencyNodes, recordDerivedRawInput, recordSourceScope, releaseUncollectedSourceValues, replaceCachedBarrierFailure, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
|
|
@@ -3,7 +3,7 @@ import { DependencyRegistryLike } from "./registry-types.js";
|
|
|
3
3
|
import { ValueParserResult } from "./valueparser.js";
|
|
4
4
|
import { ParserDependencyMetadata } from "./dependency-metadata.js";
|
|
5
5
|
import { InputTrace } from "./input-trace.js";
|
|
6
|
-
import { EffectfulCompletionSession, ExecutionContext } from "./internal/parser.js";
|
|
6
|
+
import { EffectfulCompletionSession, ExecutionContext, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
|
|
7
7
|
|
|
8
8
|
//#region src/dependency-runtime.d.ts
|
|
9
9
|
|
|
@@ -612,13 +612,29 @@ declare function extractRawInputFromState(state: unknown): string | undefined;
|
|
|
612
612
|
* @since 1.3.0
|
|
613
613
|
*/
|
|
614
614
|
declare const effectfulSchedulingNodesKey: unique symbol;
|
|
615
|
+
/**
|
|
616
|
+
* Options that steer how far a runtime-node expansion walks.
|
|
617
|
+
*
|
|
618
|
+
* @internal
|
|
619
|
+
* @since 1.3.0
|
|
620
|
+
*/
|
|
621
|
+
interface ExpandRuntimeNodesOptions {
|
|
622
|
+
/**
|
|
623
|
+
* Stops the walk at an exclusive parser—an `or()`, `longestMatch()`, or
|
|
624
|
+
* `conditional()` alternative—that has not opted into source
|
|
625
|
+
* collection, so a scope of its own is not folded into the enclosing
|
|
626
|
+
* one. A hook that expands descendants itself must forward this to
|
|
627
|
+
* its own expansion.
|
|
628
|
+
*/
|
|
629
|
+
readonly structuralOnly?: boolean;
|
|
630
|
+
}
|
|
615
631
|
/**
|
|
616
632
|
* The shape of the {@link effectfulSchedulingNodesKey} hook.
|
|
617
633
|
*
|
|
618
634
|
* @internal
|
|
619
635
|
* @since 1.3.0
|
|
620
636
|
*/
|
|
621
|
-
type EffectfulSchedulingNodesFn = (state: unknown, parentPath: readonly PropertyKey[] | undefined) => readonly RuntimeNode[];
|
|
637
|
+
type EffectfulSchedulingNodesFn = (state: unknown, parentPath: readonly PropertyKey[] | undefined, options?: ExpandRuntimeNodesOptions) => readonly RuntimeNode[];
|
|
622
638
|
/**
|
|
623
639
|
* Opt-in marker for parsers whose {@link effectfulSchedulingNodesKey}
|
|
624
640
|
* hook also defines their explicit-source *collection* scope.
|
|
@@ -929,6 +945,22 @@ declare function resolveStateWithRuntime(state: unknown, runtime: DependencyRunt
|
|
|
929
945
|
* @since 1.0.0
|
|
930
946
|
*/
|
|
931
947
|
declare function resolveStateWithRuntimeAsync(state: unknown, runtime: DependencyRuntimeContext): Promise<unknown>;
|
|
948
|
+
/**
|
|
949
|
+
* Determines whether a parser state represents an explicit match (the user
|
|
950
|
+
* provided input) rather than an initial/pending state.
|
|
951
|
+
*
|
|
952
|
+
* @param fieldState The parser's state.
|
|
953
|
+
* @param parser The parser owning that state.
|
|
954
|
+
* @returns `true` when the state reflects command-line input, whether or
|
|
955
|
+
* not that input passed validation.
|
|
956
|
+
* @internal
|
|
957
|
+
* @since 1.3.0
|
|
958
|
+
*/
|
|
959
|
+
declare function isMatchedState(fieldState: unknown, parser: {
|
|
960
|
+
readonly dependencyMetadata?: ParserDependencyMetadata;
|
|
961
|
+
readonly initialState?: unknown;
|
|
962
|
+
readonly [unmatchedNonCliDependencySourceStateMarker]?: true;
|
|
963
|
+
}): boolean;
|
|
932
964
|
/**
|
|
933
965
|
* Builds {@link RuntimeNode}s from field→parser pairs and a state record.
|
|
934
966
|
*
|
|
@@ -961,5 +993,18 @@ declare function buildRuntimeNodesFromArray(parsers: ReadonlyArray<{
|
|
|
961
993
|
readonly dependencyMetadata?: ParserDependencyMetadata;
|
|
962
994
|
readonly initialState?: unknown;
|
|
963
995
|
}>, stateArray: readonly unknown[], parentPath?: readonly PropertyKey[]): readonly RuntimeNode[];
|
|
996
|
+
/**
|
|
997
|
+
* Reads a derived parser state's snapshotted default dependency values.
|
|
998
|
+
*
|
|
999
|
+
* Nodes must carry the parse-time snapshot so replay never re-evaluates a
|
|
1000
|
+
* dynamic `getDefaultDependencyValues()` thunk.
|
|
1001
|
+
*
|
|
1002
|
+
* @param state The derived parser's state.
|
|
1003
|
+
* @returns The snapshotted values, or `undefined` when the state carries
|
|
1004
|
+
* none.
|
|
1005
|
+
* @internal
|
|
1006
|
+
* @since 1.3.0
|
|
1007
|
+
*/
|
|
1008
|
+
declare function getDefaultDependencySnapshot(state: unknown): readonly unknown[] | undefined;
|
|
964
1009
|
//#endregion
|
|
965
|
-
export { BarrierCompletionDemandEdge, BarrierCompletionDependencies, BarrierResolution, CompleteEffectfulSourcesOptions, DependencyRequest, DependencyResolution, DependencyRuntimeContext, EffectfulSchedulingNodesFn, EffectfulSourceCompletion, EffectfulSourceCompletionResult, ReplayKey, ResolveDerivedSourceValuesOptions, RuntimeNode, SchedulingBarrierContext, SourceDefaultFailure, buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, forkRuntimeForCommittedSubtree, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, recordSourceScope, releaseUncollectedSourceValues, replaceCachedBarrierFailure, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
|
|
1010
|
+
export { BarrierCompletionDemandEdge, BarrierCompletionDependencies, BarrierResolution, CompleteEffectfulSourcesOptions, DependencyRequest, DependencyResolution, DependencyRuntimeContext, EffectfulSchedulingNodesFn, EffectfulSourceCompletion, EffectfulSourceCompletionResult, ExpandRuntimeNodesOptions, ReplayKey, ResolveDerivedSourceValuesOptions, RuntimeNode, SchedulingBarrierContext, SourceDefaultFailure, buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, forkRuntimeForCommittedSubtree, getDefaultDependencySnapshot, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, isMatchedState, orderDependencyNodes, recordDerivedRawInput, recordSourceScope, releaseUncollectedSourceValues, replaceCachedBarrierFailure, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
|
|
@@ -1850,6 +1850,13 @@ async function resolveDeferredInStateAsync(state, runtime, visited = /* @__PURE_
|
|
|
1850
1850
|
/**
|
|
1851
1851
|
* Determines whether a parser state represents an explicit match (the user
|
|
1852
1852
|
* provided input) rather than an initial/pending state.
|
|
1853
|
+
*
|
|
1854
|
+
* @param fieldState The parser's state.
|
|
1855
|
+
* @param parser The parser owning that state.
|
|
1856
|
+
* @returns `true` when the state reflects command-line input, whether or
|
|
1857
|
+
* not that input passed validation.
|
|
1858
|
+
* @internal
|
|
1859
|
+
* @since 1.3.0
|
|
1853
1860
|
*/
|
|
1854
1861
|
function isMatchedState(fieldState, parser) {
|
|
1855
1862
|
if (fieldState === void 0) return false;
|
|
@@ -1922,6 +1929,18 @@ function buildRuntimeNodesFromArray(parsers, stateArray, parentPath) {
|
|
|
1922
1929
|
}
|
|
1923
1930
|
return nodes;
|
|
1924
1931
|
}
|
|
1932
|
+
/**
|
|
1933
|
+
* Reads a derived parser state's snapshotted default dependency values.
|
|
1934
|
+
*
|
|
1935
|
+
* Nodes must carry the parse-time snapshot so replay never re-evaluates a
|
|
1936
|
+
* dynamic `getDefaultDependencyValues()` thunk.
|
|
1937
|
+
*
|
|
1938
|
+
* @param state The derived parser's state.
|
|
1939
|
+
* @returns The snapshotted values, or `undefined` when the state carries
|
|
1940
|
+
* none.
|
|
1941
|
+
* @internal
|
|
1942
|
+
* @since 1.3.0
|
|
1943
|
+
*/
|
|
1925
1944
|
function getDefaultDependencySnapshot(state) {
|
|
1926
1945
|
return getDefaultDependencySnapshotInner(state, /* @__PURE__ */ new Set());
|
|
1927
1946
|
}
|
|
@@ -1947,4 +1966,4 @@ function getDefaultDependencySnapshotInner(state, visited) {
|
|
|
1947
1966
|
}
|
|
1948
1967
|
|
|
1949
1968
|
//#endregion
|
|
1950
|
-
export { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, forkRuntimeForCommittedSubtree, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, orderDependencyNodes, recordDerivedRawInput, recordSourceScope, releaseUncollectedSourceValues, replaceCachedBarrierFailure, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
|
|
1969
|
+
export { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectDemandedDependencyIds, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyFingerprint, createDependencyRuntimeContext, createReplayKey, defineForwardedEffectfulSchedulingNodes, derivedRawInputKey, effectfulSchedulingNodesKey, exclusiveSourceScopeKey, extractRawInputFromState, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, forkRuntimeForCommittedSubtree, getDefaultDependencySnapshot, guaranteedStaticSourceIdsKey, hasInactiveCompletion, includeSourceFailureChain, isMatchedState, orderDependencyNodes, recordDerivedRawInput, recordSourceScope, releaseUncollectedSourceValues, replaceCachedBarrierFailure, replayDerivedParser, replayDerivedParserAsync, resolveDerivedSourceValues, resolveDerivedSourceValuesAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync, serializeSchedulingPath, sourceCollectionExpansionKey, staticSourceScopeKey };
|
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.2582",
|
|
4
4
|
"description": "Type-safe combinatorial command-line interface parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -237,7 +237,7 @@
|
|
|
237
237
|
},
|
|
238
238
|
"sideEffects": false,
|
|
239
239
|
"devDependencies": {
|
|
240
|
-
"@optique/env": "1.3.0-dev.
|
|
240
|
+
"@optique/env": "1.3.0-dev.2582+e069abd2",
|
|
241
241
|
"@types/node": "^24.0.0",
|
|
242
242
|
"fast-check": "^4.7.0",
|
|
243
243
|
"tsdown": "^0.13.0",
|