Files
bun.sh/test/bundler/bundler_naming.test.ts
Jarred Sumner ecd23df4ca Fix banner positioning with --format=cjs --target=bun (#22641)
## Summary
- Fixes incorrect banner positioning when using `--banner` with
`--format=cjs` and `--target=bun`
- Ensures Bun-specific comments (`// @bun @bun-cjs`) appear before user
banner content
- Properly extracts and positions hashbangs from banner content

## Problem
When using `--banner` with `--format=cjs --target=bun`, the banner was
incorrectly placed before the `// @bun @bun-cjs` comment and CJS wrapper
function, breaking the module format that Bun expects.

## Solution
Implemented proper ordering:
1. **Hashbang** (from source file or extracted from banner if it starts
with `#!`)
2. **@bun comments** (e.g., `// @bun`, `// @bun @bun-cjs`, `// @bun
@bytecode`)
3. **CJS wrapper** `(function(exports, require, module, __filename,
__dirname) {`
4. **Banner content** (excluding any extracted hashbang)

## Test plan
- [x] Added comprehensive tests for banner positioning with CJS/ESM and
Bun target
- [x] Tests cover hashbang extraction from banners
- [x] Tests verify proper ordering with bytecode generation
- [x] All existing tests pass

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-14 01:01:22 -07:00

306 lines
7.2 KiB
TypeScript

import { describe } from "bun:test";
import { ESBUILD, itBundled } from "./expectBundled";
describe("bundler", () => {
itBundled("naming/EntryNamingCollission", {
files: {
"/a/entry.js": /* js */ `
console.log(1);
`,
"/b/entry.js": /* js */ `
console.log(2);
`,
},
entryNaming: "[name].[ext]",
entryPointsRaw: ["./a/entry.js", "./b/entry.js"],
bundleErrors: {
// expectBundled does not support newlines.
"<bun>": [`Multiple files share the same output path`],
},
});
itBundled("naming/ImplicitOutbase1", {
files: {
"/a/entry.js": /* js */ `
console.log(1);
`,
"/b/entry.js": /* js */ `
console.log(2);
`,
},
entryPointsRaw: ["./a/entry.js", "./b/entry.js"],
run: [
{
file: "/out/a/entry.js",
stdout: "1",
},
{
file: "/out/b/entry.js",
stdout: "2",
},
],
});
itBundled("naming/ImplicitOutbase2", {
files: {
"/a/hello/entry.js": /* js */ `
import data from '../dependency'
console.log(data);
`,
"/a/dependency.js": /* js */ `
export default 1;
`,
"/a/hello/world/entry.js": /* js */ `
console.log(2);
`,
"/a/hello/world/a/a/a/a/a/a/a/entry.js": /* js */ `
console.log(3);
`,
},
entryPointsRaw: ["./a/hello/entry.js", "./a/hello/world/entry.js", "./a/hello/world/a/a/a/a/a/a/a/entry.js"],
run: [
{
file: "/out/entry.js",
stdout: "1",
},
{
file: "/out/world/entry.js",
stdout: "2",
},
{
file: "/out/world/a/a/a/a/a/a/a/entry.js",
stdout: "3",
},
],
});
itBundled("naming/EntryNamingTemplate1", {
files: {
"/a/hello/entry.js": /* js */ `
import data from '../dependency'
console.log(data);
`,
"/a/dependency.js": /* js */ `
export default 1;
`,
"/a/hello/world/entry.js": /* js */ `
console.log(2);
`,
"/a/hello/world/a/a/a/a/a/a/a/entry.js": /* js */ `
console.log(3);
`,
},
entryNaming: "files/[dir]/file.[ext]",
entryPointsRaw: ["./a/hello/entry.js", "./a/hello/world/entry.js", "./a/hello/world/a/a/a/a/a/a/a/entry.js"],
run: [
{
file: "/out/files/file.js",
stdout: "1",
},
{
file: "/out/files/world/file.js",
stdout: "2",
},
{
file: "/out/files/world/a/a/a/a/a/a/a/file.js",
stdout: "3",
},
],
});
itBundled("naming/EntryNamingTemplate2", {
todo: true,
files: {
"/src/first.js": /* js */ `
console.log(1);
`,
"/src/second/third.js": /* js */ `
console.log(2);
`,
},
entryNaming: "[ext]/prefix[dir]suffix/file.[ext]",
entryPointsRaw: ["./src/first.js", "./src/second/third.js"],
run: [
{
file: "/out/js/prefix/secondsuffix/file.js",
stdout: "2",
},
{
file: "/out/js/prefix/suffix/file.js",
stdout: "1",
},
],
});
itBundled("naming/AssetNaming", {
files: {
"/src/lib/first/file.js": /* js */ `
import file from "../second/data.file";
console.log(file);
`,
"/src/lib/second/data.file": `
this is a file
`,
},
root: "/src",
entryNaming: "hello.[ext]",
assetNaming: "test.[ext]",
entryPointsRaw: ["./src/lib/first/file.js"],
run: {
file: "/out/hello.js",
stdout: "./test.file",
},
});
itBundled("naming/AssetNamingMkdir", {
files: {
"/src/lib/first/file.js": /* js */ `
import file from "../second/data.file";
console.log(file);
`,
"/src/lib/second/data.file": `
this is a file
`,
},
root: "/src",
entryNaming: "hello.[ext]",
assetNaming: "subdir/test.[ext]",
entryPointsRaw: ["./src/lib/first/file.js"],
run: {
file: "/out/hello.js",
stdout: "./subdir/test.file",
},
});
itBundled("naming/AssetNamingDir", {
files: {
"/src/lib/first/file.js": /* js */ `
import file from "../second/data.file";
console.log(file);
`,
"/src/lib/second/data.file": `
this is a file
`,
},
root: "/src",
entryNaming: "hello.[ext]",
assetNaming: "[dir]/test.[ext]",
entryPointsRaw: ["./src/lib/first/file.js"],
loader: ESBUILD
? {
".file": "file",
}
: undefined,
run: [
{
file: "/out/hello.js",
stdout: "./lib/second/test.file",
},
],
});
itBundled("naming/AssetNoOverwrite", {
todo: true,
files: {
"/src/entry.js": /* js */ `
import asset1 from "./asset1.file";
import asset2 from "./asset2.file";
console.log(asset1, asset2);
`,
"/src/asset1.file": `
file 1
`,
"/src/asset2.file": `
file 2
`,
},
root: "/src",
assetNaming: "same-filename.txt",
entryPointsRaw: ["./src/entry.js"],
loader: {
".file": "file",
},
bundleErrors: {
"<bun>": ['Multiple files share the same output path: "same-filename.txt"'],
},
});
itBundled("naming/AssetFileLoaderPath1", {
files: {
"/src/entry.js": /* js */ `
import asset1 from "./asset1.file";
console.log(asset1);
`,
"/src/asset1.file": `
file 1
`,
//
"/out/hello/_": "",
},
root: "/src",
entryNaming: "lib/entry.js",
assetNaming: "hello/same-filename.txt",
entryPointsRaw: ["./src/entry.js"],
loader: {
".file": "file",
},
});
itBundled("naming/NonexistantRoot", ({ root }) => ({
backend: "cli",
files: {
"/src/entry.js": /* js */ `
import asset1 from "./asset1.file";
console.log(asset1);
`,
"/src/asset1.file": `
file 1
`,
},
root: "/lib",
entryPointsRaw: ["./src/entry.js"],
bundleErrors: {
// "<bun>": [`FileNotFound: failed to open root directory: ${root}/lib`],
},
}));
itBundled("naming/EntrypointOutsideOfRoot", {
todo: true,
files: {
"/src/hello/entry.js": /* js */ `
console.log(1);
`,
"/src/root/file.js": /* js */ `
console.log(2);
`,
},
root: "/src/root",
entryPointsRaw: ["./src/hello/entry.js"],
run: {
file: "/out/_.._/hello/file.js",
},
});
itBundled("naming/WithPathTraversal", {
files: {
"/a/hello/entry.js": /* js */ `
import data from '../dependency'
console.log(data);
`,
"/a/dependency.js": /* js */ `
export default 1;
`,
"/a/hello/world/entry.js": /* js */ `
console.log(2);
`,
"/a/hello/world/a/a/a/a/a/a/a/entry.js": /* js */ `
console.log(3);
`,
},
entryNaming: "foo/../bar/[dir]/file.[ext]",
entryPointsRaw: ["./a/hello/entry.js", "./a/hello/world/entry.js", "./a/hello/world/a/a/a/a/a/a/a/entry.js"],
run: [
{
file: "/out/bar/file.js",
stdout: "1",
},
{
file: "/out/bar/world/file.js",
stdout: "2",
},
{
file: "/out/bar/world/a/a/a/a/a/a/a/file.js",
stdout: "3",
},
],
});
});