parseman 0.42.0 → 0.42.1

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.
@@ -2742,6 +2742,74 @@ function markUnusedValues(root) {
2742
2742
  visit(resolveRoot(root), true);
2743
2743
  }
2744
2744
 
2745
+ // src/combinators/grammar.ts
2746
+ function annotateResultLines(result, index) {
2747
+ const annotated = { ...result, span: annotateSpan(result.span, index) };
2748
+ const errors = annotated.errors;
2749
+ if (errors) {
2750
+ ;
2751
+ annotated.errors = errors.map((error) => ({
2752
+ ...error,
2753
+ span: annotateSpan(error.span, index)
2754
+ }));
2755
+ }
2756
+ return annotated;
2757
+ }
2758
+ function createParseLineContext(input, pos) {
2759
+ const lineIndex = createLineIndex();
2760
+ if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
2761
+ return { lineIndex, lineScannedTo: pos };
2762
+ }
2763
+ function parser(opts, root) {
2764
+ const clearTrivia = opts.trivia === null;
2765
+ return {
2766
+ _tag: "grammar",
2767
+ _meta: root._meta,
2768
+ _def: {
2769
+ tag: "grammar",
2770
+ parser: root,
2771
+ triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2772
+ clearTrivia,
2773
+ ...opts.captureTrivia ? { captureTrivia: true } : {},
2774
+ trackLines: opts.trackLines ?? false
2775
+ },
2776
+ parse(input, pos, _ctx) {
2777
+ const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
2778
+ const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
2779
+ const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
2780
+ const ctx = {
2781
+ ..._ctx,
2782
+ trackLines,
2783
+ ...lineIndex ? { _lineIndex: lineIndex } : {},
2784
+ ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
2785
+ // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
2786
+ ...clearTrivia ? {
2787
+ trivia: void 0,
2788
+ triviaKindLabels: void 0
2789
+ } : opts.trivia != null ? {
2790
+ trivia: opts.trivia,
2791
+ ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
2792
+ } : {},
2793
+ ...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
2794
+ // Kind-filter for per-node capture. Resolve against this scope's trivia
2795
+ // labels — this parser's own trivia if it declares one, else the INHERITED
2796
+ // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
2797
+ // trivia is inherited rather than re-declared here. No labels → undefined
2798
+ // (capture all).
2799
+ ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
2800
+ };
2801
+ const result = root.parse(input, pos ?? 0, ctx);
2802
+ if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
2803
+ _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
2804
+ }
2805
+ return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
2806
+ }
2807
+ };
2808
+ }
2809
+ function noTrivia(root) {
2810
+ return parser({ trivia: null }, root);
2811
+ }
2812
+
2745
2813
  // src/combinators/parser.ts
2746
2814
  var RULE_ORDER = "__parsemanRuleOrder";
2747
2815
  function tagRule(r, key) {
@@ -2817,6 +2885,21 @@ function rules(a, b) {
2817
2885
  if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
2818
2886
  }
2819
2887
  }
2888
+ if (options?.trackLines === true) {
2889
+ for (const key of Object.keys(definitions)) {
2890
+ const rule = cache[key];
2891
+ if (rule && !rule._meta.isTrivia) rule._meta.grammarTrackLines = true;
2892
+ }
2893
+ for (const key of Object.keys(definitions)) {
2894
+ const rule = cache[key];
2895
+ if (rule && !rule._meta.isTrivia && rule._def.tag !== "grammar") {
2896
+ const wrapped = parser({ trackLines: true }, rule);
2897
+ tagRule(wrapped, key);
2898
+ wrapped._meta.grammarTrackLines = true;
2899
+ cache[key] = wrapped;
2900
+ }
2901
+ }
2902
+ }
2820
2903
  for (const key of Object.keys(definitions)) {
2821
2904
  markUnusedValues(cache[key]);
2822
2905
  }
@@ -3273,74 +3356,6 @@ function field(name, combinator) {
3273
3356
  };
3274
3357
  }
3275
3358
 
3276
- // src/combinators/grammar.ts
3277
- function annotateResultLines(result, index) {
3278
- const annotated = { ...result, span: annotateSpan(result.span, index) };
3279
- const errors = annotated.errors;
3280
- if (errors) {
3281
- ;
3282
- annotated.errors = errors.map((error) => ({
3283
- ...error,
3284
- span: annotateSpan(error.span, index)
3285
- }));
3286
- }
3287
- return annotated;
3288
- }
3289
- function createParseLineContext(input, pos) {
3290
- const lineIndex = createLineIndex();
3291
- if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
3292
- return { lineIndex, lineScannedTo: pos };
3293
- }
3294
- function parser(opts, root) {
3295
- const clearTrivia = opts.trivia === null;
3296
- return {
3297
- _tag: "grammar",
3298
- _meta: root._meta,
3299
- _def: {
3300
- tag: "grammar",
3301
- parser: root,
3302
- triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
3303
- clearTrivia,
3304
- ...opts.captureTrivia ? { captureTrivia: true } : {},
3305
- trackLines: opts.trackLines ?? false
3306
- },
3307
- parse(input, pos, _ctx) {
3308
- const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
3309
- const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
3310
- const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
3311
- const ctx = {
3312
- ..._ctx,
3313
- trackLines,
3314
- ...lineIndex ? { _lineIndex: lineIndex } : {},
3315
- ...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
3316
- // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
3317
- ...clearTrivia ? {
3318
- trivia: void 0,
3319
- triviaKindLabels: void 0
3320
- } : opts.trivia != null ? {
3321
- trivia: opts.trivia,
3322
- ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
3323
- } : {},
3324
- ...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
3325
- // Kind-filter for per-node capture. Resolve against this scope's trivia
3326
- // labels — this parser's own trivia if it declares one, else the INHERITED
3327
- // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
3328
- // trivia is inherited rather than re-declared here. No labels → undefined
3329
- // (capture all).
3330
- ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
3331
- };
3332
- const result = root.parse(input, pos ?? 0, ctx);
3333
- if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
3334
- _ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
3335
- }
3336
- return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
3337
- }
3338
- };
3339
- }
3340
- function noTrivia(root) {
3341
- return parser({ trivia: null }, root);
3342
- }
3343
-
3344
3359
  // src/combinators/token.ts
3345
3360
  function token(root) {
3346
3361
  const meta = {
@@ -3437,7 +3452,7 @@ function leaf(root, fn) {
3437
3452
  }
3438
3453
 
3439
3454
  // src/version.ts
3440
- var PARSEMAN_VERSION = "0.42.0";
3455
+ var PARSEMAN_VERSION = "0.42.1";
3441
3456
 
3442
3457
  // src/cst/host-mode.ts
3443
3458
  var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
@@ -6805,13 +6820,16 @@ function reindentStmts(stmts, targetLevels) {
6805
6820
  const targetPrefix = " ".repeat(targetLevels);
6806
6821
  return stmts.map((s) => s.trim().length === 0 ? "" : targetPrefix + s.slice(minLeading));
6807
6822
  }
6808
- function failReturn(expected, posExpr) {
6823
+ function failReturn(ctx, expected, posExpr) {
6824
+ if (ctx.lineTracking) return `return { ok: false, expected: [${expected}], span: ${emitSpanExpr(ctx, posExpr, posExpr)} }`;
6809
6825
  return `return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
6810
6826
  }
6811
- function failReturnArr(expectedArr, posExpr) {
6827
+ function failReturnArr(ctx, expectedArr, posExpr) {
6828
+ if (ctx.lineTracking) return `return { ok: false, expected: ${expectedArr}, span: ${emitSpanExpr(ctx, posExpr, posExpr)} }`;
6812
6829
  return `return { ok: false, expected: ${expectedArr}, span: { start: ${posExpr}, end: ${posExpr} } }`;
6813
6830
  }
6814
- function committedReturnArr(expectedArr, posExpr) {
6831
+ function committedReturnArr(ctx, expectedArr, posExpr) {
6832
+ if (ctx.lineTracking) return `return { ok: false, expected: [...${expectedArr}], span: ${emitSpanExpr(ctx, posExpr, posExpr)}, committed: true }`;
6815
6833
  return `return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} }, committed: true }`;
6816
6834
  }
6817
6835
  function hoistExpected(ctx, constArrSource) {
@@ -6836,7 +6854,7 @@ function failBody(ctx, expected, posExpr) {
6836
6854
  if (!ctx.recordFail) return probe ? `{ ${probe}${trace}break ${ctx.failLabel} }` : trace ? `{ ${trace}break ${ctx.failLabel} }` : `break ${ctx.failLabel}`;
6837
6855
  return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${hoistExpected(ctx, `[${expected}]`)}; ${trace}break ${ctx.failLabel} }`;
6838
6856
  }
6839
- return probe + trace + failReturn(expected, posExpr);
6857
+ return probe + trace + failReturn(ctx, expected, posExpr);
6840
6858
  }
6841
6859
  function failArrBody(ctx, expectedArr, posExpr, constant = true) {
6842
6860
  const probe = probeUpdate(ctx, expectedArr, posExpr, constant);
@@ -6846,18 +6864,19 @@ function failArrBody(ctx, expectedArr, posExpr, constant = true) {
6846
6864
  const fx = constant ? hoistExpected(ctx, expectedArr) : expectedArr;
6847
6865
  return `{ ${probe}_ctx._fe = ${posExpr}; _ctx._fx = ${fx}; ${trace}break ${ctx.failLabel} }`;
6848
6866
  }
6849
- if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: { start: ${posExpr}, end: ${posExpr} } }`;
6850
- return probe + trace + failReturnArr(expectedArr, posExpr);
6867
+ if (!constant) return `${probe}${trace}return { ok: false, expected: [...${expectedArr}], span: ${ctx.lineTracking ? emitSpanExpr(ctx, posExpr, posExpr) : `{ start: ${posExpr}, end: ${posExpr} }`} }`;
6868
+ return probe + trace + failReturnArr(ctx, expectedArr, posExpr);
6851
6869
  }
6852
- function resultFromRecorded(feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
6853
- return `return { ok: false, expected: [...${fxExpr}], span: { start: ${feExpr}, end: ${feExpr} }, ...(_ctx._fc ? { committed: true } : {}) }`;
6870
+ function resultFromRecorded(ctx, feExpr = "_ctx._fe", fxExpr = "_ctx._fx") {
6871
+ const spanExpr = ctx.lineTracking ? emitSpanExpr(ctx, feExpr, feExpr) : `{ start: ${feExpr}, end: ${feExpr} }`;
6872
+ return `return { ok: false, expected: [...${fxExpr}], span: ${spanExpr}, ...(_ctx._fc ? { committed: true } : {}) }`;
6854
6873
  }
6855
6874
  function committedFailBody(ctx, expectedArr = "_ctx._fx", posExpr = "_ctx._fe") {
6856
6875
  if (ctx.failLabel) {
6857
6876
  if (!ctx.recordFail) return `{ _ctx._fc = true; break ${ctx.failLabel} }`;
6858
6877
  return `{ _ctx._fc = true; _ctx._fe = ${posExpr}; _ctx._fx = ${expectedArr}; break ${ctx.failLabel} }`;
6859
6878
  }
6860
- return committedReturnArr(expectedArr, posExpr);
6879
+ return committedReturnArr(ctx, expectedArr, posExpr);
6861
6880
  }
6862
6881
  function propagateFailBody(ctx, srcCtx = "_ctx") {
6863
6882
  if (srcCtx !== "_ctx") {
@@ -6865,10 +6884,10 @@ function propagateFailBody(ctx, srcCtx = "_ctx") {
6865
6884
  if (!ctx.recordFail) return `break ${ctx.failLabel}`;
6866
6885
  return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; break ${ctx.failLabel} }`;
6867
6886
  }
6868
- return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded()} }`;
6887
+ return `{ _ctx._fe = ${srcCtx}._fe; _ctx._fx = ${srcCtx}._fx; _ctx._fc = ${srcCtx}._fc; ${resultFromRecorded(ctx)} }`;
6869
6888
  }
6870
6889
  if (ctx.failLabel) return `break ${ctx.failLabel}`;
6871
- return resultFromRecorded();
6890
+ return resultFromRecorded(ctx);
6872
6891
  }
6873
6892
  function emitIfFail(ctx, cond, body) {
6874
6893
  return [
@@ -8301,7 +8320,7 @@ function emitAttempt(p, def, ctx, pos) {
8301
8320
  if (!ctx.recovery && !ctx.coverage && needsFirstSetGuard(def.parser)) {
8302
8321
  const gcV = v(ctx, "_agc");
8303
8322
  const gExp = armStaticExpected(ctx, def.parser);
8304
- const gFail = ctx.failLabel ? `{ _ctx._fe = ${pos};${ctx.recordFail ? ` _ctx._fx = ${gExp};` : ""} break ${ctx.failLabel} }` : `{ _ctx._fe = ${pos}; ${failReturnArr(gExp, pos)} }`;
8323
+ const gFail = ctx.failLabel ? `{ _ctx._fe = ${pos};${ctx.recordFail ? ` _ctx._fx = ${gExp};` : ""} break ${ctx.failLabel} }` : `{ _ctx._fe = ${pos}; ${failReturnArr(ctx, gExp, pos)} }`;
8305
8324
  preGuard.push(
8306
8325
  `${ind(ctx)}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
8307
8326
  `${ind(ctx)}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
@@ -8800,7 +8819,7 @@ ${i}const ${chV} = ${chAlloc}, ${rawV} = ${profileRecognizer} ? undefined : [],
8800
8819
  if (!ctx.recovery && !ctx.coverage && (capturesChildren || structural) && needsFirstSetGuard(def.parser)) {
8801
8820
  const gcV = v(ctx, "_ngc");
8802
8821
  const gExp = armStaticExpected(ctx, def.parser);
8803
- const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(gExp, pos);
8822
+ const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(ctx, gExp, pos);
8804
8823
  preGuard.push(
8805
8824
  `${i}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
8806
8825
  `${i}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
@@ -9316,6 +9335,7 @@ function hasLineTrackingDef(p, seen = /* @__PURE__ */ new Set()) {
9316
9335
  if (seen.has(p)) return false;
9317
9336
  seen.add(p);
9318
9337
  const d = p._def;
9338
+ if (p._meta.grammarTrackLines) return true;
9319
9339
  if (d.tag === "grammar" && d.trackLines) return true;
9320
9340
  if (d.tag === "lazy") {
9321
9341
  try {
@@ -9673,6 +9693,7 @@ function compile(combinator, mapFnSources, opts) {
9673
9693
  const grammarTrivia = combinator._meta.grammarTrivia;
9674
9694
  const grammarScanSkip = combinator._meta.grammarScanSkip;
9675
9695
  const grammarHostMode = combinator._meta.grammarHostMode;
9696
+ const grammarTrackLines = combinator._meta.grammarTrackLines;
9676
9697
  const ctx = {
9677
9698
  vars: 0,
9678
9699
  indent: 1,
@@ -9693,7 +9714,7 @@ function compile(combinator, mapFnSources, opts) {
9693
9714
  capturing: hasNodeDef(combinator),
9694
9715
  recovery: opts?.recovery ?? false,
9695
9716
  hostMode: opts?.hostMode ?? grammarHostMode ?? "ast",
9696
- lineTracking: opts?.trackLines === true || hasLineTrackingDef(combinator),
9717
+ lineTracking: opts?.trackLines === true || grammarTrackLines === true || hasLineTrackingDef(combinator),
9697
9718
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(combinator), entry: combinator } } : {},
9698
9719
  lazyUsage: analyzeLazyUsage(combinator),
9699
9720
  ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
@@ -9857,6 +9878,7 @@ function compileRuleMap(ruleMap, opts) {
9857
9878
  const grammarTrivia = opts?.trivia;
9858
9879
  const grammarScanSkip = opts?.scanSkip ?? ruleMap.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
9859
9880
  const grammarHostMode = opts?.hostMode ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
9881
+ const grammarTrackLines = opts?.trackLines === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
9860
9882
  const ctx = {
9861
9883
  vars: 0,
9862
9884
  indent: 1,
@@ -9877,6 +9899,7 @@ function compileRuleMap(ruleMap, opts) {
9877
9899
  capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
9878
9900
  recovery: opts?.recovery ?? false,
9879
9901
  hostMode: grammarHostMode ?? "ast",
9902
+ lineTracking: grammarTrackLines,
9880
9903
  ...opts?.coverage ? { coverage: { plan: buildGrammarPlan(ruleMap.map(([, rule]) => rule), coverageWinners) } } : {},
9881
9904
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
9882
9905
  ...grammarTrivia ? { activeTrivia: grammarTrivia, triviaKindLabels: grammarTrivia._meta.triviaKindLabels } : {},
@@ -9910,6 +9933,10 @@ function compileRuleMap(ruleMap, opts) {
9910
9933
  const mfCovered = ctx.mapFns.length === 0 || derivedSrcs !== void 0;
9911
9934
  const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
9912
9935
  if (!canInline) return null;
9936
+ if (ctx.lineTracking) {
9937
+ ctx.needsLineTrack = true;
9938
+ ctx.needsLineSpan = true;
9939
+ }
9913
9940
  const mfDecl = derivedSrcs?.length ? ` const ${mfRef(ctx)} = [${derivedSrcs.join(", ")}]` : "";
9914
9941
  const buildDecl = buildSources?.length ? ` const ${buildRef(ctx)} = [${buildSources.join(", ")}]` : "";
9915
9942
  const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
@@ -9939,15 +9966,23 @@ function compileRuleMap(ruleMap, opts) {
9939
9966
  };
9940
9967
  const entryFnText = (r, rule) => {
9941
9968
  const ruleId = entryRuleId(rule);
9969
+ const linePreamble = ctx.lineTracking ? [
9970
+ ` if (_ctx._lineStarts === undefined) _ctx = { ..._ctx, trackLines: true, _lineStarts: [0], _lineScannedTo: 0 }`,
9971
+ ` else _ctx.trackLines = true`,
9972
+ ` if (_pos > (_ctx._lineScannedTo ?? 0)) _trackLines(_ctx, input, 0, _pos)`
9973
+ ] : [];
9974
+ const resultSpan = ctx.lineTracking ? `_spanLines(_ctx, _pos, ${r.endVar})` : `{ start: _pos, end: ${r.endVar} }`;
9942
9975
  const body = ruleId === void 0 ? [
9976
+ ...linePreamble,
9943
9977
  ` let pos = _pos`,
9944
9978
  ...r.stmts,
9945
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
9979
+ ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`
9946
9980
  ] : [
9981
+ ...linePreamble,
9947
9982
  ` const _coverageResult = (() => {`,
9948
9983
  ` let pos = _pos`,
9949
9984
  ...r.stmts,
9950
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
9985
+ ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`,
9951
9986
  ` })()`,
9952
9987
  ` if (!_coverageResult.ok) _ctx._grammarTrace?.write({ id: ${JSON.stringify(ruleId)}, phase: 'failure', offset: _coverageResult.span.start })`,
9953
9988
  ` return _coverageResult`
@@ -9985,6 +10020,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
9985
10020
  const grammarTrivia = opts?.trivia ?? ruleMapArg.map(([, r]) => r._meta.grammarTrivia).find(Boolean);
9986
10021
  const grammarScanSkip = opts?.scanSkip ?? ruleMapArg.map(([, r]) => r._meta.grammarScanSkip).find(Boolean);
9987
10022
  const grammarHostMode = opts?.hostMode ?? ruleMapArg.map(([, r]) => r._meta.grammarHostMode).find(Boolean);
10023
+ const grammarTrackLines = opts?.trackLines === true || ruleMapArg.some(([, r]) => r._meta.grammarTrackLines === true);
9988
10024
  const ruleMap = ruleMapArg.filter(([, val]) => {
9989
10025
  const d = val._def;
9990
10026
  if (d.tag !== "lazy") return true;
@@ -10019,6 +10055,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
10019
10055
  capturing: opts?.captureTerminals === true || ruleMap.some(([, rule]) => hasNodeDef(rule)),
10020
10056
  recovery: opts?.recovery ?? false,
10021
10057
  hostMode: grammarHostMode ?? "ast",
10058
+ lineTracking: grammarTrackLines,
10022
10059
  ...opts?.coverage ? { coverage: { plan: opts.coverage } } : {},
10023
10060
  lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
10024
10061
  ns,
@@ -10115,6 +10152,10 @@ function compileLinkable(ruleMapArg, ns, opts) {
10115
10152
  perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
10116
10153
  }
10117
10154
  if (ctx.runtimeParsers.length !== 0) return null;
10155
+ if (ctx.lineTracking) {
10156
+ ctx.needsLineTrack = true;
10157
+ ctx.needsLineSpan = true;
10158
+ }
10118
10159
  const mfSrcs = ctx.mapFns.length > 0 && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : null;
10119
10160
  const buildSrcs = ctx.buildFns.length > 0 && ctx.buildSrcs.every((s) => s !== null) ? ctx.buildSrcs : null;
10120
10161
  const ruleFns = /* @__PURE__ */ new Map();
@@ -10128,6 +10169,8 @@ function compileLinkable(ruleMapArg, ns, opts) {
10128
10169
  const mfDecl = ctx.mapFns.length === 0 ? "" : mfSrcs ? `const ${mfRef(ctx)} = [${mfSrcs.join(", ")}]` : `const ${mfRef(ctx)} = _env[${JSON.stringify(nsp(ctx) + "mf")}]`;
10129
10170
  const buildDecl = ctx.buildFns.length === 0 ? "" : buildSrcs ? `const ${buildRef(ctx)} = [${buildSrcs.join(", ")}]` : `const ${buildRef(ctx)} = _env[${JSON.stringify(nsp(ctx) + "build")}]`;
10130
10171
  const prelude = [
10172
+ ctx.needsLineTrack ? LINE_TRACK_DECL : "",
10173
+ ctx.needsLineSpan ? LINE_SPAN_DECL : "",
10131
10174
  ...ctx.regexDecls,
10132
10175
  ...ctx.expectedDecls,
10133
10176
  mfDecl,
@@ -10136,11 +10179,18 @@ function compileLinkable(ruleMapArg, ns, opts) {
10136
10179
  ].filter(Boolean);
10137
10180
  const wrappers = /* @__PURE__ */ new Map();
10138
10181
  for (const { key, rule, r } of perEntry) {
10182
+ const linePreamble = ctx.lineTracking ? [
10183
+ ` if (_ctx._lineStarts === undefined) _ctx = { ..._ctx, trackLines: true, _lineStarts: [0], _lineScannedTo: 0 }`,
10184
+ ` else _ctx.trackLines = true`,
10185
+ ` if (_pos > (_ctx._lineScannedTo ?? 0)) _trackLines(_ctx, input, 0, _pos)`
10186
+ ] : [];
10187
+ const resultSpan = ctx.lineTracking ? `_spanLines(_ctx, _pos, ${r.endVar})` : `{ start: _pos, end: ${r.endVar} }`;
10139
10188
  wrappers.set(key, publicRuleWrapperSource(rule, [
10140
10189
  `function(input, _pos, _ctx) {`,
10190
+ ...linePreamble,
10141
10191
  ` let pos = _pos`,
10142
10192
  ...r.stmts,
10143
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
10193
+ ` return { ok: true, value: ${r.valueVar}, span: ${resultSpan} }`,
10144
10194
  `}`
10145
10195
  ].join("\n"), ctx.triviaKindLabels));
10146
10196
  }
@@ -10974,7 +11024,8 @@ function materializePiece(p, trivia2, captureTerminals = false, hostMode) {
10974
11024
  const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns, {
10975
11025
  ...trivia2 ? { trivia: trivia2 } : {},
10976
11026
  ...captureTerminals ? { captureTerminals: true } : {},
10977
- ...hostMode ? { hostMode } : {}
11027
+ ...hostMode ? { hostMode } : {},
11028
+ ...p.trackLines ? { trackLines: true } : {}
10978
11029
  });
10979
11030
  if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
10980
11031
  return pieces;
@@ -12221,6 +12272,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12221
12272
  const macroImports = [];
12222
12273
  const allNames = /* @__PURE__ */ new Set();
12223
12274
  const importBindings = /* @__PURE__ */ new Map();
12275
+ const ordinaryImports = [];
12224
12276
  for (const stmt of body) {
12225
12277
  if (stmt.type !== "ImportDeclaration") continue;
12226
12278
  const s = stmt;
@@ -12229,12 +12281,17 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12229
12281
  return key === "type" && a.value.value === "macro";
12230
12282
  });
12231
12283
  if (!isMacro) {
12284
+ const specifiers = [];
12232
12285
  for (const spec of s.specifiers) {
12233
12286
  if (spec.type === "ImportSpecifier") {
12234
12287
  const imported = spec.imported.name ?? spec.local.name;
12235
12288
  importBindings.set(spec.local.name, { source: s.source.value, imported });
12289
+ specifiers.push({ type: spec.type, local: spec.local.name, start: spec.start, end: spec.end });
12290
+ } else {
12291
+ specifiers.push({ type: spec.type, local: spec.local.name, start: spec.start, end: spec.end });
12236
12292
  }
12237
12293
  }
12294
+ ordinaryImports.push({ start: s.start, end: s.end, specifiers });
12238
12295
  continue;
12239
12296
  }
12240
12297
  const names = /* @__PURE__ */ new Set();
@@ -12245,6 +12302,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12245
12302
  for (const n of names) allNames.add(n);
12246
12303
  }
12247
12304
  if (macroImports.length === 0) return null;
12305
+ const unwrapVd = (stmt) => stmt.type === "VariableDeclaration" ? stmt : stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" ? stmt.declaration : null;
12248
12306
  const factoryDecls = /* @__PURE__ */ new Map();
12249
12307
  for (const stmt of body) {
12250
12308
  const decl = stmt.type === "ExportNamedDeclaration" ? stmt.declaration : stmt;
@@ -12262,6 +12320,101 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12262
12320
  }
12263
12321
  }
12264
12322
  }
12323
+ const topLevelFunction = (moduleBody, name) => {
12324
+ for (const st of moduleBody) {
12325
+ const decl = st.type === "ExportNamedDeclaration" ? st.declaration : st;
12326
+ const idn = decl?.type === "FunctionDeclaration" ? decl.id : void 0;
12327
+ if (idn?.name === name) return decl ?? null;
12328
+ }
12329
+ return null;
12330
+ };
12331
+ const isParsemanMacroImport = (stmt) => {
12332
+ if (stmt.type !== "ImportDeclaration") return false;
12333
+ const s = stmt;
12334
+ return moduleAliases.has(s.source.value) && s.attributes.some((a) => {
12335
+ const key = a.key.type === "Identifier" ? a.key.name : String(a.key.value);
12336
+ return key === "type" && a.value.value === "macro";
12337
+ });
12338
+ };
12339
+ const sourceScopeUntil = (moduleBody, source, until) => {
12340
+ const out = /* @__PURE__ */ new Map();
12341
+ for (const stmt of moduleBody) {
12342
+ if (stmt.type === "ImportDeclaration") {
12343
+ if (!isParsemanMacroImport(stmt)) return null;
12344
+ continue;
12345
+ }
12346
+ if (stmt.type === "FunctionDeclaration") continue;
12347
+ if (stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "FunctionDeclaration") continue;
12348
+ if (stmt.type === "ExportNamedDeclaration" && !stmt.declaration) {
12349
+ if (stmt.source) return null;
12350
+ continue;
12351
+ }
12352
+ const vd = unwrapVd(stmt);
12353
+ if (!vd || vd.kind !== "const") return null;
12354
+ for (const decl of vd.declarations) {
12355
+ const d = decl;
12356
+ const idn = d.id;
12357
+ const init = d.init;
12358
+ if (idn.type !== "Identifier" && idn.type !== "BindingIdentifier" || !idn.name || !init) return null;
12359
+ if (init.type === "ArrowFunctionExpression" || init.type === "FunctionExpression") continue;
12360
+ const mapFnSources = [];
12361
+ const combi = evaluateExpr(init, out, source, mapFnSources);
12362
+ if (combi) {
12363
+ if (stmt.start < until) out.set(idn.name, { combi, mfSrcs: mapFnSources });
12364
+ continue;
12365
+ }
12366
+ const wordFactory = evaluateWordFactory(init, out, source);
12367
+ if (wordFactory) {
12368
+ if (stmt.start < until) {
12369
+ ;
12370
+ out.set(idn.name, wordFactory);
12371
+ }
12372
+ continue;
12373
+ }
12374
+ const whenFactory = evaluateWhenFactory(init, out, source);
12375
+ if (whenFactory) {
12376
+ if (stmt.start < until) {
12377
+ ;
12378
+ out.set(idn.name, whenFactory);
12379
+ }
12380
+ continue;
12381
+ }
12382
+ const combiArray = evaluateCombinatorArray(init, out, source);
12383
+ if (combiArray) {
12384
+ if (stmt.start < until) {
12385
+ ;
12386
+ out.set(idn.name, combiArray);
12387
+ }
12388
+ continue;
12389
+ }
12390
+ return null;
12391
+ }
12392
+ continue;
12393
+ }
12394
+ return out;
12395
+ };
12396
+ const usedImportedFactories = /* @__PURE__ */ new Set();
12397
+ const markUsedImportedFactories = (names) => {
12398
+ for (const name of names ?? []) usedImportedFactories.add(name);
12399
+ };
12400
+ for (const [localName, binding] of importBindings) {
12401
+ const file = resolvePrivateSourceModule(id, binding.source);
12402
+ if (!file) continue;
12403
+ const mod = parseModuleCached(file);
12404
+ if (!mod) continue;
12405
+ const localFor = exportLocalName(mod.body, binding.imported);
12406
+ const init = localFor ? topLevelInit(mod.body, localFor) ?? topLevelFunction(mod.body, localFor) : null;
12407
+ if (!init || init.type !== "ArrowFunctionExpression" && init.type !== "FunctionExpression" && init.type !== "FunctionDeclaration") continue;
12408
+ const factoryScope = sourceScopeUntil(mod.body, mod.src, init.start);
12409
+ if (!factoryScope) continue;
12410
+ factoryDecls.set(localName, {
12411
+ fn: init,
12412
+ declaredAt: -1,
12413
+ code: mod.src,
12414
+ scope: factoryScope,
12415
+ imported: true
12416
+ });
12417
+ }
12265
12418
  const scope = /* @__PURE__ */ new Map();
12266
12419
  const replacements = [];
12267
12420
  const warnings = [];
@@ -12291,6 +12444,9 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12291
12444
  }
12292
12445
  const namedFactory = factoryArgRaw.type === "Identifier" ? factoryDecls.get(factoryArgRaw.name) : void 0;
12293
12446
  const factoryArg = namedFactory !== void 0 && namedFactory.declaredAt <= init.start ? namedFactory.fn : factoryArgRaw;
12447
+ const factoryScope = namedFactory?.scope ?? scope;
12448
+ const factoryCode = namedFactory?.code ?? code;
12449
+ const importedFactory = namedFactory?.imported === true && factoryArg === namedFactory.fn ? factoryArgRaw.name : void 0;
12294
12450
  const optionsArg = optionsFirst ? arg0 : arg1;
12295
12451
  const optionValue = (name) => optionsArg?.type === "ObjectExpression" ? (optionsArg.properties ?? []).find(
12296
12452
  (p) => p.key?.name === name
@@ -12301,7 +12457,13 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12301
12457
  warn(init.start, `${label2}: rules({ hostMode }) must be the literal 'ast' or 'cst'`);
12302
12458
  return null;
12303
12459
  }
12304
- const ruleMap = evaluateParserFactory(factoryArg, scope, code, []);
12460
+ const trackLinesValue = optionValue("trackLines");
12461
+ const gTrackLines = trackLinesValue?.type === "Literal" ? trackLinesValue.value : void 0;
12462
+ if (trackLinesValue !== void 0 && typeof gTrackLines !== "boolean") {
12463
+ warn(init.start, `${label2}: rules({ trackLines }) must be a boolean literal`);
12464
+ return null;
12465
+ }
12466
+ const ruleMap = evaluateParserFactory(factoryArg, factoryScope, factoryCode, []);
12305
12467
  if (!ruleMap) {
12306
12468
  warn(init.start, `${label2}: rules(...) factory isn't statically evaluable`);
12307
12469
  return null;
@@ -12326,12 +12488,26 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12326
12488
  }
12327
12489
  }
12328
12490
  }
12329
- return { ruleMap, ...gTrivia ? { trivia: gTrivia } : {}, ...gScanSkip ? { scanSkip: gScanSkip } : {} };
12491
+ if (gTrackLines === true) {
12492
+ for (const rule of ruleMap.values()) {
12493
+ if (rule && !rule._meta.isTrivia) {
12494
+ ;
12495
+ rule._meta.grammarTrackLines = true;
12496
+ }
12497
+ }
12498
+ }
12499
+ return {
12500
+ ruleMap,
12501
+ ...gTrivia ? { trivia: gTrivia } : {},
12502
+ ...gScanSkip ? { scanSkip: gScanSkip } : {},
12503
+ ...gTrackLines === true ? { trackLines: true } : {},
12504
+ ...importedFactory ? { importedFactory } : {}
12505
+ };
12330
12506
  };
12331
12507
  const compileRulesFactory = (init, label2) => {
12332
12508
  const evaluated = evaluateRulesFactory(init, label2);
12333
12509
  if (!evaluated) return null;
12334
- const compiled = compileRuleMap([...evaluated.ruleMap], { ...evaluated.trivia ? { trivia: evaluated.trivia } : {}, ...evaluated.scanSkip ? { scanSkip: evaluated.scanSkip } : {}, recovery, coverage: grammarCoverage });
12510
+ const compiled = compileRuleMap([...evaluated.ruleMap], { ...evaluated.trivia ? { trivia: evaluated.trivia } : {}, ...evaluated.scanSkip ? { scanSkip: evaluated.scanSkip } : {}, ...evaluated.trackLines ? { trackLines: true } : {}, recovery, coverage: grammarCoverage });
12335
12511
  return {
12336
12512
  replacement: compiled?.replacement ?? null,
12337
12513
  ruleMap: evaluated.ruleMap,
@@ -12339,7 +12515,9 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12339
12515
  hostBranchElided: compiled?.hostBranchElided ?? false,
12340
12516
  ...compiled?.coverageDefinitions ? { coverageDefinitions: compiled.coverageDefinitions } : {},
12341
12517
  ...evaluated.trivia ? { trivia: evaluated.trivia } : {},
12342
- ...evaluated.scanSkip ? { scanSkip: evaluated.scanSkip } : {}
12518
+ ...evaluated.scanSkip ? { scanSkip: evaluated.scanSkip } : {},
12519
+ ...evaluated.trackLines ? { trackLines: true } : {},
12520
+ ...evaluated.importedFactory ? { importedFactory: evaluated.importedFactory } : {}
12343
12521
  };
12344
12522
  };
12345
12523
  const isRulesCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "rules";
@@ -12359,7 +12537,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12359
12537
  };
12360
12538
  const isSpread = (it) => "__spreadLocal" in it;
12361
12539
  const isIR = (it) => "ir" in it && !("ruleFns" in it);
12362
- const serializeItem = (it) => isSpread(it) ? `...(${it.__spreadLocal}[Symbol.for('parseman.composedPieces')] ?? [])` : isIR(it) ? `{ ns: ${JSON.stringify(it.ns)}, ir: ${JSON.stringify(it.ir)} }` : serializePieces(it);
12540
+ const serializeItem = (it) => isSpread(it) ? `...(${it.__spreadLocal}[Symbol.for('parseman.composedPieces')] ?? [])` : isIR(it) ? `{ ns: ${JSON.stringify(it.ns)}, ir: ${JSON.stringify(it.ir)}${it.trackLines ? ", trackLines: true" : ""} }` : serializePieces(it);
12363
12541
  const serializeList = (list) => `[${list.map(serializeItem).join(", ")}]`;
12364
12542
  const withCarriedPieces = (grammarExpr, list) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.composedPieces'), { value: ${serializeList(list)}, enumerable: false })`;
12365
12543
  const withLeafMarker = (grammarExpr) => `/* @__PURE__ */ Object.defineProperty(${grammarExpr}, Symbol.for('parseman.leafComposed'), { value: true, enumerable: false })`;
@@ -12490,10 +12668,11 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12490
12668
  const localCarried = (rm, label2, composing, scanSkip) => {
12491
12669
  const entries = [...rm];
12492
12670
  const ns = nsFor(label2);
12671
+ const trackLines = entries.some(([, rule]) => rule?._meta?.grammarTrackLines === true);
12493
12672
  const ir = serializeRuleMap(entries, scanSkip);
12494
- if (ir) return { carried: [{ ns, ir }] };
12673
+ if (ir) return { carried: [{ ns, ir, ...trackLines ? { trackLines: true } : {} }] };
12495
12674
  warn(0, `${label2}: rule map could not be serialized to IR; carrying FULL pieces instead. The artifact is correct but larger, and a downstream compose cannot re-lower it. Re-run with PARSEMAN_IR_DEBUG=1 to print the exact combinator that blocked serialization.`);
12496
- const p = compileLinkable(entries, ns, { ...composing ? { trivia: composing } : {}, ...scanSkip ? { scanSkip } : {}, recovery });
12675
+ const p = compileLinkable(entries, ns, { ...composing ? { trivia: composing } : {}, ...scanSkip ? { scanSkip } : {}, ...trackLines ? { trackLines: true } : {}, recovery });
12497
12676
  return p ? { carried: [p] } : null;
12498
12677
  };
12499
12678
  const argPieces = (arg, label2, composing) => {
@@ -12511,7 +12690,10 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12511
12690
  const innerArg = argPieces(inner, `${label2}_pick`);
12512
12691
  if (!innerArg) return null;
12513
12692
  try {
12514
- return { carried: pickPieces(materializeCarried(innerArg.carried, ownTrivia(inner)), names) };
12693
+ return {
12694
+ carried: pickPieces(materializeCarried(innerArg.carried, ownTrivia(inner)), names),
12695
+ ...innerArg.importedFactories ? { importedFactories: innerArg.importedFactories } : {}
12696
+ };
12515
12697
  } catch (e) {
12516
12698
  warn(arg.start, `pick(): ${e.message}`);
12517
12699
  return null;
@@ -12519,7 +12701,8 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12519
12701
  }
12520
12702
  if (isRulesCall(arg)) {
12521
12703
  const evaluated = evaluateRulesFactory(arg, label2);
12522
- return evaluated ? localCarried(evaluated.ruleMap, label2, composing, evaluated.scanSkip) : null;
12704
+ const carried = evaluated ? localCarried(evaluated.ruleMap, label2, composing, evaluated.scanSkip) : null;
12705
+ return carried ? { ...carried, ...evaluated?.importedFactory ? { importedFactories: [evaluated.importedFactory] } : {} } : null;
12523
12706
  }
12524
12707
  if (arg.type === "Identifier") {
12525
12708
  const name = arg.name;
@@ -12591,6 +12774,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12591
12774
  }
12592
12775
  const composing = composingTrivia(elements);
12593
12776
  const carried = [];
12777
+ const importedFactories = [];
12594
12778
  for (let i = 0; i < elements.length; i++) {
12595
12779
  const r = argPieces(elements[i], `compose${init.start}_${i}`, composing);
12596
12780
  if (!r) {
@@ -12598,6 +12782,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12598
12782
  return null;
12599
12783
  }
12600
12784
  carried.push(...r.carried);
12785
+ importedFactories.push(...r.importedFactories ?? []);
12601
12786
  }
12602
12787
  const detailed = once(() => carriedRuleMapsDetailed(carried));
12603
12788
  runFusedGatingDiagnostic(
@@ -12607,7 +12792,12 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12607
12792
  );
12608
12793
  const pieces = materializeCarried(carried, composing, false, cHostMode);
12609
12794
  try {
12610
- return { replacement: emitFusedSource(pieces), carried, ...composing ? { trivia: composing } : {} };
12795
+ return {
12796
+ replacement: emitFusedSource(pieces),
12797
+ carried,
12798
+ ...composing ? { trivia: composing } : {},
12799
+ ...importedFactories.length ? { importedFactories } : {}
12800
+ };
12611
12801
  } catch (e) {
12612
12802
  warn(init.start, `compose(): ${e.message}; falling back to runtime`);
12613
12803
  return null;
@@ -12628,10 +12818,12 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12628
12818
  const localArg = elements[elements.length - 1];
12629
12819
  let localRules = null;
12630
12820
  let localScanSkip;
12821
+ const importedFactories = [];
12631
12822
  if (isRulesCall(localArg)) {
12632
12823
  const evaluated = evaluateRulesFactory(localArg, `composeLeaf${init.start}`);
12633
12824
  localRules = evaluated?.ruleMap ?? null;
12634
12825
  localScanSkip = evaluated?.scanSkip;
12826
+ if (evaluated?.importedFactory) importedFactories.push(evaluated.importedFactory);
12635
12827
  } else if (localArg.type === "Identifier") {
12636
12828
  const name = localArg.name;
12637
12829
  localRules = localRuleMaps.get(name) ?? null;
@@ -12650,6 +12842,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12650
12842
  return null;
12651
12843
  }
12652
12844
  carried.push(...r.carried);
12845
+ importedFactories.push(...r.importedFactories ?? []);
12653
12846
  }
12654
12847
  try {
12655
12848
  const localNs = nsFor(`composeLeaf${init.start}`);
@@ -12675,13 +12868,15 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12675
12868
  return null;
12676
12869
  }
12677
12870
  const replacement = withLeafMarker(emitFusedSource(grammarCoverage ? recognitionPieces : [...recognitionPieces, plainLocalPiece]));
12678
- return { replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)) };
12871
+ return {
12872
+ replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)),
12873
+ ...importedFactories.length ? { importedFactories } : {}
12874
+ };
12679
12875
  } catch (e) {
12680
12876
  warn(init.start, `composeLeaf(): ${e.message}`);
12681
12877
  return null;
12682
12878
  }
12683
12879
  };
12684
- const unwrapVd = (stmt) => stmt.type === "VariableDeclaration" ? stmt : stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" ? stmt.declaration : null;
12685
12880
  const refNames = /* @__PURE__ */ new Set();
12686
12881
  for (const stmt of body) {
12687
12882
  const innerVd = unwrapVd(stmt);
@@ -12765,6 +12960,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12765
12960
  const ns = nsFor(varName);
12766
12961
  const pieces = exportPrefix || compiledRules.replacement === null ? compileLinkable([...compiledRules.ruleMap], ns, {
12767
12962
  ...compiledRules.scanSkip ? { scanSkip: compiledRules.scanSkip } : {},
12963
+ ...compiledRules.trackLines ? { trackLines: true } : {},
12768
12964
  recovery
12769
12965
  }) : null;
12770
12966
  if (compiledRules.replacement === null) {
@@ -12784,9 +12980,12 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12784
12980
  }
12785
12981
  if (exportPrefix && pieces && !pieces.mfFns.length && !pieces.buildFns.length) {
12786
12982
  const ir = serializeRuleMap([...compiledRules.ruleMap], compiledRules.scanSkip);
12787
- replacement = withCarriedPieces(replacement, [ir ? { ns, ir } : pieces]);
12983
+ replacement = withCarriedPieces(replacement, [ir ? { ns, ir, ...compiledRules.trackLines ? { trackLines: true } : {} } : pieces]);
12788
12984
  }
12789
12985
  replacements.push({ start: init.start, end: init.end, replacement });
12986
+ if (compiledRules.replacement !== null) {
12987
+ markUsedImportedFactories(compiledRules.importedFactory ? [compiledRules.importedFactory] : void 0);
12988
+ }
12790
12989
  continue;
12791
12990
  }
12792
12991
  if (isComposeCall(init)) {
@@ -12799,6 +12998,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12799
12998
  if (fused.trivia) localComposedTrivia.set(varName, fused.trivia);
12800
12999
  const replacement = exportPrefix ? withCarriedPieces(fused.replacement, fused.carried) : fused.replacement;
12801
13000
  replacements.push({ start: init.start, end: init.end, replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement)) });
13001
+ markUsedImportedFactories(fused.importedFactories);
12802
13002
  continue;
12803
13003
  }
12804
13004
  if (isComposeLeafCall(init)) {
@@ -12807,6 +13007,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12807
13007
  throw new Error(`${id}:${lineOf(init.start)} \u2014 composeLeaf() must macro-fuse; runtime composition is forbidden`);
12808
13008
  }
12809
13009
  replacements.push({ start: init.start, end: init.end, replacement: fused.replacement });
13010
+ markUsedImportedFactories(fused.importedFactories);
12810
13011
  continue;
12811
13012
  }
12812
13013
  const mapFnSources = [];
@@ -12895,6 +13096,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12895
13096
  end: stmtEnd,
12896
13097
  replacement: lines.join("\n")
12897
13098
  });
13099
+ markUsedImportedFactories(compiledRules.importedFactory ? [compiledRules.importedFactory] : void 0);
12898
13100
  }
12899
13101
  }
12900
13102
  }
@@ -12903,6 +13105,40 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
12903
13105
  imp.fullyResolved = !anyUnresolved && !keepMacroImport;
12904
13106
  }
12905
13107
  const ms = new MagicString(code);
13108
+ const replacementRanges = runtimeComposeFallback ? [] : replacements.map(({ start, end }) => ({ start, end }));
13109
+ const isInsideReplacement = (start, end) => replacementRanges.some((r) => start >= r.start && end <= r.end);
13110
+ const importedBindingStillReferenced = (local) => {
13111
+ const walk2 = (node2, parent, parentKey) => {
13112
+ if (!node2 || typeof node2 !== "object") return false;
13113
+ const rec = node2;
13114
+ if (rec.type === "ImportDeclaration") return false;
13115
+ if (typeof rec.start === "number" && typeof rec.end === "number" && isInsideReplacement(rec.start, rec.end)) return false;
13116
+ if ((rec.type === "Identifier" || rec.type === "BindingIdentifier") && rec.name === local) {
13117
+ if (parentKey === "key" && (parent?.type === "ObjectProperty" || parent?.type === "Property" || parent?.type === "PropertyDefinition") && parent.computed !== true) return false;
13118
+ if (parentKey === "property" && parent?.type === "StaticMemberExpression") return false;
13119
+ if (parentKey === "property" && parent?.type === "MemberExpression" && parent.computed !== true) return false;
13120
+ return true;
13121
+ }
13122
+ for (const key of Object.keys(rec)) {
13123
+ if (key === "type" || key === "start" || key === "end") continue;
13124
+ const value = rec[key];
13125
+ if (Array.isArray(value)) {
13126
+ if (value.some((child) => walk2(child, rec, key))) return true;
13127
+ } else if (walk2(value, rec, key)) {
13128
+ return true;
13129
+ }
13130
+ }
13131
+ return false;
13132
+ };
13133
+ return body.some((stmt) => walk2(stmt));
13134
+ };
13135
+ for (const imp of ordinaryImports) {
13136
+ if (!runtimeComposeFallback && imp.specifiers.length > 0 && imp.specifiers.every(
13137
+ (spec) => spec.type === "ImportSpecifier" && usedImportedFactories.has(spec.local) && !importedBindingStillReferenced(spec.local)
13138
+ )) {
13139
+ ms.remove(imp.start, imp.end);
13140
+ }
13141
+ }
12906
13142
  if (!anyUnresolved) {
12907
13143
  for (const { start, end } of defineRemovals) ms.remove(start, end);
12908
13144
  }