parseman 0.45.0 → 0.46.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.
- package/dist/analysis/choice-cost-gate.d.ts +158 -0
- package/dist/analysis/choice-cost-gate.d.ts.map +1 -0
- package/dist/analysis/choice-cost-render.d.ts +88 -0
- package/dist/analysis/choice-cost-render.d.ts.map +1 -0
- package/dist/analysis/choice-cost.d.ts +383 -0
- package/dist/analysis/choice-cost.d.ts.map +1 -0
- package/dist/analysis/corpus.d.ts +73 -0
- package/dist/analysis/corpus.d.ts.map +1 -0
- package/dist/analysis/diagnose-render.d.ts +65 -0
- package/dist/analysis/diagnose-render.d.ts.map +1 -0
- package/dist/analysis/diagnose.d.ts +15 -0
- package/dist/analysis/diagnose.d.ts.map +1 -1
- package/dist/analysis/diagnostics.cjs +11272 -0
- package/dist/analysis/diagnostics.cjs.map +7 -0
- package/dist/analysis/diagnostics.d.ts +27 -0
- package/dist/analysis/diagnostics.d.ts.map +1 -0
- package/dist/analysis/diagnostics.js +11249 -0
- package/dist/analysis/diagnostics.js.map +7 -0
- package/dist/analysis/fix-render.d.ts +43 -0
- package/dist/analysis/fix-render.d.ts.map +1 -0
- package/dist/analysis/fix.d.ts +172 -0
- package/dist/analysis/fix.d.ts.map +1 -0
- package/dist/analysis/gating.d.ts +8 -0
- package/dist/analysis/gating.d.ts.map +1 -1
- package/dist/analysis/rebuild.d.ts +61 -0
- package/dist/analysis/rebuild.d.ts.map +1 -0
- package/dist/analysis/terminal.d.ts +142 -0
- package/dist/analysis/terminal.d.ts.map +1 -0
- package/dist/cli/index.cjs +12507 -0
- package/dist/cli/index.cjs.map +7 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +12484 -0
- package/dist/cli/index.js.map +7 -0
- package/dist/compiler/build-arity.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +44 -6
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/module-hoist.d.ts +106 -0
- package/dist/compiler/module-hoist.d.ts.map +1 -0
- package/dist/index.cjs +1297 -297
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1297 -297
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs.map +2 -2
- package/dist/language-service/index.js.map +2 -2
- package/dist/plugin/evaluator.d.ts +1 -1
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/free-identifiers.d.ts +23 -0
- package/dist/plugin/free-identifiers.d.ts.map +1 -0
- package/dist/plugin/index.cjs +429 -43
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +429 -43
- package/dist/plugin/index.js.map +4 -4
- package/dist/plugin/reducer-resolver.d.ts +17 -1
- package/dist/plugin/reducer-resolver.d.ts.map +1 -1
- package/dist/spec/index.cjs +2 -1
- package/dist/spec/index.cjs.map +2 -2
- package/dist/spec/index.js +2 -1
- package/dist/spec/index.js.map +2 -2
- package/dist/version.d.ts +1 -1
- package/package.json +18 -3
package/dist/plugin/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import * as fs2 from "node:fs";
|
|
3
3
|
import * as path2 from "node:path";
|
|
4
4
|
import { createUnplugin } from "unplugin";
|
|
5
|
-
import { parseSync as
|
|
5
|
+
import { parseSync as parseSync4 } from "oxc-parser";
|
|
6
6
|
import { ResolverFactory } from "oxc-resolver";
|
|
7
7
|
import MagicString from "magic-string";
|
|
8
8
|
|
|
@@ -1492,8 +1492,8 @@ function classifyTriviaArm(arm) {
|
|
|
1492
1492
|
}
|
|
1493
1493
|
const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
|
|
1494
1494
|
if (lc) {
|
|
1495
|
-
const
|
|
1496
|
-
return { kind: "untilLineBreak", code: (
|
|
1495
|
+
const marker2 = lc[1];
|
|
1496
|
+
return { kind: "untilLineBreak", code: (marker2.length === 2 ? marker2[1] : marker2[0]).charCodeAt(0) };
|
|
1497
1497
|
}
|
|
1498
1498
|
return null;
|
|
1499
1499
|
}
|
|
@@ -3391,7 +3391,8 @@ var RESOLVER_REASONS = {
|
|
|
3391
3391
|
"unresolved-import": "its module could not be resolved or parsed",
|
|
3392
3392
|
"not-found": "the name did not resolve to any binding",
|
|
3393
3393
|
"computed": "it is a computed expression",
|
|
3394
|
-
"foreign-source": "it is named
|
|
3394
|
+
"foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
|
|
3395
|
+
"ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
|
|
3395
3396
|
};
|
|
3396
3397
|
function unconfirmableReason(def, src) {
|
|
3397
3398
|
const declared = def.buildArityUnresolved;
|
|
@@ -3920,7 +3921,7 @@ function leaf(root, fn) {
|
|
|
3920
3921
|
}
|
|
3921
3922
|
|
|
3922
3923
|
// src/version.ts
|
|
3923
|
-
var PARSEMAN_VERSION = "0.
|
|
3924
|
+
var PARSEMAN_VERSION = "0.46.0";
|
|
3924
3925
|
|
|
3925
3926
|
// src/cst/host-mode.ts
|
|
3926
3927
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -5540,15 +5541,15 @@ function parseStringShape(source) {
|
|
|
5540
5541
|
if (source.length < 3 || source[source.length - 1] !== q) return null;
|
|
5541
5542
|
const inner = source.slice(1, -1);
|
|
5542
5543
|
const CLS = String.raw`\[\^((?:\\.|[^\]])+)\]`;
|
|
5543
|
-
const
|
|
5544
|
+
const ESC2 = String.raw`\\\\(\.|\[\\s\\S\]|\[\\S\\s\])`;
|
|
5544
5545
|
let body;
|
|
5545
5546
|
let esc;
|
|
5546
|
-
let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${
|
|
5547
|
+
let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${ESC2}\\)\\*$`).exec(inner);
|
|
5547
5548
|
if (m) {
|
|
5548
5549
|
body = m[1];
|
|
5549
5550
|
esc = m[2];
|
|
5550
5551
|
} else {
|
|
5551
|
-
m = new RegExp(`^\\((?:\\?:)?${
|
|
5552
|
+
m = new RegExp(`^\\((?:\\?:)?${ESC2}\\|${CLS}\\)\\*$`).exec(inner);
|
|
5552
5553
|
if (m) {
|
|
5553
5554
|
esc = m[1];
|
|
5554
5555
|
body = m[2];
|
|
@@ -11224,7 +11225,7 @@ function pickPieces(pieces, names) {
|
|
|
11224
11225
|
const filt = (m, pc) => new Map([...m].filter(([k]) => keep.has(k) && winner.get(k) === pc));
|
|
11225
11226
|
return pieces.map((pc) => ({ ...pc, keys: pc.keys.filter((k) => keep.has(k) && winner.get(k) === pc), ruleFns: filt(pc.ruleFns, pc), wrappers: filt(pc.wrappers, pc), deps: filt(pc.deps, pc), nodeMeta: filt(pc.nodeMeta, pc) })).filter((pc) => pc.keys.length > 0);
|
|
11226
11227
|
}
|
|
11227
|
-
function fusedBody(pieces) {
|
|
11228
|
+
function fusedBody(pieces, hoist) {
|
|
11228
11229
|
for (const p of pieces) {
|
|
11229
11230
|
if (p.v === void 0) {
|
|
11230
11231
|
throw new Error(
|
|
@@ -11264,8 +11265,7 @@ function fusedBody(pieces) {
|
|
|
11264
11265
|
const wrapperEntries = [...winner].map(([k, p]) => `${JSON.stringify(k)}: ${p.wrappers.get(k)}`);
|
|
11265
11266
|
const reflection = mergeGrammarReflections([...winner].map(([k, p]) => p.nodeMeta.get(k) ?? { nodes: [] }));
|
|
11266
11267
|
const { mode, elided } = hostModeOfPieces(pieces);
|
|
11267
|
-
const
|
|
11268
|
-
...lines,
|
|
11268
|
+
const tailSrc = [
|
|
11269
11269
|
"const _map = {",
|
|
11270
11270
|
wrapperEntries.join(",\n"),
|
|
11271
11271
|
"}",
|
|
@@ -11281,6 +11281,7 @@ function fusedBody(pieces) {
|
|
|
11281
11281
|
"}",
|
|
11282
11282
|
"return _map"
|
|
11283
11283
|
].join("\n");
|
|
11284
|
+
const rawBody = [...lines, tailSrc].join("\n");
|
|
11284
11285
|
const ANY2 = { kind: "any" };
|
|
11285
11286
|
const EMPTY3 = { kind: "empty" };
|
|
11286
11287
|
const recipes = /* @__PURE__ */ new Map();
|
|
@@ -11321,7 +11322,7 @@ function fusedBody(pieces) {
|
|
|
11321
11322
|
}
|
|
11322
11323
|
if (!changed) break;
|
|
11323
11324
|
}
|
|
11324
|
-
const
|
|
11325
|
+
const resolveFS = (src) => src.replace(
|
|
11325
11326
|
// Rule name + code-point var are both JS identifiers (rule names are validated
|
|
11326
11327
|
// at compile time — see assertRuleName in codegen), so an identifier class
|
|
11327
11328
|
// matches every well-formed placeholder.
|
|
@@ -11332,6 +11333,7 @@ function fusedBody(pieces) {
|
|
|
11332
11333
|
return `(${firstSetCond(codevar, fs3)})`;
|
|
11333
11334
|
}
|
|
11334
11335
|
);
|
|
11336
|
+
const body = hoist === void 0 ? resolveFS(rawBody) : [...hoist.claim(lines.map(resolveFS)), resolveFS(tailSrc)].join("\n");
|
|
11335
11337
|
const env = {};
|
|
11336
11338
|
for (const p of contributingPieces) {
|
|
11337
11339
|
if (p.mfFns.length) env[`${p.ns}mf`] = p.mfFns;
|
|
@@ -11349,8 +11351,8 @@ function hostModeOfPieces(pieces) {
|
|
|
11349
11351
|
}
|
|
11350
11352
|
return { mode, elided: elided.length > 0 };
|
|
11351
11353
|
}
|
|
11352
|
-
function emitFusedSource(pieces) {
|
|
11353
|
-
const { body, env } = fusedBody(pieces);
|
|
11354
|
+
function emitFusedSource(pieces, hoist) {
|
|
11355
|
+
const { body, env } = fusedBody(pieces, hoist);
|
|
11354
11356
|
if (Object.keys(env).length > 0) {
|
|
11355
11357
|
throw new Error("emitFusedSource: artifact carries non-static callbacks (runtime-only); cannot emit static source");
|
|
11356
11358
|
}
|
|
@@ -11373,6 +11375,34 @@ function materializePiece(p, trivia2, captureTerminals = false, hostMode) {
|
|
|
11373
11375
|
return pieces;
|
|
11374
11376
|
}
|
|
11375
11377
|
|
|
11378
|
+
// src/functional/run.ts
|
|
11379
|
+
var SELECT_EXAMPLE = "run(entry, input, { rootTrivia: { select: ['blockComment', 'lineComment'] } })";
|
|
11380
|
+
var REMOVED_RUN_RESULT_FIELDS = [
|
|
11381
|
+
[
|
|
11382
|
+
"triviaMap",
|
|
11383
|
+
`It was a dense root-trivia index built on every parse; root trivia is now an OPT-IN sparse capture, because most grammars paid for an index they never read. Migration: name the trivia labels your grammar defines \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia\`, whose \`.index\` carries the labels and gap lookups \`triviaMap\` exposed.`
|
|
11384
|
+
],
|
|
11385
|
+
[
|
|
11386
|
+
"triviaLog",
|
|
11387
|
+
`It was the flat \`start, end[, kindIndex]\` log every other trivia view was derived from, and it is no longer allocated at all \u2014 not empty, absent. Migration: request the labels you need \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia.rows\`. Do NOT reuse a stride-2/3 reader: rows are a different width and a different unit (one row per SELECTED marker, not one per trivia chunk), so an old loop reads confidently wrong offsets rather than failing.`
|
|
11388
|
+
],
|
|
11389
|
+
[
|
|
11390
|
+
"triviaKindLabels",
|
|
11391
|
+
`It was already optional, so nothing ever flagged its disappearance \u2014 and \`triviaKindMask(undefined, \u2026)\` means "capture everything", so reading it now silently WIDENS capture instead of erroring. Migration: request labels \u2014 ${SELECT_EXAMPLE} \u2014 then the set you asked for is \`RunResult.rootTrivia.select\` and the resolved table is \`RunResult.rootTrivia.index.labels\`.`
|
|
11392
|
+
]
|
|
11393
|
+
];
|
|
11394
|
+
|
|
11395
|
+
// src/analysis/choice-cost-render.ts
|
|
11396
|
+
var ESC = "\x1B";
|
|
11397
|
+
var ANSI = {
|
|
11398
|
+
dim: `${ESC}[2m`,
|
|
11399
|
+
bold: `${ESC}[1m`,
|
|
11400
|
+
red: `${ESC}[31m`,
|
|
11401
|
+
yellow: `${ESC}[33m`,
|
|
11402
|
+
cyan: `${ESC}[36m`,
|
|
11403
|
+
reset: `${ESC}[0m`
|
|
11404
|
+
};
|
|
11405
|
+
|
|
11376
11406
|
// src/combinators/gate.ts
|
|
11377
11407
|
function gate(predicate) {
|
|
11378
11408
|
const meta = {
|
|
@@ -11392,23 +11422,6 @@ function gate(predicate) {
|
|
|
11392
11422
|
};
|
|
11393
11423
|
}
|
|
11394
11424
|
|
|
11395
|
-
// src/functional/run.ts
|
|
11396
|
-
var SELECT_EXAMPLE = "run(entry, input, { rootTrivia: { select: ['blockComment', 'lineComment'] } })";
|
|
11397
|
-
var REMOVED_RUN_RESULT_FIELDS = [
|
|
11398
|
-
[
|
|
11399
|
-
"triviaMap",
|
|
11400
|
-
`It was a dense root-trivia index built on every parse; root trivia is now an OPT-IN sparse capture, because most grammars paid for an index they never read. Migration: name the trivia labels your grammar defines \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia\`, whose \`.index\` carries the labels and gap lookups \`triviaMap\` exposed.`
|
|
11401
|
-
],
|
|
11402
|
-
[
|
|
11403
|
-
"triviaLog",
|
|
11404
|
-
`It was the flat \`start, end[, kindIndex]\` log every other trivia view was derived from, and it is no longer allocated at all \u2014 not empty, absent. Migration: request the labels you need \u2014 ${SELECT_EXAMPLE} \u2014 and read \`RunResult.rootTrivia.rows\`. Do NOT reuse a stride-2/3 reader: rows are a different width and a different unit (one row per SELECTED marker, not one per trivia chunk), so an old loop reads confidently wrong offsets rather than failing.`
|
|
11405
|
-
],
|
|
11406
|
-
[
|
|
11407
|
-
"triviaKindLabels",
|
|
11408
|
-
`It was already optional, so nothing ever flagged its disappearance \u2014 and \`triviaKindMask(undefined, \u2026)\` means "capture everything", so reading it now silently WIDENS capture instead of erroring. Migration: request labels \u2014 ${SELECT_EXAMPLE} \u2014 then the set you asked for is \`RunResult.rootTrivia.select\` and the resolved table is \`RunResult.rootTrivia.index.labels\`.`
|
|
11409
|
-
]
|
|
11410
|
-
];
|
|
11411
|
-
|
|
11412
11425
|
// src/index.ts
|
|
11413
11426
|
registerRegexAnalyzer(firstSetFromRegex);
|
|
11414
11427
|
|
|
@@ -11602,8 +11615,10 @@ function stripTsFromSource(node2, code) {
|
|
|
11602
11615
|
return out + code.slice(cur, end);
|
|
11603
11616
|
}
|
|
11604
11617
|
var _reducers = null;
|
|
11605
|
-
|
|
11618
|
+
var _entrySource = null;
|
|
11619
|
+
function setReducerResolver(r, entrySource = null) {
|
|
11606
11620
|
_reducers = r;
|
|
11621
|
+
_entrySource = entrySource;
|
|
11607
11622
|
}
|
|
11608
11623
|
function isWordFactory(v2) {
|
|
11609
11624
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
@@ -11975,6 +11990,9 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
11975
11990
|
const resolved = _reducers?.resolve(buildSrc, be.start, code);
|
|
11976
11991
|
if (resolved) {
|
|
11977
11992
|
if (resolved.src !== null) combi._def.buildSigSrc = resolved.src;
|
|
11993
|
+
if (_entrySource !== null && code !== _entrySource && resolved.src !== null && be.type === "Identifier") {
|
|
11994
|
+
combi._def.buildSrc = resolved.src;
|
|
11995
|
+
}
|
|
11978
11996
|
if (combi._def.buildArity === void 0 && resolved.arity !== null) combi._def.buildArity = resolved.arity;
|
|
11979
11997
|
if (resolved.reason !== void 0) combi._def.buildArityUnresolved = resolved.reason;
|
|
11980
11998
|
}
|
|
@@ -12790,6 +12808,8 @@ function createReducerResolver(entryFile, body, src) {
|
|
|
12790
12808
|
const scopes = buildScopeTree(body, src.length);
|
|
12791
12809
|
markReassignments(body, scopes);
|
|
12792
12810
|
const entry = { file: entryFile, src, body, scopes };
|
|
12811
|
+
const registered = /* @__PURE__ */ new Map();
|
|
12812
|
+
const ambiguous = /* @__PURE__ */ new Set();
|
|
12793
12813
|
const fromBinding = (mod, binding, memberName, hops, seen) => {
|
|
12794
12814
|
if (hops > MAX_HOPS) return { arity: null, src: null, reason: "not-found" };
|
|
12795
12815
|
if (binding.reassigned) return { arity: null, src: null, reason: "reassigned" };
|
|
@@ -12834,19 +12854,342 @@ function createReducerResolver(entryFile, body, src) {
|
|
|
12834
12854
|
return { arity, src: mod.src.slice(init.start, init.end), ...reason ? { reason } : {} };
|
|
12835
12855
|
};
|
|
12836
12856
|
return {
|
|
12857
|
+
register(file) {
|
|
12858
|
+
const mod = analyseModuleFile(file);
|
|
12859
|
+
if (!mod) return false;
|
|
12860
|
+
if (mod.src === src) return true;
|
|
12861
|
+
const prior = registered.get(mod.src);
|
|
12862
|
+
if (prior !== void 0 && prior.file !== mod.file) {
|
|
12863
|
+
ambiguous.add(mod.src);
|
|
12864
|
+
registered.delete(mod.src);
|
|
12865
|
+
return false;
|
|
12866
|
+
}
|
|
12867
|
+
if (!ambiguous.has(mod.src)) registered.set(mod.src, mod);
|
|
12868
|
+
return !ambiguous.has(mod.src);
|
|
12869
|
+
},
|
|
12837
12870
|
resolve(exprSrc, offset, offsetSrc) {
|
|
12838
12871
|
const text = exprSrc.trim();
|
|
12839
12872
|
const ident = IDENT_RE.test(text) ? text : null;
|
|
12840
12873
|
const member = ident ? null : MEMBER_RE.exec(text);
|
|
12841
12874
|
if (!ident && !member) return null;
|
|
12842
|
-
|
|
12875
|
+
const mod = offsetSrc === src ? entry : registered.get(offsetSrc);
|
|
12876
|
+
if (!mod) {
|
|
12877
|
+
return { arity: null, src: null, reason: ambiguous.has(offsetSrc) ? "ambiguous-source" : "foreign-source" };
|
|
12878
|
+
}
|
|
12843
12879
|
const name = ident ?? member[1];
|
|
12844
12880
|
const memberName = ident ? void 0 : member[2];
|
|
12845
|
-
const hit = lookup(scopeAt(scopes, offset), name);
|
|
12881
|
+
const hit = lookup(scopeAt(mod.scopes, offset), name);
|
|
12846
12882
|
if (!hit) return { arity: null, src: null, reason: "not-found" };
|
|
12847
|
-
return fromBinding(
|
|
12883
|
+
return fromBinding(mod, hit.binding, memberName, 0, /* @__PURE__ */ new Set());
|
|
12884
|
+
}
|
|
12885
|
+
};
|
|
12886
|
+
}
|
|
12887
|
+
|
|
12888
|
+
// src/plugin/free-identifiers.ts
|
|
12889
|
+
import { parseSync as parseSync3 } from "oxc-parser";
|
|
12890
|
+
var isNode = (v2) => typeof v2 === "object" && v2 !== null && typeof v2.type === "string";
|
|
12891
|
+
var TYPE_KEYS = /* @__PURE__ */ new Set([
|
|
12892
|
+
"typeAnnotation",
|
|
12893
|
+
"returnType",
|
|
12894
|
+
"typeParameters",
|
|
12895
|
+
"typeArguments",
|
|
12896
|
+
"superTypeArguments",
|
|
12897
|
+
"typeName",
|
|
12898
|
+
"implements",
|
|
12899
|
+
"extends",
|
|
12900
|
+
"accessibility"
|
|
12901
|
+
]);
|
|
12902
|
+
var TS_VALUE_WRAPPERS = /* @__PURE__ */ new Set([
|
|
12903
|
+
"TSAsExpression",
|
|
12904
|
+
"TSSatisfiesExpression",
|
|
12905
|
+
"TSNonNullExpression",
|
|
12906
|
+
"TSInstantiationExpression",
|
|
12907
|
+
"TSTypeAssertion"
|
|
12908
|
+
]);
|
|
12909
|
+
var HOST_GLOBALS = /* @__PURE__ */ new Set([
|
|
12910
|
+
...Object.getOwnPropertyNames(globalThis),
|
|
12911
|
+
"undefined",
|
|
12912
|
+
"NaN",
|
|
12913
|
+
"Infinity",
|
|
12914
|
+
"globalThis",
|
|
12915
|
+
"arguments",
|
|
12916
|
+
"window",
|
|
12917
|
+
"document",
|
|
12918
|
+
"self",
|
|
12919
|
+
"navigator",
|
|
12920
|
+
"location",
|
|
12921
|
+
"top",
|
|
12922
|
+
"parent",
|
|
12923
|
+
"require",
|
|
12924
|
+
"module",
|
|
12925
|
+
"exports",
|
|
12926
|
+
"__dirname",
|
|
12927
|
+
"__filename"
|
|
12928
|
+
]);
|
|
12929
|
+
function bindPattern(pattern, out) {
|
|
12930
|
+
if (!isNode(pattern)) return;
|
|
12931
|
+
switch (pattern.type) {
|
|
12932
|
+
case "Identifier":
|
|
12933
|
+
case "BindingIdentifier":
|
|
12934
|
+
out.add(String(pattern.name));
|
|
12935
|
+
return;
|
|
12936
|
+
case "ObjectPattern":
|
|
12937
|
+
for (const prop of pattern.properties ?? []) {
|
|
12938
|
+
if (!isNode(prop)) continue;
|
|
12939
|
+
if (prop.type === "RestElement" || prop.type === "BindingRestElement") bindPattern(prop.argument, out);
|
|
12940
|
+
else bindPattern(prop.value, out);
|
|
12941
|
+
}
|
|
12942
|
+
return;
|
|
12943
|
+
case "ArrayPattern":
|
|
12944
|
+
for (const el of pattern.elements ?? []) bindPattern(el, out);
|
|
12945
|
+
return;
|
|
12946
|
+
case "AssignmentPattern":
|
|
12947
|
+
bindPattern(pattern.left, out);
|
|
12948
|
+
return;
|
|
12949
|
+
case "RestElement":
|
|
12950
|
+
case "BindingRestElement":
|
|
12951
|
+
bindPattern(pattern.argument, out);
|
|
12952
|
+
return;
|
|
12953
|
+
case "TSParameterProperty":
|
|
12954
|
+
bindPattern(pattern.parameter, out);
|
|
12955
|
+
return;
|
|
12956
|
+
default:
|
|
12957
|
+
return;
|
|
12958
|
+
}
|
|
12959
|
+
}
|
|
12960
|
+
function collectBindings(node2, out) {
|
|
12961
|
+
if (Array.isArray(node2)) {
|
|
12962
|
+
for (const child of node2) collectBindings(child, out);
|
|
12963
|
+
return;
|
|
12964
|
+
}
|
|
12965
|
+
if (!isNode(node2)) return;
|
|
12966
|
+
switch (node2.type) {
|
|
12967
|
+
case "ImportSpecifier":
|
|
12968
|
+
case "ImportDefaultSpecifier":
|
|
12969
|
+
case "ImportNamespaceSpecifier":
|
|
12970
|
+
if (isNode(node2.local)) out.add(String(node2.local.name));
|
|
12971
|
+
break;
|
|
12972
|
+
case "VariableDeclarator":
|
|
12973
|
+
bindPattern(node2.id, out);
|
|
12974
|
+
break;
|
|
12975
|
+
case "FunctionDeclaration":
|
|
12976
|
+
case "FunctionExpression":
|
|
12977
|
+
case "TSDeclareFunction":
|
|
12978
|
+
case "ArrowFunctionExpression":
|
|
12979
|
+
if (isNode(node2.id)) out.add(String(node2.id.name));
|
|
12980
|
+
for (const p of node2.params?.items ?? node2.params ?? []) bindPattern(p, out);
|
|
12981
|
+
if (isNode(node2.params) && node2.params.rest) bindPattern(node2.params.rest, out);
|
|
12982
|
+
break;
|
|
12983
|
+
case "ClassDeclaration":
|
|
12984
|
+
case "ClassExpression":
|
|
12985
|
+
if (isNode(node2.id)) out.add(String(node2.id.name));
|
|
12986
|
+
break;
|
|
12987
|
+
case "CatchClause":
|
|
12988
|
+
if (node2.param) {
|
|
12989
|
+
bindPattern(isNode(node2.param) && node2.param.pattern ? node2.param.pattern : node2.param, out);
|
|
12990
|
+
}
|
|
12991
|
+
break;
|
|
12992
|
+
default:
|
|
12993
|
+
break;
|
|
12994
|
+
}
|
|
12995
|
+
for (const key of Object.keys(node2)) {
|
|
12996
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
12997
|
+
collectBindings(node2[key], out);
|
|
12998
|
+
}
|
|
12999
|
+
}
|
|
13000
|
+
var FUNCTION_TYPES2 = /* @__PURE__ */ new Set(["ArrowFunctionExpression", "FunctionExpression", "FunctionDeclaration"]);
|
|
13001
|
+
function describeTopLevel(stmt) {
|
|
13002
|
+
const declared = /* @__PURE__ */ new Set();
|
|
13003
|
+
let target = stmt;
|
|
13004
|
+
let prefix = "";
|
|
13005
|
+
let exported = false;
|
|
13006
|
+
if (stmt.type === "ExportNamedDeclaration" || stmt.type === "ExportDefaultDeclaration") {
|
|
13007
|
+
exported = true;
|
|
13008
|
+
prefix = "export ";
|
|
13009
|
+
if (!isNode(stmt.declaration)) return { declared, exported, declaresOnlyFunctions: false, label: `${prefix}{ \u2026 }` };
|
|
13010
|
+
target = stmt.declaration;
|
|
13011
|
+
}
|
|
13012
|
+
if (target.type === "VariableDeclaration") {
|
|
13013
|
+
const decls = (target.declarations ?? []).filter(isNode);
|
|
13014
|
+
for (const d of decls) bindPattern(d.id, declared);
|
|
13015
|
+
const declaresOnlyFunctions = decls.length > 0 && decls.every((d) => isNode(d.init) && FUNCTION_TYPES2.has(d.init.type));
|
|
13016
|
+
const name = [...declared][0];
|
|
13017
|
+
return {
|
|
13018
|
+
declared,
|
|
13019
|
+
exported,
|
|
13020
|
+
declaresOnlyFunctions,
|
|
13021
|
+
label: name ? `${prefix}${String(target.kind)} ${name}` : null
|
|
13022
|
+
};
|
|
13023
|
+
}
|
|
13024
|
+
if (target.type === "FunctionDeclaration" && isNode(target.id)) {
|
|
13025
|
+
declared.add(String(target.id.name));
|
|
13026
|
+
return { declared, exported, declaresOnlyFunctions: true, label: `${prefix}function ${String(target.id.name)}` };
|
|
13027
|
+
}
|
|
13028
|
+
if (target.type === "ClassDeclaration" && isNode(target.id)) {
|
|
13029
|
+
declared.add(String(target.id.name));
|
|
13030
|
+
return { declared, exported, declaresOnlyFunctions: false, label: `${prefix}class ${String(target.id.name)}` };
|
|
13031
|
+
}
|
|
13032
|
+
return { declared, exported, declaresOnlyFunctions: false, label: null };
|
|
13033
|
+
}
|
|
13034
|
+
function findFreeIdentifiers(code, filename) {
|
|
13035
|
+
let parsed;
|
|
13036
|
+
try {
|
|
13037
|
+
parsed = parseSync3(filename, code);
|
|
13038
|
+
} catch {
|
|
13039
|
+
return [];
|
|
13040
|
+
}
|
|
13041
|
+
if (parsed.errors.length > 0) return [];
|
|
13042
|
+
const bound = /* @__PURE__ */ new Set();
|
|
13043
|
+
collectBindings(parsed.program.body, bound);
|
|
13044
|
+
const lineStarts = [0];
|
|
13045
|
+
for (let i = 0; i < code.length; i++) if (code.charCodeAt(i) === 10) lineStarts.push(i + 1);
|
|
13046
|
+
const positionOf = (offset) => {
|
|
13047
|
+
let lo = 0;
|
|
13048
|
+
let hi = lineStarts.length - 1;
|
|
13049
|
+
while (lo < hi) {
|
|
13050
|
+
const mid = lo + hi + 1 >> 1;
|
|
13051
|
+
if (lineStarts[mid] <= offset) lo = mid;
|
|
13052
|
+
else hi = mid - 1;
|
|
13053
|
+
}
|
|
13054
|
+
return { line: lo + 1, column: offset - lineStarts[lo] + 1 };
|
|
13055
|
+
};
|
|
13056
|
+
const statements = parsed.program.body.filter(isNode);
|
|
13057
|
+
const tops = statements.map(describeTopLevel);
|
|
13058
|
+
const candidates = [];
|
|
13059
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13060
|
+
const readIn = /* @__PURE__ */ new Map();
|
|
13061
|
+
const visit = (node2, stmt, insideFunction) => {
|
|
13062
|
+
if (Array.isArray(node2)) {
|
|
13063
|
+
for (const child of node2) visit(child, stmt, insideFunction);
|
|
13064
|
+
return;
|
|
13065
|
+
}
|
|
13066
|
+
if (!isNode(node2)) return;
|
|
13067
|
+
const type = node2.type;
|
|
13068
|
+
if (type === "ImportDeclaration" || type === "ExportAllDeclaration") return;
|
|
13069
|
+
if (type === "MetaProperty" || type === "PrivateIdentifier") return;
|
|
13070
|
+
if (type === "ExportNamedDeclaration" && node2.source) return;
|
|
13071
|
+
if (type.startsWith("TS")) {
|
|
13072
|
+
if (TS_VALUE_WRAPPERS.has(type)) visit(node2.expression, stmt, insideFunction);
|
|
13073
|
+
return;
|
|
13074
|
+
}
|
|
13075
|
+
if (type === "Identifier" || type === "IdentifierReference") {
|
|
13076
|
+
const name = String(node2.name);
|
|
13077
|
+
let readers = readIn.get(name);
|
|
13078
|
+
if (!readers) readIn.set(name, readers = /* @__PURE__ */ new Set());
|
|
13079
|
+
readers.add(stmt);
|
|
13080
|
+
if (bound.has(name) || HOST_GLOBALS.has(name)) return;
|
|
13081
|
+
const offset = typeof node2.start === "number" ? node2.start : 0;
|
|
13082
|
+
const { line, column } = positionOf(offset);
|
|
13083
|
+
const key = `${name}@${line}:${column}`;
|
|
13084
|
+
if (seen.has(key)) return;
|
|
13085
|
+
seen.add(key);
|
|
13086
|
+
candidates.push({ name, line, column, enclosing: tops[stmt].label, stmt, insideFunction });
|
|
13087
|
+
return;
|
|
13088
|
+
}
|
|
13089
|
+
const nowInsideFunction = insideFunction || FUNCTION_TYPES2.has(type);
|
|
13090
|
+
for (const key of Object.keys(node2)) {
|
|
13091
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
13092
|
+
if (TYPE_KEYS.has(key)) continue;
|
|
13093
|
+
if (key === "key" && node2.computed !== true) continue;
|
|
13094
|
+
if (key === "property" && node2.computed !== true) continue;
|
|
13095
|
+
if (key === "label") continue;
|
|
13096
|
+
if (key === "exported") continue;
|
|
13097
|
+
if (key === "imported") continue;
|
|
13098
|
+
visit(node2[key], stmt, nowInsideFunction);
|
|
13099
|
+
}
|
|
13100
|
+
};
|
|
13101
|
+
for (let i = 0; i < statements.length; i++) visit(statements[i], i, false);
|
|
13102
|
+
return candidates.filter((c) => {
|
|
13103
|
+
const top = tops[c.stmt];
|
|
13104
|
+
if (!c.insideFunction || top.exported || !top.declaresOnlyFunctions || top.declared.size === 0) return true;
|
|
13105
|
+
for (const name of top.declared) {
|
|
13106
|
+
const readers = readIn.get(name);
|
|
13107
|
+
if (readers && [...readers].some((i) => i !== c.stmt)) return true;
|
|
13108
|
+
}
|
|
13109
|
+
return false;
|
|
13110
|
+
}).map(({ name, line, column, enclosing }) => ({ name, line, column, enclosing }));
|
|
13111
|
+
}
|
|
13112
|
+
|
|
13113
|
+
// src/compiler/module-hoist.ts
|
|
13114
|
+
var marker = (id) => `/*@pmh:${id}@*/`;
|
|
13115
|
+
var MARKER_RE = /\/\*@pmh:(\d+)@\*\/\n?/g;
|
|
13116
|
+
var HOIST_MARKER_PROBE = /\/\*@pmh:\d+@\*\//;
|
|
13117
|
+
var DECL_RE = /^(?:const|let|var|function\*?)\s+([A-Za-z_$][\w$]*)/;
|
|
13118
|
+
var ALWAYS_LOCAL = /* @__PURE__ */ new Set(["_map", "_k", "_env"]);
|
|
13119
|
+
function declaredNames(text) {
|
|
13120
|
+
const out = [];
|
|
13121
|
+
for (const line of text.split("\n")) {
|
|
13122
|
+
const m = DECL_RE.exec(line);
|
|
13123
|
+
if (m) out.push(m[1]);
|
|
13124
|
+
}
|
|
13125
|
+
return out;
|
|
13126
|
+
}
|
|
13127
|
+
function createModuleHoist() {
|
|
13128
|
+
const texts = [];
|
|
13129
|
+
const claim = (decls) => decls.map((text) => {
|
|
13130
|
+
const id = texts.length;
|
|
13131
|
+
texts.push(text);
|
|
13132
|
+
return marker(id);
|
|
13133
|
+
});
|
|
13134
|
+
const finalize = () => {
|
|
13135
|
+
const nameTexts = /* @__PURE__ */ new Map();
|
|
13136
|
+
const textCount = /* @__PURE__ */ new Map();
|
|
13137
|
+
const textNames = /* @__PURE__ */ new Map();
|
|
13138
|
+
const order = [];
|
|
13139
|
+
for (const text of texts) {
|
|
13140
|
+
const seen = textCount.get(text);
|
|
13141
|
+
textCount.set(text, (seen ?? 0) + 1);
|
|
13142
|
+
if (seen === void 0) {
|
|
13143
|
+
order.push(text);
|
|
13144
|
+
const names = declaredNames(text);
|
|
13145
|
+
textNames.set(text, names);
|
|
13146
|
+
for (const n of names) {
|
|
13147
|
+
const s = nameTexts.get(n);
|
|
13148
|
+
if (s) s.add(text);
|
|
13149
|
+
else nameTexts.set(n, /* @__PURE__ */ new Set([text]));
|
|
13150
|
+
}
|
|
13151
|
+
}
|
|
13152
|
+
}
|
|
13153
|
+
const hoisted = new Set(
|
|
13154
|
+
order.filter(
|
|
13155
|
+
(text) => (textCount.get(text) ?? 0) >= 2 && textNames.get(text).length > 0 && textNames.get(text).every((n) => !ALWAYS_LOCAL.has(n) && nameTexts.get(n).size === 1)
|
|
13156
|
+
)
|
|
13157
|
+
);
|
|
13158
|
+
for (; ; ) {
|
|
13159
|
+
const localNames = [];
|
|
13160
|
+
for (const [n, ts] of nameTexts) {
|
|
13161
|
+
if (ts.size !== 1 || !hoisted.has([...ts][0])) localNames.push(n);
|
|
13162
|
+
}
|
|
13163
|
+
let changed = false;
|
|
13164
|
+
for (const text of [...hoisted]) {
|
|
13165
|
+
if (localNames.some((n) => new RegExp(`\\b${escapeName(n)}\\b`).test(text))) {
|
|
13166
|
+
hoisted.delete(text);
|
|
13167
|
+
changed = true;
|
|
13168
|
+
}
|
|
13169
|
+
}
|
|
13170
|
+
if (!changed) break;
|
|
12848
13171
|
}
|
|
13172
|
+
const preludeTexts = order.filter((t) => hoisted.has(t));
|
|
13173
|
+
const prelude = preludeTexts.length === 0 ? "" : `${preludeTexts.join("\n")}
|
|
13174
|
+
`;
|
|
13175
|
+
const removed = texts.reduce((n, t) => hoisted.has(t) ? n + t.length + 1 : n, 0);
|
|
13176
|
+
return {
|
|
13177
|
+
prelude,
|
|
13178
|
+
savedBytes: removed - prelude.length,
|
|
13179
|
+
hoistedNames: preludeTexts.flatMap((t) => textNames.get(t)),
|
|
13180
|
+
resolve: (src) => src.replace(MARKER_RE, (m, idStr) => {
|
|
13181
|
+
const text = texts[Number(idStr)];
|
|
13182
|
+
if (text === void 0) throw new Error(`parseman: unknown hoist marker ${m}`);
|
|
13183
|
+
if (hoisted.has(text)) return "";
|
|
13184
|
+
return m.endsWith("\n") ? `${text}
|
|
13185
|
+
` : text;
|
|
13186
|
+
})
|
|
13187
|
+
};
|
|
12849
13188
|
};
|
|
13189
|
+
return { claim, finalize };
|
|
13190
|
+
}
|
|
13191
|
+
function escapeName(n) {
|
|
13192
|
+
return n.replace(/\$/g, "\\$");
|
|
12850
13193
|
}
|
|
12851
13194
|
|
|
12852
13195
|
// src/plugin/index.ts
|
|
@@ -12942,7 +13285,7 @@ function parseModuleCached(filePath) {
|
|
|
12942
13285
|
let parsed = null;
|
|
12943
13286
|
try {
|
|
12944
13287
|
const src = fs2.readFileSync(filePath, "utf8");
|
|
12945
|
-
const r =
|
|
13288
|
+
const r = parseSync4(filePath, src);
|
|
12946
13289
|
if (r.errors.length === 0) parsed = { body: r.program.body, src };
|
|
12947
13290
|
} catch {
|
|
12948
13291
|
}
|
|
@@ -13083,7 +13426,7 @@ function lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recov
|
|
|
13083
13426
|
const source = fs2.readFileSync(file, "utf8");
|
|
13084
13427
|
const transformed = transformMacro(source, file, moduleAliases, warnUnloweredRegex, recovery);
|
|
13085
13428
|
if (!transformed || transformed.warnings.length > 0) return null;
|
|
13086
|
-
const parsed =
|
|
13429
|
+
const parsed = parseSync4(file, transformed.code);
|
|
13087
13430
|
parsedModule = parsed.errors.length === 0 ? { body: parsed.program.body, src: transformed.code } : null;
|
|
13088
13431
|
return parsedModule;
|
|
13089
13432
|
} catch {
|
|
@@ -13107,7 +13450,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13107
13450
|
function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recovery, grammarCoverage) {
|
|
13108
13451
|
let result;
|
|
13109
13452
|
try {
|
|
13110
|
-
result =
|
|
13453
|
+
result = parseSync4(id, code);
|
|
13111
13454
|
} catch {
|
|
13112
13455
|
return null;
|
|
13113
13456
|
}
|
|
@@ -13164,7 +13507,8 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13164
13507
|
}
|
|
13165
13508
|
}
|
|
13166
13509
|
}
|
|
13167
|
-
|
|
13510
|
+
const reducerResolver = createReducerResolver(id, body, code);
|
|
13511
|
+
setReducerResolver(reducerResolver, code);
|
|
13168
13512
|
const topLevelFunction = (moduleBody, name) => {
|
|
13169
13513
|
for (const st of moduleBody) {
|
|
13170
13514
|
const decl = st.type === "ExportNamedDeclaration" ? st.declaration : st;
|
|
@@ -13259,15 +13603,18 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13259
13603
|
scope: factoryScope,
|
|
13260
13604
|
imported: true
|
|
13261
13605
|
});
|
|
13606
|
+
reducerResolver.register(file);
|
|
13262
13607
|
}
|
|
13263
13608
|
const scope = /* @__PURE__ */ new Map();
|
|
13264
13609
|
const replacements = [];
|
|
13265
13610
|
const warnings = [];
|
|
13611
|
+
const moduleHoist = grammarCoverage ? void 0 : createModuleHoist();
|
|
13266
13612
|
beginLoweringCapture();
|
|
13267
13613
|
beginInlineCapCapture();
|
|
13268
13614
|
beginDegradationCapture();
|
|
13269
13615
|
let anyUnresolved = false;
|
|
13270
13616
|
let keepMacroImport = false;
|
|
13617
|
+
const exportedFactories = [];
|
|
13271
13618
|
let runtimeComposeFallback = false;
|
|
13272
13619
|
let ruleMapHolderCounter = 0;
|
|
13273
13620
|
const lineOf = (pos) => {
|
|
@@ -13626,7 +13973,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13626
13973
|
const pieces = materializeCarried(carried, composing, false, cHostMode);
|
|
13627
13974
|
try {
|
|
13628
13975
|
return {
|
|
13629
|
-
replacement: emitFusedSource(pieces),
|
|
13976
|
+
replacement: emitFusedSource(pieces, moduleHoist),
|
|
13630
13977
|
carried,
|
|
13631
13978
|
...composing ? { trivia: composing } : {},
|
|
13632
13979
|
...importedFactories.length ? { importedFactories } : {}
|
|
@@ -13694,7 +14041,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13694
14041
|
warn(init.start, "composeLeaf(): every pre-final grammar must explicitly prove recognition-only");
|
|
13695
14042
|
return null;
|
|
13696
14043
|
}
|
|
13697
|
-
const replacement = withLeafMarker(emitFusedSource(grammarCoverage ? recognitionPieces : [...recognitionPieces, plainLocalPiece]));
|
|
14044
|
+
const replacement = withLeafMarker(emitFusedSource(grammarCoverage ? recognitionPieces : [...recognitionPieces, plainLocalPiece], moduleHoist));
|
|
13698
14045
|
return {
|
|
13699
14046
|
replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement, `${id} composeLeaf()`)),
|
|
13700
14047
|
...importedFactories.length ? { importedFactories } : {}
|
|
@@ -13879,7 +14226,10 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13879
14226
|
scope.set(varName, staticValue);
|
|
13880
14227
|
continue;
|
|
13881
14228
|
}
|
|
13882
|
-
if (factoryDecls.has(varName))
|
|
14229
|
+
if (factoryDecls.has(varName)) {
|
|
14230
|
+
if (exportPrefix) exportedFactories.push({ name: varName, pos: init.start });
|
|
14231
|
+
continue;
|
|
14232
|
+
}
|
|
13883
14233
|
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
13884
14234
|
continue;
|
|
13885
14235
|
}
|
|
@@ -13950,6 +14300,14 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13950
14300
|
for (const imp of macroImports) {
|
|
13951
14301
|
imp.fullyResolved = !anyUnresolved && !keepMacroImport;
|
|
13952
14302
|
}
|
|
14303
|
+
if (exportedFactories.length > 0 && macroImports.some((imp) => imp.fullyResolved)) {
|
|
14304
|
+
const which = exportedFactories.map((f) => ` - ${id}:${lineOf(f.pos)} \u2014 export const ${f.name}`).join("\n");
|
|
14305
|
+
throw new Error(
|
|
14306
|
+
`${id} \u2014 a rules() factory cannot be exported; lowering leaves its body verbatim, so the export would ship a binding that throws ReferenceError on first call:
|
|
14307
|
+
${which}
|
|
14308
|
+
Drop the \`export\`. The factory is macro-only; \`rules(${exportedFactories[0].name})\` is lowered in place and needs no runtime value.`
|
|
14309
|
+
);
|
|
14310
|
+
}
|
|
13953
14311
|
const ms = new MagicString(code);
|
|
13954
14312
|
const replacementRanges = runtimeComposeFallback ? [] : replacements.map(({ start, end }) => ({ start, end }));
|
|
13955
14313
|
const isInsideReplacement = (start, end) => replacementRanges.some((r) => start >= r.start && end <= r.end);
|
|
@@ -13998,8 +14356,21 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13998
14356
|
}
|
|
13999
14357
|
}
|
|
14000
14358
|
const applied = runtimeComposeFallback ? [] : replacements;
|
|
14359
|
+
const hoisted = applied.length > 0 ? moduleHoist?.finalize() : void 0;
|
|
14001
14360
|
for (const { start, end, replacement } of applied.slice().sort((a, b) => b.start - a.start)) {
|
|
14002
|
-
ms.overwrite(start, end, replacement);
|
|
14361
|
+
ms.overwrite(start, end, hoisted ? hoisted.resolve(replacement) : replacement);
|
|
14362
|
+
}
|
|
14363
|
+
if (hoisted !== void 0 && hoisted.prelude !== "") {
|
|
14364
|
+
const claiming = applied.filter((r) => HOIST_MARKER_PROBE.test(r.replacement));
|
|
14365
|
+
if (claiming.length === 0) {
|
|
14366
|
+
throw new Error(`${id} \u2014 internal: a module-hoist prelude was produced but no applied replacement carries a hoist marker`);
|
|
14367
|
+
}
|
|
14368
|
+
const firstStart = Math.min(...claiming.map((r) => r.start));
|
|
14369
|
+
const anchor = body.find((s) => s.start <= firstStart && firstStart < s.end);
|
|
14370
|
+
if (anchor === void 0) {
|
|
14371
|
+
throw new Error(`${id} \u2014 internal: no top-level statement encloses macro replacement at ${firstStart}`);
|
|
14372
|
+
}
|
|
14373
|
+
ms.appendLeft(anchor.start, hoisted.prelude);
|
|
14003
14374
|
}
|
|
14004
14375
|
if (applied.length > 0) {
|
|
14005
14376
|
ms.prepend(
|
|
@@ -14009,6 +14380,21 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
14009
14380
|
`
|
|
14010
14381
|
);
|
|
14011
14382
|
}
|
|
14383
|
+
if (applied.length > 0) {
|
|
14384
|
+
let sourceFree = null;
|
|
14385
|
+
const freeInSource = () => sourceFree ??= new Set(findFreeIdentifiers(code, id).map((f) => f.name));
|
|
14386
|
+
const free = findFreeIdentifiers(ms.toString(), id).filter((f) => !freeInSource().has(f.name));
|
|
14387
|
+
if (free.length > 0) {
|
|
14388
|
+
const macroProvided = free.filter((f) => allNames.has(f.name));
|
|
14389
|
+
const where = (f) => ` - ${id}:${f.line}:${f.column} \u2014 \`${f.name}\`` + (f.enclosing ? `, inside \`${f.enclosing}\`` : "");
|
|
14390
|
+
const cause = macroProvided.length > 0 ? `
|
|
14391
|
+
${macroProvided.length === free.length ? "All" : `${macroProvided.length}`} of these came from the \`with { type: 'macro' }\` import, which was removed because every macro declaration lowered. Something still names them verbatim \u2014 a declaration parseman left as text rather than compiling. Make that declaration macro-buildable, or stop exporting it so lowering can drop it.` : "";
|
|
14392
|
+
throw new Error(
|
|
14393
|
+
`${id} \u2014 parseman will not emit this module: ${free.length} identifier(s) are read but bound by nothing, so it would throw ReferenceError at runtime (positions are in the EMITTED module):
|
|
14394
|
+
${free.map(where).join("\n")}${cause}`
|
|
14395
|
+
);
|
|
14396
|
+
}
|
|
14397
|
+
}
|
|
14012
14398
|
for (const line of formatInlineCapSites(endInlineCapCapture(), resolveInlineMax())) warnings.push(`${id}: ${line}`);
|
|
14013
14399
|
const unlowered = endLoweringCapture();
|
|
14014
14400
|
if (warnUnloweredRegex) {
|