@optique/core 1.2.2 → 1.2.4
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 +346 -24
- package/dist/constructs.js +347 -25
- package/dist/internal/parser.cjs +35 -0
- package/dist/internal/parser.d.cts +62 -1
- package/dist/internal/parser.d.ts +62 -1
- package/dist/internal/parser.js +33 -1
- package/dist/modifiers.cjs +53 -0
- package/dist/modifiers.js +54 -1
- package/package.json +2 -2
package/dist/constructs.js
CHANGED
|
@@ -6,7 +6,7 @@ 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
8
|
import { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, createDependencyRuntimeContext, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync } from "./dependency-runtime.js";
|
|
9
|
-
import { defineInheritedAnnotationParser, getParserSuggestRuntimeNodes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
|
|
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";
|
|
12
12
|
import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
|
|
@@ -79,8 +79,8 @@ function unionLeadingNames(parsers) {
|
|
|
79
79
|
* Computes `leadingNames` for shared-buffer compositions (`tuple()`,
|
|
80
80
|
* `object()`, `merge()`, `concat()`).
|
|
81
81
|
*
|
|
82
|
-
*
|
|
83
|
-
* round-robin parse loop). Once a
|
|
82
|
+
* Sources are processed in descending priority order (matching the
|
|
83
|
+
* round-robin parse loop). Once a source with `acceptingAnyToken` is
|
|
84
84
|
* encountered, no lower-priority children can match at position 0, so
|
|
85
85
|
* their names are excluded.
|
|
86
86
|
*/
|
|
@@ -1529,6 +1529,33 @@ function createLongestMatch(...args) {
|
|
|
1529
1529
|
return fluent(multiResult);
|
|
1530
1530
|
}
|
|
1531
1531
|
/**
|
|
1532
|
+
* Creates the initial parse error shared by object-like combinators.
|
|
1533
|
+
* @param context The current parser context.
|
|
1534
|
+
* @param noMatchContext The kinds of input accepted by the combinator.
|
|
1535
|
+
* @param errors Optional custom error formatters.
|
|
1536
|
+
* @returns A zero-consumption parse error.
|
|
1537
|
+
*/
|
|
1538
|
+
function createObjectLikeInitialError(context, noMatchContext, errors) {
|
|
1539
|
+
if (context.buffer.length < 1) {
|
|
1540
|
+
const customEndOfInput = errors?.endOfInput;
|
|
1541
|
+
return {
|
|
1542
|
+
consumed: 0,
|
|
1543
|
+
error: customEndOfInput ? typeof customEndOfInput === "function" ? customEndOfInput(noMatchContext) : customEndOfInput : generateNoMatchError(noMatchContext)
|
|
1544
|
+
};
|
|
1545
|
+
}
|
|
1546
|
+
const token = context.buffer[0];
|
|
1547
|
+
const customMessage = errors?.unexpectedInput;
|
|
1548
|
+
if (customMessage) return {
|
|
1549
|
+
consumed: 0,
|
|
1550
|
+
error: typeof customMessage === "function" ? customMessage(token) : customMessage
|
|
1551
|
+
};
|
|
1552
|
+
const baseError = message`Unexpected option or argument: ${token}.`;
|
|
1553
|
+
return {
|
|
1554
|
+
consumed: 0,
|
|
1555
|
+
error: createErrorWithSuggestions(baseError, token, context.usage, "both", errors?.suggestions)
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1532
1559
|
* Internal sync helper for object suggest functionality.
|
|
1533
1560
|
* @internal
|
|
1534
1561
|
*/
|
|
@@ -1921,19 +1948,53 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
1921
1948
|
checkDuplicateReachableLeadingCommandNames(parserPairs.map(([field, parser]) => [field, parser]));
|
|
1922
1949
|
const noMatchContext = analyzeNoMatchContext(parserKeys.map((k) => parsers[k]));
|
|
1923
1950
|
const combinedMode = parserKeys.some((k) => parsers[k].mode === "async") ? "async" : "sync";
|
|
1924
|
-
const getInitialError = (context) => (
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1951
|
+
const getInitialError = (context) => createObjectLikeInitialError(context, noMatchContext, options.errors);
|
|
1952
|
+
const adaptFieldLaneResult = (context, field, parser, fieldState, result) => {
|
|
1953
|
+
if (!result.success) return result;
|
|
1954
|
+
if (result.consumed.length === 0 && result.next.state === fieldState) return {
|
|
1955
|
+
success: true,
|
|
1956
|
+
next: context,
|
|
1957
|
+
consumed: []
|
|
1958
|
+
};
|
|
1959
|
+
const mergedExec = mergeChildExec(context.exec, result.next.exec);
|
|
1960
|
+
const nextState = result.next.state === fieldState ? context.state : {
|
|
1961
|
+
...context.state,
|
|
1962
|
+
[field]: getWrappedChildState(context.state, result.next.state, parser)
|
|
1963
|
+
};
|
|
1964
|
+
return {
|
|
1965
|
+
success: true,
|
|
1966
|
+
next: {
|
|
1967
|
+
...context,
|
|
1968
|
+
buffer: result.next.buffer,
|
|
1969
|
+
optionsTerminated: result.next.optionsTerminated,
|
|
1970
|
+
state: nextState,
|
|
1971
|
+
...mergedExec != null ? {
|
|
1972
|
+
trace: mergedExec.trace,
|
|
1973
|
+
exec: mergedExec,
|
|
1974
|
+
dependencyRegistry: mergedExec.dependencyRegistry
|
|
1975
|
+
} : {}
|
|
1976
|
+
},
|
|
1977
|
+
consumed: result.consumed
|
|
1978
|
+
};
|
|
1979
|
+
};
|
|
1980
|
+
const objectZeroConsumptionGroup = {};
|
|
1981
|
+
const objectParseLanes = parserPairs.map(([field, parser]) => ({
|
|
1982
|
+
priority: parser.priority,
|
|
1983
|
+
zeroConsumptionGroup: objectZeroConsumptionGroup,
|
|
1984
|
+
settlesZeroConsumption: false,
|
|
1985
|
+
leadingNames: parser.leadingNames,
|
|
1986
|
+
acceptingAnyToken: parser.acceptingAnyToken,
|
|
1987
|
+
parse(context) {
|
|
1988
|
+
const fieldState = createFieldStateGetter(context.state, getObjectParseChildState)(field, parser);
|
|
1989
|
+
return dispatchByMode(combinedMode, () => {
|
|
1990
|
+
const result = parser.parse(withChildContext$1(context, field, fieldState, parser));
|
|
1991
|
+
return adaptFieldLaneResult(context, field, parser, fieldState, result);
|
|
1992
|
+
}, async () => {
|
|
1993
|
+
const result = await parser.parse(withChildContext$1(context, field, fieldState, parser));
|
|
1994
|
+
return adaptFieldLaneResult(context, field, parser, fieldState, result);
|
|
1995
|
+
});
|
|
1996
|
+
}
|
|
1997
|
+
}));
|
|
1937
1998
|
const parseSync = (context) => {
|
|
1938
1999
|
let error = getInitialError(context);
|
|
1939
2000
|
let currentContext = context;
|
|
@@ -2452,6 +2513,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
|
|
|
2452
2513
|
configurable: true,
|
|
2453
2514
|
enumerable: false
|
|
2454
2515
|
});
|
|
2516
|
+
defineParseLanes(objectParser, objectParseLanes);
|
|
2455
2517
|
defineInheritedAnnotationParser(objectParser);
|
|
2456
2518
|
return fluent(objectParser);
|
|
2457
2519
|
}
|
|
@@ -3803,6 +3865,7 @@ function merge(...args) {
|
|
|
3803
3865
|
const syncParsers = syncSorted.map(([p]) => p);
|
|
3804
3866
|
if (!options.allowDuplicates) checkDuplicateOptionNames(sorted.map(([parser, originalIndex]) => [String(originalIndex), parser.usage]));
|
|
3805
3867
|
checkDuplicateReachableLeadingCommandNames(sorted.map(([parser, originalIndex]) => [String(originalIndex), parser]));
|
|
3868
|
+
const noMatchContext = analyzeNoMatchContext(rawParsers);
|
|
3806
3869
|
const mergedFieldParsers = collectChildFieldParsers(parsers);
|
|
3807
3870
|
const duplicateOutputFieldNames = collectDuplicateFieldNames(mergedFieldParsers);
|
|
3808
3871
|
const parserStateKey = (index) => `__parser_${index}`;
|
|
@@ -3855,7 +3918,140 @@ function merge(...args) {
|
|
|
3855
3918
|
[localObjectStateKey(index)]: result.next.state
|
|
3856
3919
|
};
|
|
3857
3920
|
};
|
|
3858
|
-
const
|
|
3921
|
+
const adaptMergeLaneResult = (parser, context, parserState, parsedState, result, index) => {
|
|
3922
|
+
if (!result.success) return result;
|
|
3923
|
+
const mergedExec = mergeChildExec(context.exec, result.next.exec);
|
|
3924
|
+
const newState = result.next.state === parsedState ? context.state : mergeResultState(parser, context, parserState, result, index);
|
|
3925
|
+
return {
|
|
3926
|
+
success: true,
|
|
3927
|
+
next: {
|
|
3928
|
+
...context,
|
|
3929
|
+
buffer: result.next.buffer,
|
|
3930
|
+
optionsTerminated: result.next.optionsTerminated,
|
|
3931
|
+
state: newState,
|
|
3932
|
+
...mergedExec != null ? {
|
|
3933
|
+
trace: mergedExec.trace,
|
|
3934
|
+
exec: mergedExec,
|
|
3935
|
+
dependencyRegistry: mergedExec.dependencyRegistry
|
|
3936
|
+
} : {}
|
|
3937
|
+
},
|
|
3938
|
+
consumed: result.consumed
|
|
3939
|
+
};
|
|
3940
|
+
};
|
|
3941
|
+
const childrenInDeclarationOrder = sorted.map(([parser, originalIndex], sortedIndex) => ({
|
|
3942
|
+
parser,
|
|
3943
|
+
originalIndex,
|
|
3944
|
+
sortedIndex
|
|
3945
|
+
})).toSorted((a, b) => a.originalIndex - b.originalIndex);
|
|
3946
|
+
const mergeParseLanes = childrenInDeclarationOrder.flatMap(({ parser, sortedIndex }) => {
|
|
3947
|
+
const occurrenceConsumptionGroups = /* @__PURE__ */ new WeakMap();
|
|
3948
|
+
const occurrenceZeroConsumptionGroups = /* @__PURE__ */ new WeakMap();
|
|
3949
|
+
const scopeConsumptionGroup = (group$1) => {
|
|
3950
|
+
const existing = occurrenceConsumptionGroups.get(group$1);
|
|
3951
|
+
if (existing != null) return existing;
|
|
3952
|
+
const scoped = {};
|
|
3953
|
+
occurrenceConsumptionGroups.set(group$1, scoped);
|
|
3954
|
+
return scoped;
|
|
3955
|
+
};
|
|
3956
|
+
const childLanes = getOwnParseLanes(parser);
|
|
3957
|
+
const lanes = childLanes ?? [{
|
|
3958
|
+
priority: parser.priority,
|
|
3959
|
+
leadingNames: parser.leadingNames,
|
|
3960
|
+
acceptingAnyToken: parser.acceptingAnyToken,
|
|
3961
|
+
parse(context) {
|
|
3962
|
+
return parser.parse(context);
|
|
3963
|
+
}
|
|
3964
|
+
}];
|
|
3965
|
+
return lanes.map((lane) => ({
|
|
3966
|
+
priority: lane.priority,
|
|
3967
|
+
zeroConsumptionGroup: (() => {
|
|
3968
|
+
const group$1 = lane.zeroConsumptionGroup ?? lane;
|
|
3969
|
+
const existing = occurrenceZeroConsumptionGroups.get(group$1);
|
|
3970
|
+
if (existing != null) return existing;
|
|
3971
|
+
const scoped = {};
|
|
3972
|
+
occurrenceZeroConsumptionGroups.set(group$1, scoped);
|
|
3973
|
+
return scoped;
|
|
3974
|
+
})(),
|
|
3975
|
+
settlesZeroConsumption: lane.settlesZeroConsumption,
|
|
3976
|
+
leadingNames: lane.leadingNames,
|
|
3977
|
+
acceptingAnyToken: lane.acceptingAnyToken,
|
|
3978
|
+
requiredConsumptionGroups: lane.requiredConsumptionGroups?.map((group$1) => ({
|
|
3979
|
+
id: scopeConsumptionGroup(group$1.id),
|
|
3980
|
+
...group$1.isActive == null ? {} : { isActive(state) {
|
|
3981
|
+
if (state == null || typeof state !== "object") return false;
|
|
3982
|
+
const parserState = extractParserStateFromState(parser, state, sortedIndex);
|
|
3983
|
+
return group$1.isActive?.(parserState) ?? true;
|
|
3984
|
+
} }
|
|
3985
|
+
})),
|
|
3986
|
+
parse(context) {
|
|
3987
|
+
const parserState = extractParserState(parser, context, sortedIndex);
|
|
3988
|
+
const childContext = withChildContext$1(context, sortedIndex, parserState, parser);
|
|
3989
|
+
return dispatchByMode(combinedMode, () => {
|
|
3990
|
+
const result = lane.parse(childContext);
|
|
3991
|
+
return adaptMergeLaneResult(parser, context, parserState, childContext.state, result, sortedIndex);
|
|
3992
|
+
}, async () => {
|
|
3993
|
+
const result = await lane.parse(childContext);
|
|
3994
|
+
return adaptMergeLaneResult(parser, context, parserState, childContext.state, result, sortedIndex);
|
|
3995
|
+
});
|
|
3996
|
+
}
|
|
3997
|
+
}));
|
|
3998
|
+
}).toSorted((a, b) => b.priority - a.priority);
|
|
3999
|
+
const settleZeroConsumptionLanes = (context, laneResults) => {
|
|
4000
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4001
|
+
for (const lane of mergeParseLanes) {
|
|
4002
|
+
const group$1 = lane.zeroConsumptionGroup ?? lane;
|
|
4003
|
+
const groupedLanes = groups.get(group$1);
|
|
4004
|
+
if (groupedLanes == null) groups.set(group$1, [lane]);
|
|
4005
|
+
else groupedLanes.push(lane);
|
|
4006
|
+
}
|
|
4007
|
+
const settledGroups = [];
|
|
4008
|
+
for (const groupedLanes of groups.values()) {
|
|
4009
|
+
const groupSucceeded = groupedLanes.every((lane) => {
|
|
4010
|
+
const result = laneResults.get(lane);
|
|
4011
|
+
return lane.settlesZeroConsumption !== false && result?.success === true && result.consumed.length === 0 && (lane.requiredConsumptionGroups?.length ?? 0) === 0;
|
|
4012
|
+
});
|
|
4013
|
+
if (!groupSucceeded) return null;
|
|
4014
|
+
settledGroups.push(groupedLanes);
|
|
4015
|
+
}
|
|
4016
|
+
let settledContext = context;
|
|
4017
|
+
for (const groupedLanes of settledGroups) for (const lane of groupedLanes) {
|
|
4018
|
+
const result = laneResults.get(lane);
|
|
4019
|
+
if (result?.success !== true) continue;
|
|
4020
|
+
const originalState = context.state;
|
|
4021
|
+
const resultState = result.next.state;
|
|
4022
|
+
const nextState = { ...settledContext.state };
|
|
4023
|
+
const stateKeys = new Set([...Reflect.ownKeys(originalState), ...Reflect.ownKeys(resultState)]);
|
|
4024
|
+
for (const key of stateKeys) {
|
|
4025
|
+
const originalHasKey = Object.hasOwn(originalState, key);
|
|
4026
|
+
const resultHasKey = Object.hasOwn(resultState, key);
|
|
4027
|
+
if (originalHasKey === resultHasKey && originalState[key] === resultState[key]) continue;
|
|
4028
|
+
if (resultHasKey) nextState[key] = resultState[key];
|
|
4029
|
+
else delete nextState[key];
|
|
4030
|
+
}
|
|
4031
|
+
const mergedExec = mergeChildExec(settledContext.exec, result.next.exec);
|
|
4032
|
+
settledContext = {
|
|
4033
|
+
...settledContext,
|
|
4034
|
+
buffer: result.next.buffer,
|
|
4035
|
+
optionsTerminated: result.next.optionsTerminated,
|
|
4036
|
+
state: nextState,
|
|
4037
|
+
...mergedExec != null ? {
|
|
4038
|
+
trace: mergedExec.trace,
|
|
4039
|
+
exec: mergedExec,
|
|
4040
|
+
dependencyRegistry: mergedExec.dependencyRegistry
|
|
4041
|
+
} : {}
|
|
4042
|
+
};
|
|
4043
|
+
}
|
|
4044
|
+
return {
|
|
4045
|
+
success: true,
|
|
4046
|
+
next: settledContext,
|
|
4047
|
+
consumed: []
|
|
4048
|
+
};
|
|
4049
|
+
};
|
|
4050
|
+
const canTryPositionalLaneAfterFailure = (lane, context) => {
|
|
4051
|
+
const token = context.buffer[0];
|
|
4052
|
+
return token != null && (context.optionsTerminated || !token.startsWith("-")) && (lane.acceptingAnyToken || lane.leadingNames.has(token));
|
|
4053
|
+
};
|
|
4054
|
+
const parseChildrenSync = (context) => {
|
|
3859
4055
|
let currentContext = context;
|
|
3860
4056
|
let zeroConsumedSuccess = null;
|
|
3861
4057
|
for (let i = 0; i < syncParsers.length; i++) {
|
|
@@ -3896,11 +4092,10 @@ function merge(...args) {
|
|
|
3896
4092
|
};
|
|
3897
4093
|
return {
|
|
3898
4094
|
success: false,
|
|
3899
|
-
|
|
3900
|
-
error: message`No matching option or argument found.`
|
|
4095
|
+
...createObjectLikeInitialError(context, noMatchContext)
|
|
3901
4096
|
};
|
|
3902
4097
|
};
|
|
3903
|
-
const
|
|
4098
|
+
const parseChildrenAsync = async (context) => {
|
|
3904
4099
|
let currentContext = context;
|
|
3905
4100
|
let zeroConsumedSuccess = null;
|
|
3906
4101
|
for (let i = 0; i < parsers.length; i++) {
|
|
@@ -3942,8 +4137,133 @@ function merge(...args) {
|
|
|
3942
4137
|
};
|
|
3943
4138
|
return {
|
|
3944
4139
|
success: false,
|
|
3945
|
-
|
|
3946
|
-
|
|
4140
|
+
...createObjectLikeInitialError(context, noMatchContext)
|
|
4141
|
+
};
|
|
4142
|
+
};
|
|
4143
|
+
const parseSync = (context) => {
|
|
4144
|
+
let currentContext = context;
|
|
4145
|
+
let error = createObjectLikeInitialError(context, noMatchContext);
|
|
4146
|
+
const allConsumed = [];
|
|
4147
|
+
const consumedLanes = /* @__PURE__ */ new Set();
|
|
4148
|
+
const consumedGroups = /* @__PURE__ */ new Set();
|
|
4149
|
+
const laneResults = /* @__PURE__ */ new Map();
|
|
4150
|
+
let attemptedLane = false;
|
|
4151
|
+
let madeProgress = true;
|
|
4152
|
+
while (madeProgress && currentContext.buffer.length > 0) {
|
|
4153
|
+
madeProgress = false;
|
|
4154
|
+
let consumingError = null;
|
|
4155
|
+
for (const lane of mergeParseLanes) {
|
|
4156
|
+
if (consumingError != null && lane.priority < consumingError.priority) {
|
|
4157
|
+
if (!canTryPositionalLaneAfterFailure(lane, currentContext)) continue;
|
|
4158
|
+
}
|
|
4159
|
+
attemptedLane = true;
|
|
4160
|
+
const result = lane.parse(currentContext);
|
|
4161
|
+
laneResults.set(lane, result);
|
|
4162
|
+
if (result.success && result.consumed.length > 0) {
|
|
4163
|
+
currentContext = result.next;
|
|
4164
|
+
allConsumed.push(...result.consumed);
|
|
4165
|
+
consumedLanes.add(lane);
|
|
4166
|
+
for (const group$1 of lane.requiredConsumptionGroups ?? []) if (group$1.isActive?.(result.next.state) !== false) consumedGroups.add(group$1.id);
|
|
4167
|
+
madeProgress = true;
|
|
4168
|
+
break;
|
|
4169
|
+
}
|
|
4170
|
+
if (!result.success) {
|
|
4171
|
+
if (result.consumed > 0 && consumingError == null) consumingError = {
|
|
4172
|
+
priority: lane.priority,
|
|
4173
|
+
result
|
|
4174
|
+
};
|
|
4175
|
+
if (error.consumed < result.consumed) error = result;
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
if (!madeProgress && consumingError != null && allConsumed.length === 0) return consumingError.result;
|
|
4179
|
+
}
|
|
4180
|
+
if (allConsumed.length === 0) {
|
|
4181
|
+
if (attemptedLane) {
|
|
4182
|
+
const settled = settleZeroConsumptionLanes(context, laneResults);
|
|
4183
|
+
return settled ?? {
|
|
4184
|
+
...error,
|
|
4185
|
+
success: false
|
|
4186
|
+
};
|
|
4187
|
+
}
|
|
4188
|
+
const fallback = parseChildrenSync(context);
|
|
4189
|
+
if (!fallback.success && fallback.consumed < error.consumed) return {
|
|
4190
|
+
...error,
|
|
4191
|
+
success: false
|
|
4192
|
+
};
|
|
4193
|
+
return fallback;
|
|
4194
|
+
}
|
|
4195
|
+
for (const lane of mergeParseLanes) {
|
|
4196
|
+
if (consumedLanes.has(lane) || lane.leadingNames.size > 0 || lane.acceptingAnyToken || lane.requiredConsumptionGroups?.some((group$1) => !consumedGroups.has(group$1.id)) === true) continue;
|
|
4197
|
+
const result = lane.parse(currentContext);
|
|
4198
|
+
if (result.success && result.consumed.length === 0 && result.next.state !== currentContext.state) currentContext = result.next;
|
|
4199
|
+
}
|
|
4200
|
+
return {
|
|
4201
|
+
success: true,
|
|
4202
|
+
next: currentContext,
|
|
4203
|
+
consumed: allConsumed
|
|
4204
|
+
};
|
|
4205
|
+
};
|
|
4206
|
+
const parseAsync = async (context) => {
|
|
4207
|
+
let currentContext = context;
|
|
4208
|
+
let error = createObjectLikeInitialError(context, noMatchContext);
|
|
4209
|
+
const allConsumed = [];
|
|
4210
|
+
const consumedLanes = /* @__PURE__ */ new Set();
|
|
4211
|
+
const consumedGroups = /* @__PURE__ */ new Set();
|
|
4212
|
+
const laneResults = /* @__PURE__ */ new Map();
|
|
4213
|
+
let attemptedLane = false;
|
|
4214
|
+
let madeProgress = true;
|
|
4215
|
+
while (madeProgress && currentContext.buffer.length > 0) {
|
|
4216
|
+
madeProgress = false;
|
|
4217
|
+
let consumingError = null;
|
|
4218
|
+
for (const lane of mergeParseLanes) {
|
|
4219
|
+
if (consumingError != null && lane.priority < consumingError.priority) {
|
|
4220
|
+
if (!canTryPositionalLaneAfterFailure(lane, currentContext)) continue;
|
|
4221
|
+
}
|
|
4222
|
+
attemptedLane = true;
|
|
4223
|
+
const result = await lane.parse(currentContext);
|
|
4224
|
+
laneResults.set(lane, result);
|
|
4225
|
+
if (result.success && result.consumed.length > 0) {
|
|
4226
|
+
currentContext = result.next;
|
|
4227
|
+
allConsumed.push(...result.consumed);
|
|
4228
|
+
consumedLanes.add(lane);
|
|
4229
|
+
for (const group$1 of lane.requiredConsumptionGroups ?? []) if (group$1.isActive?.(result.next.state) !== false) consumedGroups.add(group$1.id);
|
|
4230
|
+
madeProgress = true;
|
|
4231
|
+
break;
|
|
4232
|
+
}
|
|
4233
|
+
if (!result.success) {
|
|
4234
|
+
if (result.consumed > 0 && consumingError == null) consumingError = {
|
|
4235
|
+
priority: lane.priority,
|
|
4236
|
+
result
|
|
4237
|
+
};
|
|
4238
|
+
if (error.consumed < result.consumed) error = result;
|
|
4239
|
+
}
|
|
4240
|
+
}
|
|
4241
|
+
if (!madeProgress && consumingError != null && allConsumed.length === 0) return consumingError.result;
|
|
4242
|
+
}
|
|
4243
|
+
if (allConsumed.length === 0) {
|
|
4244
|
+
if (attemptedLane) {
|
|
4245
|
+
const settled = settleZeroConsumptionLanes(context, laneResults);
|
|
4246
|
+
return settled ?? {
|
|
4247
|
+
...error,
|
|
4248
|
+
success: false
|
|
4249
|
+
};
|
|
4250
|
+
}
|
|
4251
|
+
const fallback = await parseChildrenAsync(context);
|
|
4252
|
+
if (!fallback.success && fallback.consumed < error.consumed) return {
|
|
4253
|
+
...error,
|
|
4254
|
+
success: false
|
|
4255
|
+
};
|
|
4256
|
+
return fallback;
|
|
4257
|
+
}
|
|
4258
|
+
for (const lane of mergeParseLanes) {
|
|
4259
|
+
if (consumedLanes.has(lane) || lane.leadingNames.size > 0 || lane.acceptingAnyToken || lane.requiredConsumptionGroups?.some((group$1) => !consumedGroups.has(group$1.id)) === true) continue;
|
|
4260
|
+
const result = await lane.parse(currentContext);
|
|
4261
|
+
if (result.success && result.consumed.length === 0 && result.next.state !== currentContext.state) currentContext = result.next;
|
|
4262
|
+
}
|
|
4263
|
+
return {
|
|
4264
|
+
success: true,
|
|
4265
|
+
next: currentContext,
|
|
4266
|
+
consumed: allConsumed
|
|
3947
4267
|
};
|
|
3948
4268
|
};
|
|
3949
4269
|
const mergeParser = {
|
|
@@ -3951,10 +4271,10 @@ function merge(...args) {
|
|
|
3951
4271
|
$valueType: [],
|
|
3952
4272
|
$stateType: [],
|
|
3953
4273
|
[fieldParsersKey]: mergedFieldParsers,
|
|
3954
|
-
priority: Math.max(...
|
|
4274
|
+
priority: Math.max(...mergeParseLanes.map((lane) => lane.priority)),
|
|
3955
4275
|
usage: applyHiddenToUsage(parsers.flatMap((p) => p.usage), options.hidden),
|
|
3956
|
-
leadingNames: sharedBufferLeadingNames(
|
|
3957
|
-
acceptingAnyToken:
|
|
4276
|
+
leadingNames: sharedBufferLeadingNames(mergeParseLanes),
|
|
4277
|
+
acceptingAnyToken: mergeParseLanes.some((lane) => lane.acceptingAnyToken),
|
|
3958
4278
|
initialState,
|
|
3959
4279
|
canSkip(state, exec) {
|
|
3960
4280
|
return parsers.every((parser, index) => {
|
|
@@ -4429,6 +4749,7 @@ function merge(...args) {
|
|
|
4429
4749
|
};
|
|
4430
4750
|
}
|
|
4431
4751
|
};
|
|
4752
|
+
defineParseLanes(mergeParser, mergeParseLanes);
|
|
4432
4753
|
defineInheritedAnnotationParser(mergeParser);
|
|
4433
4754
|
return fluent(mergeParser);
|
|
4434
4755
|
}
|
|
@@ -5111,6 +5432,7 @@ function group(label, parser, options = {}) {
|
|
|
5111
5432
|
};
|
|
5112
5433
|
}
|
|
5113
5434
|
};
|
|
5435
|
+
defineParseLanes(groupParser, getOwnParseLanes(parser));
|
|
5114
5436
|
Object.defineProperty(groupParser, extractPhase2SeedKey, {
|
|
5115
5437
|
value(state, exec) {
|
|
5116
5438
|
return extractPhase2Seed(parser, state, exec);
|
package/dist/internal/parser.cjs
CHANGED
|
@@ -8,6 +8,12 @@ const require_input_trace = require('../input-trace.cjs');
|
|
|
8
8
|
|
|
9
9
|
//#region src/internal/parser.ts
|
|
10
10
|
/**
|
|
11
|
+
* Internal symbol used by transparent combinators to expose independently
|
|
12
|
+
* competing parse operations to shared-buffer parents.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
const parseLanesKey = Symbol("parseLanes");
|
|
16
|
+
/**
|
|
11
17
|
* Internal marker for wrappers whose `{ hasCliValue: false }` states should
|
|
12
18
|
* be treated as unmatched dependency-source states during completion-time
|
|
13
19
|
* Phase 1.
|
|
@@ -387,6 +393,32 @@ function composeWrappedSourceMetadata(dependencyMetadata, wrapSource) {
|
|
|
387
393
|
};
|
|
388
394
|
}
|
|
389
395
|
/**
|
|
396
|
+
* Defines internal parse-lane metadata without exposing it through object
|
|
397
|
+
* spreads used by custom parser wrappers.
|
|
398
|
+
*
|
|
399
|
+
* @internal
|
|
400
|
+
*/
|
|
401
|
+
function defineParseLanes(parser, lanes) {
|
|
402
|
+
if (lanes == null) return;
|
|
403
|
+
Object.defineProperty(parser, parseLanesKey, {
|
|
404
|
+
value: lanes,
|
|
405
|
+
configurable: true,
|
|
406
|
+
enumerable: false
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Gets parse-lane metadata defined directly on a parser.
|
|
411
|
+
*
|
|
412
|
+
* Inherited metadata belongs to the parser's prototype and must not bypass an
|
|
413
|
+
* overriding `parse()` implementation on a custom wrapper.
|
|
414
|
+
*
|
|
415
|
+
* @internal
|
|
416
|
+
*/
|
|
417
|
+
function getOwnParseLanes(parser) {
|
|
418
|
+
if (!Object.hasOwn(parser, parseLanesKey)) return void 0;
|
|
419
|
+
return parser[parseLanesKey];
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
390
422
|
* Marks a parser as inheriting parent-state annotations through wrapper-state
|
|
391
423
|
* reconstruction.
|
|
392
424
|
*
|
|
@@ -854,15 +886,18 @@ exports.annotationWrapperRequiresSourceBindingKey = annotationWrapperRequiresSou
|
|
|
854
886
|
exports.composeWrappedSourceMetadata = composeWrappedSourceMetadata;
|
|
855
887
|
exports.createParserContext = createParserContext;
|
|
856
888
|
exports.defineInheritedAnnotationParser = defineInheritedAnnotationParser;
|
|
889
|
+
exports.defineParseLanes = defineParseLanes;
|
|
857
890
|
exports.defineSourceBindingOnlyAnnotationCompletionParser = defineSourceBindingOnlyAnnotationCompletionParser;
|
|
858
891
|
exports.getDelegatingSuggestRuntimeNodes = getDelegatingSuggestRuntimeNodes;
|
|
859
892
|
exports.getDocPage = getDocPage;
|
|
860
893
|
exports.getDocPageAsync = getDocPageAsync;
|
|
861
894
|
exports.getDocPageSync = getDocPageSync;
|
|
895
|
+
exports.getOwnParseLanes = getOwnParseLanes;
|
|
862
896
|
exports.getParserSuggestRuntimeNodes = getParserSuggestRuntimeNodes;
|
|
863
897
|
exports.inheritParentAnnotationsKey = inheritParentAnnotationsKey;
|
|
864
898
|
exports.parse = parse;
|
|
865
899
|
exports.parseAsync = parseAsync;
|
|
900
|
+
exports.parseLanesKey = parseLanesKey;
|
|
866
901
|
exports.parseSync = parseSync;
|
|
867
902
|
exports.suggest = suggest;
|
|
868
903
|
exports.suggestAsync = suggestAsync;
|
|
@@ -42,6 +42,51 @@ type ModeValue<M extends Mode, T> = M extends "async" ? Promise<T> : T;
|
|
|
42
42
|
* @since 0.9.0
|
|
43
43
|
*/
|
|
44
44
|
type ModeIterable<M extends Mode, T> = M extends "async" ? AsyncIterable<T> : Iterable<T>;
|
|
45
|
+
/**
|
|
46
|
+
* Internal symbol used by transparent combinators to expose independently
|
|
47
|
+
* competing parse operations to shared-buffer parents.
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
declare const parseLanesKey: unique symbol;
|
|
51
|
+
/**
|
|
52
|
+
* An owner-consumption requirement for a parse lane.
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
interface ParseLaneConsumptionGroup {
|
|
56
|
+
/** Identity shared by lanes belonging to the same owning parser. */
|
|
57
|
+
readonly id: object;
|
|
58
|
+
/** Whether the owning parser is active after a consuming lane succeeds. */
|
|
59
|
+
readonly isActive?: (state: unknown) => boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A state-preserving parse operation that competes at one exact priority.
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
interface ParseLane<TState> {
|
|
66
|
+
/** The exact priority at which this lane competes. */
|
|
67
|
+
readonly priority: number;
|
|
68
|
+
/**
|
|
69
|
+
* Identity shared by lanes that must all succeed before their
|
|
70
|
+
* zero-consumption state updates can be committed.
|
|
71
|
+
*/
|
|
72
|
+
readonly zeroConsumptionGroup?: object;
|
|
73
|
+
/**
|
|
74
|
+
* Whether a zero-consumption success can settle the owning parser while
|
|
75
|
+
* input remains. Defaults to `true`.
|
|
76
|
+
*/
|
|
77
|
+
readonly settlesZeroConsumption?: boolean;
|
|
78
|
+
/** Fixed tokens reachable through this lane. */
|
|
79
|
+
readonly leadingNames: ReadonlySet<string>;
|
|
80
|
+
/** Whether this lane accepts any positional token. */
|
|
81
|
+
readonly acceptingAnyToken: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Groups in which a zero-consumption update is valid only after another
|
|
84
|
+
* lane in every group has consumed input during the same arbitration.
|
|
85
|
+
*/
|
|
86
|
+
readonly requiredConsumptionGroups?: readonly ParseLaneConsumptionGroup[];
|
|
87
|
+
/** Parses through the owning parser's state and execution context. */
|
|
88
|
+
parse(context: ParserContext<TState>): ParserResult<TState> | Promise<ParserResult<TState>>;
|
|
89
|
+
}
|
|
45
90
|
/**
|
|
46
91
|
* Combines multiple modes into a single mode.
|
|
47
92
|
* If any mode is `"async"`, the result is `"async"`; otherwise `"sync"`.
|
|
@@ -851,6 +896,22 @@ declare function getDelegatingSuggestRuntimeNodes<TInnerState>(innerParser: Pars
|
|
|
851
896
|
* @internal
|
|
852
897
|
*/
|
|
853
898
|
declare function composeWrappedSourceMetadata(dependencyMetadata: ParserDependencyMetadata | undefined, wrapSource: (source: NonNullable<ParserDependencyMetadata["source"]>) => NonNullable<ParserDependencyMetadata["source"]>): ParserDependencyMetadata | undefined;
|
|
899
|
+
/**
|
|
900
|
+
* Defines internal parse-lane metadata without exposing it through object
|
|
901
|
+
* spreads used by custom parser wrappers.
|
|
902
|
+
*
|
|
903
|
+
* @internal
|
|
904
|
+
*/
|
|
905
|
+
declare function defineParseLanes<TState>(parser: object, lanes: readonly ParseLane<TState>[] | undefined): void;
|
|
906
|
+
/**
|
|
907
|
+
* Gets parse-lane metadata defined directly on a parser.
|
|
908
|
+
*
|
|
909
|
+
* Inherited metadata belongs to the parser's prototype and must not bypass an
|
|
910
|
+
* overriding `parse()` implementation on a custom wrapper.
|
|
911
|
+
*
|
|
912
|
+
* @internal
|
|
913
|
+
*/
|
|
914
|
+
declare function getOwnParseLanes<TState>(parser: object): readonly ParseLane<TState>[] | undefined;
|
|
854
915
|
/**
|
|
855
916
|
* Marks a parser as inheriting parent-state annotations through wrapper-state
|
|
856
917
|
* reconstruction.
|
|
@@ -999,4 +1060,4 @@ declare function getDocPage(parser: Parser<"sync", unknown, unknown>, argsOrOpti
|
|
|
999
1060
|
declare function getDocPage(parser: Parser<"async", unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): Promise<DocPage | undefined>;
|
|
1000
1061
|
declare function getDocPage<M extends Mode>(parser: Parser<M, unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): ModeValue<M, DocPage | undefined>;
|
|
1001
1062
|
//#endregion
|
|
1002
|
-
export { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, type ParseOptions, Parser, ParserContext, ParserResult, Result, Suggestion, annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
|
|
1063
|
+
export { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, ParseLane, ParseLaneConsumptionGroup, type ParseOptions, Parser, ParserContext, ParserResult, Result, Suggestion, annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseLanesKey, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
|
|
@@ -42,6 +42,51 @@ type ModeValue<M extends Mode, T> = M extends "async" ? Promise<T> : T;
|
|
|
42
42
|
* @since 0.9.0
|
|
43
43
|
*/
|
|
44
44
|
type ModeIterable<M extends Mode, T> = M extends "async" ? AsyncIterable<T> : Iterable<T>;
|
|
45
|
+
/**
|
|
46
|
+
* Internal symbol used by transparent combinators to expose independently
|
|
47
|
+
* competing parse operations to shared-buffer parents.
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
declare const parseLanesKey: unique symbol;
|
|
51
|
+
/**
|
|
52
|
+
* An owner-consumption requirement for a parse lane.
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
interface ParseLaneConsumptionGroup {
|
|
56
|
+
/** Identity shared by lanes belonging to the same owning parser. */
|
|
57
|
+
readonly id: object;
|
|
58
|
+
/** Whether the owning parser is active after a consuming lane succeeds. */
|
|
59
|
+
readonly isActive?: (state: unknown) => boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A state-preserving parse operation that competes at one exact priority.
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
interface ParseLane<TState> {
|
|
66
|
+
/** The exact priority at which this lane competes. */
|
|
67
|
+
readonly priority: number;
|
|
68
|
+
/**
|
|
69
|
+
* Identity shared by lanes that must all succeed before their
|
|
70
|
+
* zero-consumption state updates can be committed.
|
|
71
|
+
*/
|
|
72
|
+
readonly zeroConsumptionGroup?: object;
|
|
73
|
+
/**
|
|
74
|
+
* Whether a zero-consumption success can settle the owning parser while
|
|
75
|
+
* input remains. Defaults to `true`.
|
|
76
|
+
*/
|
|
77
|
+
readonly settlesZeroConsumption?: boolean;
|
|
78
|
+
/** Fixed tokens reachable through this lane. */
|
|
79
|
+
readonly leadingNames: ReadonlySet<string>;
|
|
80
|
+
/** Whether this lane accepts any positional token. */
|
|
81
|
+
readonly acceptingAnyToken: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Groups in which a zero-consumption update is valid only after another
|
|
84
|
+
* lane in every group has consumed input during the same arbitration.
|
|
85
|
+
*/
|
|
86
|
+
readonly requiredConsumptionGroups?: readonly ParseLaneConsumptionGroup[];
|
|
87
|
+
/** Parses through the owning parser's state and execution context. */
|
|
88
|
+
parse(context: ParserContext<TState>): ParserResult<TState> | Promise<ParserResult<TState>>;
|
|
89
|
+
}
|
|
45
90
|
/**
|
|
46
91
|
* Combines multiple modes into a single mode.
|
|
47
92
|
* If any mode is `"async"`, the result is `"async"`; otherwise `"sync"`.
|
|
@@ -851,6 +896,22 @@ declare function getDelegatingSuggestRuntimeNodes<TInnerState>(innerParser: Pars
|
|
|
851
896
|
* @internal
|
|
852
897
|
*/
|
|
853
898
|
declare function composeWrappedSourceMetadata(dependencyMetadata: ParserDependencyMetadata | undefined, wrapSource: (source: NonNullable<ParserDependencyMetadata["source"]>) => NonNullable<ParserDependencyMetadata["source"]>): ParserDependencyMetadata | undefined;
|
|
899
|
+
/**
|
|
900
|
+
* Defines internal parse-lane metadata without exposing it through object
|
|
901
|
+
* spreads used by custom parser wrappers.
|
|
902
|
+
*
|
|
903
|
+
* @internal
|
|
904
|
+
*/
|
|
905
|
+
declare function defineParseLanes<TState>(parser: object, lanes: readonly ParseLane<TState>[] | undefined): void;
|
|
906
|
+
/**
|
|
907
|
+
* Gets parse-lane metadata defined directly on a parser.
|
|
908
|
+
*
|
|
909
|
+
* Inherited metadata belongs to the parser's prototype and must not bypass an
|
|
910
|
+
* overriding `parse()` implementation on a custom wrapper.
|
|
911
|
+
*
|
|
912
|
+
* @internal
|
|
913
|
+
*/
|
|
914
|
+
declare function getOwnParseLanes<TState>(parser: object): readonly ParseLane<TState>[] | undefined;
|
|
854
915
|
/**
|
|
855
916
|
* Marks a parser as inheriting parent-state annotations through wrapper-state
|
|
856
917
|
* reconstruction.
|
|
@@ -999,4 +1060,4 @@ declare function getDocPage(parser: Parser<"sync", unknown, unknown>, argsOrOpti
|
|
|
999
1060
|
declare function getDocPage(parser: Parser<"async", unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): Promise<DocPage | undefined>;
|
|
1000
1061
|
declare function getDocPage<M extends Mode>(parser: Parser<M, unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): ModeValue<M, DocPage | undefined>;
|
|
1001
1062
|
//#endregion
|
|
1002
|
-
export { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, type ParseOptions, Parser, ParserContext, ParserResult, Result, Suggestion, annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
|
|
1063
|
+
export { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, ParseLane, ParseLaneConsumptionGroup, type ParseOptions, Parser, ParserContext, ParserResult, Result, Suggestion, annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseLanesKey, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
|