From a884a623d3d6825f1fd3e5221e4eab1726ffeb29 Mon Sep 17 00:00:00 2001 From: Osraka <98612432+Osraka@users.noreply.github.com> Date: Fri, 9 Oct 2026 17:24:37 +0300 Subject: [PATCH 1/3] fix(cli): preserve inline script diagnostic positions --- bend2/main.ts | 22 ++++++++++++++++++++-- tests/io/bundle_inline.js | 18 +++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/bend2/main.ts b/bend2/main.ts index 32cd6c871..09713d7d8 100755 --- a/bend2/main.ts +++ b/bend2/main.ts @@ -497,6 +497,18 @@ async function cli_bundle(page: string, dir: string): Promise { ({ contents: code.get(a.path)!, loader: "js" })); build.onLoad({ filter: /\.html$/ }, async (a) => { const src = await Bun.file(a.path).text(); + const marks: string[] = []; + const marked = new HTMLRewriter().on("script", { + element(el) { + const type = el.getAttribute("type")?.trim().toLowerCase(); + if (type === "module" && !el.hasAttribute("src")) { + let mark = "BEND_INLINE_START_" + marks.length + "_"; + while (src.includes(mark)) mark += "_"; + marks.push(mark); + el.prepend(mark); + } + }, + }).transform(src); const mods: { id: string; text: string }[] = []; let mod: { id: string; text: string } | null = null; const html = new HTMLRewriter().on("script", { @@ -520,8 +532,14 @@ async function cli_bundle(page: string, dir: string): Promise { }).transform(src); let end = 0; let line = 0; - for (const m of mods) { - const at = src.indexOf(m.text, end); + let added = 0; + let search = 0; + for (let i = 0; i < mods.length; i++) { + const m = mods[i]; + const found = marked.indexOf(marks[i], search); + const at = found - added; + search = found + marks[i].length; + added += marks[i].length; line += src.slice(end, at).split("\n").length - 1; const col = at - src.lastIndexOf("\n", at - 1) - 1; code.set(m.id, "\n".repeat(line) + " ".repeat(col) + m.text); diff --git a/tests/io/bundle_inline.js b/tests/io/bundle_inline.js index 111750914..b564006a4 100644 --- a/tests/io/bundle_inline.js +++ b/tests/io/bundle_inline.js @@ -15,6 +15,12 @@ function bundle_inline() { put("ok.html", '\n"); put("bad.html", '

\n\nconst x = ;\n\n'); + put("repeated.html", '\n\n'); + put("multi.html", '\n' + + '\n' + + '\n' + + '\n'); if (build("ok.html").status !== 0) { return 1; } @@ -24,7 +30,17 @@ function bundle_inline() { return 2; } const bad = build("bad.html"); - return bad.status === 1 && bad.stderr.includes("bad.html:4:") ? 0 : 3; + if (bad.status !== 1 || !bad.stderr.includes("bad.html:4:11")) { + return 3; + } + const repeated = build("repeated.html"); + if (repeated.status !== 1 + || !repeated.stderr.includes("repeated.html:7:11")) { + return 4; + } + const multi = build("multi.html"); + return multi.status === 1 && multi.stderr.includes("multi.html:9:11") + ? 0 : 5; } finally { fs.rmSync(dir, { recursive: true, force: true }); } From a7d66e959ed5ceb5538ebcf6a6560fb4b6cc8a18 Mon Sep 17 00:00:00 2001 From: Osraka <98612432+Osraka@users.noreply.github.com> Date: Sun, 11 Oct 2026 11:52:09 +0300 Subject: [PATCH 2/3] fix(cli): skip contentless inline module scripts --- bend2/main.ts | 19 ++++++++++++++----- tests/io/bundle_inline.js | 8 +++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/bend2/main.ts b/bend2/main.ts index 09713d7d8..791819421 100755 --- a/bend2/main.ts +++ b/bend2/main.ts @@ -484,6 +484,15 @@ function cli_base(what?: string): void { // cli_bundle builds a page. Bun skips inline module scripts (#1400), so the // inline plugin moves each to a virtual file beside its page, padded so an // error points at the page's own line and column. +function is_inline_module(el: { + getAttribute(name: string): string | null; + hasAttribute(name: string): boolean; + canHaveContent: boolean; +}): boolean { + return el.canHaveContent && !el.hasAttribute("src") + && el.getAttribute("type")?.trim().toLowerCase() === "module"; +} + async function cli_bundle(page: string, dir: string): Promise { const code = new Map(); const inline: BunPlugin = { @@ -500,10 +509,11 @@ async function cli_bundle(page: string, dir: string): Promise { const marks: string[] = []; const marked = new HTMLRewriter().on("script", { element(el) { - const type = el.getAttribute("type")?.trim().toLowerCase(); - if (type === "module" && !el.hasAttribute("src")) { + if (is_inline_module(el)) { let mark = "BEND_INLINE_START_" + marks.length + "_"; - while (src.includes(mark)) mark += "_"; + while (src.includes(mark)) { + mark += "_"; + } marks.push(mark); el.prepend(mark); } @@ -513,9 +523,8 @@ async function cli_bundle(page: string, dir: string): Promise { let mod: { id: string; text: string } | null = null; const html = new HTMLRewriter().on("script", { element(el) { - const type = el.getAttribute("type")?.trim().toLowerCase(); mod = null; - if (type === "module" && !el.hasAttribute("src")) { + if (is_inline_module(el)) { const name = "." + path.basename(a.path) + ".bend-inline-" + mods.length + ".js"; mod = { id: path.join(path.dirname(a.path), name), text: "" }; diff --git a/tests/io/bundle_inline.js b/tests/io/bundle_inline.js index b564006a4..edca677ef 100644 --- a/tests/io/bundle_inline.js +++ b/tests/io/bundle_inline.js @@ -12,12 +12,14 @@ function bundle_inline() { path.join(dir, page), "-o", path.join(dir, "out")); try { put("m.bend", "import Base\n\nlaw main:\n U32\n\ndef main():\n 42\n"); - put("ok.html", '\n"); put("bad.html", '

\n\nconst x = ;\n\n'); put("repeated.html", '\n\n'); - put("multi.html", '\n' + put("multi.html", '\n' + + '\n' + '\n' + '\n' + '\n'); @@ -39,7 +41,7 @@ function bundle_inline() { return 4; } const multi = build("multi.html"); - return multi.status === 1 && multi.stderr.includes("multi.html:9:11") + return multi.status === 1 && multi.stderr.includes("multi.html:10:11") ? 0 : 5; } finally { fs.rmSync(dir, { recursive: true, force: true }); From 1750ac8b749b67c306a88b4450ec6ecd240ecc31 Mon Sep 17 00:00:00 2001 From: Lorenzo Battistela Date: Sun, 11 Oct 2026 07:42:00 -0300 Subject: [PATCH 3/3] fix(cli): one page mark, lines counted from the page; covers svg CDATA --- bend2/main.ts | 39 +++++++++++++++------------------------ tests/io/bundle_inline.js | 3 ++- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/bend2/main.ts b/bend2/main.ts index 791819421..f26292508 100755 --- a/bend2/main.ts +++ b/bend2/main.ts @@ -481,18 +481,15 @@ function cli_base(what?: string): void { cli_say(1, want.join("\n\n") + "\n"); } -// cli_bundle builds a page. Bun skips inline module scripts (#1400), so the -// inline plugin moves each to a virtual file beside its page, padded so an -// error points at the page's own line and column. -function is_inline_module(el: { - getAttribute(name: string): string | null; - hasAttribute(name: string): boolean; - canHaveContent: boolean; -}): boolean { +// An inline module script; an empty svg \n'); put("multi.html", '\n' + + '\n' + '\n' + '\n' + '\n' @@ -41,7 +42,7 @@ function bundle_inline() { return 4; } const multi = build("multi.html"); - return multi.status === 1 && multi.stderr.includes("multi.html:10:11") + return multi.status === 1 && multi.stderr.includes("multi.html:12:11") ? 0 : 5; } finally { fs.rmSync(dir, { recursive: true, force: true });