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.cjs
CHANGED
|
@@ -37,7 +37,7 @@ module.exports = __toCommonJS(plugin_exports);
|
|
|
37
37
|
var fs2 = __toESM(require("node:fs"), 1);
|
|
38
38
|
var path2 = __toESM(require("node:path"), 1);
|
|
39
39
|
var import_unplugin = require("unplugin");
|
|
40
|
-
var
|
|
40
|
+
var import_oxc_parser4 = require("oxc-parser");
|
|
41
41
|
var import_oxc_resolver = require("oxc-resolver");
|
|
42
42
|
var import_magic_string = __toESM(require("magic-string"), 1);
|
|
43
43
|
|
|
@@ -1527,8 +1527,8 @@ function classifyTriviaArm(arm) {
|
|
|
1527
1527
|
}
|
|
1528
1528
|
const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
|
|
1529
1529
|
if (lc) {
|
|
1530
|
-
const
|
|
1531
|
-
return { kind: "untilLineBreak", code: (
|
|
1530
|
+
const marker2 = lc[1];
|
|
1531
|
+
return { kind: "untilLineBreak", code: (marker2.length === 2 ? marker2[1] : marker2[0]).charCodeAt(0) };
|
|
1532
1532
|
}
|
|
1533
1533
|
return null;
|
|
1534
1534
|
}
|
|
@@ -3426,7 +3426,8 @@ var RESOLVER_REASONS = {
|
|
|
3426
3426
|
"unresolved-import": "its module could not be resolved or parsed",
|
|
3427
3427
|
"not-found": "the name did not resolve to any binding",
|
|
3428
3428
|
"computed": "it is a computed expression",
|
|
3429
|
-
"foreign-source": "it is named
|
|
3429
|
+
"foreign-source": "it is named in a module the resolver was never told about, so its offsets index no scope tree the resolver holds",
|
|
3430
|
+
"ambiguous-source": "two distinct registered modules hold byte-identical text, so that text no longer names the module its offsets index"
|
|
3430
3431
|
};
|
|
3431
3432
|
function unconfirmableReason(def, src) {
|
|
3432
3433
|
const declared = def.buildArityUnresolved;
|
|
@@ -3955,7 +3956,7 @@ function leaf(root, fn) {
|
|
|
3955
3956
|
}
|
|
3956
3957
|
|
|
3957
3958
|
// src/version.ts
|
|
3958
|
-
var PARSEMAN_VERSION = "0.
|
|
3959
|
+
var PARSEMAN_VERSION = "0.46.0";
|
|
3959
3960
|
|
|
3960
3961
|
// src/cst/host-mode.ts
|
|
3961
3962
|
var FUSED_HOST_MODE = /* @__PURE__ */ Symbol.for("parseman.fusedHostMode");
|
|
@@ -5575,15 +5576,15 @@ function parseStringShape(source) {
|
|
|
5575
5576
|
if (source.length < 3 || source[source.length - 1] !== q) return null;
|
|
5576
5577
|
const inner = source.slice(1, -1);
|
|
5577
5578
|
const CLS = String.raw`\[\^((?:\\.|[^\]])+)\]`;
|
|
5578
|
-
const
|
|
5579
|
+
const ESC2 = String.raw`\\\\(\.|\[\\s\\S\]|\[\\S\\s\])`;
|
|
5579
5580
|
let body;
|
|
5580
5581
|
let esc;
|
|
5581
|
-
let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${
|
|
5582
|
+
let m = new RegExp(`^\\((?:\\?:)?${CLS}\\|${ESC2}\\)\\*$`).exec(inner);
|
|
5582
5583
|
if (m) {
|
|
5583
5584
|
body = m[1];
|
|
5584
5585
|
esc = m[2];
|
|
5585
5586
|
} else {
|
|
5586
|
-
m = new RegExp(`^\\((?:\\?:)?${
|
|
5587
|
+
m = new RegExp(`^\\((?:\\?:)?${ESC2}\\|${CLS}\\)\\*$`).exec(inner);
|
|
5587
5588
|
if (m) {
|
|
5588
5589
|
esc = m[1];
|
|
5589
5590
|
body = m[2];
|
|
@@ -11259,7 +11260,7 @@ function pickPieces(pieces, names) {
|
|
|
11259
11260
|
const filt = (m, pc) => new Map([...m].filter(([k]) => keep.has(k) && winner.get(k) === pc));
|
|
11260
11261
|
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);
|
|
11261
11262
|
}
|
|
11262
|
-
function fusedBody(pieces) {
|
|
11263
|
+
function fusedBody(pieces, hoist) {
|
|
11263
11264
|
for (const p of pieces) {
|
|
11264
11265
|
if (p.v === void 0) {
|
|
11265
11266
|
throw new Error(
|
|
@@ -11299,8 +11300,7 @@ function fusedBody(pieces) {
|
|
|
11299
11300
|
const wrapperEntries = [...winner].map(([k, p]) => `${JSON.stringify(k)}: ${p.wrappers.get(k)}`);
|
|
11300
11301
|
const reflection = mergeGrammarReflections([...winner].map(([k, p]) => p.nodeMeta.get(k) ?? { nodes: [] }));
|
|
11301
11302
|
const { mode, elided } = hostModeOfPieces(pieces);
|
|
11302
|
-
const
|
|
11303
|
-
...lines,
|
|
11303
|
+
const tailSrc = [
|
|
11304
11304
|
"const _map = {",
|
|
11305
11305
|
wrapperEntries.join(",\n"),
|
|
11306
11306
|
"}",
|
|
@@ -11316,6 +11316,7 @@ function fusedBody(pieces) {
|
|
|
11316
11316
|
"}",
|
|
11317
11317
|
"return _map"
|
|
11318
11318
|
].join("\n");
|
|
11319
|
+
const rawBody = [...lines, tailSrc].join("\n");
|
|
11319
11320
|
const ANY2 = { kind: "any" };
|
|
11320
11321
|
const EMPTY3 = { kind: "empty" };
|
|
11321
11322
|
const recipes = /* @__PURE__ */ new Map();
|
|
@@ -11356,7 +11357,7 @@ function fusedBody(pieces) {
|
|
|
11356
11357
|
}
|
|
11357
11358
|
if (!changed) break;
|
|
11358
11359
|
}
|
|
11359
|
-
const
|
|
11360
|
+
const resolveFS = (src) => src.replace(
|
|
11360
11361
|
// Rule name + code-point var are both JS identifiers (rule names are validated
|
|
11361
11362
|
// at compile time — see assertRuleName in codegen), so an identifier class
|
|
11362
11363
|
// matches every well-formed placeholder.
|
|
@@ -11367,6 +11368,7 @@ function fusedBody(pieces) {
|
|
|
11367
11368
|
return `(${firstSetCond(codevar, fs3)})`;
|
|
11368
11369
|
}
|
|
11369
11370
|
);
|
|
11371
|
+
const body = hoist === void 0 ? resolveFS(rawBody) : [...hoist.claim(lines.map(resolveFS)), resolveFS(tailSrc)].join("\n");
|
|
11370
11372
|
const env = {};
|
|
11371
11373
|
for (const p of contributingPieces) {
|
|
11372
11374
|
if (p.mfFns.length) env[`${p.ns}mf`] = p.mfFns;
|
|
@@ -11384,8 +11386,8 @@ function hostModeOfPieces(pieces) {
|
|
|
11384
11386
|
}
|
|
11385
11387
|
return { mode, elided: elided.length > 0 };
|
|
11386
11388
|
}
|
|
11387
|
-
function emitFusedSource(pieces) {
|
|
11388
|
-
const { body, env } = fusedBody(pieces);
|
|
11389
|
+
function emitFusedSource(pieces, hoist) {
|
|
11390
|
+
const { body, env } = fusedBody(pieces, hoist);
|
|
11389
11391
|
if (Object.keys(env).length > 0) {
|
|
11390
11392
|
throw new Error("emitFusedSource: artifact carries non-static callbacks (runtime-only); cannot emit static source");
|
|
11391
11393
|
}
|
|
@@ -11408,6 +11410,34 @@ function materializePiece(p, trivia2, captureTerminals = false, hostMode) {
|
|
|
11408
11410
|
return pieces;
|
|
11409
11411
|
}
|
|
11410
11412
|
|
|
11413
|
+
// src/functional/run.ts
|
|
11414
|
+
var SELECT_EXAMPLE = "run(entry, input, { rootTrivia: { select: ['blockComment', 'lineComment'] } })";
|
|
11415
|
+
var REMOVED_RUN_RESULT_FIELDS = [
|
|
11416
|
+
[
|
|
11417
|
+
"triviaMap",
|
|
11418
|
+
`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.`
|
|
11419
|
+
],
|
|
11420
|
+
[
|
|
11421
|
+
"triviaLog",
|
|
11422
|
+
`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.`
|
|
11423
|
+
],
|
|
11424
|
+
[
|
|
11425
|
+
"triviaKindLabels",
|
|
11426
|
+
`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\`.`
|
|
11427
|
+
]
|
|
11428
|
+
];
|
|
11429
|
+
|
|
11430
|
+
// src/analysis/choice-cost-render.ts
|
|
11431
|
+
var ESC = "\x1B";
|
|
11432
|
+
var ANSI = {
|
|
11433
|
+
dim: `${ESC}[2m`,
|
|
11434
|
+
bold: `${ESC}[1m`,
|
|
11435
|
+
red: `${ESC}[31m`,
|
|
11436
|
+
yellow: `${ESC}[33m`,
|
|
11437
|
+
cyan: `${ESC}[36m`,
|
|
11438
|
+
reset: `${ESC}[0m`
|
|
11439
|
+
};
|
|
11440
|
+
|
|
11411
11441
|
// src/combinators/gate.ts
|
|
11412
11442
|
function gate(predicate) {
|
|
11413
11443
|
const meta = {
|
|
@@ -11427,23 +11457,6 @@ function gate(predicate) {
|
|
|
11427
11457
|
};
|
|
11428
11458
|
}
|
|
11429
11459
|
|
|
11430
|
-
// src/functional/run.ts
|
|
11431
|
-
var SELECT_EXAMPLE = "run(entry, input, { rootTrivia: { select: ['blockComment', 'lineComment'] } })";
|
|
11432
|
-
var REMOVED_RUN_RESULT_FIELDS = [
|
|
11433
|
-
[
|
|
11434
|
-
"triviaMap",
|
|
11435
|
-
`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.`
|
|
11436
|
-
],
|
|
11437
|
-
[
|
|
11438
|
-
"triviaLog",
|
|
11439
|
-
`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.`
|
|
11440
|
-
],
|
|
11441
|
-
[
|
|
11442
|
-
"triviaKindLabels",
|
|
11443
|
-
`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\`.`
|
|
11444
|
-
]
|
|
11445
|
-
];
|
|
11446
|
-
|
|
11447
11460
|
// src/index.ts
|
|
11448
11461
|
registerRegexAnalyzer(firstSetFromRegex);
|
|
11449
11462
|
|
|
@@ -11637,8 +11650,10 @@ function stripTsFromSource(node2, code) {
|
|
|
11637
11650
|
return out + code.slice(cur, end);
|
|
11638
11651
|
}
|
|
11639
11652
|
var _reducers = null;
|
|
11640
|
-
|
|
11653
|
+
var _entrySource = null;
|
|
11654
|
+
function setReducerResolver(r, entrySource = null) {
|
|
11641
11655
|
_reducers = r;
|
|
11656
|
+
_entrySource = entrySource;
|
|
11642
11657
|
}
|
|
11643
11658
|
function isWordFactory(v2) {
|
|
11644
11659
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
@@ -12010,6 +12025,9 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
12010
12025
|
const resolved = _reducers?.resolve(buildSrc, be.start, code);
|
|
12011
12026
|
if (resolved) {
|
|
12012
12027
|
if (resolved.src !== null) combi._def.buildSigSrc = resolved.src;
|
|
12028
|
+
if (_entrySource !== null && code !== _entrySource && resolved.src !== null && be.type === "Identifier") {
|
|
12029
|
+
combi._def.buildSrc = resolved.src;
|
|
12030
|
+
}
|
|
12013
12031
|
if (combi._def.buildArity === void 0 && resolved.arity !== null) combi._def.buildArity = resolved.arity;
|
|
12014
12032
|
if (resolved.reason !== void 0) combi._def.buildArityUnresolved = resolved.reason;
|
|
12015
12033
|
}
|
|
@@ -12825,6 +12843,8 @@ function createReducerResolver(entryFile, body, src) {
|
|
|
12825
12843
|
const scopes = buildScopeTree(body, src.length);
|
|
12826
12844
|
markReassignments(body, scopes);
|
|
12827
12845
|
const entry = { file: entryFile, src, body, scopes };
|
|
12846
|
+
const registered = /* @__PURE__ */ new Map();
|
|
12847
|
+
const ambiguous = /* @__PURE__ */ new Set();
|
|
12828
12848
|
const fromBinding = (mod, binding, memberName, hops, seen) => {
|
|
12829
12849
|
if (hops > MAX_HOPS) return { arity: null, src: null, reason: "not-found" };
|
|
12830
12850
|
if (binding.reassigned) return { arity: null, src: null, reason: "reassigned" };
|
|
@@ -12869,19 +12889,342 @@ function createReducerResolver(entryFile, body, src) {
|
|
|
12869
12889
|
return { arity, src: mod.src.slice(init.start, init.end), ...reason ? { reason } : {} };
|
|
12870
12890
|
};
|
|
12871
12891
|
return {
|
|
12892
|
+
register(file) {
|
|
12893
|
+
const mod = analyseModuleFile(file);
|
|
12894
|
+
if (!mod) return false;
|
|
12895
|
+
if (mod.src === src) return true;
|
|
12896
|
+
const prior = registered.get(mod.src);
|
|
12897
|
+
if (prior !== void 0 && prior.file !== mod.file) {
|
|
12898
|
+
ambiguous.add(mod.src);
|
|
12899
|
+
registered.delete(mod.src);
|
|
12900
|
+
return false;
|
|
12901
|
+
}
|
|
12902
|
+
if (!ambiguous.has(mod.src)) registered.set(mod.src, mod);
|
|
12903
|
+
return !ambiguous.has(mod.src);
|
|
12904
|
+
},
|
|
12872
12905
|
resolve(exprSrc, offset, offsetSrc) {
|
|
12873
12906
|
const text = exprSrc.trim();
|
|
12874
12907
|
const ident = IDENT_RE.test(text) ? text : null;
|
|
12875
12908
|
const member = ident ? null : MEMBER_RE.exec(text);
|
|
12876
12909
|
if (!ident && !member) return null;
|
|
12877
|
-
|
|
12910
|
+
const mod = offsetSrc === src ? entry : registered.get(offsetSrc);
|
|
12911
|
+
if (!mod) {
|
|
12912
|
+
return { arity: null, src: null, reason: ambiguous.has(offsetSrc) ? "ambiguous-source" : "foreign-source" };
|
|
12913
|
+
}
|
|
12878
12914
|
const name = ident ?? member[1];
|
|
12879
12915
|
const memberName = ident ? void 0 : member[2];
|
|
12880
|
-
const hit = lookup(scopeAt(scopes, offset), name);
|
|
12916
|
+
const hit = lookup(scopeAt(mod.scopes, offset), name);
|
|
12881
12917
|
if (!hit) return { arity: null, src: null, reason: "not-found" };
|
|
12882
|
-
return fromBinding(
|
|
12918
|
+
return fromBinding(mod, hit.binding, memberName, 0, /* @__PURE__ */ new Set());
|
|
12919
|
+
}
|
|
12920
|
+
};
|
|
12921
|
+
}
|
|
12922
|
+
|
|
12923
|
+
// src/plugin/free-identifiers.ts
|
|
12924
|
+
var import_oxc_parser3 = require("oxc-parser");
|
|
12925
|
+
var isNode = (v2) => typeof v2 === "object" && v2 !== null && typeof v2.type === "string";
|
|
12926
|
+
var TYPE_KEYS = /* @__PURE__ */ new Set([
|
|
12927
|
+
"typeAnnotation",
|
|
12928
|
+
"returnType",
|
|
12929
|
+
"typeParameters",
|
|
12930
|
+
"typeArguments",
|
|
12931
|
+
"superTypeArguments",
|
|
12932
|
+
"typeName",
|
|
12933
|
+
"implements",
|
|
12934
|
+
"extends",
|
|
12935
|
+
"accessibility"
|
|
12936
|
+
]);
|
|
12937
|
+
var TS_VALUE_WRAPPERS = /* @__PURE__ */ new Set([
|
|
12938
|
+
"TSAsExpression",
|
|
12939
|
+
"TSSatisfiesExpression",
|
|
12940
|
+
"TSNonNullExpression",
|
|
12941
|
+
"TSInstantiationExpression",
|
|
12942
|
+
"TSTypeAssertion"
|
|
12943
|
+
]);
|
|
12944
|
+
var HOST_GLOBALS = /* @__PURE__ */ new Set([
|
|
12945
|
+
...Object.getOwnPropertyNames(globalThis),
|
|
12946
|
+
"undefined",
|
|
12947
|
+
"NaN",
|
|
12948
|
+
"Infinity",
|
|
12949
|
+
"globalThis",
|
|
12950
|
+
"arguments",
|
|
12951
|
+
"window",
|
|
12952
|
+
"document",
|
|
12953
|
+
"self",
|
|
12954
|
+
"navigator",
|
|
12955
|
+
"location",
|
|
12956
|
+
"top",
|
|
12957
|
+
"parent",
|
|
12958
|
+
"require",
|
|
12959
|
+
"module",
|
|
12960
|
+
"exports",
|
|
12961
|
+
"__dirname",
|
|
12962
|
+
"__filename"
|
|
12963
|
+
]);
|
|
12964
|
+
function bindPattern(pattern, out) {
|
|
12965
|
+
if (!isNode(pattern)) return;
|
|
12966
|
+
switch (pattern.type) {
|
|
12967
|
+
case "Identifier":
|
|
12968
|
+
case "BindingIdentifier":
|
|
12969
|
+
out.add(String(pattern.name));
|
|
12970
|
+
return;
|
|
12971
|
+
case "ObjectPattern":
|
|
12972
|
+
for (const prop of pattern.properties ?? []) {
|
|
12973
|
+
if (!isNode(prop)) continue;
|
|
12974
|
+
if (prop.type === "RestElement" || prop.type === "BindingRestElement") bindPattern(prop.argument, out);
|
|
12975
|
+
else bindPattern(prop.value, out);
|
|
12976
|
+
}
|
|
12977
|
+
return;
|
|
12978
|
+
case "ArrayPattern":
|
|
12979
|
+
for (const el of pattern.elements ?? []) bindPattern(el, out);
|
|
12980
|
+
return;
|
|
12981
|
+
case "AssignmentPattern":
|
|
12982
|
+
bindPattern(pattern.left, out);
|
|
12983
|
+
return;
|
|
12984
|
+
case "RestElement":
|
|
12985
|
+
case "BindingRestElement":
|
|
12986
|
+
bindPattern(pattern.argument, out);
|
|
12987
|
+
return;
|
|
12988
|
+
case "TSParameterProperty":
|
|
12989
|
+
bindPattern(pattern.parameter, out);
|
|
12990
|
+
return;
|
|
12991
|
+
default:
|
|
12992
|
+
return;
|
|
12993
|
+
}
|
|
12994
|
+
}
|
|
12995
|
+
function collectBindings(node2, out) {
|
|
12996
|
+
if (Array.isArray(node2)) {
|
|
12997
|
+
for (const child of node2) collectBindings(child, out);
|
|
12998
|
+
return;
|
|
12999
|
+
}
|
|
13000
|
+
if (!isNode(node2)) return;
|
|
13001
|
+
switch (node2.type) {
|
|
13002
|
+
case "ImportSpecifier":
|
|
13003
|
+
case "ImportDefaultSpecifier":
|
|
13004
|
+
case "ImportNamespaceSpecifier":
|
|
13005
|
+
if (isNode(node2.local)) out.add(String(node2.local.name));
|
|
13006
|
+
break;
|
|
13007
|
+
case "VariableDeclarator":
|
|
13008
|
+
bindPattern(node2.id, out);
|
|
13009
|
+
break;
|
|
13010
|
+
case "FunctionDeclaration":
|
|
13011
|
+
case "FunctionExpression":
|
|
13012
|
+
case "TSDeclareFunction":
|
|
13013
|
+
case "ArrowFunctionExpression":
|
|
13014
|
+
if (isNode(node2.id)) out.add(String(node2.id.name));
|
|
13015
|
+
for (const p of node2.params?.items ?? node2.params ?? []) bindPattern(p, out);
|
|
13016
|
+
if (isNode(node2.params) && node2.params.rest) bindPattern(node2.params.rest, out);
|
|
13017
|
+
break;
|
|
13018
|
+
case "ClassDeclaration":
|
|
13019
|
+
case "ClassExpression":
|
|
13020
|
+
if (isNode(node2.id)) out.add(String(node2.id.name));
|
|
13021
|
+
break;
|
|
13022
|
+
case "CatchClause":
|
|
13023
|
+
if (node2.param) {
|
|
13024
|
+
bindPattern(isNode(node2.param) && node2.param.pattern ? node2.param.pattern : node2.param, out);
|
|
13025
|
+
}
|
|
13026
|
+
break;
|
|
13027
|
+
default:
|
|
13028
|
+
break;
|
|
13029
|
+
}
|
|
13030
|
+
for (const key of Object.keys(node2)) {
|
|
13031
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
13032
|
+
collectBindings(node2[key], out);
|
|
13033
|
+
}
|
|
13034
|
+
}
|
|
13035
|
+
var FUNCTION_TYPES2 = /* @__PURE__ */ new Set(["ArrowFunctionExpression", "FunctionExpression", "FunctionDeclaration"]);
|
|
13036
|
+
function describeTopLevel(stmt) {
|
|
13037
|
+
const declared = /* @__PURE__ */ new Set();
|
|
13038
|
+
let target = stmt;
|
|
13039
|
+
let prefix = "";
|
|
13040
|
+
let exported = false;
|
|
13041
|
+
if (stmt.type === "ExportNamedDeclaration" || stmt.type === "ExportDefaultDeclaration") {
|
|
13042
|
+
exported = true;
|
|
13043
|
+
prefix = "export ";
|
|
13044
|
+
if (!isNode(stmt.declaration)) return { declared, exported, declaresOnlyFunctions: false, label: `${prefix}{ \u2026 }` };
|
|
13045
|
+
target = stmt.declaration;
|
|
13046
|
+
}
|
|
13047
|
+
if (target.type === "VariableDeclaration") {
|
|
13048
|
+
const decls = (target.declarations ?? []).filter(isNode);
|
|
13049
|
+
for (const d of decls) bindPattern(d.id, declared);
|
|
13050
|
+
const declaresOnlyFunctions = decls.length > 0 && decls.every((d) => isNode(d.init) && FUNCTION_TYPES2.has(d.init.type));
|
|
13051
|
+
const name = [...declared][0];
|
|
13052
|
+
return {
|
|
13053
|
+
declared,
|
|
13054
|
+
exported,
|
|
13055
|
+
declaresOnlyFunctions,
|
|
13056
|
+
label: name ? `${prefix}${String(target.kind)} ${name}` : null
|
|
13057
|
+
};
|
|
13058
|
+
}
|
|
13059
|
+
if (target.type === "FunctionDeclaration" && isNode(target.id)) {
|
|
13060
|
+
declared.add(String(target.id.name));
|
|
13061
|
+
return { declared, exported, declaresOnlyFunctions: true, label: `${prefix}function ${String(target.id.name)}` };
|
|
13062
|
+
}
|
|
13063
|
+
if (target.type === "ClassDeclaration" && isNode(target.id)) {
|
|
13064
|
+
declared.add(String(target.id.name));
|
|
13065
|
+
return { declared, exported, declaresOnlyFunctions: false, label: `${prefix}class ${String(target.id.name)}` };
|
|
13066
|
+
}
|
|
13067
|
+
return { declared, exported, declaresOnlyFunctions: false, label: null };
|
|
13068
|
+
}
|
|
13069
|
+
function findFreeIdentifiers(code, filename) {
|
|
13070
|
+
let parsed;
|
|
13071
|
+
try {
|
|
13072
|
+
parsed = (0, import_oxc_parser3.parseSync)(filename, code);
|
|
13073
|
+
} catch {
|
|
13074
|
+
return [];
|
|
13075
|
+
}
|
|
13076
|
+
if (parsed.errors.length > 0) return [];
|
|
13077
|
+
const bound = /* @__PURE__ */ new Set();
|
|
13078
|
+
collectBindings(parsed.program.body, bound);
|
|
13079
|
+
const lineStarts = [0];
|
|
13080
|
+
for (let i = 0; i < code.length; i++) if (code.charCodeAt(i) === 10) lineStarts.push(i + 1);
|
|
13081
|
+
const positionOf = (offset) => {
|
|
13082
|
+
let lo = 0;
|
|
13083
|
+
let hi = lineStarts.length - 1;
|
|
13084
|
+
while (lo < hi) {
|
|
13085
|
+
const mid = lo + hi + 1 >> 1;
|
|
13086
|
+
if (lineStarts[mid] <= offset) lo = mid;
|
|
13087
|
+
else hi = mid - 1;
|
|
13088
|
+
}
|
|
13089
|
+
return { line: lo + 1, column: offset - lineStarts[lo] + 1 };
|
|
13090
|
+
};
|
|
13091
|
+
const statements = parsed.program.body.filter(isNode);
|
|
13092
|
+
const tops = statements.map(describeTopLevel);
|
|
13093
|
+
const candidates = [];
|
|
13094
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13095
|
+
const readIn = /* @__PURE__ */ new Map();
|
|
13096
|
+
const visit = (node2, stmt, insideFunction) => {
|
|
13097
|
+
if (Array.isArray(node2)) {
|
|
13098
|
+
for (const child of node2) visit(child, stmt, insideFunction);
|
|
13099
|
+
return;
|
|
13100
|
+
}
|
|
13101
|
+
if (!isNode(node2)) return;
|
|
13102
|
+
const type = node2.type;
|
|
13103
|
+
if (type === "ImportDeclaration" || type === "ExportAllDeclaration") return;
|
|
13104
|
+
if (type === "MetaProperty" || type === "PrivateIdentifier") return;
|
|
13105
|
+
if (type === "ExportNamedDeclaration" && node2.source) return;
|
|
13106
|
+
if (type.startsWith("TS")) {
|
|
13107
|
+
if (TS_VALUE_WRAPPERS.has(type)) visit(node2.expression, stmt, insideFunction);
|
|
13108
|
+
return;
|
|
13109
|
+
}
|
|
13110
|
+
if (type === "Identifier" || type === "IdentifierReference") {
|
|
13111
|
+
const name = String(node2.name);
|
|
13112
|
+
let readers = readIn.get(name);
|
|
13113
|
+
if (!readers) readIn.set(name, readers = /* @__PURE__ */ new Set());
|
|
13114
|
+
readers.add(stmt);
|
|
13115
|
+
if (bound.has(name) || HOST_GLOBALS.has(name)) return;
|
|
13116
|
+
const offset = typeof node2.start === "number" ? node2.start : 0;
|
|
13117
|
+
const { line, column } = positionOf(offset);
|
|
13118
|
+
const key = `${name}@${line}:${column}`;
|
|
13119
|
+
if (seen.has(key)) return;
|
|
13120
|
+
seen.add(key);
|
|
13121
|
+
candidates.push({ name, line, column, enclosing: tops[stmt].label, stmt, insideFunction });
|
|
13122
|
+
return;
|
|
13123
|
+
}
|
|
13124
|
+
const nowInsideFunction = insideFunction || FUNCTION_TYPES2.has(type);
|
|
13125
|
+
for (const key of Object.keys(node2)) {
|
|
13126
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
13127
|
+
if (TYPE_KEYS.has(key)) continue;
|
|
13128
|
+
if (key === "key" && node2.computed !== true) continue;
|
|
13129
|
+
if (key === "property" && node2.computed !== true) continue;
|
|
13130
|
+
if (key === "label") continue;
|
|
13131
|
+
if (key === "exported") continue;
|
|
13132
|
+
if (key === "imported") continue;
|
|
13133
|
+
visit(node2[key], stmt, nowInsideFunction);
|
|
13134
|
+
}
|
|
13135
|
+
};
|
|
13136
|
+
for (let i = 0; i < statements.length; i++) visit(statements[i], i, false);
|
|
13137
|
+
return candidates.filter((c) => {
|
|
13138
|
+
const top = tops[c.stmt];
|
|
13139
|
+
if (!c.insideFunction || top.exported || !top.declaresOnlyFunctions || top.declared.size === 0) return true;
|
|
13140
|
+
for (const name of top.declared) {
|
|
13141
|
+
const readers = readIn.get(name);
|
|
13142
|
+
if (readers && [...readers].some((i) => i !== c.stmt)) return true;
|
|
13143
|
+
}
|
|
13144
|
+
return false;
|
|
13145
|
+
}).map(({ name, line, column, enclosing }) => ({ name, line, column, enclosing }));
|
|
13146
|
+
}
|
|
13147
|
+
|
|
13148
|
+
// src/compiler/module-hoist.ts
|
|
13149
|
+
var marker = (id) => `/*@pmh:${id}@*/`;
|
|
13150
|
+
var MARKER_RE = /\/\*@pmh:(\d+)@\*\/\n?/g;
|
|
13151
|
+
var HOIST_MARKER_PROBE = /\/\*@pmh:\d+@\*\//;
|
|
13152
|
+
var DECL_RE = /^(?:const|let|var|function\*?)\s+([A-Za-z_$][\w$]*)/;
|
|
13153
|
+
var ALWAYS_LOCAL = /* @__PURE__ */ new Set(["_map", "_k", "_env"]);
|
|
13154
|
+
function declaredNames(text) {
|
|
13155
|
+
const out = [];
|
|
13156
|
+
for (const line of text.split("\n")) {
|
|
13157
|
+
const m = DECL_RE.exec(line);
|
|
13158
|
+
if (m) out.push(m[1]);
|
|
13159
|
+
}
|
|
13160
|
+
return out;
|
|
13161
|
+
}
|
|
13162
|
+
function createModuleHoist() {
|
|
13163
|
+
const texts = [];
|
|
13164
|
+
const claim = (decls) => decls.map((text) => {
|
|
13165
|
+
const id = texts.length;
|
|
13166
|
+
texts.push(text);
|
|
13167
|
+
return marker(id);
|
|
13168
|
+
});
|
|
13169
|
+
const finalize = () => {
|
|
13170
|
+
const nameTexts = /* @__PURE__ */ new Map();
|
|
13171
|
+
const textCount = /* @__PURE__ */ new Map();
|
|
13172
|
+
const textNames = /* @__PURE__ */ new Map();
|
|
13173
|
+
const order = [];
|
|
13174
|
+
for (const text of texts) {
|
|
13175
|
+
const seen = textCount.get(text);
|
|
13176
|
+
textCount.set(text, (seen ?? 0) + 1);
|
|
13177
|
+
if (seen === void 0) {
|
|
13178
|
+
order.push(text);
|
|
13179
|
+
const names = declaredNames(text);
|
|
13180
|
+
textNames.set(text, names);
|
|
13181
|
+
for (const n of names) {
|
|
13182
|
+
const s = nameTexts.get(n);
|
|
13183
|
+
if (s) s.add(text);
|
|
13184
|
+
else nameTexts.set(n, /* @__PURE__ */ new Set([text]));
|
|
13185
|
+
}
|
|
13186
|
+
}
|
|
13187
|
+
}
|
|
13188
|
+
const hoisted = new Set(
|
|
13189
|
+
order.filter(
|
|
13190
|
+
(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)
|
|
13191
|
+
)
|
|
13192
|
+
);
|
|
13193
|
+
for (; ; ) {
|
|
13194
|
+
const localNames = [];
|
|
13195
|
+
for (const [n, ts] of nameTexts) {
|
|
13196
|
+
if (ts.size !== 1 || !hoisted.has([...ts][0])) localNames.push(n);
|
|
13197
|
+
}
|
|
13198
|
+
let changed = false;
|
|
13199
|
+
for (const text of [...hoisted]) {
|
|
13200
|
+
if (localNames.some((n) => new RegExp(`\\b${escapeName(n)}\\b`).test(text))) {
|
|
13201
|
+
hoisted.delete(text);
|
|
13202
|
+
changed = true;
|
|
13203
|
+
}
|
|
13204
|
+
}
|
|
13205
|
+
if (!changed) break;
|
|
12883
13206
|
}
|
|
13207
|
+
const preludeTexts = order.filter((t) => hoisted.has(t));
|
|
13208
|
+
const prelude = preludeTexts.length === 0 ? "" : `${preludeTexts.join("\n")}
|
|
13209
|
+
`;
|
|
13210
|
+
const removed = texts.reduce((n, t) => hoisted.has(t) ? n + t.length + 1 : n, 0);
|
|
13211
|
+
return {
|
|
13212
|
+
prelude,
|
|
13213
|
+
savedBytes: removed - prelude.length,
|
|
13214
|
+
hoistedNames: preludeTexts.flatMap((t) => textNames.get(t)),
|
|
13215
|
+
resolve: (src) => src.replace(MARKER_RE, (m, idStr) => {
|
|
13216
|
+
const text = texts[Number(idStr)];
|
|
13217
|
+
if (text === void 0) throw new Error(`parseman: unknown hoist marker ${m}`);
|
|
13218
|
+
if (hoisted.has(text)) return "";
|
|
13219
|
+
return m.endsWith("\n") ? `${text}
|
|
13220
|
+
` : text;
|
|
13221
|
+
})
|
|
13222
|
+
};
|
|
12884
13223
|
};
|
|
13224
|
+
return { claim, finalize };
|
|
13225
|
+
}
|
|
13226
|
+
function escapeName(n) {
|
|
13227
|
+
return n.replace(/\$/g, "\\$");
|
|
12885
13228
|
}
|
|
12886
13229
|
|
|
12887
13230
|
// src/plugin/index.ts
|
|
@@ -12977,7 +13320,7 @@ function parseModuleCached(filePath) {
|
|
|
12977
13320
|
let parsed = null;
|
|
12978
13321
|
try {
|
|
12979
13322
|
const src = fs2.readFileSync(filePath, "utf8");
|
|
12980
|
-
const r = (0,
|
|
13323
|
+
const r = (0, import_oxc_parser4.parseSync)(filePath, src);
|
|
12981
13324
|
if (r.errors.length === 0) parsed = { body: r.program.body, src };
|
|
12982
13325
|
} catch {
|
|
12983
13326
|
}
|
|
@@ -13118,7 +13461,7 @@ function lowerPrivateSourceModule(file, moduleAliases, warnUnloweredRegex, recov
|
|
|
13118
13461
|
const source = fs2.readFileSync(file, "utf8");
|
|
13119
13462
|
const transformed = transformMacro(source, file, moduleAliases, warnUnloweredRegex, recovery);
|
|
13120
13463
|
if (!transformed || transformed.warnings.length > 0) return null;
|
|
13121
|
-
const parsed = (0,
|
|
13464
|
+
const parsed = (0, import_oxc_parser4.parseSync)(file, transformed.code);
|
|
13122
13465
|
parsedModule = parsed.errors.length === 0 ? { body: parsed.program.body, src: transformed.code } : null;
|
|
13123
13466
|
return parsedModule;
|
|
13124
13467
|
} catch {
|
|
@@ -13142,7 +13485,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
13142
13485
|
function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recovery, grammarCoverage) {
|
|
13143
13486
|
let result;
|
|
13144
13487
|
try {
|
|
13145
|
-
result = (0,
|
|
13488
|
+
result = (0, import_oxc_parser4.parseSync)(id, code);
|
|
13146
13489
|
} catch {
|
|
13147
13490
|
return null;
|
|
13148
13491
|
}
|
|
@@ -13199,7 +13542,8 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13199
13542
|
}
|
|
13200
13543
|
}
|
|
13201
13544
|
}
|
|
13202
|
-
|
|
13545
|
+
const reducerResolver = createReducerResolver(id, body, code);
|
|
13546
|
+
setReducerResolver(reducerResolver, code);
|
|
13203
13547
|
const topLevelFunction = (moduleBody, name) => {
|
|
13204
13548
|
for (const st of moduleBody) {
|
|
13205
13549
|
const decl = st.type === "ExportNamedDeclaration" ? st.declaration : st;
|
|
@@ -13294,15 +13638,18 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13294
13638
|
scope: factoryScope,
|
|
13295
13639
|
imported: true
|
|
13296
13640
|
});
|
|
13641
|
+
reducerResolver.register(file);
|
|
13297
13642
|
}
|
|
13298
13643
|
const scope = /* @__PURE__ */ new Map();
|
|
13299
13644
|
const replacements = [];
|
|
13300
13645
|
const warnings = [];
|
|
13646
|
+
const moduleHoist = grammarCoverage ? void 0 : createModuleHoist();
|
|
13301
13647
|
beginLoweringCapture();
|
|
13302
13648
|
beginInlineCapCapture();
|
|
13303
13649
|
beginDegradationCapture();
|
|
13304
13650
|
let anyUnresolved = false;
|
|
13305
13651
|
let keepMacroImport = false;
|
|
13652
|
+
const exportedFactories = [];
|
|
13306
13653
|
let runtimeComposeFallback = false;
|
|
13307
13654
|
let ruleMapHolderCounter = 0;
|
|
13308
13655
|
const lineOf = (pos) => {
|
|
@@ -13661,7 +14008,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13661
14008
|
const pieces = materializeCarried(carried, composing, false, cHostMode);
|
|
13662
14009
|
try {
|
|
13663
14010
|
return {
|
|
13664
|
-
replacement: emitFusedSource(pieces),
|
|
14011
|
+
replacement: emitFusedSource(pieces, moduleHoist),
|
|
13665
14012
|
carried,
|
|
13666
14013
|
...composing ? { trivia: composing } : {},
|
|
13667
14014
|
...importedFactories.length ? { importedFactories } : {}
|
|
@@ -13729,7 +14076,7 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13729
14076
|
warn(init.start, "composeLeaf(): every pre-final grammar must explicitly prove recognition-only");
|
|
13730
14077
|
return null;
|
|
13731
14078
|
}
|
|
13732
|
-
const replacement = withLeafMarker(emitFusedSource(grammarCoverage ? recognitionPieces : [...recognitionPieces, plainLocalPiece]));
|
|
14079
|
+
const replacement = withLeafMarker(emitFusedSource(grammarCoverage ? recognitionPieces : [...recognitionPieces, plainLocalPiece], moduleHoist));
|
|
13733
14080
|
return {
|
|
13734
14081
|
replacement: withCoverageDefinitions(replacement, emittedCoverageDefinitions(replacement, `${id} composeLeaf()`)),
|
|
13735
14082
|
...importedFactories.length ? { importedFactories } : {}
|
|
@@ -13914,7 +14261,10 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13914
14261
|
scope.set(varName, staticValue);
|
|
13915
14262
|
continue;
|
|
13916
14263
|
}
|
|
13917
|
-
if (factoryDecls.has(varName))
|
|
14264
|
+
if (factoryDecls.has(varName)) {
|
|
14265
|
+
if (exportPrefix) exportedFactories.push({ name: varName, pos: init.start });
|
|
14266
|
+
continue;
|
|
14267
|
+
}
|
|
13918
14268
|
warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
|
|
13919
14269
|
continue;
|
|
13920
14270
|
}
|
|
@@ -13985,6 +14335,14 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
13985
14335
|
for (const imp of macroImports) {
|
|
13986
14336
|
imp.fullyResolved = !anyUnresolved && !keepMacroImport;
|
|
13987
14337
|
}
|
|
14338
|
+
if (exportedFactories.length > 0 && macroImports.some((imp) => imp.fullyResolved)) {
|
|
14339
|
+
const which = exportedFactories.map((f) => ` - ${id}:${lineOf(f.pos)} \u2014 export const ${f.name}`).join("\n");
|
|
14340
|
+
throw new Error(
|
|
14341
|
+
`${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:
|
|
14342
|
+
${which}
|
|
14343
|
+
Drop the \`export\`. The factory is macro-only; \`rules(${exportedFactories[0].name})\` is lowered in place and needs no runtime value.`
|
|
14344
|
+
);
|
|
14345
|
+
}
|
|
13988
14346
|
const ms = new import_magic_string.default(code);
|
|
13989
14347
|
const replacementRanges = runtimeComposeFallback ? [] : replacements.map(({ start, end }) => ({ start, end }));
|
|
13990
14348
|
const isInsideReplacement = (start, end) => replacementRanges.some((r) => start >= r.start && end <= r.end);
|
|
@@ -14033,8 +14391,21 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
14033
14391
|
}
|
|
14034
14392
|
}
|
|
14035
14393
|
const applied = runtimeComposeFallback ? [] : replacements;
|
|
14394
|
+
const hoisted = applied.length > 0 ? moduleHoist?.finalize() : void 0;
|
|
14036
14395
|
for (const { start, end, replacement } of applied.slice().sort((a, b) => b.start - a.start)) {
|
|
14037
|
-
ms.overwrite(start, end, replacement);
|
|
14396
|
+
ms.overwrite(start, end, hoisted ? hoisted.resolve(replacement) : replacement);
|
|
14397
|
+
}
|
|
14398
|
+
if (hoisted !== void 0 && hoisted.prelude !== "") {
|
|
14399
|
+
const claiming = applied.filter((r) => HOIST_MARKER_PROBE.test(r.replacement));
|
|
14400
|
+
if (claiming.length === 0) {
|
|
14401
|
+
throw new Error(`${id} \u2014 internal: a module-hoist prelude was produced but no applied replacement carries a hoist marker`);
|
|
14402
|
+
}
|
|
14403
|
+
const firstStart = Math.min(...claiming.map((r) => r.start));
|
|
14404
|
+
const anchor = body.find((s) => s.start <= firstStart && firstStart < s.end);
|
|
14405
|
+
if (anchor === void 0) {
|
|
14406
|
+
throw new Error(`${id} \u2014 internal: no top-level statement encloses macro replacement at ${firstStart}`);
|
|
14407
|
+
}
|
|
14408
|
+
ms.appendLeft(anchor.start, hoisted.prelude);
|
|
14038
14409
|
}
|
|
14039
14410
|
if (applied.length > 0) {
|
|
14040
14411
|
ms.prepend(
|
|
@@ -14044,6 +14415,21 @@ function transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recover
|
|
|
14044
14415
|
`
|
|
14045
14416
|
);
|
|
14046
14417
|
}
|
|
14418
|
+
if (applied.length > 0) {
|
|
14419
|
+
let sourceFree = null;
|
|
14420
|
+
const freeInSource = () => sourceFree ??= new Set(findFreeIdentifiers(code, id).map((f) => f.name));
|
|
14421
|
+
const free = findFreeIdentifiers(ms.toString(), id).filter((f) => !freeInSource().has(f.name));
|
|
14422
|
+
if (free.length > 0) {
|
|
14423
|
+
const macroProvided = free.filter((f) => allNames.has(f.name));
|
|
14424
|
+
const where = (f) => ` - ${id}:${f.line}:${f.column} \u2014 \`${f.name}\`` + (f.enclosing ? `, inside \`${f.enclosing}\`` : "");
|
|
14425
|
+
const cause = macroProvided.length > 0 ? `
|
|
14426
|
+
${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.` : "";
|
|
14427
|
+
throw new Error(
|
|
14428
|
+
`${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):
|
|
14429
|
+
${free.map(where).join("\n")}${cause}`
|
|
14430
|
+
);
|
|
14431
|
+
}
|
|
14432
|
+
}
|
|
14047
14433
|
for (const line of formatInlineCapSites(endInlineCapCapture(), resolveInlineMax())) warnings.push(`${id}: ${line}`);
|
|
14048
14434
|
const unlowered = endLoweringCapture();
|
|
14049
14435
|
if (warnUnloweredRegex) {
|