@optique/core 1.0.6 → 1.0.7

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.
@@ -77,8 +77,8 @@ function unionLeadingNames(parsers) {
77
77
  * Computes `leadingNames` for shared-buffer compositions (`tuple()`,
78
78
  * `object()`, `merge()`, `concat()`).
79
79
  *
80
- * Children are processed in descending priority order (matching the
81
- * round-robin parse loop). Once a child with `acceptingAnyToken` is
80
+ * Sources are processed in descending priority order (matching the
81
+ * round-robin parse loop). Once a source with `acceptingAnyToken` is
82
82
  * encountered, no lower-priority children can match at position 0, so
83
83
  * their names are excluded.
84
84
  */
@@ -1867,6 +1867,52 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1867
1867
  const noMatchContext = analyzeNoMatchContext(parserKeys.map((k) => parsers[k]));
1868
1868
  const combinedMode = parserKeys.some((k) => parsers[k].mode === "async") ? "async" : "sync";
1869
1869
  const getInitialError = (context) => createObjectLikeInitialError(context, noMatchContext, options.errors);
1870
+ const adaptFieldLaneResult = (context, field, parser, fieldState, result) => {
1871
+ if (!result.success) return result;
1872
+ if (result.consumed.length === 0 && result.next.state === fieldState) return {
1873
+ success: true,
1874
+ next: context,
1875
+ consumed: []
1876
+ };
1877
+ const mergedExec = require_execution_context.mergeChildExec(context.exec, result.next.exec);
1878
+ const nextState = result.next.state === fieldState ? context.state : {
1879
+ ...context.state,
1880
+ [field]: require_annotation_state.getWrappedChildState(context.state, result.next.state, parser)
1881
+ };
1882
+ return {
1883
+ success: true,
1884
+ next: {
1885
+ ...context,
1886
+ buffer: result.next.buffer,
1887
+ optionsTerminated: result.next.optionsTerminated,
1888
+ state: nextState,
1889
+ ...mergedExec != null ? {
1890
+ trace: mergedExec.trace,
1891
+ exec: mergedExec,
1892
+ dependencyRegistry: mergedExec.dependencyRegistry
1893
+ } : {}
1894
+ },
1895
+ consumed: result.consumed
1896
+ };
1897
+ };
1898
+ const objectZeroConsumptionGroup = {};
1899
+ const objectParseLanes = parserPairs.map(([field, parser]) => ({
1900
+ priority: parser.priority,
1901
+ zeroConsumptionGroup: objectZeroConsumptionGroup,
1902
+ settlesZeroConsumption: false,
1903
+ leadingNames: parser.leadingNames,
1904
+ acceptingAnyToken: parser.acceptingAnyToken,
1905
+ parse(context) {
1906
+ const fieldState = createFieldStateGetter(context.state, getObjectParseChildState)(field, parser);
1907
+ return require_mode_dispatch.dispatchByMode(combinedMode, () => {
1908
+ const result = parser.parse(withChildContext$1(context, field, fieldState, parser));
1909
+ return adaptFieldLaneResult(context, field, parser, fieldState, result);
1910
+ }, async () => {
1911
+ const result = await parser.parse(withChildContext$1(context, field, fieldState, parser));
1912
+ return adaptFieldLaneResult(context, field, parser, fieldState, result);
1913
+ });
1914
+ }
1915
+ }));
1870
1916
  const parseSync = (context) => {
1871
1917
  let error = getInitialError(context);
1872
1918
  let currentContext = context;
@@ -2360,6 +2406,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2360
2406
  configurable: true,
2361
2407
  enumerable: false
2362
2408
  });
2409
+ require_parser.defineParseLanes(objectParser, objectParseLanes);
2363
2410
  require_parser.defineInheritedAnnotationParser(objectParser);
2364
2411
  return objectParser;
2365
2412
  }
@@ -3027,17 +3074,17 @@ function merge(...args) {
3027
3074
  if (parser.initialState === void 0) initialState[parserStateKey(i)] = void 0;
3028
3075
  else if (parser.initialState && typeof parser.initialState === "object") for (const field in parser.initialState) initialState[field] = parser.initialState[field];
3029
3076
  }
3030
- const extractParserState = (parser, context, index) => {
3077
+ const extractParserState = (parser, state, index) => {
3031
3078
  if (parser.initialState === void 0) {
3032
3079
  const key = parserStateKey(index);
3033
- if (context.state && typeof context.state === "object" && key in context.state) return context.state[key];
3080
+ if (state && typeof state === "object" && key in state) return state[key];
3034
3081
  return void 0;
3035
3082
  } else if (parser.initialState && typeof parser.initialState === "object") {
3036
3083
  const localStateKey = localObjectStateKey(index);
3037
- if (shouldPreserveLocalChildState(parser) && context.state && typeof context.state === "object" && localStateKey in context.state) return context.state[localStateKey];
3038
- if (context.state && typeof context.state === "object") {
3084
+ if (shouldPreserveLocalChildState(parser) && state && typeof state === "object" && localStateKey in state) return state[localStateKey];
3085
+ if (state && typeof state === "object") {
3039
3086
  const extractedState = {};
3040
- for (const field in parser.initialState) extractedState[field] = field in context.state ? context.state[field] : parser.initialState[field];
3087
+ for (const field in parser.initialState) extractedState[field] = field in state ? state[field] : parser.initialState[field];
3041
3088
  return extractedState;
3042
3089
  }
3043
3090
  return parser.initialState;
@@ -3067,12 +3114,145 @@ function merge(...args) {
3067
3114
  [localObjectStateKey(index)]: result.next.state
3068
3115
  };
3069
3116
  };
3070
- const parseSync = (context) => {
3117
+ const adaptMergeLaneResult = (parser, context, parserState, parsedState, result, index) => {
3118
+ if (!result.success) return result;
3119
+ const mergedExec = require_execution_context.mergeChildExec(context.exec, result.next.exec);
3120
+ const newState = result.next.state === parsedState ? context.state : mergeResultState(parser, context, parserState, result, index);
3121
+ return {
3122
+ success: true,
3123
+ next: {
3124
+ ...context,
3125
+ buffer: result.next.buffer,
3126
+ optionsTerminated: result.next.optionsTerminated,
3127
+ state: newState,
3128
+ ...mergedExec != null ? {
3129
+ trace: mergedExec.trace,
3130
+ exec: mergedExec,
3131
+ dependencyRegistry: mergedExec.dependencyRegistry
3132
+ } : {}
3133
+ },
3134
+ consumed: result.consumed
3135
+ };
3136
+ };
3137
+ const childrenInDeclarationOrder = sorted.map(([parser, originalIndex], sortedIndex) => ({
3138
+ parser,
3139
+ originalIndex,
3140
+ sortedIndex
3141
+ })).toSorted((a, b) => a.originalIndex - b.originalIndex);
3142
+ const mergeParseLanes = childrenInDeclarationOrder.flatMap(({ parser, sortedIndex }) => {
3143
+ const occurrenceConsumptionGroups = /* @__PURE__ */ new WeakMap();
3144
+ const occurrenceZeroConsumptionGroups = /* @__PURE__ */ new WeakMap();
3145
+ const scopeConsumptionGroup = (group$1) => {
3146
+ const existing = occurrenceConsumptionGroups.get(group$1);
3147
+ if (existing != null) return existing;
3148
+ const scoped = {};
3149
+ occurrenceConsumptionGroups.set(group$1, scoped);
3150
+ return scoped;
3151
+ };
3152
+ const childLanes = require_parser.getOwnParseLanes(parser);
3153
+ const lanes = childLanes ?? [{
3154
+ priority: parser.priority,
3155
+ leadingNames: parser.leadingNames,
3156
+ acceptingAnyToken: parser.acceptingAnyToken,
3157
+ parse(context) {
3158
+ return parser.parse(context);
3159
+ }
3160
+ }];
3161
+ return lanes.map((lane) => ({
3162
+ priority: lane.priority,
3163
+ zeroConsumptionGroup: (() => {
3164
+ const group$1 = lane.zeroConsumptionGroup ?? lane;
3165
+ const existing = occurrenceZeroConsumptionGroups.get(group$1);
3166
+ if (existing != null) return existing;
3167
+ const scoped = {};
3168
+ occurrenceZeroConsumptionGroups.set(group$1, scoped);
3169
+ return scoped;
3170
+ })(),
3171
+ settlesZeroConsumption: lane.settlesZeroConsumption,
3172
+ leadingNames: lane.leadingNames,
3173
+ acceptingAnyToken: lane.acceptingAnyToken,
3174
+ requiredConsumptionGroups: lane.requiredConsumptionGroups?.map((group$1) => ({
3175
+ id: scopeConsumptionGroup(group$1.id),
3176
+ ...group$1.isActive == null ? {} : { isActive(state) {
3177
+ if (state == null || typeof state !== "object") return false;
3178
+ const parserState = extractParserState(parser, state, sortedIndex);
3179
+ return group$1.isActive?.(parserState) ?? true;
3180
+ } }
3181
+ })),
3182
+ parse(context) {
3183
+ const parserState = extractParserState(parser, context.state, sortedIndex);
3184
+ const childContext = withChildContext$1(context, sortedIndex, parserState, parser);
3185
+ return require_mode_dispatch.dispatchByMode(combinedMode, () => {
3186
+ const result = lane.parse(childContext);
3187
+ return adaptMergeLaneResult(parser, context, parserState, childContext.state, result, sortedIndex);
3188
+ }, async () => {
3189
+ const result = await lane.parse(childContext);
3190
+ return adaptMergeLaneResult(parser, context, parserState, childContext.state, result, sortedIndex);
3191
+ });
3192
+ }
3193
+ }));
3194
+ }).toSorted((a, b) => b.priority - a.priority);
3195
+ const settleZeroConsumptionLanes = (context, laneResults) => {
3196
+ const groups = /* @__PURE__ */ new Map();
3197
+ for (const lane of mergeParseLanes) {
3198
+ const group$1 = lane.zeroConsumptionGroup ?? lane;
3199
+ const groupedLanes = groups.get(group$1);
3200
+ if (groupedLanes == null) groups.set(group$1, [lane]);
3201
+ else groupedLanes.push(lane);
3202
+ }
3203
+ const settledGroups = [];
3204
+ for (const groupedLanes of groups.values()) {
3205
+ const groupSucceeded = groupedLanes.every((lane) => {
3206
+ const result = laneResults.get(lane);
3207
+ return lane.settlesZeroConsumption !== false && result?.success === true && result.consumed.length === 0 && (lane.requiredConsumptionGroups?.length ?? 0) === 0;
3208
+ });
3209
+ if (!groupSucceeded) return null;
3210
+ settledGroups.push(groupedLanes);
3211
+ }
3212
+ let settledContext = context;
3213
+ for (const groupedLanes of settledGroups) for (const lane of groupedLanes) {
3214
+ const result = laneResults.get(lane);
3215
+ if (result?.success !== true) continue;
3216
+ const originalState = context.state;
3217
+ const resultState = result.next.state;
3218
+ const nextState = { ...settledContext.state };
3219
+ const stateKeys = new Set([...Reflect.ownKeys(originalState), ...Reflect.ownKeys(resultState)]);
3220
+ for (const key of stateKeys) {
3221
+ const originalHasKey = Object.hasOwn(originalState, key);
3222
+ const resultHasKey = Object.hasOwn(resultState, key);
3223
+ if (originalHasKey === resultHasKey && originalState[key] === resultState[key]) continue;
3224
+ if (resultHasKey) nextState[key] = resultState[key];
3225
+ else delete nextState[key];
3226
+ }
3227
+ const mergedExec = require_execution_context.mergeChildExec(settledContext.exec, result.next.exec);
3228
+ settledContext = {
3229
+ ...settledContext,
3230
+ buffer: result.next.buffer,
3231
+ optionsTerminated: result.next.optionsTerminated,
3232
+ state: nextState,
3233
+ ...mergedExec != null ? {
3234
+ trace: mergedExec.trace,
3235
+ exec: mergedExec,
3236
+ dependencyRegistry: mergedExec.dependencyRegistry
3237
+ } : {}
3238
+ };
3239
+ }
3240
+ return {
3241
+ success: true,
3242
+ next: settledContext,
3243
+ consumed: []
3244
+ };
3245
+ };
3246
+ const canTryPositionalLaneAfterFailure = (lane, context) => {
3247
+ const token = context.buffer[0];
3248
+ return token != null && (context.optionsTerminated || !token.startsWith("-")) && (lane.acceptingAnyToken || lane.leadingNames.has(token));
3249
+ };
3250
+ const parseChildrenSync = (context) => {
3071
3251
  let currentContext = context;
3072
3252
  let zeroConsumedSuccess = null;
3073
3253
  for (let i = 0; i < syncParsers.length; i++) {
3074
3254
  const parser = syncParsers[i];
3075
- const parserState = extractParserState(parser, currentContext, i);
3255
+ const parserState = extractParserState(parser, currentContext.state, i);
3076
3256
  const result = parser.parse(withChildContext$1(currentContext, i, parserState, parser));
3077
3257
  if (result.success) {
3078
3258
  const mergedExec = require_execution_context.mergeChildExec(currentContext.exec, result.next.exec);
@@ -3111,12 +3291,12 @@ function merge(...args) {
3111
3291
  ...createObjectLikeInitialError(context, noMatchContext)
3112
3292
  };
3113
3293
  };
3114
- const parseAsync = async (context) => {
3294
+ const parseChildrenAsync = async (context) => {
3115
3295
  let currentContext = context;
3116
3296
  let zeroConsumedSuccess = null;
3117
3297
  for (let i = 0; i < parsers.length; i++) {
3118
3298
  const parser = parsers[i];
3119
- const parserState = extractParserState(parser, currentContext, i);
3299
+ const parserState = extractParserState(parser, currentContext.state, i);
3120
3300
  const resultOrPromise = parser.parse(withChildContext$1(currentContext, i, parserState, parser));
3121
3301
  const result = await resultOrPromise;
3122
3302
  if (result.success) {
@@ -3156,15 +3336,141 @@ function merge(...args) {
3156
3336
  ...createObjectLikeInitialError(context, noMatchContext)
3157
3337
  };
3158
3338
  };
3339
+ const parseSync = (context) => {
3340
+ let currentContext = context;
3341
+ let error = createObjectLikeInitialError(context, noMatchContext);
3342
+ const allConsumed = [];
3343
+ const consumedLanes = /* @__PURE__ */ new Set();
3344
+ const consumedGroups = /* @__PURE__ */ new Set();
3345
+ const laneResults = /* @__PURE__ */ new Map();
3346
+ let attemptedLane = false;
3347
+ let madeProgress = true;
3348
+ while (madeProgress && currentContext.buffer.length > 0) {
3349
+ madeProgress = false;
3350
+ let consumingError = null;
3351
+ for (const lane of mergeParseLanes) {
3352
+ if (consumingError != null && lane.priority < consumingError.priority) {
3353
+ if (!canTryPositionalLaneAfterFailure(lane, currentContext)) continue;
3354
+ }
3355
+ attemptedLane = true;
3356
+ const result = lane.parse(currentContext);
3357
+ laneResults.set(lane, result);
3358
+ if (result.success && result.consumed.length > 0) {
3359
+ currentContext = result.next;
3360
+ allConsumed.push(...result.consumed);
3361
+ consumedLanes.add(lane);
3362
+ for (const group$1 of lane.requiredConsumptionGroups ?? []) if (group$1.isActive?.(result.next.state) !== false) consumedGroups.add(group$1.id);
3363
+ madeProgress = true;
3364
+ break;
3365
+ }
3366
+ if (!result.success) {
3367
+ if (result.consumed > 0 && consumingError == null) consumingError = {
3368
+ priority: lane.priority,
3369
+ result
3370
+ };
3371
+ if (error.consumed < result.consumed) error = result;
3372
+ }
3373
+ }
3374
+ if (!madeProgress && consumingError != null && allConsumed.length === 0) return consumingError.result;
3375
+ }
3376
+ if (allConsumed.length === 0) {
3377
+ if (attemptedLane) {
3378
+ const settled = settleZeroConsumptionLanes(context, laneResults);
3379
+ return settled ?? {
3380
+ ...error,
3381
+ success: false
3382
+ };
3383
+ }
3384
+ const fallback = parseChildrenSync(context);
3385
+ if (!fallback.success && fallback.consumed < error.consumed) return {
3386
+ ...error,
3387
+ success: false
3388
+ };
3389
+ return fallback;
3390
+ }
3391
+ for (const lane of mergeParseLanes) {
3392
+ if (consumedLanes.has(lane) || lane.leadingNames.size > 0 || lane.acceptingAnyToken || lane.requiredConsumptionGroups?.some((group$1) => !consumedGroups.has(group$1.id)) === true) continue;
3393
+ const result = lane.parse(currentContext);
3394
+ if (result.success && result.consumed.length === 0 && result.next.state !== currentContext.state) currentContext = result.next;
3395
+ }
3396
+ return {
3397
+ success: true,
3398
+ next: currentContext,
3399
+ consumed: allConsumed
3400
+ };
3401
+ };
3402
+ const parseAsync = async (context) => {
3403
+ let currentContext = context;
3404
+ let error = createObjectLikeInitialError(context, noMatchContext);
3405
+ const allConsumed = [];
3406
+ const consumedLanes = /* @__PURE__ */ new Set();
3407
+ const consumedGroups = /* @__PURE__ */ new Set();
3408
+ const laneResults = /* @__PURE__ */ new Map();
3409
+ let attemptedLane = false;
3410
+ let madeProgress = true;
3411
+ while (madeProgress && currentContext.buffer.length > 0) {
3412
+ madeProgress = false;
3413
+ let consumingError = null;
3414
+ for (const lane of mergeParseLanes) {
3415
+ if (consumingError != null && lane.priority < consumingError.priority) {
3416
+ if (!canTryPositionalLaneAfterFailure(lane, currentContext)) continue;
3417
+ }
3418
+ attemptedLane = true;
3419
+ const result = await lane.parse(currentContext);
3420
+ laneResults.set(lane, result);
3421
+ if (result.success && result.consumed.length > 0) {
3422
+ currentContext = result.next;
3423
+ allConsumed.push(...result.consumed);
3424
+ consumedLanes.add(lane);
3425
+ for (const group$1 of lane.requiredConsumptionGroups ?? []) if (group$1.isActive?.(result.next.state) !== false) consumedGroups.add(group$1.id);
3426
+ madeProgress = true;
3427
+ break;
3428
+ }
3429
+ if (!result.success) {
3430
+ if (result.consumed > 0 && consumingError == null) consumingError = {
3431
+ priority: lane.priority,
3432
+ result
3433
+ };
3434
+ if (error.consumed < result.consumed) error = result;
3435
+ }
3436
+ }
3437
+ if (!madeProgress && consumingError != null && allConsumed.length === 0) return consumingError.result;
3438
+ }
3439
+ if (allConsumed.length === 0) {
3440
+ if (attemptedLane) {
3441
+ const settled = settleZeroConsumptionLanes(context, laneResults);
3442
+ return settled ?? {
3443
+ ...error,
3444
+ success: false
3445
+ };
3446
+ }
3447
+ const fallback = await parseChildrenAsync(context);
3448
+ if (!fallback.success && fallback.consumed < error.consumed) return {
3449
+ ...error,
3450
+ success: false
3451
+ };
3452
+ return fallback;
3453
+ }
3454
+ for (const lane of mergeParseLanes) {
3455
+ if (consumedLanes.has(lane) || lane.leadingNames.size > 0 || lane.acceptingAnyToken || lane.requiredConsumptionGroups?.some((group$1) => !consumedGroups.has(group$1.id)) === true) continue;
3456
+ const result = await lane.parse(currentContext);
3457
+ if (result.success && result.consumed.length === 0 && result.next.state !== currentContext.state) currentContext = result.next;
3458
+ }
3459
+ return {
3460
+ success: true,
3461
+ next: currentContext,
3462
+ consumed: allConsumed
3463
+ };
3464
+ };
3159
3465
  const mergeParser = {
3160
3466
  mode: combinedMode,
3161
3467
  $valueType: [],
3162
3468
  $stateType: [],
3163
3469
  [fieldParsersKey]: mergedFieldParsers,
3164
- priority: Math.max(...parsers.map((p) => p.priority)),
3470
+ priority: Math.max(...mergeParseLanes.map((lane) => lane.priority)),
3165
3471
  usage: applyHiddenToUsage(parsers.flatMap((p) => p.usage), options.hidden),
3166
- leadingNames: sharedBufferLeadingNames(parsers),
3167
- acceptingAnyToken: parsers.some((p) => p.acceptingAnyToken),
3472
+ leadingNames: sharedBufferLeadingNames(mergeParseLanes),
3473
+ acceptingAnyToken: mergeParseLanes.some((lane) => lane.acceptingAnyToken),
3168
3474
  initialState,
3169
3475
  parse(context) {
3170
3476
  if (isAsync) return parseAsync(context);
@@ -3633,6 +3939,7 @@ function merge(...args) {
3633
3939
  };
3634
3940
  }
3635
3941
  };
3942
+ require_parser.defineParseLanes(mergeParser, mergeParseLanes);
3636
3943
  require_parser.defineInheritedAnnotationParser(mergeParser);
3637
3944
  return mergeParser;
3638
3945
  }
@@ -4310,6 +4617,7 @@ function group(label, parser, options = {}) {
4310
4617
  };
4311
4618
  }
4312
4619
  };
4620
+ require_parser.defineParseLanes(groupParser, require_parser.getOwnParseLanes(parser));
4313
4621
  Object.defineProperty(groupParser, require_phase2_seed.extractPhase2SeedKey, {
4314
4622
  value(state, exec) {
4315
4623
  return require_phase2_seed.extractPhase2Seed(parser, state, exec);
@@ -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 { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
12
12
  import { completeOrExtractPhase2Seed, extractPhase2Seed, extractPhase2SeedKey, phase2SeedFromValueResult } from "./phase2-seed.js";
@@ -77,8 +77,8 @@ function unionLeadingNames(parsers) {
77
77
  * Computes `leadingNames` for shared-buffer compositions (`tuple()`,
78
78
  * `object()`, `merge()`, `concat()`).
79
79
  *
80
- * Children are processed in descending priority order (matching the
81
- * round-robin parse loop). Once a child with `acceptingAnyToken` is
80
+ * Sources are processed in descending priority order (matching the
81
+ * round-robin parse loop). Once a source with `acceptingAnyToken` is
82
82
  * encountered, no lower-priority children can match at position 0, so
83
83
  * their names are excluded.
84
84
  */
@@ -1867,6 +1867,52 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1867
1867
  const noMatchContext = analyzeNoMatchContext(parserKeys.map((k) => parsers[k]));
1868
1868
  const combinedMode = parserKeys.some((k) => parsers[k].mode === "async") ? "async" : "sync";
1869
1869
  const getInitialError = (context) => createObjectLikeInitialError(context, noMatchContext, options.errors);
1870
+ const adaptFieldLaneResult = (context, field, parser, fieldState, result) => {
1871
+ if (!result.success) return result;
1872
+ if (result.consumed.length === 0 && result.next.state === fieldState) return {
1873
+ success: true,
1874
+ next: context,
1875
+ consumed: []
1876
+ };
1877
+ const mergedExec = mergeChildExec(context.exec, result.next.exec);
1878
+ const nextState = result.next.state === fieldState ? context.state : {
1879
+ ...context.state,
1880
+ [field]: getWrappedChildState(context.state, result.next.state, parser)
1881
+ };
1882
+ return {
1883
+ success: true,
1884
+ next: {
1885
+ ...context,
1886
+ buffer: result.next.buffer,
1887
+ optionsTerminated: result.next.optionsTerminated,
1888
+ state: nextState,
1889
+ ...mergedExec != null ? {
1890
+ trace: mergedExec.trace,
1891
+ exec: mergedExec,
1892
+ dependencyRegistry: mergedExec.dependencyRegistry
1893
+ } : {}
1894
+ },
1895
+ consumed: result.consumed
1896
+ };
1897
+ };
1898
+ const objectZeroConsumptionGroup = {};
1899
+ const objectParseLanes = parserPairs.map(([field, parser]) => ({
1900
+ priority: parser.priority,
1901
+ zeroConsumptionGroup: objectZeroConsumptionGroup,
1902
+ settlesZeroConsumption: false,
1903
+ leadingNames: parser.leadingNames,
1904
+ acceptingAnyToken: parser.acceptingAnyToken,
1905
+ parse(context) {
1906
+ const fieldState = createFieldStateGetter(context.state, getObjectParseChildState)(field, parser);
1907
+ return dispatchByMode(combinedMode, () => {
1908
+ const result = parser.parse(withChildContext$1(context, field, fieldState, parser));
1909
+ return adaptFieldLaneResult(context, field, parser, fieldState, result);
1910
+ }, async () => {
1911
+ const result = await parser.parse(withChildContext$1(context, field, fieldState, parser));
1912
+ return adaptFieldLaneResult(context, field, parser, fieldState, result);
1913
+ });
1914
+ }
1915
+ }));
1870
1916
  const parseSync = (context) => {
1871
1917
  let error = getInitialError(context);
1872
1918
  let currentContext = context;
@@ -2360,6 +2406,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2360
2406
  configurable: true,
2361
2407
  enumerable: false
2362
2408
  });
2409
+ defineParseLanes(objectParser, objectParseLanes);
2363
2410
  defineInheritedAnnotationParser(objectParser);
2364
2411
  return objectParser;
2365
2412
  }
@@ -3027,17 +3074,17 @@ function merge(...args) {
3027
3074
  if (parser.initialState === void 0) initialState[parserStateKey(i)] = void 0;
3028
3075
  else if (parser.initialState && typeof parser.initialState === "object") for (const field in parser.initialState) initialState[field] = parser.initialState[field];
3029
3076
  }
3030
- const extractParserState = (parser, context, index) => {
3077
+ const extractParserState = (parser, state, index) => {
3031
3078
  if (parser.initialState === void 0) {
3032
3079
  const key = parserStateKey(index);
3033
- if (context.state && typeof context.state === "object" && key in context.state) return context.state[key];
3080
+ if (state && typeof state === "object" && key in state) return state[key];
3034
3081
  return void 0;
3035
3082
  } else if (parser.initialState && typeof parser.initialState === "object") {
3036
3083
  const localStateKey = localObjectStateKey(index);
3037
- if (shouldPreserveLocalChildState(parser) && context.state && typeof context.state === "object" && localStateKey in context.state) return context.state[localStateKey];
3038
- if (context.state && typeof context.state === "object") {
3084
+ if (shouldPreserveLocalChildState(parser) && state && typeof state === "object" && localStateKey in state) return state[localStateKey];
3085
+ if (state && typeof state === "object") {
3039
3086
  const extractedState = {};
3040
- for (const field in parser.initialState) extractedState[field] = field in context.state ? context.state[field] : parser.initialState[field];
3087
+ for (const field in parser.initialState) extractedState[field] = field in state ? state[field] : parser.initialState[field];
3041
3088
  return extractedState;
3042
3089
  }
3043
3090
  return parser.initialState;
@@ -3067,12 +3114,145 @@ function merge(...args) {
3067
3114
  [localObjectStateKey(index)]: result.next.state
3068
3115
  };
3069
3116
  };
3070
- const parseSync = (context) => {
3117
+ const adaptMergeLaneResult = (parser, context, parserState, parsedState, result, index) => {
3118
+ if (!result.success) return result;
3119
+ const mergedExec = mergeChildExec(context.exec, result.next.exec);
3120
+ const newState = result.next.state === parsedState ? context.state : mergeResultState(parser, context, parserState, result, index);
3121
+ return {
3122
+ success: true,
3123
+ next: {
3124
+ ...context,
3125
+ buffer: result.next.buffer,
3126
+ optionsTerminated: result.next.optionsTerminated,
3127
+ state: newState,
3128
+ ...mergedExec != null ? {
3129
+ trace: mergedExec.trace,
3130
+ exec: mergedExec,
3131
+ dependencyRegistry: mergedExec.dependencyRegistry
3132
+ } : {}
3133
+ },
3134
+ consumed: result.consumed
3135
+ };
3136
+ };
3137
+ const childrenInDeclarationOrder = sorted.map(([parser, originalIndex], sortedIndex) => ({
3138
+ parser,
3139
+ originalIndex,
3140
+ sortedIndex
3141
+ })).toSorted((a, b) => a.originalIndex - b.originalIndex);
3142
+ const mergeParseLanes = childrenInDeclarationOrder.flatMap(({ parser, sortedIndex }) => {
3143
+ const occurrenceConsumptionGroups = /* @__PURE__ */ new WeakMap();
3144
+ const occurrenceZeroConsumptionGroups = /* @__PURE__ */ new WeakMap();
3145
+ const scopeConsumptionGroup = (group$1) => {
3146
+ const existing = occurrenceConsumptionGroups.get(group$1);
3147
+ if (existing != null) return existing;
3148
+ const scoped = {};
3149
+ occurrenceConsumptionGroups.set(group$1, scoped);
3150
+ return scoped;
3151
+ };
3152
+ const childLanes = getOwnParseLanes(parser);
3153
+ const lanes = childLanes ?? [{
3154
+ priority: parser.priority,
3155
+ leadingNames: parser.leadingNames,
3156
+ acceptingAnyToken: parser.acceptingAnyToken,
3157
+ parse(context) {
3158
+ return parser.parse(context);
3159
+ }
3160
+ }];
3161
+ return lanes.map((lane) => ({
3162
+ priority: lane.priority,
3163
+ zeroConsumptionGroup: (() => {
3164
+ const group$1 = lane.zeroConsumptionGroup ?? lane;
3165
+ const existing = occurrenceZeroConsumptionGroups.get(group$1);
3166
+ if (existing != null) return existing;
3167
+ const scoped = {};
3168
+ occurrenceZeroConsumptionGroups.set(group$1, scoped);
3169
+ return scoped;
3170
+ })(),
3171
+ settlesZeroConsumption: lane.settlesZeroConsumption,
3172
+ leadingNames: lane.leadingNames,
3173
+ acceptingAnyToken: lane.acceptingAnyToken,
3174
+ requiredConsumptionGroups: lane.requiredConsumptionGroups?.map((group$1) => ({
3175
+ id: scopeConsumptionGroup(group$1.id),
3176
+ ...group$1.isActive == null ? {} : { isActive(state) {
3177
+ if (state == null || typeof state !== "object") return false;
3178
+ const parserState = extractParserState(parser, state, sortedIndex);
3179
+ return group$1.isActive?.(parserState) ?? true;
3180
+ } }
3181
+ })),
3182
+ parse(context) {
3183
+ const parserState = extractParserState(parser, context.state, sortedIndex);
3184
+ const childContext = withChildContext$1(context, sortedIndex, parserState, parser);
3185
+ return dispatchByMode(combinedMode, () => {
3186
+ const result = lane.parse(childContext);
3187
+ return adaptMergeLaneResult(parser, context, parserState, childContext.state, result, sortedIndex);
3188
+ }, async () => {
3189
+ const result = await lane.parse(childContext);
3190
+ return adaptMergeLaneResult(parser, context, parserState, childContext.state, result, sortedIndex);
3191
+ });
3192
+ }
3193
+ }));
3194
+ }).toSorted((a, b) => b.priority - a.priority);
3195
+ const settleZeroConsumptionLanes = (context, laneResults) => {
3196
+ const groups = /* @__PURE__ */ new Map();
3197
+ for (const lane of mergeParseLanes) {
3198
+ const group$1 = lane.zeroConsumptionGroup ?? lane;
3199
+ const groupedLanes = groups.get(group$1);
3200
+ if (groupedLanes == null) groups.set(group$1, [lane]);
3201
+ else groupedLanes.push(lane);
3202
+ }
3203
+ const settledGroups = [];
3204
+ for (const groupedLanes of groups.values()) {
3205
+ const groupSucceeded = groupedLanes.every((lane) => {
3206
+ const result = laneResults.get(lane);
3207
+ return lane.settlesZeroConsumption !== false && result?.success === true && result.consumed.length === 0 && (lane.requiredConsumptionGroups?.length ?? 0) === 0;
3208
+ });
3209
+ if (!groupSucceeded) return null;
3210
+ settledGroups.push(groupedLanes);
3211
+ }
3212
+ let settledContext = context;
3213
+ for (const groupedLanes of settledGroups) for (const lane of groupedLanes) {
3214
+ const result = laneResults.get(lane);
3215
+ if (result?.success !== true) continue;
3216
+ const originalState = context.state;
3217
+ const resultState = result.next.state;
3218
+ const nextState = { ...settledContext.state };
3219
+ const stateKeys = new Set([...Reflect.ownKeys(originalState), ...Reflect.ownKeys(resultState)]);
3220
+ for (const key of stateKeys) {
3221
+ const originalHasKey = Object.hasOwn(originalState, key);
3222
+ const resultHasKey = Object.hasOwn(resultState, key);
3223
+ if (originalHasKey === resultHasKey && originalState[key] === resultState[key]) continue;
3224
+ if (resultHasKey) nextState[key] = resultState[key];
3225
+ else delete nextState[key];
3226
+ }
3227
+ const mergedExec = mergeChildExec(settledContext.exec, result.next.exec);
3228
+ settledContext = {
3229
+ ...settledContext,
3230
+ buffer: result.next.buffer,
3231
+ optionsTerminated: result.next.optionsTerminated,
3232
+ state: nextState,
3233
+ ...mergedExec != null ? {
3234
+ trace: mergedExec.trace,
3235
+ exec: mergedExec,
3236
+ dependencyRegistry: mergedExec.dependencyRegistry
3237
+ } : {}
3238
+ };
3239
+ }
3240
+ return {
3241
+ success: true,
3242
+ next: settledContext,
3243
+ consumed: []
3244
+ };
3245
+ };
3246
+ const canTryPositionalLaneAfterFailure = (lane, context) => {
3247
+ const token = context.buffer[0];
3248
+ return token != null && (context.optionsTerminated || !token.startsWith("-")) && (lane.acceptingAnyToken || lane.leadingNames.has(token));
3249
+ };
3250
+ const parseChildrenSync = (context) => {
3071
3251
  let currentContext = context;
3072
3252
  let zeroConsumedSuccess = null;
3073
3253
  for (let i = 0; i < syncParsers.length; i++) {
3074
3254
  const parser = syncParsers[i];
3075
- const parserState = extractParserState(parser, currentContext, i);
3255
+ const parserState = extractParserState(parser, currentContext.state, i);
3076
3256
  const result = parser.parse(withChildContext$1(currentContext, i, parserState, parser));
3077
3257
  if (result.success) {
3078
3258
  const mergedExec = mergeChildExec(currentContext.exec, result.next.exec);
@@ -3111,12 +3291,12 @@ function merge(...args) {
3111
3291
  ...createObjectLikeInitialError(context, noMatchContext)
3112
3292
  };
3113
3293
  };
3114
- const parseAsync = async (context) => {
3294
+ const parseChildrenAsync = async (context) => {
3115
3295
  let currentContext = context;
3116
3296
  let zeroConsumedSuccess = null;
3117
3297
  for (let i = 0; i < parsers.length; i++) {
3118
3298
  const parser = parsers[i];
3119
- const parserState = extractParserState(parser, currentContext, i);
3299
+ const parserState = extractParserState(parser, currentContext.state, i);
3120
3300
  const resultOrPromise = parser.parse(withChildContext$1(currentContext, i, parserState, parser));
3121
3301
  const result = await resultOrPromise;
3122
3302
  if (result.success) {
@@ -3156,15 +3336,141 @@ function merge(...args) {
3156
3336
  ...createObjectLikeInitialError(context, noMatchContext)
3157
3337
  };
3158
3338
  };
3339
+ const parseSync = (context) => {
3340
+ let currentContext = context;
3341
+ let error = createObjectLikeInitialError(context, noMatchContext);
3342
+ const allConsumed = [];
3343
+ const consumedLanes = /* @__PURE__ */ new Set();
3344
+ const consumedGroups = /* @__PURE__ */ new Set();
3345
+ const laneResults = /* @__PURE__ */ new Map();
3346
+ let attemptedLane = false;
3347
+ let madeProgress = true;
3348
+ while (madeProgress && currentContext.buffer.length > 0) {
3349
+ madeProgress = false;
3350
+ let consumingError = null;
3351
+ for (const lane of mergeParseLanes) {
3352
+ if (consumingError != null && lane.priority < consumingError.priority) {
3353
+ if (!canTryPositionalLaneAfterFailure(lane, currentContext)) continue;
3354
+ }
3355
+ attemptedLane = true;
3356
+ const result = lane.parse(currentContext);
3357
+ laneResults.set(lane, result);
3358
+ if (result.success && result.consumed.length > 0) {
3359
+ currentContext = result.next;
3360
+ allConsumed.push(...result.consumed);
3361
+ consumedLanes.add(lane);
3362
+ for (const group$1 of lane.requiredConsumptionGroups ?? []) if (group$1.isActive?.(result.next.state) !== false) consumedGroups.add(group$1.id);
3363
+ madeProgress = true;
3364
+ break;
3365
+ }
3366
+ if (!result.success) {
3367
+ if (result.consumed > 0 && consumingError == null) consumingError = {
3368
+ priority: lane.priority,
3369
+ result
3370
+ };
3371
+ if (error.consumed < result.consumed) error = result;
3372
+ }
3373
+ }
3374
+ if (!madeProgress && consumingError != null && allConsumed.length === 0) return consumingError.result;
3375
+ }
3376
+ if (allConsumed.length === 0) {
3377
+ if (attemptedLane) {
3378
+ const settled = settleZeroConsumptionLanes(context, laneResults);
3379
+ return settled ?? {
3380
+ ...error,
3381
+ success: false
3382
+ };
3383
+ }
3384
+ const fallback = parseChildrenSync(context);
3385
+ if (!fallback.success && fallback.consumed < error.consumed) return {
3386
+ ...error,
3387
+ success: false
3388
+ };
3389
+ return fallback;
3390
+ }
3391
+ for (const lane of mergeParseLanes) {
3392
+ if (consumedLanes.has(lane) || lane.leadingNames.size > 0 || lane.acceptingAnyToken || lane.requiredConsumptionGroups?.some((group$1) => !consumedGroups.has(group$1.id)) === true) continue;
3393
+ const result = lane.parse(currentContext);
3394
+ if (result.success && result.consumed.length === 0 && result.next.state !== currentContext.state) currentContext = result.next;
3395
+ }
3396
+ return {
3397
+ success: true,
3398
+ next: currentContext,
3399
+ consumed: allConsumed
3400
+ };
3401
+ };
3402
+ const parseAsync = async (context) => {
3403
+ let currentContext = context;
3404
+ let error = createObjectLikeInitialError(context, noMatchContext);
3405
+ const allConsumed = [];
3406
+ const consumedLanes = /* @__PURE__ */ new Set();
3407
+ const consumedGroups = /* @__PURE__ */ new Set();
3408
+ const laneResults = /* @__PURE__ */ new Map();
3409
+ let attemptedLane = false;
3410
+ let madeProgress = true;
3411
+ while (madeProgress && currentContext.buffer.length > 0) {
3412
+ madeProgress = false;
3413
+ let consumingError = null;
3414
+ for (const lane of mergeParseLanes) {
3415
+ if (consumingError != null && lane.priority < consumingError.priority) {
3416
+ if (!canTryPositionalLaneAfterFailure(lane, currentContext)) continue;
3417
+ }
3418
+ attemptedLane = true;
3419
+ const result = await lane.parse(currentContext);
3420
+ laneResults.set(lane, result);
3421
+ if (result.success && result.consumed.length > 0) {
3422
+ currentContext = result.next;
3423
+ allConsumed.push(...result.consumed);
3424
+ consumedLanes.add(lane);
3425
+ for (const group$1 of lane.requiredConsumptionGroups ?? []) if (group$1.isActive?.(result.next.state) !== false) consumedGroups.add(group$1.id);
3426
+ madeProgress = true;
3427
+ break;
3428
+ }
3429
+ if (!result.success) {
3430
+ if (result.consumed > 0 && consumingError == null) consumingError = {
3431
+ priority: lane.priority,
3432
+ result
3433
+ };
3434
+ if (error.consumed < result.consumed) error = result;
3435
+ }
3436
+ }
3437
+ if (!madeProgress && consumingError != null && allConsumed.length === 0) return consumingError.result;
3438
+ }
3439
+ if (allConsumed.length === 0) {
3440
+ if (attemptedLane) {
3441
+ const settled = settleZeroConsumptionLanes(context, laneResults);
3442
+ return settled ?? {
3443
+ ...error,
3444
+ success: false
3445
+ };
3446
+ }
3447
+ const fallback = await parseChildrenAsync(context);
3448
+ if (!fallback.success && fallback.consumed < error.consumed) return {
3449
+ ...error,
3450
+ success: false
3451
+ };
3452
+ return fallback;
3453
+ }
3454
+ for (const lane of mergeParseLanes) {
3455
+ if (consumedLanes.has(lane) || lane.leadingNames.size > 0 || lane.acceptingAnyToken || lane.requiredConsumptionGroups?.some((group$1) => !consumedGroups.has(group$1.id)) === true) continue;
3456
+ const result = await lane.parse(currentContext);
3457
+ if (result.success && result.consumed.length === 0 && result.next.state !== currentContext.state) currentContext = result.next;
3458
+ }
3459
+ return {
3460
+ success: true,
3461
+ next: currentContext,
3462
+ consumed: allConsumed
3463
+ };
3464
+ };
3159
3465
  const mergeParser = {
3160
3466
  mode: combinedMode,
3161
3467
  $valueType: [],
3162
3468
  $stateType: [],
3163
3469
  [fieldParsersKey]: mergedFieldParsers,
3164
- priority: Math.max(...parsers.map((p) => p.priority)),
3470
+ priority: Math.max(...mergeParseLanes.map((lane) => lane.priority)),
3165
3471
  usage: applyHiddenToUsage(parsers.flatMap((p) => p.usage), options.hidden),
3166
- leadingNames: sharedBufferLeadingNames(parsers),
3167
- acceptingAnyToken: parsers.some((p) => p.acceptingAnyToken),
3472
+ leadingNames: sharedBufferLeadingNames(mergeParseLanes),
3473
+ acceptingAnyToken: mergeParseLanes.some((lane) => lane.acceptingAnyToken),
3168
3474
  initialState,
3169
3475
  parse(context) {
3170
3476
  if (isAsync) return parseAsync(context);
@@ -3633,6 +3939,7 @@ function merge(...args) {
3633
3939
  };
3634
3940
  }
3635
3941
  };
3942
+ defineParseLanes(mergeParser, mergeParseLanes);
3636
3943
  defineInheritedAnnotationParser(mergeParser);
3637
3944
  return mergeParser;
3638
3945
  }
@@ -4310,6 +4617,7 @@ function group(label, parser, options = {}) {
4310
4617
  };
4311
4618
  }
4312
4619
  };
4620
+ defineParseLanes(groupParser, getOwnParseLanes(parser));
4313
4621
  Object.defineProperty(groupParser, extractPhase2SeedKey, {
4314
4622
  value(state, exec) {
4315
4623
  return extractPhase2Seed(parser, state, exec);
@@ -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.
@@ -385,6 +391,32 @@ function composeWrappedSourceMetadata(dependencyMetadata, wrapSource) {
385
391
  };
386
392
  }
387
393
  /**
394
+ * Defines internal parse-lane metadata without exposing it through object
395
+ * spreads used by custom parser wrappers.
396
+ *
397
+ * @internal
398
+ */
399
+ function defineParseLanes(parser, lanes) {
400
+ if (lanes == null) return;
401
+ Object.defineProperty(parser, parseLanesKey, {
402
+ value: lanes,
403
+ configurable: true,
404
+ enumerable: false
405
+ });
406
+ }
407
+ /**
408
+ * Gets parse-lane metadata defined directly on a parser.
409
+ *
410
+ * Inherited metadata belongs to the parser's prototype and must not bypass an
411
+ * overriding `parse()` implementation on a custom wrapper.
412
+ *
413
+ * @internal
414
+ */
415
+ function getOwnParseLanes(parser) {
416
+ if (!Object.hasOwn(parser, parseLanesKey)) return void 0;
417
+ return parser[parseLanesKey];
418
+ }
419
+ /**
388
420
  * Marks a parser as inheriting parent-state annotations through wrapper-state
389
421
  * reconstruction.
390
422
  *
@@ -712,11 +744,13 @@ exports.annotationWrapperRequiresSourceBindingKey = annotationWrapperRequiresSou
712
744
  exports.composeWrappedSourceMetadata = composeWrappedSourceMetadata;
713
745
  exports.createParserContext = createParserContext;
714
746
  exports.defineInheritedAnnotationParser = defineInheritedAnnotationParser;
747
+ exports.defineParseLanes = defineParseLanes;
715
748
  exports.defineSourceBindingOnlyAnnotationCompletionParser = defineSourceBindingOnlyAnnotationCompletionParser;
716
749
  exports.getDelegatingSuggestRuntimeNodes = getDelegatingSuggestRuntimeNodes;
717
750
  exports.getDocPage = getDocPage;
718
751
  exports.getDocPageAsync = getDocPageAsync;
719
752
  exports.getDocPageSync = getDocPageSync;
753
+ exports.getOwnParseLanes = getOwnParseLanes;
720
754
  exports.getParserSuggestRuntimeNodes = getParserSuggestRuntimeNodes;
721
755
  exports.inheritParentAnnotationsKey = inheritParentAnnotationsKey;
722
756
  exports.parse = parse;
@@ -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"`.
@@ -148,6 +193,13 @@ interface Parser<M extends Mode = "sync", TValue = unknown, TState = unknown> {
148
193
  * state when parsing starts.
149
194
  */
150
195
  readonly initialState: TState;
196
+ /**
197
+ * Independently competing parse operations exposed by transparent
198
+ * combinators. Shared-buffer parents use these to arbitrate below an
199
+ * aggregate parser boundary without bypassing the owner's state adapters.
200
+ * @internal
201
+ */
202
+ readonly [parseLanesKey]?: readonly ParseLane<TState>[];
151
203
  /**
152
204
  * Internal marker for wrappers whose `{ hasCliValue: false }` states should
153
205
  * be treated as unmatched dependency-source states during completion-time
@@ -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"`.
@@ -148,6 +193,13 @@ interface Parser<M extends Mode = "sync", TValue = unknown, TState = unknown> {
148
193
  * state when parsing starts.
149
194
  */
150
195
  readonly initialState: TState;
196
+ /**
197
+ * Independently competing parse operations exposed by transparent
198
+ * combinators. Shared-buffer parents use these to arbitrate below an
199
+ * aggregate parser boundary without bypassing the owner's state adapters.
200
+ * @internal
201
+ */
202
+ readonly [parseLanesKey]?: readonly ParseLane<TState>[];
151
203
  /**
152
204
  * Internal marker for wrappers whose `{ hasCliValue: false }` states should
153
205
  * be treated as unmatched dependency-source states during completion-time
@@ -8,6 +8,12 @@ import { createInputTrace } from "../input-trace.js";
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.
@@ -385,6 +391,32 @@ function composeWrappedSourceMetadata(dependencyMetadata, wrapSource) {
385
391
  };
386
392
  }
387
393
  /**
394
+ * Defines internal parse-lane metadata without exposing it through object
395
+ * spreads used by custom parser wrappers.
396
+ *
397
+ * @internal
398
+ */
399
+ function defineParseLanes(parser, lanes) {
400
+ if (lanes == null) return;
401
+ Object.defineProperty(parser, parseLanesKey, {
402
+ value: lanes,
403
+ configurable: true,
404
+ enumerable: false
405
+ });
406
+ }
407
+ /**
408
+ * Gets parse-lane metadata defined directly on a parser.
409
+ *
410
+ * Inherited metadata belongs to the parser's prototype and must not bypass an
411
+ * overriding `parse()` implementation on a custom wrapper.
412
+ *
413
+ * @internal
414
+ */
415
+ function getOwnParseLanes(parser) {
416
+ if (!Object.hasOwn(parser, parseLanesKey)) return void 0;
417
+ return parser[parseLanesKey];
418
+ }
419
+ /**
388
420
  * Marks a parser as inheriting parent-state annotations through wrapper-state
389
421
  * reconstruction.
390
422
  *
@@ -708,4 +740,4 @@ function buildDocPage(parser, context, args) {
708
740
  }
709
741
 
710
742
  //#endregion
711
- export { annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
743
+ export { annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
@@ -226,6 +226,44 @@ function processOptionalStyleResult(result, innerState, context) {
226
226
  };
227
227
  return result;
228
228
  }
229
+ function adaptOptionalStyleParseLanes(parser) {
230
+ const lanes = require_parser.getOwnParseLanes(parser);
231
+ if (lanes == null) return void 0;
232
+ const consumptionGroup = {};
233
+ return lanes.map((lane) => ({
234
+ priority: lane.priority,
235
+ zeroConsumptionGroup: lane.zeroConsumptionGroup,
236
+ settlesZeroConsumption: lane.settlesZeroConsumption,
237
+ leadingNames: lane.leadingNames,
238
+ acceptingAnyToken: false,
239
+ requiredConsumptionGroups: [...lane.requiredConsumptionGroups?.map((group) => ({
240
+ id: group.id,
241
+ ...group.isActive == null ? {} : { isActive(state) {
242
+ const innerState = Array.isArray(state) ? state[0] : parser.initialState;
243
+ return group.isActive?.(innerState) ?? true;
244
+ } }
245
+ })) ?? [], {
246
+ id: consumptionGroup,
247
+ isActive(state) {
248
+ return Array.isArray(state);
249
+ }
250
+ }],
251
+ parse(context) {
252
+ const innerState = deriveOptionalInnerParseState(context.state, parser);
253
+ const innerContext = {
254
+ ...context,
255
+ state: innerState
256
+ };
257
+ return require_mode_dispatch.dispatchByMode(parser.mode, () => {
258
+ const result = lane.parse(innerContext);
259
+ return processOptionalStyleResult(result, innerState, context);
260
+ }, async () => {
261
+ const result = await lane.parse(innerContext);
262
+ return processOptionalStyleResult(result, innerState, context);
263
+ });
264
+ }
265
+ }));
266
+ }
229
267
  /**
230
268
  * Creates a `shouldDeferCompletion` adapter that unwraps the outer state
231
269
  * shape (`[TState] | undefined`) used by {@link optional} and
@@ -410,6 +448,7 @@ function optional(parser) {
410
448
  const composed = require_dependency_metadata.composeDependencyMetadata(parser.dependencyMetadata, "optional");
411
449
  if (composed != null) optionalParser.dependencyMetadata = composed;
412
450
  }
451
+ require_parser.defineParseLanes(optionalParser, adaptOptionalStyleParseLanes(parser));
413
452
  require_parser.defineInheritedAnnotationParser(optionalParser);
414
453
  require_parser.defineSourceBindingOnlyAnnotationCompletionParser(optionalParser);
415
454
  return optionalParser;
@@ -639,6 +678,7 @@ function withDefault(parser, defaultValue, options) {
639
678
  } });
640
679
  if (composed != null) withDefaultParser.dependencyMetadata = composed;
641
680
  }
681
+ require_parser.defineParseLanes(withDefaultParser, adaptOptionalStyleParseLanes(parser));
642
682
  require_parser.defineInheritedAnnotationParser(withDefaultParser);
643
683
  require_parser.defineSourceBindingOnlyAnnotationCompletionParser(withDefaultParser);
644
684
  return withDefaultParser;
@@ -778,6 +818,7 @@ function map(parser, transform) {
778
818
  return parser.getDocFragments(state, void 0);
779
819
  }
780
820
  };
821
+ require_parser.defineParseLanes(mappedParser, require_parser.getOwnParseLanes(parser));
781
822
  delete mappedParser.normalizeValue;
782
823
  delete mappedParser.validateValue;
783
824
  if ("placeholder" in parser) Object.defineProperty(mappedParser, "placeholder", {
@@ -1484,6 +1525,7 @@ function multiple(parser, options = {}) {
1484
1525
  */
1485
1526
  function nonEmpty(parser) {
1486
1527
  const syncParser = parser;
1528
+ const consumptionGroup = {};
1487
1529
  const processNonEmptyResult = (result) => {
1488
1530
  if (!result.success) return result;
1489
1531
  if (result.consumed.length === 0) return {
@@ -1531,6 +1573,17 @@ function nonEmpty(parser) {
1531
1573
  return syncParser.getDocFragments(state, defaultValue);
1532
1574
  }
1533
1575
  };
1576
+ require_parser.defineParseLanes(nonEmptyParser, require_parser.getOwnParseLanes(parser)?.map((lane) => ({
1577
+ priority: lane.priority,
1578
+ zeroConsumptionGroup: lane.zeroConsumptionGroup,
1579
+ settlesZeroConsumption: lane.settlesZeroConsumption,
1580
+ leadingNames: lane.leadingNames,
1581
+ acceptingAnyToken: lane.acceptingAnyToken,
1582
+ requiredConsumptionGroups: [...lane.requiredConsumptionGroups ?? [], { id: consumptionGroup }],
1583
+ parse(context) {
1584
+ return lane.parse(context);
1585
+ }
1586
+ })));
1534
1587
  if ("placeholder" in parser) Object.defineProperty(nonEmptyParser, "placeholder", {
1535
1588
  get() {
1536
1589
  return parser.placeholder;
package/dist/modifiers.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { annotateFreshArray, annotationKey, getAnnotations, inheritAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper } from "./internal/annotations.js";
2
2
  import { formatMessage, message, text } from "./message.js";
3
3
  import { dispatchByMode, dispatchIterableByMode, mapModeValue, wrapForMode } from "./internal/mode-dispatch.js";
4
- import { defineInheritedAnnotationParser, defineSourceBindingOnlyAnnotationCompletionParser, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
4
+ import { defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getOwnParseLanes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
5
5
  import { getDelegatedAnnotationState, hasDelegatedAnnotationCarrier, isAnnotationWrappedInitialState, normalizeDelegatedAnnotationState, normalizeNestedDelegatedAnnotationState } from "./annotation-state.js";
6
6
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
7
7
  import { completeOrExtractPhase2Seed, extractPhase2Seed, extractPhase2SeedKey, phase2SeedFromValueResult } from "./phase2-seed.js";
@@ -226,6 +226,44 @@ function processOptionalStyleResult(result, innerState, context) {
226
226
  };
227
227
  return result;
228
228
  }
229
+ function adaptOptionalStyleParseLanes(parser) {
230
+ const lanes = getOwnParseLanes(parser);
231
+ if (lanes == null) return void 0;
232
+ const consumptionGroup = {};
233
+ return lanes.map((lane) => ({
234
+ priority: lane.priority,
235
+ zeroConsumptionGroup: lane.zeroConsumptionGroup,
236
+ settlesZeroConsumption: lane.settlesZeroConsumption,
237
+ leadingNames: lane.leadingNames,
238
+ acceptingAnyToken: false,
239
+ requiredConsumptionGroups: [...lane.requiredConsumptionGroups?.map((group) => ({
240
+ id: group.id,
241
+ ...group.isActive == null ? {} : { isActive(state) {
242
+ const innerState = Array.isArray(state) ? state[0] : parser.initialState;
243
+ return group.isActive?.(innerState) ?? true;
244
+ } }
245
+ })) ?? [], {
246
+ id: consumptionGroup,
247
+ isActive(state) {
248
+ return Array.isArray(state);
249
+ }
250
+ }],
251
+ parse(context) {
252
+ const innerState = deriveOptionalInnerParseState(context.state, parser);
253
+ const innerContext = {
254
+ ...context,
255
+ state: innerState
256
+ };
257
+ return dispatchByMode(parser.mode, () => {
258
+ const result = lane.parse(innerContext);
259
+ return processOptionalStyleResult(result, innerState, context);
260
+ }, async () => {
261
+ const result = await lane.parse(innerContext);
262
+ return processOptionalStyleResult(result, innerState, context);
263
+ });
264
+ }
265
+ }));
266
+ }
229
267
  /**
230
268
  * Creates a `shouldDeferCompletion` adapter that unwraps the outer state
231
269
  * shape (`[TState] | undefined`) used by {@link optional} and
@@ -410,6 +448,7 @@ function optional(parser) {
410
448
  const composed = composeDependencyMetadata(parser.dependencyMetadata, "optional");
411
449
  if (composed != null) optionalParser.dependencyMetadata = composed;
412
450
  }
451
+ defineParseLanes(optionalParser, adaptOptionalStyleParseLanes(parser));
413
452
  defineInheritedAnnotationParser(optionalParser);
414
453
  defineSourceBindingOnlyAnnotationCompletionParser(optionalParser);
415
454
  return optionalParser;
@@ -639,6 +678,7 @@ function withDefault(parser, defaultValue, options) {
639
678
  } });
640
679
  if (composed != null) withDefaultParser.dependencyMetadata = composed;
641
680
  }
681
+ defineParseLanes(withDefaultParser, adaptOptionalStyleParseLanes(parser));
642
682
  defineInheritedAnnotationParser(withDefaultParser);
643
683
  defineSourceBindingOnlyAnnotationCompletionParser(withDefaultParser);
644
684
  return withDefaultParser;
@@ -778,6 +818,7 @@ function map(parser, transform) {
778
818
  return parser.getDocFragments(state, void 0);
779
819
  }
780
820
  };
821
+ defineParseLanes(mappedParser, getOwnParseLanes(parser));
781
822
  delete mappedParser.normalizeValue;
782
823
  delete mappedParser.validateValue;
783
824
  if ("placeholder" in parser) Object.defineProperty(mappedParser, "placeholder", {
@@ -1484,6 +1525,7 @@ function multiple(parser, options = {}) {
1484
1525
  */
1485
1526
  function nonEmpty(parser) {
1486
1527
  const syncParser = parser;
1528
+ const consumptionGroup = {};
1487
1529
  const processNonEmptyResult = (result) => {
1488
1530
  if (!result.success) return result;
1489
1531
  if (result.consumed.length === 0) return {
@@ -1531,6 +1573,17 @@ function nonEmpty(parser) {
1531
1573
  return syncParser.getDocFragments(state, defaultValue);
1532
1574
  }
1533
1575
  };
1576
+ defineParseLanes(nonEmptyParser, getOwnParseLanes(parser)?.map((lane) => ({
1577
+ priority: lane.priority,
1578
+ zeroConsumptionGroup: lane.zeroConsumptionGroup,
1579
+ settlesZeroConsumption: lane.settlesZeroConsumption,
1580
+ leadingNames: lane.leadingNames,
1581
+ acceptingAnyToken: lane.acceptingAnyToken,
1582
+ requiredConsumptionGroups: [...lane.requiredConsumptionGroups ?? [], { id: consumptionGroup }],
1583
+ parse(context) {
1584
+ return lane.parse(context);
1585
+ }
1586
+ })));
1534
1587
  if ("placeholder" in parser) Object.defineProperty(nonEmptyParser, "placeholder", {
1535
1588
  get() {
1536
1589
  return parser.placeholder;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",