parseman 0.39.1 → 0.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +9 -0
  2. package/dist/combinators/node.d.ts +15 -0
  3. package/dist/combinators/node.d.ts.map +1 -1
  4. package/dist/compiler/codegen.d.ts.map +1 -1
  5. package/dist/compiler/inline-callback.d.ts +9 -0
  6. package/dist/compiler/inline-callback.d.ts.map +1 -1
  7. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  8. package/dist/compiler/value-usage.d.ts.map +1 -1
  9. package/dist/cst/trivia-entries.d.ts +52 -0
  10. package/dist/cst/trivia-entries.d.ts.map +1 -1
  11. package/dist/functional/run.d.ts +11 -2
  12. package/dist/functional/run.d.ts.map +1 -1
  13. package/dist/index.cjs +326 -91
  14. package/dist/index.cjs.map +4 -4
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +326 -91
  18. package/dist/index.js.map +4 -4
  19. package/dist/language-service/index.cjs +155 -2
  20. package/dist/language-service/index.cjs.map +4 -4
  21. package/dist/language-service/index.js +155 -2
  22. package/dist/language-service/index.js.map +4 -4
  23. package/dist/plugin/evaluator.d.ts.map +1 -1
  24. package/dist/plugin/index.cjs +196 -58
  25. package/dist/plugin/index.cjs.map +4 -4
  26. package/dist/plugin/index.js +196 -58
  27. package/dist/plugin/index.js.map +4 -4
  28. package/dist/run/index.cjs +155 -1
  29. package/dist/run/index.cjs.map +4 -4
  30. package/dist/run/index.d.ts +7 -4
  31. package/dist/run/index.d.ts.map +1 -1
  32. package/dist/run/index.js +155 -1
  33. package/dist/run/index.js.map +4 -4
  34. package/dist/spec/index.cjs +35 -11
  35. package/dist/spec/index.cjs.map +2 -2
  36. package/dist/spec/index.js +35 -11
  37. package/dist/spec/index.js.map +2 -2
  38. package/dist/types.d.ts +1 -0
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/version.d.ts +1 -1
  41. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -2586,9 +2586,11 @@ function markUnusedValues(root) {
2586
2586
  visit(def.parser, consumed);
2587
2587
  visit(def.sentinel, false);
2588
2588
  return;
2589
+ case "token":
2590
+ visit(def.parser, false);
2591
+ return;
2589
2592
  case "label":
2590
2593
  case "trivia":
2591
- case "token":
2592
2594
  case "attempt":
2593
2595
  case "withCtx":
2594
2596
  case "expect":
@@ -2990,12 +2992,30 @@ function isCstChild(value) {
2990
2992
  function missingInferredType() {
2991
2993
  throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
2992
2994
  }
2995
+ function normalizeProject(project) {
2996
+ if (project === void 0) return void 0;
2997
+ if (!Number.isInteger(project) || project < 0) {
2998
+ throw new Error("node() project child must be a non-negative integer");
2999
+ }
3000
+ return project;
3001
+ }
3002
+ function projectChild(children2, project, type) {
3003
+ if (!(project in children2)) {
3004
+ throw new Error(`node(${JSON.stringify(type)}) project child ${project} was not captured`);
3005
+ }
3006
+ return unwrapChild(children2[project]);
3007
+ }
2993
3008
  function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
2994
3009
  const hasExplicitType = typeof typeOrCombinator === "string";
2995
3010
  const type = hasExplicitType ? typeOrCombinator : void 0;
2996
3011
  const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
2997
- const build = hasExplicitType ? buildOrOpts : combinatorOrBuild;
2998
- const opts = hasExplicitType ? maybeOpts : buildOrOpts;
3012
+ const buildArg = hasExplicitType ? buildOrOpts : combinatorOrBuild;
3013
+ const build = typeof buildArg === "function" ? buildArg : void 0;
3014
+ const opts = typeof buildArg === "function" ? maybeOpts : buildArg ?? maybeOpts;
3015
+ const project = normalizeProject(opts?.project);
3016
+ if (project !== void 0 && build !== void 0) {
3017
+ throw new Error("node() options cannot combine project with a build callback");
3018
+ }
2999
3019
  const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
3000
3020
  const meta = {
3001
3021
  firstSet: combinator._meta.firstSet,
@@ -3009,11 +3029,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3009
3029
  if (unwrap && collapse) {
3010
3030
  throw new Error("node() options cannot set both unwrap and collapse");
3011
3031
  }
3012
- const def = unwrap || collapse || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
3013
- const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
3014
- const clonesState = build ? buildReadsState(def) : true;
3032
+ if (project !== void 0 && (unwrap || collapse)) {
3033
+ throw new Error("node() options cannot combine project with unwrap or collapse");
3034
+ }
3035
+ const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
3036
+ const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
3037
+ const clonesState = build ? buildReadsState(def) : project === void 0;
3015
3038
  const hasOwnFields = parserHasOwnFields(combinator);
3016
- const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : true);
3039
+ const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
3017
3040
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
3018
3041
  let failExpected;
3019
3042
  return {
@@ -3028,14 +3051,15 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3028
3051
  }
3029
3052
  return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
3030
3053
  }
3031
- const hostCst = build !== void 0 && cstOutputHost(ctx.build);
3054
+ const hasDirectValue = build !== void 0 || project !== void 0;
3055
+ const hostCst = hasDirectValue && cstOutputHost(ctx.build);
3032
3056
  const effTrivia = capturesTrivia || hostCst;
3033
3057
  const effFields = capturesFields || hostCst && hasOwnFields;
3034
3058
  const saved = beginCstNodeCapture(ctx);
3035
3059
  const savedFields = ctx._fields;
3036
3060
  ctx._fields = effFields ? [] : void 0;
3037
3061
  const savedMask = ctx._triviaCaptureMask;
3038
- if (build === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
3062
+ if (build === void 0 && project === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
3039
3063
  ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
3040
3064
  }
3041
3065
  if (!effTrivia) ctx.captureTrivia = false;
@@ -3053,7 +3077,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3053
3077
  const nodeType = def.type ?? missingInferredType();
3054
3078
  const cstOutput = cstOutputHost(ctx.build);
3055
3079
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
3056
- const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, hostState) : build(children2, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
3080
+ const built = unwrap && children2.length === 1 ? unwrapChild(children2[0]) : collapse && children2.length === 1 ? children2[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children2.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children2[0], children2, rawChildren) ? children2[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, hostState) : projectChild(children2, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, hostState) : build(children2, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children2, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children: children2 };
3057
3081
  const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span: r.span };
3058
3082
  if (saved.buf !== void 0 || saved.ch !== void 0) {
3059
3083
  pushCstChild(ctx, built, rawEntry);
@@ -3331,7 +3355,7 @@ function leaf(root, fn) {
3331
3355
  }
3332
3356
 
3333
3357
  // src/version.ts
3334
- var PARSEMAN_VERSION = "0.39.1";
3358
+ var PARSEMAN_VERSION = "0.41.0";
3335
3359
 
3336
3360
  // src/cst/host-mode.ts
3337
3361
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -6275,7 +6299,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
6275
6299
  ` if (${m.end} > _e) {`,
6276
6300
  ` if (_cap) {`,
6277
6301
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
6278
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << kindIndex}))) _ctx._cstTriviaLog.push(_e, ${m.end}, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
6302
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << kindIndex}))) _ctx._cstTriviaLog.push(_e, ${m.end}, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${kindIndex})`,
6279
6303
  ` }`,
6280
6304
  ` _e = ${m.end}`,
6281
6305
  ` continue`,
@@ -6331,7 +6355,7 @@ function analyzeTriviaFastPath(trivia2) {
6331
6355
  var CAP_RECORD = [
6332
6356
  ` if (_cap && _e > _pos) {`,
6333
6357
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
6334
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6358
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6335
6359
  ` }`
6336
6360
  ].join("\n");
6337
6361
  function composeFastLoop(shapes) {
@@ -6391,7 +6415,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6391
6415
  ` const _ce = _e + _m${i}[0].length`,
6392
6416
  ` if (_cap) {`,
6393
6417
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6394
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
6418
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
6395
6419
  ` }`,
6396
6420
  ` _e = _ce`,
6397
6421
  ` _matched = true`,
@@ -6429,7 +6453,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6429
6453
  ` const _ce = _r${i}.span.end`,
6430
6454
  ` if (_cap) {`,
6431
6455
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6432
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
6456
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia && (_ctx._triviaCaptureMask === undefined || (_ctx._triviaCaptureMask & ${1 << k}))) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
6433
6457
  ` }`,
6434
6458
  ` _e = _ce`,
6435
6459
  ` _matched = true`,
@@ -6515,6 +6539,9 @@ function transformFnSource(fn, fnSrc) {
6515
6539
  function replaceParam(body, param, valueVar) {
6516
6540
  return body.replace(new RegExp(`\\b${escapeRegExp2(param)}\\b`, "g"), valueVar);
6517
6541
  }
6542
+ function hasExplicitObjectKey(body, param) {
6543
+ return new RegExp(`\\b${escapeRegExp2(param)}\\b\\s*:`).test(body);
6544
+ }
6518
6545
  function stripForIdCheck(body) {
6519
6546
  return body.replace(/'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"/g, '""').replace(/\bas\s+const\b/g, "").replace(/\b[A-Za-z_$][\w$]*\s*:/g, ":");
6520
6547
  }
@@ -6557,10 +6584,19 @@ function tryInlineDestructureTransform(src, valueVars) {
6557
6584
  const allowed = new Set(valueVars);
6558
6585
  for (let i = 0; i < slots.length; i++) {
6559
6586
  const name = slots[i];
6560
- if (name) body = replaceParam(body, name, valueVars[i]);
6587
+ if (!name) continue;
6588
+ if (hasExplicitObjectKey(body, name)) return null;
6589
+ body = replaceParam(body, name, valueVars[i]);
6561
6590
  }
6562
6591
  return hasFreeIdentifiers(body, allowed) ? null : body;
6563
6592
  }
6593
+ function isDispatchTailOnlyTransform(src) {
6594
+ const m = src.match(/^\(\s*\[([^\]]*)\]\s*\)\s*=>\s*(.+)$/s);
6595
+ if (!m) return false;
6596
+ const slots = parseArrayDestructure(m[1], 2);
6597
+ const tail = slots[1];
6598
+ return tail !== null && m[2].trim() === tail;
6599
+ }
6564
6600
 
6565
6601
  // src/compiler/codegen.ts
6566
6602
  function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
@@ -6811,6 +6847,17 @@ function ensureRegexDecl(ctx, source, flags) {
6811
6847
  }
6812
6848
  return rName;
6813
6849
  }
6850
+ function ensurePlainRegexDecl(ctx, source, flags) {
6851
+ const f = flags.replace(/[gy]/g, "");
6852
+ const key = `${source}/${f}`;
6853
+ let rName = ctx.regexMap.get(key);
6854
+ if (rName === void 0) {
6855
+ rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
6856
+ ctx.regexDecls.push(`const ${rName} = ${new RegExp(source, f).toString()}`);
6857
+ ctx.regexMap.set(key, rName);
6858
+ }
6859
+ return rName;
6860
+ }
6814
6861
  function ensureTriviaFn(ctx) {
6815
6862
  const trivia2 = ctx.activeTrivia;
6816
6863
  const existing = ctx.triviaFnNames.get(trivia2);
@@ -6876,7 +6923,7 @@ function ensureTriviaFn(ctx) {
6876
6923
  ` }`,
6877
6924
  ` if (_cap && _e > _pos) {`,
6878
6925
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
6879
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6926
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6880
6927
  ` }`,
6881
6928
  ` return _e`,
6882
6929
  `}`
@@ -7337,14 +7384,19 @@ function emitSeqValues(def, ctx, pos) {
7337
7384
  continue;
7338
7385
  } else {
7339
7386
  const trivFn = ensureTriviaFn(ctx);
7387
+ const markLog = v(ctx, "_mklg");
7340
7388
  const scanEndV = v(ctx, "_sne");
7341
- stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
7389
+ const capArg = ctx.noHoist ? "0" : "_ctx._triviaLog !== undefined ? 2 : 0";
7390
+ stmts.push(
7391
+ `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7392
+ `${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`
7393
+ );
7342
7394
  const r2 = emit(def.parsers[i], ctx, scanEndV);
7343
7395
  stmts.push(...r2.stmts);
7344
7396
  const endAfterV = v(ctx, "_sea");
7345
7397
  stmts.push(
7346
7398
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7347
- `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
7399
+ `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}`
7348
7400
  );
7349
7401
  valueVars.push(r2.valueVar);
7350
7402
  continue;
@@ -7574,19 +7626,20 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
7574
7626
  return false;
7575
7627
  }
7576
7628
  }
7577
- function emitDispatchCombinator(parser2, def, ctx, pos) {
7629
+ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7578
7630
  if (parserUsesRouted2(def.selector)) {
7579
7631
  throw new Error("parseman: routed() can only appear inside a dispatch() branch");
7580
7632
  }
7581
7633
  const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
7582
7634
  const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
7583
7635
  const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
7584
- const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
7585
- const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
7586
- const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
7587
- const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
7588
- const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
7589
- const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
7636
+ const selectorNeedsRollback = hasRoutedBranch && (ctx.capturing === true && capturesLeaf(def.selector) || ctx.activeTrivia !== void 0 && parserHasTriviaSite(def.selector) || parserEnablesTriviaCapture(def.selector) || parserHasOwnFields(def.selector) || mayRecordRecoveryError(def.selector, !!ctx.recovery));
7637
+ const selectorLeafMark = selectorNeedsRollback ? v(ctx, "_dsl") : null;
7638
+ const selectorRawMark = selectorNeedsRollback ? v(ctx, "_dsr") : null;
7639
+ const selectorTriviaMark = selectorNeedsRollback ? v(ctx, "_dst") : null;
7640
+ const selectorLogMark = selectorNeedsRollback ? v(ctx, "_dsg") : null;
7641
+ const selectorFieldMark = selectorNeedsRollback ? v(ctx, "_dsf") : null;
7642
+ const selectorErrorMark = selectorNeedsRollback ? v(ctx, "_dse") : null;
7590
7643
  const selector = emit(def.selector, ctx, pos);
7591
7644
  const outV = v(ctx, "_dval");
7592
7645
  const outE = v(ctx, "_dend");
@@ -7611,13 +7664,14 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7611
7664
  stmts.push(head);
7612
7665
  ctx.indent++;
7613
7666
  const usesRouted = branchUsesRouted2(entry);
7614
- const routedV = usesRouted ? v(ctx, "_drt") : null;
7667
+ const needsRoutedContext = usesRouted && routedNeedsContextBridge(parser3, ctx);
7668
+ const routedV = needsRoutedContext ? v(ctx, "_drt") : null;
7615
7669
  const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
7616
7670
  const errMark = mayError ? v(ctx, "_derr") : null;
7617
7671
  const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
7618
- if (routedV) {
7672
+ if (usesRouted) {
7619
7673
  stmts.push(
7620
- `${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
7674
+ ...routedV ? [`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`] : [],
7621
7675
  ...selectorLeafMark ? [
7622
7676
  `${ind(ctx)}if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${selectorLeafMark}) _ctx._cstLeaves.length = ${selectorLeafMark}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${selectorRawMark}) _ctx._cstRawChildren.length = ${selectorRawMark}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${selectorTriviaMark}) _ctx._cstTriviaLog.length = ${selectorTriviaMark}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${selectorLogMark}) _ctx._triviaLog.length = ${selectorLogMark}; if (_ctx._fields && _ctx._fields.length !== ${selectorFieldMark}) _ctx._fields.length = ${selectorFieldMark}; if (_ctx._errors && _ctx._errors.length !== ${selectorErrorMark}) _ctx._errors.length = ${selectorErrorMark}`
7623
7677
  ] : []
@@ -7625,7 +7679,17 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7625
7679
  }
7626
7680
  if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
7627
7681
  if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
7682
+ const savedRoutedLocal = ctx.routedLocal;
7683
+ const savedNoHoist = ctx.noHoist;
7684
+ if (usesRouted && !needsRoutedContext) {
7685
+ ctx.routedLocal = { valueVar: selector.valueVar, startVar: pos, endVar: selector.endVar };
7686
+ ctx.noHoist = true;
7687
+ } else if (usesRouted) {
7688
+ ctx.routedLocal = void 0;
7689
+ }
7628
7690
  const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
7691
+ ctx.routedLocal = savedRoutedLocal;
7692
+ ctx.noHoist = savedNoHoist;
7629
7693
  stmts.push(...coverageAttempt(ctx, coverageId, pos));
7630
7694
  const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
7631
7695
  const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
@@ -7635,7 +7699,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7635
7699
  ...tail.stmts,
7636
7700
  `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
7637
7701
  ...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
7638
- `${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
7702
+ `${ind(ctx)}${outV} = ${valueMode === "tail" ? tail.valVar : `[${selector.valueVar}, ${tail.valVar}]`}`,
7639
7703
  `${ind(ctx)}${outE} = ${tail.endVar}`,
7640
7704
  ...coverageHit(ctx, coverageId, pos, tail.endVar)
7641
7705
  );
@@ -7650,7 +7714,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7650
7714
  }
7651
7715
  const emitMatcherTails = () => {
7652
7716
  for (const matcher of def.matchers ?? []) {
7653
- emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
7717
+ emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(ctx, keyV, matcher), coverageIds[coverageIndex++]);
7654
7718
  wroteBranch = true;
7655
7719
  }
7656
7720
  };
@@ -7675,10 +7739,10 @@ function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
7675
7739
  }
7676
7740
  return parts.join(" && ");
7677
7741
  }
7678
- function emitDispatchMatcherCondition(valueVar, matcher) {
7742
+ function emitDispatchMatcherCondition(ctx, valueVar, matcher) {
7679
7743
  if (matcher.kind === "matches") {
7680
7744
  const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
7681
- return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
7745
+ return `${ensurePlainRegexDecl(ctx, matcher.value, flags)}.test(${valueVar})`;
7682
7746
  }
7683
7747
  const text = matcher.value;
7684
7748
  const parts = [`${valueVar}.length >= ${text.length}`];
@@ -7881,6 +7945,28 @@ function emitsAsNamedFn(p, ctx) {
7881
7945
  const usage = ctx.lazyUsage;
7882
7946
  return !!usage && !ctx.noHoist && !ctx.capAsTrivia && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && (usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE;
7883
7947
  }
7948
+ function routedNeedsContextBridge(p, ctx, seen = /* @__PURE__ */ new Set()) {
7949
+ if (seen.has(p)) return false;
7950
+ seen.add(p);
7951
+ if (p._def.tag === "lazy") {
7952
+ if (ctx.ruleNames?.has(p) || ctx.namedParsers.has(p)) return parserUsesRouted2(p);
7953
+ const usage = ctx.lazyUsage;
7954
+ if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
7955
+ try {
7956
+ return routedNeedsContextBridge(p._def.thunk(), ctx, seen);
7957
+ } catch {
7958
+ return parserUsesRouted2(p);
7959
+ }
7960
+ }
7961
+ return parserUsesRouted2(p);
7962
+ }
7963
+ if (ctx.ruleNames?.has(p)) return parserUsesRouted2(p);
7964
+ if (ctx.namedParsers.has(p)) return parserUsesRouted2(p);
7965
+ const d = p._def;
7966
+ if (d.tag === "dispatch") return false;
7967
+ if (d.tag === "withCtx") return parserUsesRouted2(d.parser);
7968
+ return childrenOf2(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
7969
+ }
7884
7970
  function armReplayInScope(arm, ctx) {
7885
7971
  let p = arm;
7886
7972
  for (; ; ) {
@@ -8131,15 +8217,16 @@ function emitSepBy(_p, def, ctx, pos) {
8131
8217
  const itemFailBreak = (sepEndVar, sepRb, postSepRb) => def.trailing === void 0 ? `${sepRb}break` : `${postSepRb}${curV} = ${sepEndVar}; break`;
8132
8218
  const postSepMarks = () => {
8133
8219
  if (def.trailing === void 0 || !ctx.capturing) return { decl: [], rb: "" };
8134
- const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg");
8220
+ const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg"), fl = v(ctx, "_tlf");
8135
8221
  return {
8136
8222
  decl: [
8137
8223
  `${ind(ctx)}const ${lv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8138
8224
  `${ind(ctx)}const ${rw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8139
8225
  `${ind(ctx)}const ${tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8140
- `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`
8226
+ `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8227
+ `${ind(ctx)}const ${fl} = _ctx._fields ? _ctx._fields.length : 0`
8141
8228
  ],
8142
- rb: `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${lv}) _ctx._cstLeaves.length = ${lv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${rw}) _ctx._cstRawChildren.length = ${rw}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${tl}) _ctx._cstTriviaLog.length = ${tl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${lg}) _ctx._triviaLog.length = ${lg}; `
8229
+ rb: `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${lv}) _ctx._cstLeaves.length = ${lv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${rw}) _ctx._cstRawChildren.length = ${rw}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${tl}) _ctx._cstTriviaLog.length = ${tl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${lg}) _ctx._triviaLog.length = ${lg}; if (_ctx._fields && _ctx._fields.length !== ${fl}) _ctx._fields.length = ${fl}; `
8143
8230
  };
8144
8231
  };
8145
8232
  if (rec) {
@@ -8178,16 +8265,18 @@ function emitSepBy(_p, def, ctx, pos) {
8178
8265
  const markTl = v(ctx, "_mktl");
8179
8266
  const markLog = v(ctx, "_mklg");
8180
8267
  const markLv = v(ctx, "_mklv");
8268
+ const markFld = v(ctx, "_mkf");
8181
8269
  const spV = v(ctx, "_sp");
8182
8270
  stmts.push(
8183
8271
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8184
8272
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8185
8273
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8186
8274
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8275
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`,
8187
8276
  `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`
8188
8277
  );
8189
8278
  sepAtPos = spV;
8190
- const rollbackToSep = `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markV}) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${markTl}) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}; `;
8279
+ const rollbackToSep = `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markV}) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog && _ctx._cstTriviaLog.length !== ${markTl}) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}; if (_ctx._fields && _ctx._fields.length !== ${markFld}) _ctx._fields.length = ${markFld}; `;
8191
8280
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8192
8281
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8193
8282
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
@@ -8225,16 +8314,18 @@ function emitSepBy(_p, def, ctx, pos) {
8225
8314
  } else {
8226
8315
  const markLv = ctx.capturing ? v(ctx, "_mklv") : null;
8227
8316
  const markRw = ctx.capturing ? v(ctx, "_mkrw") : null;
8317
+ const markFld = ctx.capturing ? v(ctx, "_mkf") : null;
8228
8318
  if (markLv) {
8229
8319
  stmts.push(
8230
8320
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8231
- `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
8321
+ `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8322
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`
8232
8323
  );
8233
8324
  }
8234
8325
  const sep = emitFallible(def.separator, ctx, sepAtPos, true);
8235
8326
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep;
8236
8327
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8237
- const nextRb = markLv ? `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markRw}) _ctx._cstRawChildren.length = ${markRw}; ` : "";
8328
+ const nextRb = markLv ? `if (_ctx._cstLeaves && _ctx._cstLeaves.length !== ${markLv}) _ctx._cstLeaves.length = ${markLv}; if (_ctx._cstRawChildren && _ctx._cstRawChildren.length !== ${markRw}) _ctx._cstRawChildren.length = ${markRw}; if (_ctx._fields && _ctx._fields.length !== ${markFld}) _ctx._fields.length = ${markFld}; ` : "";
8238
8329
  const post = postSepMarks();
8239
8330
  stmts.push(...post.decl);
8240
8331
  const next = emitFallible(def.parser, ctx, sepEnd, true);
@@ -8304,7 +8395,7 @@ function emitScanTo(def, ctx, pos) {
8304
8395
  return { stmts, valueVar: valV, endVar: curV };
8305
8396
  }
8306
8397
  function emitNot(def, ctx, pos) {
8307
- const sinksLive = !!ctx.capturing || !!ctx.recovery;
8398
+ const sinksLive = !!ctx.capturing || !!ctx.recovery || !!ctx.activeTrivia;
8308
8399
  const leaves = sinksLive ? v(ctx, "_ntl") : null;
8309
8400
  const raw = sinksLive ? v(ctx, "_ntr") : null;
8310
8401
  const tl = sinksLive ? v(ctx, "_ntt") : null;
@@ -8343,6 +8434,17 @@ function emitPeek(def, ctx, pos) {
8343
8434
  };
8344
8435
  }
8345
8436
  function emitRouted(ctx, pos) {
8437
+ const local = ctx.routedLocal;
8438
+ if (local !== void 0) {
8439
+ return {
8440
+ stmts: [
8441
+ ...emitIfFail(ctx, `${local.startVar} !== ${pos}`, failBody(ctx, '"routed()"', pos)),
8442
+ ...emitLeafCapture(ctx, local.valueVar, local.startVar, local.endVar)
8443
+ ],
8444
+ valueVar: local.valueVar,
8445
+ endVar: local.endVar
8446
+ };
8447
+ }
8346
8448
  const item = v(ctx, "_rt");
8347
8449
  return {
8348
8450
  stmts: [
@@ -8494,14 +8596,20 @@ function emitLeaf(def, ctx, pos) {
8494
8596
  endVar: inner.endVar
8495
8597
  };
8496
8598
  }
8599
+ function emitNodeProjectExpr(type, project, chV) {
8600
+ const child = `${chV}[${project}]`;
8601
+ const missing = `(() => { throw new Error(${JSON.stringify(`node(${JSON.stringify(type)}) project child ${project} was not captured`)}) })()`;
8602
+ const value = `(${child} !== null && typeof ${child} === 'object' && ${child}._tag === 'leaf' ? ${child}.value : ${child})`;
8603
+ return `(${project} in ${chV} ? ${value} : ${missing})`;
8604
+ }
8497
8605
  function emitNode(def, ctx, pos) {
8498
8606
  if (def.type === void 0) {
8499
8607
  throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
8500
8608
  }
8501
- const structural = def.build === void 0;
8502
- const mkType = structural ? null : analyzeMkInlineBuild(def);
8609
+ const structural = def.build === void 0 && def.project === void 0;
8610
+ const mkType = structural || def.project !== void 0 ? null : analyzeMkInlineBuild(def);
8503
8611
  let buildIdx = null;
8504
- if (!mkType && !structural) {
8612
+ if (!mkType && !structural && def.project === void 0) {
8505
8613
  buildIdx = ctx.buildFns.length;
8506
8614
  ctx.buildFns.push(def.build);
8507
8615
  ctx.buildSrcs.push(def.buildSrc ?? null);
@@ -8509,12 +8617,13 @@ function emitNode(def, ctx, pos) {
8509
8617
  const i = ind(ctx);
8510
8618
  const cstOut = ctx.hostMode === "cst" && !structural;
8511
8619
  if (!structural && !cstOut) ctx.hostBranchElided = true;
8512
- const capturesTrivia = cstOut || mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && buildReadsTrivia(def);
8513
- const clonesState = !structural && (cstOut || buildReadsState(def));
8514
- const capturesChildren = !structural && (cstOut || mkType !== null || def.unwrap || def.collapse || buildReadsChildren(def));
8515
- const capturesRaw = !structural && (cstOut || mkType !== null || buildReadsRaw(def));
8620
+ const hasProject = def.project !== void 0;
8621
+ const capturesTrivia = cstOut || mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && !hasProject && buildReadsTrivia(def);
8622
+ const clonesState = !structural && (cstOut || !hasProject && buildReadsState(def));
8623
+ const capturesChildren = !structural && (cstOut || mkType !== null || def.unwrap || def.collapse || def.project !== void 0 || buildReadsChildren(def));
8624
+ const capturesRaw = !structural && (cstOut || mkType !== null || def.project === void 0 && buildReadsRaw(def));
8516
8625
  const hasFields = parserHasOwnFields(def.parser);
8517
- const capturesFields = hasFields && !structural && (cstOut || buildReadsFields(def));
8626
+ const capturesFields = hasFields && !structural && (cstOut || !hasProject && buildReadsFields(def));
8518
8627
  const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
8519
8628
  const chV = v(ctx, "_ch");
8520
8629
  const rawV = v(ctx, "_raw");
@@ -8612,7 +8721,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8612
8721
  );
8613
8722
  }
8614
8723
  const ndV = v(ctx, "_nd");
8615
- const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
8724
+ const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : def.project !== void 0 ? emitNodeProjectExpr(def.type, def.project, chV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
8616
8725
  const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
8617
8726
  const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
8618
8727
  const hostCollapseExpr = structural ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
@@ -8831,6 +8940,9 @@ function emitDispatch(p, ctx, pos) {
8831
8940
  return emitSepBy(p, def, ctx, pos);
8832
8941
  case "transform": {
8833
8942
  const fnSrc = transformFnSource(def.fn, def.fnSrc);
8943
+ if (fnSrc && def.parser._def.tag === "dispatch" && isDispatchTailOnlyTransform(fnSrc)) {
8944
+ return emitDispatchCombinator(def.parser, def.parser._def, ctx, pos, "tail");
8945
+ }
8834
8946
  if (fnSrc && def.parser._def.tag === "sequence") {
8835
8947
  const seqR = emitSeqValues(def.parser._def, ctx, pos);
8836
8948
  const inlined = tryInlineDestructureTransform(fnSrc, seqR.valueVars);
@@ -9520,8 +9632,8 @@ function assertRuleName(name) {
9520
9632
  );
9521
9633
  }
9522
9634
  }
9523
- function publicRuleWrapperSource(rule, fnSource) {
9524
- const labels = rule._meta.triviaKindLabels;
9635
+ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels) {
9636
+ const labels = rule._meta.triviaKindLabels ?? ambientTriviaKindLabels;
9525
9637
  if (labels === void 0) return fnSource;
9526
9638
  return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
9527
9639
  }
@@ -9690,7 +9802,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9690
9802
  ...r.stmts,
9691
9803
  ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
9692
9804
  `}`
9693
- ].join("\n")));
9805
+ ].join("\n"), ctx.triviaKindLabels));
9694
9806
  }
9695
9807
  const firstSets = /* @__PURE__ */ new Map();
9696
9808
  const firstSetRecipes = /* @__PURE__ */ new Map();
@@ -9897,6 +10009,10 @@ function repeatOpts(min, max, trailing) {
9897
10009
  if (trailing !== void 0) parts.push(`trailing: ${JSON.stringify(trailing)}`);
9898
10010
  return parts.length === 0 ? "" : `, { ${parts.join(", ")} }`;
9899
10011
  }
10012
+ function projectOpt(project) {
10013
+ if (project === void 0) return void 0;
10014
+ return `project: ${project}`;
10015
+ }
9900
10016
  function matcherExpr(entry) {
9901
10017
  switch (entry.kind) {
9902
10018
  case "startsWith":
@@ -10290,9 +10406,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10290
10406
  }
10291
10407
  case "node": {
10292
10408
  if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
10409
+ const projectEntry = projectOpt(def.project);
10293
10410
  const optEntries = [
10294
10411
  ...def.unwrap ? ["unwrap: true"] : [],
10295
10412
  ...def.collapse ? ["collapse: true"] : [],
10413
+ ...projectEntry === void 0 ? [] : [projectEntry],
10296
10414
  ...def.captureTrivia ? ["captureTrivia: true"] : [],
10297
10415
  ...def.trailingTrivia ? ["trailingTrivia: true"] : []
10298
10416
  ];
@@ -11202,8 +11320,158 @@ function parseDoc(registry, rootRule, input, opts = {}) {
11202
11320
  return new ParseDocImpl(registry, rootRule, opts, { abs: null }, [fail], null, input);
11203
11321
  }
11204
11322
 
11323
+ // src/cst/trivia-entries.ts
11324
+ var EMPTY_INDICES = Object.freeze([]);
11325
+ var EMPTY_GAPS = Object.freeze([]);
11326
+ function entryOffset(i, stride) {
11327
+ return i * stride;
11328
+ }
11329
+ function triviaEntries(log, labels, opts) {
11330
+ const baseStride = opts?.nodeLog ? 3 : 2;
11331
+ const stride = labels ? baseStride + 1 : baseStride;
11332
+ const length = Math.floor(log.length / stride);
11333
+ return {
11334
+ length,
11335
+ labels,
11336
+ stride,
11337
+ start(i) {
11338
+ return log[entryOffset(i, stride)];
11339
+ },
11340
+ end(i) {
11341
+ return log[entryOffset(i, stride) + 1];
11342
+ },
11343
+ insertIndex(i) {
11344
+ return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
11345
+ },
11346
+ kindIndex(i) {
11347
+ if (!labels) return void 0;
11348
+ return log[entryOffset(i, stride) + baseStride];
11349
+ },
11350
+ kind(i) {
11351
+ const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
11352
+ return ki !== void 0 ? labels[ki] : void 0;
11353
+ },
11354
+ text(i, input) {
11355
+ const s = log[entryOffset(i, stride)];
11356
+ const e = log[entryOffset(i, stride) + 1];
11357
+ return input.slice(s, e);
11358
+ }
11359
+ };
11360
+ }
11361
+ function appendEntryRange(map, key, first, last) {
11362
+ let indices = map.get(key);
11363
+ if (!indices) {
11364
+ indices = [];
11365
+ map.set(key, indices);
11366
+ }
11367
+ for (let i = first; i <= last; i++) indices.push(i);
11368
+ }
11369
+ function buildGap(entries, start, end, first, last) {
11370
+ const entryIndices = [];
11371
+ for (let i = first; i <= last; i++) entryIndices.push(i);
11372
+ return {
11373
+ start,
11374
+ end,
11375
+ entryIndices,
11376
+ hasKind(kind) {
11377
+ for (const i of entryIndices) {
11378
+ if (entries.kind(i) === kind) return true;
11379
+ }
11380
+ return false;
11381
+ },
11382
+ text(input) {
11383
+ return input.slice(start, end);
11384
+ }
11385
+ };
11386
+ }
11387
+ function buildRootMaps(entries) {
11388
+ const before = /* @__PURE__ */ new Map();
11389
+ const after = /* @__PURE__ */ new Map();
11390
+ const beforeGaps = /* @__PURE__ */ new Map();
11391
+ const afterGaps = /* @__PURE__ */ new Map();
11392
+ const gaps = [];
11393
+ if (entries.length === 0) return { before, after, beforeGaps, afterGaps, gaps };
11394
+ const appendGap = (first2, last, start2, end2) => {
11395
+ const gap = buildGap(entries, start2, end2, first2, last);
11396
+ gaps.push(gap);
11397
+ afterGaps.set(start2, gap);
11398
+ beforeGaps.set(end2, gap);
11399
+ appendEntryRange(after, start2, first2, last);
11400
+ appendEntryRange(before, end2, first2, last);
11401
+ };
11402
+ let first = 0;
11403
+ let start = entries.start(0);
11404
+ let end = entries.end(0);
11405
+ for (let i = 1; i < entries.length; i++) {
11406
+ const nextStart = entries.start(i);
11407
+ const nextEnd = entries.end(i);
11408
+ if (nextStart === end) {
11409
+ end = nextEnd;
11410
+ continue;
11411
+ }
11412
+ appendGap(first, i - 1, start, end);
11413
+ first = i;
11414
+ start = nextStart;
11415
+ end = nextEnd;
11416
+ }
11417
+ appendGap(first, entries.length - 1, start, end);
11418
+ return { before, after, beforeGaps, afterGaps, gaps };
11419
+ }
11420
+ function buildRootTriviaIndex(log, labels) {
11421
+ const entries = triviaEntries(log, labels);
11422
+ let maps;
11423
+ const getMaps = () => {
11424
+ maps ??= buildRootMaps(entries);
11425
+ return maps;
11426
+ };
11427
+ return {
11428
+ entries,
11429
+ labels,
11430
+ get before() {
11431
+ return getMaps().before;
11432
+ },
11433
+ get after() {
11434
+ return getMaps().after;
11435
+ },
11436
+ entryIndicesBefore(offset) {
11437
+ return getMaps().before.get(offset) ?? EMPTY_INDICES;
11438
+ },
11439
+ entryIndicesAfter(offset) {
11440
+ return getMaps().after.get(offset) ?? EMPTY_INDICES;
11441
+ },
11442
+ gapBefore(offset) {
11443
+ return getMaps().beforeGaps.get(offset);
11444
+ },
11445
+ gapAfter(offset) {
11446
+ return getMaps().afterGaps.get(offset);
11447
+ },
11448
+ gaps() {
11449
+ return getMaps().gaps;
11450
+ },
11451
+ gapsWithKind(kind) {
11452
+ const kinds = typeof kind === "string" ? [kind] : kind;
11453
+ const matches2 = [];
11454
+ for (const gap of getMaps().gaps) {
11455
+ for (const k of kinds) {
11456
+ if (gap.hasKind(k)) {
11457
+ matches2.push(gap);
11458
+ break;
11459
+ }
11460
+ }
11461
+ }
11462
+ return matches2.length === 0 ? EMPTY_GAPS : matches2;
11463
+ }
11464
+ };
11465
+ }
11466
+
11205
11467
  // src/functional/run.ts
11206
11468
  var invoke = (r, input, pos, ctx) => typeof r === "function" ? r(input, pos, ctx) : r.parse(input, pos, ctx);
11469
+ function triviaKindLabelsFromRunnable(r) {
11470
+ if (!r) return void 0;
11471
+ if (typeof r === "function") return r._meta?.triviaKindLabels;
11472
+ const grammarTrivia = r._meta.grammarTrivia;
11473
+ return r._meta.triviaKindLabels ?? grammarTrivia?._meta.triviaKindLabels ?? (r._def.tag === "grammar" ? r._def.triviaParser?._meta.triviaKindLabels : void 0);
11474
+ }
11207
11475
  function runOnce(entry, input, options, phase, profileState) {
11208
11476
  if (typeof entry !== "function" && typeof entry?.parse !== "function") {
11209
11477
  throw new TypeError(
@@ -11216,6 +11484,7 @@ function runOnce(entry, input, options, phase, profileState) {
11216
11484
  const skipGlobalSinks = phase === "recognizer" || phase === "capture";
11217
11485
  const grammarTrivia = typeof entry !== "function" ? entry._meta.grammarTrivia : void 0;
11218
11486
  const grammarScanSkip = typeof entry !== "function" ? entry._meta.grammarScanSkip : void 0;
11487
+ const triviaKindLabels = triviaKindLabelsFromRunnable(entry) ?? triviaKindLabelsFromRunnable(options.trivia);
11219
11488
  const stamped = entry;
11220
11489
  assertHostModeCompatible(
11221
11490
  typeof entry === "function" ? stamped[FUSED_HOST_MODE] ?? "ast" : entry._meta.grammarHostMode ?? "ast",
@@ -11227,7 +11496,7 @@ function runOnce(entry, input, options, phase, profileState) {
11227
11496
  ...skipGlobalSinks ? { _pmProfile: profile } : { _triviaLog: triviaLog, _errors: errors, ...profile === void 0 ? {} : { _pmProfile: profile } },
11228
11497
  build: options.build,
11229
11498
  state: options.state,
11230
- ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...grammarTrivia._meta.triviaKindLabels ? { triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {} } : {},
11499
+ ...grammarTrivia !== void 0 ? { trivia: grammarTrivia, ...triviaKindLabels ? { triviaKindLabels } : {} } : triviaKindLabels ? { triviaKindLabels } : {},
11231
11500
  ...grammarScanSkip !== void 0 ? { scanSkip: grammarScanSkip } : {},
11232
11501
  ...options.triviaCaptureMask !== void 0 ? { _triviaCaptureMask: options.triviaCaptureMask } : {},
11233
11502
  ...options.tolerant ? { _tolerant: true, _rec: REC } : {},
@@ -11250,6 +11519,8 @@ function runOnce(entry, input, options, phase, profileState) {
11250
11519
  expected: r.ok ? [] : r.expected ?? [],
11251
11520
  errors,
11252
11521
  triviaLog,
11522
+ ...triviaKindLabels === void 0 ? {} : { triviaKindLabels },
11523
+ triviaMap: buildRootTriviaIndex(triviaLog, triviaKindLabels),
11253
11524
  unconsumedFrom
11254
11525
  };
11255
11526
  }
@@ -11572,7 +11843,7 @@ function coverageEntry(entry, collector, maps, trace) {
11572
11843
  case "peek":
11573
11844
  return peek(build(def.parser));
11574
11845
  case "node": {
11575
- const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
11846
+ const opts = { ...def.unwrap ? { unwrap: true } : {}, ...def.collapse ? { collapse: true } : {}, ...def.project !== void 0 ? { project: def.project } : {}, ...def.captureTrivia ? { captureTrivia: true } : {}, ...def.trailingTrivia ? { trailingTrivia: true } : {} };
11576
11847
  return def.type === void 0 ? node(build(def.parser), def.build, opts) : node(def.type, build(def.parser), def.build, opts);
11577
11848
  }
11578
11849
  case "guard":
@@ -11708,43 +11979,6 @@ function createVisitor(handlers) {
11708
11979
  return (node2) => api.visit(node2);
11709
11980
  }
11710
11981
 
11711
- // src/cst/trivia-entries.ts
11712
- function entryOffset(i, stride) {
11713
- return i * stride;
11714
- }
11715
- function triviaEntries(log, labels, opts) {
11716
- const baseStride = opts?.nodeLog ? 3 : 2;
11717
- const stride = labels ? baseStride + 1 : baseStride;
11718
- const length = Math.floor(log.length / stride);
11719
- return {
11720
- length,
11721
- labels,
11722
- stride,
11723
- start(i) {
11724
- return log[entryOffset(i, stride)];
11725
- },
11726
- end(i) {
11727
- return log[entryOffset(i, stride) + 1];
11728
- },
11729
- insertIndex(i) {
11730
- return opts?.nodeLog ? log[entryOffset(i, stride) + 2] : void 0;
11731
- },
11732
- kindIndex(i) {
11733
- if (!labels) return void 0;
11734
- return log[entryOffset(i, stride) + baseStride];
11735
- },
11736
- kind(i) {
11737
- const ki = labels ? log[entryOffset(i, stride) + baseStride] : void 0;
11738
- return ki !== void 0 ? labels[ki] : void 0;
11739
- },
11740
- text(i, input) {
11741
- const s = log[entryOffset(i, stride)];
11742
- const e = log[entryOffset(i, stride) + 1];
11743
- return input.slice(s, e);
11744
- }
11745
- };
11746
- }
11747
-
11748
11982
  // src/cst/offset-model.ts
11749
11983
  var { isFinite } = Number;
11750
11984
  function floorIndex(arr, len, x) {
@@ -11957,6 +12191,7 @@ export {
11957
12191
  blankLinesIn,
11958
12192
  buildLineIndex,
11959
12193
  buildOffsetIndex,
12194
+ buildRootTriviaIndex,
11960
12195
  buildTriviaIndex,
11961
12196
  charClassMembers,
11962
12197
  choice,