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
@@ -2582,9 +2582,11 @@ function markUnusedValues(root) {
2582
2582
  visit(def.parser, consumed);
2583
2583
  visit(def.sentinel, false);
2584
2584
  return;
2585
+ case "token":
2586
+ visit(def.parser, false);
2587
+ return;
2585
2588
  case "label":
2586
2589
  case "trivia":
2587
- case "token":
2588
2590
  case "attempt":
2589
2591
  case "withCtx":
2590
2592
  case "expect":
@@ -2986,12 +2988,30 @@ function isCstChild(value) {
2986
2988
  function missingInferredType() {
2987
2989
  throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
2988
2990
  }
2991
+ function normalizeProject(project) {
2992
+ if (project === void 0) return void 0;
2993
+ if (!Number.isInteger(project) || project < 0) {
2994
+ throw new Error("node() project child must be a non-negative integer");
2995
+ }
2996
+ return project;
2997
+ }
2998
+ function projectChild(children2, project, type) {
2999
+ if (!(project in children2)) {
3000
+ throw new Error(`node(${JSON.stringify(type)}) project child ${project} was not captured`);
3001
+ }
3002
+ return unwrapChild(children2[project]);
3003
+ }
2989
3004
  function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
2990
3005
  const hasExplicitType = typeof typeOrCombinator === "string";
2991
3006
  const type = hasExplicitType ? typeOrCombinator : void 0;
2992
3007
  const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
2993
- const build = hasExplicitType ? buildOrOpts : combinatorOrBuild;
2994
- const opts = hasExplicitType ? maybeOpts : buildOrOpts;
3008
+ const buildArg = hasExplicitType ? buildOrOpts : combinatorOrBuild;
3009
+ const build = typeof buildArg === "function" ? buildArg : void 0;
3010
+ const opts = typeof buildArg === "function" ? maybeOpts : buildArg ?? maybeOpts;
3011
+ const project = normalizeProject(opts?.project);
3012
+ if (project !== void 0 && build !== void 0) {
3013
+ throw new Error("node() options cannot combine project with a build callback");
3014
+ }
2995
3015
  const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
2996
3016
  const meta = {
2997
3017
  firstSet: combinator._meta.firstSet,
@@ -3005,11 +3025,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3005
3025
  if (unwrap && collapse) {
3006
3026
  throw new Error("node() options cannot set both unwrap and collapse");
3007
3027
  }
3008
- const def = unwrap || collapse || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
3009
- const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
3010
- const clonesState = build ? buildReadsState(def) : true;
3028
+ if (project !== void 0 && (unwrap || collapse)) {
3029
+ throw new Error("node() options cannot combine project with unwrap or collapse");
3030
+ }
3031
+ 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;
3032
+ const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
3033
+ const clonesState = build ? buildReadsState(def) : project === void 0;
3011
3034
  const hasOwnFields = parserHasOwnFields(combinator);
3012
- const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : true);
3035
+ const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
3013
3036
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
3014
3037
  let failExpected;
3015
3038
  return {
@@ -3024,14 +3047,15 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3024
3047
  }
3025
3048
  return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
3026
3049
  }
3027
- const hostCst = build !== void 0 && cstOutputHost(ctx.build);
3050
+ const hasDirectValue = build !== void 0 || project !== void 0;
3051
+ const hostCst = hasDirectValue && cstOutputHost(ctx.build);
3028
3052
  const effTrivia = capturesTrivia || hostCst;
3029
3053
  const effFields = capturesFields || hostCst && hasOwnFields;
3030
3054
  const saved = beginCstNodeCapture(ctx);
3031
3055
  const savedFields = ctx._fields;
3032
3056
  ctx._fields = effFields ? [] : void 0;
3033
3057
  const savedMask = ctx._triviaCaptureMask;
3034
- if (build === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
3058
+ if (build === void 0 && project === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
3035
3059
  ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
3036
3060
  }
3037
3061
  if (!effTrivia) ctx.captureTrivia = false;
@@ -3049,7 +3073,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
3049
3073
  const nodeType = def.type ?? missingInferredType();
3050
3074
  const cstOutput = cstOutputHost(ctx.build);
3051
3075
  const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
3052
- 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 };
3076
+ 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 };
3053
3077
  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 };
3054
3078
  if (saved.buf !== void 0 || saved.ch !== void 0) {
3055
3079
  pushCstChild(ctx, built, rawEntry);
@@ -3300,7 +3324,7 @@ function leaf(root, fn) {
3300
3324
  }
3301
3325
 
3302
3326
  // src/version.ts
3303
- var PARSEMAN_VERSION = "0.39.1";
3327
+ var PARSEMAN_VERSION = "0.41.0";
3304
3328
 
3305
3329
  // src/cst/host-mode.ts
3306
3330
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -6244,7 +6268,7 @@ function scanBranchLabeled(shape, kindIndex, mint) {
6244
6268
  ` if (${m.end} > _e) {`,
6245
6269
  ` if (_cap) {`,
6246
6270
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, ${m.end}, ${kindIndex})`,
6247
- ` 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})`,
6271
+ ` 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})`,
6248
6272
  ` }`,
6249
6273
  ` _e = ${m.end}`,
6250
6274
  ` continue`,
@@ -6300,7 +6324,7 @@ function analyzeTriviaFastPath(trivia2) {
6300
6324
  var CAP_RECORD = [
6301
6325
  ` if (_cap && _e > _pos) {`,
6302
6326
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
6303
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6327
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6304
6328
  ` }`
6305
6329
  ].join("\n");
6306
6330
  function composeFastLoop(shapes) {
@@ -6360,7 +6384,7 @@ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
6360
6384
  ` const _ce = _e + _m${i}[0].length`,
6361
6385
  ` if (_cap) {`,
6362
6386
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6363
- ` 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})`,
6387
+ ` 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})`,
6364
6388
  ` }`,
6365
6389
  ` _e = _ce`,
6366
6390
  ` _matched = true`,
@@ -6398,7 +6422,7 @@ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
6398
6422
  ` const _ce = _r${i}.span.end`,
6399
6423
  ` if (_cap) {`,
6400
6424
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
6401
- ` 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})`,
6425
+ ` 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})`,
6402
6426
  ` }`,
6403
6427
  ` _e = _ce`,
6404
6428
  ` _matched = true`,
@@ -6484,6 +6508,9 @@ function transformFnSource(fn, fnSrc) {
6484
6508
  function replaceParam(body, param, valueVar) {
6485
6509
  return body.replace(new RegExp(`\\b${escapeRegExp2(param)}\\b`, "g"), valueVar);
6486
6510
  }
6511
+ function hasExplicitObjectKey(body, param) {
6512
+ return new RegExp(`\\b${escapeRegExp2(param)}\\b\\s*:`).test(body);
6513
+ }
6487
6514
  function stripForIdCheck(body) {
6488
6515
  return body.replace(/'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"/g, '""').replace(/\bas\s+const\b/g, "").replace(/\b[A-Za-z_$][\w$]*\s*:/g, ":");
6489
6516
  }
@@ -6526,10 +6553,19 @@ function tryInlineDestructureTransform(src, valueVars) {
6526
6553
  const allowed = new Set(valueVars);
6527
6554
  for (let i = 0; i < slots.length; i++) {
6528
6555
  const name = slots[i];
6529
- if (name) body = replaceParam(body, name, valueVars[i]);
6556
+ if (!name) continue;
6557
+ if (hasExplicitObjectKey(body, name)) return null;
6558
+ body = replaceParam(body, name, valueVars[i]);
6530
6559
  }
6531
6560
  return hasFreeIdentifiers(body, allowed) ? null : body;
6532
6561
  }
6562
+ function isDispatchTailOnlyTransform(src) {
6563
+ const m = src.match(/^\(\s*\[([^\]]*)\]\s*\)\s*=>\s*(.+)$/s);
6564
+ if (!m) return false;
6565
+ const slots = parseArrayDestructure(m[1], 2);
6566
+ const tail = slots[1];
6567
+ return tail !== null && m[2].trim() === tail;
6568
+ }
6533
6569
 
6534
6570
  // src/compiler/codegen.ts
6535
6571
  function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
@@ -6788,6 +6824,17 @@ function ensureRegexDecl(ctx, source, flags) {
6788
6824
  }
6789
6825
  return rName;
6790
6826
  }
6827
+ function ensurePlainRegexDecl(ctx, source, flags) {
6828
+ const f = flags.replace(/[gy]/g, "");
6829
+ const key = `${source}/${f}`;
6830
+ let rName = ctx.regexMap.get(key);
6831
+ if (rName === void 0) {
6832
+ rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
6833
+ ctx.regexDecls.push(`const ${rName} = ${new RegExp(source, f).toString()}`);
6834
+ ctx.regexMap.set(key, rName);
6835
+ }
6836
+ return rName;
6837
+ }
6791
6838
  function ensureTriviaFn(ctx) {
6792
6839
  const trivia2 = ctx.activeTrivia;
6793
6840
  const existing = ctx.triviaFnNames.get(trivia2);
@@ -6853,7 +6900,7 @@ function ensureTriviaFn(ctx) {
6853
6900
  ` }`,
6854
6901
  ` if (_cap && _e > _pos) {`,
6855
6902
  ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
6856
- ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6903
+ ` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
6857
6904
  ` }`,
6858
6905
  ` return _e`,
6859
6906
  `}`
@@ -7314,14 +7361,19 @@ function emitSeqValues(def, ctx, pos) {
7314
7361
  continue;
7315
7362
  } else {
7316
7363
  const trivFn = ensureTriviaFn(ctx);
7364
+ const markLog = v(ctx, "_mklg");
7317
7365
  const scanEndV = v(ctx, "_sne");
7318
- stmts.push(`${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx)`);
7366
+ const capArg = ctx.noHoist ? "0" : "_ctx._triviaLog !== undefined ? 2 : 0";
7367
+ stmts.push(
7368
+ `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
7369
+ `${ind(ctx)}const ${scanEndV} = ${trivFn}(input, ${curV}, _ctx, ${capArg})`
7370
+ );
7319
7371
  const r2 = emit(def.parsers[i], ctx, scanEndV);
7320
7372
  stmts.push(...r2.stmts);
7321
7373
  const endAfterV = v(ctx, "_sea");
7322
7374
  stmts.push(
7323
7375
  `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
7324
- `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}`
7376
+ `${ind(ctx)}if (${endAfterV} > ${scanEndV}) ${curV} = ${endAfterV}; else if (_ctx._triviaLog && _ctx._triviaLog.length !== ${markLog}) _ctx._triviaLog.length = ${markLog}`
7325
7377
  );
7326
7378
  valueVars.push(r2.valueVar);
7327
7379
  continue;
@@ -7551,19 +7603,20 @@ function mayRecordRecoveryError(p, recovery, seen = /* @__PURE__ */ new Set()) {
7551
7603
  return false;
7552
7604
  }
7553
7605
  }
7554
- function emitDispatchCombinator(parser2, def, ctx, pos) {
7606
+ function emitDispatchCombinator(parser2, def, ctx, pos, valueMode = "pair") {
7555
7607
  if (parserUsesRouted2(def.selector)) {
7556
7608
  throw new Error("parseman: routed() can only appear inside a dispatch() branch");
7557
7609
  }
7558
7610
  const coverageIds = ctx.coverage?.plan.dispatches.get(parser2) ?? [];
7559
7611
  const branchUsesRouted2 = (entry) => entry.usesRouted === true || parserUsesRouted2(entry.parser);
7560
7612
  const hasRoutedBranch = def.cases.some(branchUsesRouted2) || (def.matchers ? def.matchers.some(branchUsesRouted2) : false) || (def.otherwise ? def.otherwiseUsesRouted === true || parserUsesRouted2(def.otherwise) : false);
7561
- const selectorLeafMark = hasRoutedBranch ? v(ctx, "_dsl") : null;
7562
- const selectorRawMark = hasRoutedBranch ? v(ctx, "_dsr") : null;
7563
- const selectorTriviaMark = hasRoutedBranch ? v(ctx, "_dst") : null;
7564
- const selectorLogMark = hasRoutedBranch ? v(ctx, "_dsg") : null;
7565
- const selectorFieldMark = hasRoutedBranch ? v(ctx, "_dsf") : null;
7566
- const selectorErrorMark = hasRoutedBranch ? v(ctx, "_dse") : null;
7613
+ 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));
7614
+ const selectorLeafMark = selectorNeedsRollback ? v(ctx, "_dsl") : null;
7615
+ const selectorRawMark = selectorNeedsRollback ? v(ctx, "_dsr") : null;
7616
+ const selectorTriviaMark = selectorNeedsRollback ? v(ctx, "_dst") : null;
7617
+ const selectorLogMark = selectorNeedsRollback ? v(ctx, "_dsg") : null;
7618
+ const selectorFieldMark = selectorNeedsRollback ? v(ctx, "_dsf") : null;
7619
+ const selectorErrorMark = selectorNeedsRollback ? v(ctx, "_dse") : null;
7567
7620
  const selector = emit(def.selector, ctx, pos);
7568
7621
  const outV = v(ctx, "_dval");
7569
7622
  const outE = v(ctx, "_dend");
@@ -7588,13 +7641,14 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7588
7641
  stmts.push(head);
7589
7642
  ctx.indent++;
7590
7643
  const usesRouted = branchUsesRouted2(entry);
7591
- const routedV = usesRouted ? v(ctx, "_drt") : null;
7644
+ const needsRoutedContext = usesRouted && routedNeedsContextBridge(parser3, ctx);
7645
+ const routedV = needsRoutedContext ? v(ctx, "_drt") : null;
7592
7646
  const mayError = mayRecordRecoveryError(parser3, !!ctx.recovery);
7593
7647
  const errMark = mayError ? v(ctx, "_derr") : null;
7594
7648
  const logMark = ctx.activeTrivia ? v(ctx, "_dlog") : null;
7595
- if (routedV) {
7649
+ if (usesRouted) {
7596
7650
  stmts.push(
7597
- `${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`,
7651
+ ...routedV ? [`${ind(ctx)}const ${routedV} = _ctx._routed; _ctx._routed = { value: ${selector.valueVar}, span: { start: ${pos}, end: ${selector.endVar} } }`] : [],
7598
7652
  ...selectorLeafMark ? [
7599
7653
  `${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}`
7600
7654
  ] : []
@@ -7602,7 +7656,17 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7602
7656
  }
7603
7657
  if (errMark) stmts.push(`${ind(ctx)}const ${errMark} = _ctx._errors?.length ?? 0`);
7604
7658
  if (logMark) stmts.push(`${ind(ctx)}const ${logMark} = _ctx._triviaLog?.length ?? 0`);
7659
+ const savedRoutedLocal = ctx.routedLocal;
7660
+ const savedNoHoist = ctx.noHoist;
7661
+ if (usesRouted && !needsRoutedContext) {
7662
+ ctx.routedLocal = { valueVar: selector.valueVar, startVar: pos, endVar: selector.endVar };
7663
+ ctx.noHoist = true;
7664
+ } else if (usesRouted) {
7665
+ ctx.routedLocal = void 0;
7666
+ }
7605
7667
  const tail = emitTailFallible(parser3, ctx, usesRouted ? pos : selector.endVar);
7668
+ ctx.routedLocal = savedRoutedLocal;
7669
+ ctx.noHoist = savedNoHoist;
7606
7670
  stmts.push(...coverageAttempt(ctx, coverageId, pos));
7607
7671
  const errorRollback = errMark ? `if (_ctx._errors && _ctx._errors.length !== ${errMark}) _ctx._errors.length = ${errMark}; ` : "";
7608
7672
  const logRollback = logMark ? `if (_ctx._triviaLog && _ctx._triviaLog.length !== ${logMark}) _ctx._triviaLog.length = ${logMark}; ` : "";
@@ -7612,7 +7676,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7612
7676
  ...tail.stmts,
7613
7677
  `${ind(ctx)}if (!${tail.okVar}) { ${routedRollback}${errorRollback}${logRollback}${coverageFailure}${committedFailBody(ctx)} }`,
7614
7678
  ...routedV ? [`${ind(ctx)}_ctx._routed = ${routedV}`] : [],
7615
- `${ind(ctx)}${outV} = [${selector.valueVar}, ${tail.valVar}]`,
7679
+ `${ind(ctx)}${outV} = ${valueMode === "tail" ? tail.valVar : `[${selector.valueVar}, ${tail.valVar}]`}`,
7616
7680
  `${ind(ctx)}${outE} = ${tail.endVar}`,
7617
7681
  ...coverageHit(ctx, coverageId, pos, tail.endVar)
7618
7682
  );
@@ -7627,7 +7691,7 @@ function emitDispatchCombinator(parser2, def, ctx, pos) {
7627
7691
  }
7628
7692
  const emitMatcherTails = () => {
7629
7693
  for (const matcher of def.matchers ?? []) {
7630
- emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(keyV, matcher), coverageIds[coverageIndex++]);
7694
+ emitSelectedTail(matcher, wroteBranch ? "else if" : "if", emitDispatchMatcherCondition(ctx, keyV, matcher), coverageIds[coverageIndex++]);
7631
7695
  wroteBranch = true;
7632
7696
  }
7633
7697
  };
@@ -7652,10 +7716,10 @@ function emitDispatchKeyCondition(valueVar, key, caseInsensitive) {
7652
7716
  }
7653
7717
  return parts.join(" && ");
7654
7718
  }
7655
- function emitDispatchMatcherCondition(valueVar, matcher) {
7719
+ function emitDispatchMatcherCondition(ctx, valueVar, matcher) {
7656
7720
  if (matcher.kind === "matches") {
7657
7721
  const flags = matcher.caseInsensitive && !matcher.flags?.includes("i") ? `${matcher.flags ?? ""}i` : matcher.flags ?? "";
7658
- return `${new RegExp(matcher.value, flags).toString()}.test(${valueVar})`;
7722
+ return `${ensurePlainRegexDecl(ctx, matcher.value, flags)}.test(${valueVar})`;
7659
7723
  }
7660
7724
  const text = matcher.value;
7661
7725
  const parts = [`${valueVar}.length >= ${text.length}`];
@@ -7858,6 +7922,28 @@ function emitsAsNamedFn(p, ctx) {
7858
7922
  const usage = ctx.lazyUsage;
7859
7923
  return !!usage && !ctx.noHoist && !ctx.capAsTrivia && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && (usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE;
7860
7924
  }
7925
+ function routedNeedsContextBridge(p, ctx, seen = /* @__PURE__ */ new Set()) {
7926
+ if (seen.has(p)) return false;
7927
+ seen.add(p);
7928
+ if (p._def.tag === "lazy") {
7929
+ if (ctx.ruleNames?.has(p) || ctx.namedParsers.has(p)) return parserUsesRouted2(p);
7930
+ const usage = ctx.lazyUsage;
7931
+ if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
7932
+ try {
7933
+ return routedNeedsContextBridge(p._def.thunk(), ctx, seen);
7934
+ } catch {
7935
+ return parserUsesRouted2(p);
7936
+ }
7937
+ }
7938
+ return parserUsesRouted2(p);
7939
+ }
7940
+ if (ctx.ruleNames?.has(p)) return parserUsesRouted2(p);
7941
+ if (ctx.namedParsers.has(p)) return parserUsesRouted2(p);
7942
+ const d = p._def;
7943
+ if (d.tag === "dispatch") return false;
7944
+ if (d.tag === "withCtx") return parserUsesRouted2(d.parser);
7945
+ return childrenOf2(d).some((child) => routedNeedsContextBridge(child, ctx, seen));
7946
+ }
7861
7947
  function armReplayInScope(arm, ctx) {
7862
7948
  let p = arm;
7863
7949
  for (; ; ) {
@@ -8108,15 +8194,16 @@ function emitSepBy(_p, def, ctx, pos) {
8108
8194
  const itemFailBreak = (sepEndVar, sepRb, postSepRb) => def.trailing === void 0 ? `${sepRb}break` : `${postSepRb}${curV} = ${sepEndVar}; break`;
8109
8195
  const postSepMarks = () => {
8110
8196
  if (def.trailing === void 0 || !ctx.capturing) return { decl: [], rb: "" };
8111
- const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg");
8197
+ const lv = v(ctx, "_tlv"), rw = v(ctx, "_trw"), tl = v(ctx, "_ttl"), lg = v(ctx, "_tlg"), fl = v(ctx, "_tlf");
8112
8198
  return {
8113
8199
  decl: [
8114
8200
  `${ind(ctx)}const ${lv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8115
8201
  `${ind(ctx)}const ${rw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8116
8202
  `${ind(ctx)}const ${tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8117
- `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`
8203
+ `${ind(ctx)}const ${lg} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8204
+ `${ind(ctx)}const ${fl} = _ctx._fields ? _ctx._fields.length : 0`
8118
8205
  ],
8119
- 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}; `
8206
+ 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}; `
8120
8207
  };
8121
8208
  };
8122
8209
  if (rec) {
@@ -8155,16 +8242,18 @@ function emitSepBy(_p, def, ctx, pos) {
8155
8242
  const markTl = v(ctx, "_mktl");
8156
8243
  const markLog = v(ctx, "_mklg");
8157
8244
  const markLv = v(ctx, "_mklv");
8245
+ const markFld = v(ctx, "_mkf");
8158
8246
  const spV = v(ctx, "_sp");
8159
8247
  stmts.push(
8160
8248
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8161
8249
  `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
8162
8250
  `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
8163
8251
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8252
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`,
8164
8253
  `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`
8165
8254
  );
8166
8255
  sepAtPos = spV;
8167
- 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}; `;
8256
+ 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}; `;
8168
8257
  const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
8169
8258
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
8170
8259
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollbackToSep}${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
@@ -8202,16 +8291,18 @@ function emitSepBy(_p, def, ctx, pos) {
8202
8291
  } else {
8203
8292
  const markLv = ctx.capturing ? v(ctx, "_mklv") : null;
8204
8293
  const markRw = ctx.capturing ? v(ctx, "_mkrw") : null;
8294
+ const markFld = ctx.capturing ? v(ctx, "_mkf") : null;
8205
8295
  if (markLv) {
8206
8296
  stmts.push(
8207
8297
  `${ind(ctx)}const ${markLv} = _ctx._cstLeaves ? _ctx._cstLeaves.length : 0`,
8208
- `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`
8298
+ `${ind(ctx)}const ${markRw} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
8299
+ `${ind(ctx)}const ${markFld} = _ctx._fields ? _ctx._fields.length : 0`
8209
8300
  );
8210
8301
  }
8211
8302
  const sep2 = emitFallible(def.separator, ctx, sepAtPos, true);
8212
8303
  const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = sep2;
8213
8304
  stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sep2.mayCommit ? `if (_ctx._fc) ${committedFailBody(ctx)}; ` : ""}break }`);
8214
- 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}; ` : "";
8305
+ 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}; ` : "";
8215
8306
  const post = postSepMarks();
8216
8307
  stmts.push(...post.decl);
8217
8308
  const next = emitFallible(def.parser, ctx, sepEnd, true);
@@ -8281,7 +8372,7 @@ function emitScanTo(def, ctx, pos) {
8281
8372
  return { stmts, valueVar: valV, endVar: curV };
8282
8373
  }
8283
8374
  function emitNot(def, ctx, pos) {
8284
- const sinksLive = !!ctx.capturing || !!ctx.recovery;
8375
+ const sinksLive = !!ctx.capturing || !!ctx.recovery || !!ctx.activeTrivia;
8285
8376
  const leaves = sinksLive ? v(ctx, "_ntl") : null;
8286
8377
  const raw = sinksLive ? v(ctx, "_ntr") : null;
8287
8378
  const tl = sinksLive ? v(ctx, "_ntt") : null;
@@ -8320,6 +8411,17 @@ function emitPeek(def, ctx, pos) {
8320
8411
  };
8321
8412
  }
8322
8413
  function emitRouted(ctx, pos) {
8414
+ const local = ctx.routedLocal;
8415
+ if (local !== void 0) {
8416
+ return {
8417
+ stmts: [
8418
+ ...emitIfFail(ctx, `${local.startVar} !== ${pos}`, failBody(ctx, '"routed()"', pos)),
8419
+ ...emitLeafCapture(ctx, local.valueVar, local.startVar, local.endVar)
8420
+ ],
8421
+ valueVar: local.valueVar,
8422
+ endVar: local.endVar
8423
+ };
8424
+ }
8323
8425
  const item = v(ctx, "_rt");
8324
8426
  return {
8325
8427
  stmts: [
@@ -8471,14 +8573,20 @@ function emitLeaf(def, ctx, pos) {
8471
8573
  endVar: inner.endVar
8472
8574
  };
8473
8575
  }
8576
+ function emitNodeProjectExpr(type, project, chV) {
8577
+ const child = `${chV}[${project}]`;
8578
+ const missing = `(() => { throw new Error(${JSON.stringify(`node(${JSON.stringify(type)}) project child ${project} was not captured`)}) })()`;
8579
+ const value = `(${child} !== null && typeof ${child} === 'object' && ${child}._tag === 'leaf' ? ${child}.value : ${child})`;
8580
+ return `(${project} in ${chV} ? ${value} : ${missing})`;
8581
+ }
8474
8582
  function emitNode(def, ctx, pos) {
8475
8583
  if (def.type === void 0) {
8476
8584
  throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
8477
8585
  }
8478
- const structural = def.build === void 0;
8479
- const mkType = structural ? null : analyzeMkInlineBuild(def);
8586
+ const structural = def.build === void 0 && def.project === void 0;
8587
+ const mkType = structural || def.project !== void 0 ? null : analyzeMkInlineBuild(def);
8480
8588
  let buildIdx = null;
8481
- if (!mkType && !structural) {
8589
+ if (!mkType && !structural && def.project === void 0) {
8482
8590
  buildIdx = ctx.buildFns.length;
8483
8591
  ctx.buildFns.push(def.build);
8484
8592
  ctx.buildSrcs.push(def.buildSrc ?? null);
@@ -8486,12 +8594,13 @@ function emitNode(def, ctx, pos) {
8486
8594
  const i = ind(ctx);
8487
8595
  const cstOut = ctx.hostMode === "cst" && !structural;
8488
8596
  if (!structural && !cstOut) ctx.hostBranchElided = true;
8489
- const capturesTrivia = cstOut || mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && buildReadsTrivia(def);
8490
- const clonesState = !structural && (cstOut || buildReadsState(def));
8491
- const capturesChildren = !structural && (cstOut || mkType !== null || def.unwrap || def.collapse || buildReadsChildren(def));
8492
- const capturesRaw = !structural && (cstOut || mkType !== null || buildReadsRaw(def));
8597
+ const hasProject = def.project !== void 0;
8598
+ const capturesTrivia = cstOut || mkType !== null || def.captureTrivia === true || def.trailingTrivia === true || !structural && !hasProject && buildReadsTrivia(def);
8599
+ const clonesState = !structural && (cstOut || !hasProject && buildReadsState(def));
8600
+ const capturesChildren = !structural && (cstOut || mkType !== null || def.unwrap || def.collapse || def.project !== void 0 || buildReadsChildren(def));
8601
+ const capturesRaw = !structural && (cstOut || mkType !== null || def.project === void 0 && buildReadsRaw(def));
8493
8602
  const hasFields = parserHasOwnFields(def.parser);
8494
- const capturesFields = hasFields && !structural && (cstOut || buildReadsFields(def));
8603
+ const capturesFields = hasFields && !structural && (cstOut || !hasProject && buildReadsFields(def));
8495
8604
  const innerEnablesTriviaCapture = parserEnablesTriviaCapture(def.parser);
8496
8605
  const chV = v(ctx, "_ch");
8497
8606
  const rawV = v(ctx, "_raw");
@@ -8589,7 +8698,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8589
8698
  );
8590
8699
  }
8591
8700
  const ndV = v(ctx, "_nd");
8592
- 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})`;
8701
+ 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})`;
8593
8702
  const hostBuildExpr = `_ctx._pmProfile?.phase === 'host' && _ctx._pmProfile.hostCalls++, _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
8594
8703
  const ndExpr = structural ? `_ctx.build !== undefined ? (${hostBuildExpr}) : (${buildExpr})` : cstOut ? hostBuildExpr : buildExpr;
8595
8704
  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;
@@ -8808,6 +8917,9 @@ function emitDispatch(p, ctx, pos) {
8808
8917
  return emitSepBy(p, def, ctx, pos);
8809
8918
  case "transform": {
8810
8919
  const fnSrc = transformFnSource(def.fn, def.fnSrc);
8920
+ if (fnSrc && def.parser._def.tag === "dispatch" && isDispatchTailOnlyTransform(fnSrc)) {
8921
+ return emitDispatchCombinator(def.parser, def.parser._def, ctx, pos, "tail");
8922
+ }
8811
8923
  if (fnSrc && def.parser._def.tag === "sequence") {
8812
8924
  const seqR = emitSeqValues(def.parser._def, ctx, pos);
8813
8925
  const inlined = tryInlineDestructureTransform(fnSrc, seqR.valueVars);
@@ -9497,8 +9609,8 @@ function assertRuleName(name) {
9497
9609
  );
9498
9610
  }
9499
9611
  }
9500
- function publicRuleWrapperSource(rule, fnSource) {
9501
- const labels = rule._meta.triviaKindLabels;
9612
+ function publicRuleWrapperSource(rule, fnSource, ambientTriviaKindLabels) {
9613
+ const labels = rule._meta.triviaKindLabels ?? ambientTriviaKindLabels;
9502
9614
  if (labels === void 0) return fnSource;
9503
9615
  return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
9504
9616
  }
@@ -9606,7 +9718,7 @@ function compileRuleMap(ruleMap, opts) {
9606
9718
  return [`function(input, _pos, _ctx) {`, ...body, `}`].join("\n");
9607
9719
  };
9608
9720
  const objBody = perEntry.map(({ key, rule, r }) => {
9609
- const src = publicRuleWrapperSource(rule, entryFnText(r, rule));
9721
+ const src = publicRuleWrapperSource(rule, entryFnText(r, rule), ctx.triviaKindLabels);
9610
9722
  return ` ${JSON.stringify(key)}: ${src.split("\n").join("\n ")}`;
9611
9723
  }).join(",\n");
9612
9724
  const replacement = [
@@ -9793,7 +9905,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9793
9905
  ...r.stmts,
9794
9906
  ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
9795
9907
  `}`
9796
- ].join("\n")));
9908
+ ].join("\n"), ctx.triviaKindLabels));
9797
9909
  }
9798
9910
  const firstSets = /* @__PURE__ */ new Map();
9799
9911
  const firstSetRecipes = /* @__PURE__ */ new Map();
@@ -10000,6 +10112,10 @@ function repeatOpts(min, max, trailing) {
10000
10112
  if (trailing !== void 0) parts.push(`trailing: ${JSON.stringify(trailing)}`);
10001
10113
  return parts.length === 0 ? "" : `, { ${parts.join(", ")} }`;
10002
10114
  }
10115
+ function projectOpt(project) {
10116
+ if (project === void 0) return void 0;
10117
+ return `project: ${project}`;
10118
+ }
10003
10119
  function matcherExpr(entry) {
10004
10120
  switch (entry.kind) {
10005
10121
  case "startsWith":
@@ -10393,9 +10509,11 @@ ${outerDecls.map((d) => " " + d).join("\n")}
10393
10509
  }
10394
10510
  case "node": {
10395
10511
  if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
10512
+ const projectEntry = projectOpt(def.project);
10396
10513
  const optEntries = [
10397
10514
  ...def.unwrap ? ["unwrap: true"] : [],
10398
10515
  ...def.collapse ? ["collapse: true"] : [],
10516
+ ...projectEntry === void 0 ? [] : [projectEntry],
10399
10517
  ...def.captureTrivia ? ["captureTrivia: true"] : [],
10400
10518
  ...def.trailingTrivia ? ["trailingTrivia: true"] : []
10401
10519
  ];
@@ -10640,6 +10758,10 @@ function gate(predicate) {
10640
10758
  };
10641
10759
  }
10642
10760
 
10761
+ // src/cst/trivia-entries.ts
10762
+ var EMPTY_INDICES = Object.freeze([]);
10763
+ var EMPTY_GAPS = Object.freeze([]);
10764
+
10643
10765
  // src/cst/offset-model.ts
10644
10766
  var { isFinite } = Number;
10645
10767
 
@@ -11000,6 +11122,18 @@ function scopeGet(scope, name, mfs) {
11000
11122
  if (isCombinator(entry)) return entry;
11001
11123
  return null;
11002
11124
  }
11125
+ function staticLiteralValue(expr) {
11126
+ const val = expr;
11127
+ return val.type === "Literal" || val.type === "BooleanLiteral" || val.type === "NumericLiteral" ? val.value : void 0;
11128
+ }
11129
+ function staticNodeProject(expr) {
11130
+ const literalValue = staticLiteralValue(expr);
11131
+ if (typeof literalValue === "number" && Number.isInteger(literalValue) && literalValue >= 0) {
11132
+ return { ok: true, value: literalValue };
11133
+ }
11134
+ if (typeof literalValue === "number" || literalValue !== void 0) return { ok: false };
11135
+ return { ok: false };
11136
+ }
11003
11137
  function staticNodeOptions(expr) {
11004
11138
  if (expr.type !== "ObjectExpression") return void 0;
11005
11139
  const opts = {};
@@ -11009,11 +11143,14 @@ function staticNodeOptions(expr) {
11009
11143
  const key = p.key;
11010
11144
  const name = key.type === "Identifier" ? key.name : key.type === "Literal" ? String(key.value) : void 0;
11011
11145
  if (name === "unwrap" || name === "collapse" || name === "captureTrivia" || name === "trailingTrivia") {
11012
- const val = p.value;
11013
- if ((val.type === "Literal" || val.type === "BooleanLiteral") && val.value === true) opts[name] = true;
11146
+ if (staticLiteralValue(p.value) === true) opts[name] = true;
11147
+ } else if (name === "project") {
11148
+ const project = staticNodeProject(p.value);
11149
+ if (project?.ok === false) return { project: -1 };
11150
+ if (project !== void 0) opts.project = project.value;
11014
11151
  }
11015
11152
  }
11016
- return opts.unwrap || opts.collapse || opts.captureTrivia || opts.trailingTrivia ? opts : void 0;
11153
+ return opts.unwrap || opts.collapse || opts.project !== void 0 || opts.captureTrivia || opts.trailingTrivia ? opts : void 0;
11017
11154
  }
11018
11155
  function exprToCombi(node2, scope, code, mfs) {
11019
11156
  if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
@@ -11088,9 +11225,10 @@ function exprToCombi(node2, scope, code, mfs) {
11088
11225
  const inner = anyValue(parserArg, scope, code, mfs);
11089
11226
  if (!isCombinator(inner)) return null;
11090
11227
  const be = buildArg;
11091
- const hasBuild = be !== void 0 && be.type !== "SpreadElement" && !(be.type === "Identifier" && be.name === "undefined");
11228
+ const hasBuild = be !== void 0 && be.type !== "SpreadElement" && be.type !== "ObjectExpression" && !(be.type === "Identifier" && be.name === "undefined");
11092
11229
  const buildSrc = hasBuild ? stripTsFromSource(be, code) : void 0;
11093
- const opts = optsArg !== void 0 && optsArg.type !== "SpreadElement" ? staticNodeOptions(optsArg) : void 0;
11230
+ const optionsArg = hasBuild ? optsArg : be?.type === "ObjectExpression" ? buildArg : optsArg;
11231
+ const opts = optionsArg !== void 0 && optionsArg.type !== "SpreadElement" ? staticNodeOptions(optionsArg) : void 0;
11094
11232
  try {
11095
11233
  const combi = explicitType !== void 0 ? node(explicitType, inner, hasBuild ? () => null : void 0, opts) : node(inner, hasBuild ? () => null : void 0, opts);
11096
11234
  if (combi._def.tag === "node" && buildSrc !== void 0) {