Repository navigation
docs, bun-types: correct the Bun.build sourcemap, banner and footer descriptions #42550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
robobun
wants to merge
9
commits into
main
Choose a base branch
from
robobun/a97978cf/bun-build-docs-sourcemap-banner
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
87980df
docs, bun-types: correct the Bun.build sourcemap, banner and footer d…
robobun d27aa85
docs: move the --outdir note for linked and external sourcemaps out o…
robobun a61e877
test: check the BuildConfig sourcemap, banner and footer JSDoc agains…
robobun 08c16a6
test: cover an HTML output and require the JSDoc to name what decides…
robobun aa54928
Merge remote-tracking branch 'origin/main' into robobun/a97978cf/bun-…
robobun d0ddc94
docs, bun-types: do not say which artifact BuildArtifact.sourcemap is…
robobun 86ac786
test: move the JSDoc checks to test/bundler so that every lane runs t…
robobun 20da92b
Merge remote-tracking branch 'origin/main' into robobun/a97978cf/bun-…
robobun 4a4e7e8
test: check that a build without outdir leaves no file at the path of…
robobun File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| // The API reference for `Bun.build` is generated from the JSDoc in bun.d.ts. | ||
| // Each test runs a documented option, then checks that the JSDoc of that | ||
| // option describes what the build did. | ||
| import { describe, expect, test } from "bun:test"; | ||
| import { tempDir } from "harness"; | ||
| import { existsSync, readdirSync, readFileSync } from "node:fs"; | ||
| import { join } from "node:path"; | ||
|
|
||
| const dts = readFileSync(join(import.meta.dir, "../../packages/bun-types/bun.d.ts"), "utf8"); | ||
|
|
||
| /** The JSDoc block directly above `member?:` in bun.d.ts, as one line of prose. */ | ||
| function jsdocOf(member: string): string { | ||
| const decl = dts.search(new RegExp(`^ +${member}\\?: `, "m")); | ||
| expect(decl).toBeGreaterThan(-1); | ||
| const start = dts.lastIndexOf("/**", decl); | ||
| const end = dts.indexOf("*/", start); | ||
| expect(dts.slice(end + 2, decl).trim()).toBe(""); | ||
| return dts | ||
| .slice(start + 3, end) | ||
| .replace(/^\s*\* ?/gm, "") | ||
| .replace(/\s+/g, " ") | ||
| .trim(); | ||
| } | ||
|
|
||
| /** Which `sourcemap` mode the `//# sourceMappingURL` comment of an output is. */ | ||
| function sourcemapCommentKind(text: string): "inline" | "linked" | "none" { | ||
| if (text.includes("//# sourceMappingURL=data:")) return "inline"; | ||
| if (text.includes("//# sourceMappingURL=")) return "linked"; | ||
| return "none"; | ||
| } | ||
|
|
||
| const extensionOf = (path: string) => path.slice(path.lastIndexOf(".")); | ||
|
|
||
| // With `splitting`, this page builds to one output of each type: a JavaScript | ||
| // entry point, a JavaScript chunk, a CSS file and an HTML file. | ||
| const page = { | ||
| "index.html": `<!doctype html><html><head><link rel="stylesheet" href="./style.css"><script type="module" src="./index.js"></script></head><body></body></html>`, | ||
| "index.js": `import("./lazy.js").then(m => console.log(m.default));`, | ||
| "lazy.js": `export default "lazy";`, | ||
| "style.css": `a { color: red; }`, | ||
| }; | ||
| const outputTypes = ["CSS", "HTML", "JavaScript"]; | ||
|
|
||
|
robobun marked this conversation as resolved.
Resolved
|
||
| describe.concurrent("BuildConfig JSDoc matches the runtime", () => { | ||
| test("sourcemap: what `true` is an alias for", async () => { | ||
| using dir = tempDir("jsdoc-sourcemap-true", page); | ||
| const config = { entrypoints: [join(String(dir), "index.html")], splitting: true, sourcemap: true }; | ||
|
|
||
| const observed: string[] = []; | ||
| for (const build of [await Bun.build({ ...config, outdir: join(String(dir), "out") }), await Bun.build(config)]) { | ||
| const scripts = build.outputs.filter(output => extensionOf(output.path) === ".js"); | ||
| expect(scripts.map(output => output.kind).sort()).toEqual(["chunk", "entry-point"]); | ||
| const kinds = await Promise.all(scripts.map(async output => sourcemapCommentKind(await output.text()))); | ||
| observed.push(...new Set(kinds)); | ||
| } | ||
| expect(observed).toEqual(["linked", "inline"]); | ||
|
|
||
| const sentences = jsdocOf("sourcemap") | ||
| .split(/(?<=\.)\s+/) | ||
| .filter(sentence => sentence.includes("`true`")); | ||
| const documented = sentences.flatMap(sentence => | ||
| [...sentence.matchAll(/`"(none|linked|inline|external)"`/g)].map(match => match[1]), | ||
| ); | ||
| expect(documented).toEqual(expect.arrayContaining(observed)); | ||
|
coderabbitai[bot] marked this conversation as resolved.
Resolved
robobun marked this conversation as resolved.
Resolved
|
||
| // The two builds differ only in `outdir`, so the JSDoc has to say that it decides. | ||
| expect(sentences.join(" ")).toContain("`outdir`"); | ||
| }); | ||
|
|
||
| test('sourcemap: "linked" and "external" without outdir', async () => { | ||
| using dir = tempDir("jsdoc-sourcemap-no-outdir", page); | ||
| const sources = readdirSync(String(dir)).sort(); | ||
|
|
||
| for (const sourcemap of ["linked", "external"] as const) { | ||
| const build = await Bun.build({ entrypoints: [join(String(dir), "index.html")], splitting: true, sourcemap }); | ||
| expect(build.success).toBe(true); | ||
|
|
||
| const maps = build.outputs.filter(output => output.kind === "sourcemap").map(output => output.path); | ||
| // Without `outdir` the paths are relative to the cwd and hold a content | ||
| // hash, so a file at one of them can only come from this build. | ||
| expect(maps.filter(path => existsSync(path))).toEqual([]); | ||
| const observed = await Promise.all( | ||
| build.outputs | ||
| .filter(output => output.kind !== "sourcemap") | ||
| .map(async output => ({ | ||
| ext: extensionOf(output.path), | ||
| kind: output.kind, | ||
| map: maps.includes(output.path + ".map"), | ||
| comment: sourcemapCommentKind(await output.text()), | ||
| })), | ||
| ); | ||
| observed.sort((a, b) => (a.ext + a.kind).localeCompare(b.ext + b.kind)); | ||
| const comment = sourcemap === "linked" ? "linked" : "none"; | ||
| expect({ sourcemap, maps: maps.length, observed }).toEqual({ | ||
| sourcemap, | ||
| maps: 2, | ||
| observed: [ | ||
| { ext: ".css", kind: "asset", map: false, comment: "none" }, | ||
| { ext: ".html", kind: "entry-point", map: false, comment: "none" }, | ||
| { ext: ".js", kind: "chunk", map: true, comment }, | ||
| { ext: ".js", kind: "entry-point", map: true, comment }, | ||
| ], | ||
| }); | ||
| } | ||
| expect(readdirSync(String(dir)).sort()).toEqual(sources); | ||
|
robobun marked this conversation as resolved.
Resolved
|
||
|
|
||
| const doc = jsdocOf("sourcemap"); | ||
| expect(doc).not.toMatch(/requires? `outdir`|outdir\}? (is )?required/i); | ||
| expect(doc).toContain('`kind: "sourcemap"`'); | ||
| // Only one of the three types of output file got a map, so the JSDoc has | ||
| // to name all three. | ||
| expect(outputTypes.filter(type => doc.includes(type))).toEqual(outputTypes); | ||
| }); | ||
|
|
||
| test("banner and footer: JavaScript outputs only", async () => { | ||
| using dir = tempDir("jsdoc-banner-footer", page); | ||
| const build = await Bun.build({ | ||
| entrypoints: [join(String(dir), "index.html")], | ||
| splitting: true, | ||
| banner: "/* BANNER */", | ||
| footer: "/* FOOTER */", | ||
| }); | ||
| expect(build.success).toBe(true); | ||
|
|
||
| const observed = await Promise.all( | ||
| build.outputs.map(async output => { | ||
| const text = await output.text(); | ||
| return { | ||
| ext: extensionOf(output.path), | ||
| kind: output.kind, | ||
| banner: text.includes("/* BANNER */"), | ||
| footer: text.includes("/* FOOTER */"), | ||
| }; | ||
| }), | ||
| ); | ||
| observed.sort((a, b) => (a.ext + a.kind).localeCompare(b.ext + b.kind)); | ||
| expect(observed).toEqual([ | ||
| { ext: ".css", kind: "asset", banner: false, footer: false }, | ||
| { ext: ".html", kind: "entry-point", banner: false, footer: false }, | ||
| { ext: ".js", kind: "chunk", banner: true, footer: true }, | ||
| { ext: ".js", kind: "entry-point", banner: true, footer: true }, | ||
| ]); | ||
|
|
||
| // The build made three types of output file and treated them differently, | ||
| // so the JSDoc has to name all three. | ||
| for (const member of ["banner", "footer"]) { | ||
| const doc = jsdocOf(member); | ||
| expect({ member, named: outputTypes.filter(type => doc.includes(type)) }).toEqual({ member, named: outputTypes }); | ||
| } | ||
| }); | ||
| }); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.