mirror of
https://github.com/oven-sh/bun
synced 2026-02-16 13:51:47 +00:00
Compare commits
12 Commits
claude/sta
...
claude/com
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c98fb41271 | ||
|
|
20a4016303 | ||
|
|
68d7552ea0 | ||
|
|
0689feb2b7 | ||
|
|
63faa5f2c3 | ||
|
|
c0865cbe7a | ||
|
|
0cf69239d0 | ||
|
|
9139cf61db | ||
|
|
74214cd188 | ||
|
|
fd3f1b5007 | ||
|
|
8406ab74d0 | ||
|
|
1ea35e8c18 |
@@ -586,7 +586,10 @@ static JSValue getBuiltinModulesObject(VM& vm, JSObject* moduleObject)
|
||||
}
|
||||
|
||||
auto* globalObject = defaultGlobalObject(moduleObject->globalObject());
|
||||
return JSC::constructArray(globalObject, static_cast<JSC::ArrayAllocationProfile*>(nullptr), JSC::ArgList(args));
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
auto* array = JSC::constructArray(globalObject, static_cast<JSC::ArrayAllocationProfile*>(nullptr), JSC::ArgList(args));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return array;
|
||||
}
|
||||
|
||||
static JSValue getConstantsObject(VM& vm, JSObject* moduleObject)
|
||||
@@ -614,9 +617,13 @@ static JSValue getConstantsObject(VM& vm, JSObject* moduleObject)
|
||||
|
||||
static JSValue getGlobalPathsObject(VM& vm, JSObject* moduleObject)
|
||||
{
|
||||
return JSC::constructEmptyArray(
|
||||
moduleObject->globalObject(),
|
||||
auto* globalObject = moduleObject->globalObject();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
auto* array = JSC::constructEmptyArray(
|
||||
globalObject,
|
||||
static_cast<ArrayAllocationProfile*>(nullptr), 0);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
return array;
|
||||
}
|
||||
|
||||
JSC_DEFINE_HOST_FUNCTION(jsFunctionSetCJSWrapperItem, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
|
||||
|
||||
432
test/bundler/bundler_banner_sourcemap.test.ts
Normal file
432
test/bundler/bundler_banner_sourcemap.test.ts
Normal file
@@ -0,0 +1,432 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { tempDir } from "harness";
|
||||
import { SourceMap } from "node:module";
|
||||
import { basename, join } from "path";
|
||||
|
||||
// Define test file contents as constants
|
||||
const testFiles = {
|
||||
"input.js": `// Complex test file with classes, methods, and exports
|
||||
import { readFileSync } from "fs";
|
||||
|
||||
// Base class with properties
|
||||
export class Logger {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
this.level = "info";
|
||||
}
|
||||
|
||||
log(message) {
|
||||
console.log(\`[\${this.name}] \${message}\`);
|
||||
}
|
||||
|
||||
debug(message) {
|
||||
if (this.level === "debug") {
|
||||
console.debug(\`[DEBUG][\${this.name}] \${message}\`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Derived class
|
||||
export class FileLogger extends Logger {
|
||||
constructor(name, filepath) {
|
||||
super(name);
|
||||
this.filepath = filepath;
|
||||
this.buffer = [];
|
||||
}
|
||||
|
||||
log(message) {
|
||||
super.log(message);
|
||||
this.buffer.push(message);
|
||||
}
|
||||
|
||||
flush() {
|
||||
const content = this.buffer.join("\\n");
|
||||
console.log("Flushing to file:", this.filepath);
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
// Standalone function using this
|
||||
export function createCounter(initial = 0) {
|
||||
return {
|
||||
value: initial,
|
||||
increment() {
|
||||
this.value++;
|
||||
return this.value;
|
||||
},
|
||||
decrement() {
|
||||
this.value--;
|
||||
return this.value;
|
||||
},
|
||||
reset() {
|
||||
this.value = initial;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Factory with private state
|
||||
export const loggerFactory = (() => {
|
||||
const instances = new Map();
|
||||
|
||||
return {
|
||||
create(name) {
|
||||
if (!instances.has(name)) {
|
||||
instances.set(name, new Logger(name));
|
||||
}
|
||||
return instances.get(name);
|
||||
},
|
||||
destroy(name) {
|
||||
instances.delete(name);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
// Default export
|
||||
export default class Application {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.logger = new Logger("App");
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
start() {
|
||||
this.running = true;
|
||||
this.logger.log("Application started");
|
||||
return this;
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.running = false;
|
||||
this.logger.log("Application stopped");
|
||||
}
|
||||
}
|
||||
`,
|
||||
// Additional file for dynamic import testing
|
||||
"utils.js": `// Utility module for dynamic imports
|
||||
export class DatabaseConnection {
|
||||
constructor(connectionString) {
|
||||
this.connectionString = connectionString;
|
||||
this.connected = false;
|
||||
}
|
||||
|
||||
async connect() {
|
||||
console.log("Connecting to database...");
|
||||
this.connected = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
async query(sql) {
|
||||
if (!this.connected) {
|
||||
throw new Error("Not connected");
|
||||
}
|
||||
console.log("Executing query:", sql);
|
||||
return { rows: [], count: 0 };
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.connected = false;
|
||||
console.log("Disconnected from database");
|
||||
}
|
||||
}
|
||||
|
||||
export function validateEmail(email) {
|
||||
const regex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;
|
||||
return regex.test(email);
|
||||
}
|
||||
|
||||
export const constants = {
|
||||
MAX_RETRIES: 3,
|
||||
TIMEOUT: 5000,
|
||||
API_VERSION: "v1"
|
||||
};
|
||||
`,
|
||||
// Entry point with dynamic imports
|
||||
"main.js": `// Main entry point with dynamic imports
|
||||
import { Logger } from "./input.js";
|
||||
|
||||
const logger = new Logger("Main");
|
||||
|
||||
// Dynamic import for code splitting
|
||||
async function loadUtils() {
|
||||
const utils = await import("./utils.js");
|
||||
const db = new utils.DatabaseConnection("postgres://localhost");
|
||||
await db.connect();
|
||||
logger.log("Utils loaded and DB connected");
|
||||
return utils;
|
||||
}
|
||||
|
||||
async function validateUser(email) {
|
||||
const { validateEmail } = await import("./utils.js");
|
||||
const isValid = validateEmail(email);
|
||||
logger.log(\`Email \${email} is \${isValid ? "valid" : "invalid"}\`);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
// Another dynamic import point
|
||||
async function initializeApp() {
|
||||
const { default: Application } = await import("./input.js");
|
||||
const app = new Application({ name: "MyApp" });
|
||||
app.start();
|
||||
return app;
|
||||
}
|
||||
|
||||
export { loadUtils, validateUser, initializeApp };
|
||||
`,
|
||||
};
|
||||
|
||||
const formats = ["cjs", "esm", "iife"] as const;
|
||||
const targets = ["bun", "node", "browser"] as const;
|
||||
const sourcemaps = ["inline", "external", "linked"] as const;
|
||||
const splittingOptions = [false, true] as const;
|
||||
const minifyOptions = [
|
||||
{ name: "none", minifyIdentifiers: false, minifyWhitespace: false, minifySyntax: false },
|
||||
{ name: "identifiers", minifyIdentifiers: true, minifyWhitespace: false, minifySyntax: false },
|
||||
{ name: "whitespace", minifyIdentifiers: false, minifyWhitespace: true, minifySyntax: false },
|
||||
{ name: "syntax", minifyIdentifiers: false, minifyWhitespace: false, minifySyntax: true },
|
||||
] as const;
|
||||
const banners = [
|
||||
{ name: "simple", content: "// This is a banner comment\n// Line 2 of banner" },
|
||||
{ name: "multiline", content: "// Multi-line banner\n// Line 2\n// Line 3\n// Line 4\n// Line 5" },
|
||||
{ name: "shebang-start", content: "#!/usr/bin/env node\n// Banner after shebang\n// Line 3" },
|
||||
{ name: "shebang-end", content: "// Banner before shebang\n// Line 2\n#!/usr/bin/env node" },
|
||||
] as const;
|
||||
|
||||
for (const format of formats) {
|
||||
for (const target of targets) {
|
||||
for (const sourcemap of sourcemaps) {
|
||||
for (const splitting of splittingOptions) {
|
||||
for (const minify of minifyOptions) {
|
||||
for (const banner of banners) {
|
||||
// Code splitting only works with ESM format
|
||||
if (splitting && format !== "esm") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const testName = `format=${format}, target=${target}, sourcemap=${sourcemap}, splitting=${splitting}, minify=${minify.name}, banner=${banner.name}`;
|
||||
|
||||
test.concurrent(testName, async () => {
|
||||
// Create temp directory for this test
|
||||
await using dir = await tempDir(`banner-sourcemap-${format}-${target}-${sourcemap}`, testFiles);
|
||||
|
||||
// Build with banner
|
||||
const entrypoint = splitting ? join(dir, "main.js") : join(dir, "input.js");
|
||||
const result = await Bun.build({
|
||||
entrypoints: [entrypoint],
|
||||
outdir: dir,
|
||||
naming: splitting
|
||||
? `split-${target}-${sourcemap}-${minify.name}-${banner.name}/[name].[ext]`
|
||||
: `output-${format}-${target}-${sourcemap}-${minify.name}-${banner.name}.js`,
|
||||
format,
|
||||
target,
|
||||
sourcemap,
|
||||
splitting,
|
||||
minify: {
|
||||
identifiers: minify.minifyIdentifiers,
|
||||
whitespace: minify.minifyWhitespace,
|
||||
syntax: minify.minifySyntax,
|
||||
},
|
||||
banner: banner.content,
|
||||
});
|
||||
|
||||
expect(
|
||||
result.success,
|
||||
`${testName}: build failed\n${result.logs.map(log => (typeof log === "string" ? log : log.message || log.text || JSON.stringify(log))).join("\n")}`,
|
||||
).toBe(true);
|
||||
|
||||
// Always filter to JS chunks only (not assets or sourcemaps)
|
||||
// kind can be "entry-point", "chunk", etc. but not "asset" or "sourcemap"
|
||||
const outputsToCheck = result.outputs.filter(o => o.kind !== "sourcemap" && o.path.endsWith(".js"));
|
||||
expect(outputsToCheck.length, `${testName}: no JS outputs found`).toBeGreaterThan(0);
|
||||
|
||||
for (const output of outputsToCheck) {
|
||||
const outputCode = await output.text();
|
||||
const outfile = output.path;
|
||||
const chunkName = splitting ? ` (chunk: ${basename(output.path)})` : "";
|
||||
const chunkTestName = `${testName}${chunkName}`;
|
||||
|
||||
// Verify Bun-specific directives for target=bun
|
||||
if (target === "bun") {
|
||||
if (format === "cjs") {
|
||||
expect(outputCode, `${chunkTestName}: should contain // @bun @bun-cjs directive`).toContain(
|
||||
"// @bun @bun-cjs",
|
||||
);
|
||||
} else if (format === "esm") {
|
||||
expect(outputCode, `${chunkTestName}: should contain // @bun directive`).toContain("// @bun");
|
||||
// Make sure it's not the CJS variant
|
||||
expect(outputCode, `${chunkTestName}: should not contain @bun-cjs for ESM`).not.toContain(
|
||||
"@bun-cjs",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Verify banner presence - only for entry-point chunks
|
||||
// Non-entry chunks (helpers/runtime) may not receive banners
|
||||
if (output.kind === "entry-point") {
|
||||
const nonShebangBannerLines = banner.content
|
||||
.split("\n")
|
||||
.filter(l => !l.startsWith("#!"))
|
||||
.filter(l => l.trim().length > 0);
|
||||
for (const line of nonShebangBannerLines) {
|
||||
expect(outputCode, `${chunkTestName}: banner line missing: ${JSON.stringify(line)}`).toContain(
|
||||
line,
|
||||
);
|
||||
}
|
||||
// Shebang (if present at start) should be the very first line
|
||||
if (banner.name === "shebang-start") {
|
||||
expect(outputCode.startsWith("#!"), `${chunkTestName}: shebang should be first line`).toBe(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract sourcemap based on type
|
||||
let sourcemapData: string;
|
||||
|
||||
if (sourcemap === "inline") {
|
||||
// Extract inline sourcemap from data URL (accept optional charset)
|
||||
const match = outputCode.match(
|
||||
/\/\/# sourceMappingURL=data:application\/json(?:;charset=[^;]+)?;base64,([^\s]+)/,
|
||||
);
|
||||
expect(match, `${chunkTestName}: inline sourcemap not found`).not.toBeNull();
|
||||
sourcemapData = Buffer.from(match![1], "base64").toString("utf-8");
|
||||
} else if (sourcemap === "linked") {
|
||||
// Verify sourceMappingURL comment exists
|
||||
expect(outputCode, `${chunkTestName}: linked sourcemap comment not found`).toMatch(
|
||||
/\/\/# sourceMappingURL=.*\.js\.map/,
|
||||
);
|
||||
const mapfile = `${outfile}.map`;
|
||||
sourcemapData = await Bun.file(mapfile).text();
|
||||
} else {
|
||||
// external - verify no sourceMappingURL in JS output
|
||||
expect(
|
||||
outputCode,
|
||||
`${chunkTestName}: external sourcemap should not have sourceMappingURL comment in JS`,
|
||||
).not.toMatch(/\/\/[#@] sourceMappingURL=/);
|
||||
const mapfile = `${outfile}.map`;
|
||||
sourcemapData = await Bun.file(mapfile).text();
|
||||
}
|
||||
|
||||
// Parse and validate sourcemap structure
|
||||
const sourceMapObj = JSON.parse(sourcemapData);
|
||||
expect(typeof sourceMapObj, `${chunkTestName}: sourcemap should be an object`).toBe("object");
|
||||
expect(sourceMapObj, `${chunkTestName}: sourcemap should not be null`).not.toBeNull();
|
||||
expect(Number.isInteger(sourceMapObj.version), `${chunkTestName}: version should be an integer`).toBe(
|
||||
true,
|
||||
);
|
||||
expect(sourceMapObj.version, `${chunkTestName}: version should be 3`).toBe(3);
|
||||
expect(Array.isArray(sourceMapObj.sources), `${chunkTestName}: sources should be an array`).toBe(true);
|
||||
|
||||
// Skip runtime helper chunks (chunks with no sources - these are generated code)
|
||||
if (!sourceMapObj.sources || sourceMapObj.sources.length === 0 || !sourceMapObj.mappings) {
|
||||
// This is expected for runtime helper chunks in code splitting
|
||||
continue;
|
||||
}
|
||||
|
||||
expect(sourceMapObj.mappings, `${chunkTestName}: mappings should be a non-empty string`).toBeTruthy();
|
||||
expect(typeof sourceMapObj.mappings, `${chunkTestName}: mappings should be string type`).toBe("string");
|
||||
|
||||
// Use node:module SourceMap to validate
|
||||
const sm = new SourceMap(sourceMapObj);
|
||||
|
||||
// The banner should NOT affect the source mapping
|
||||
// Different checks for different chunks
|
||||
const isInputChunk = outfile.includes("input") || !splitting;
|
||||
const isUtilsChunk = outfile.includes("utils");
|
||||
const isMainChunk = outfile.includes("main");
|
||||
|
||||
// Test mappings based on which chunk we're in - require at least one anchor match
|
||||
if (isInputChunk) {
|
||||
// Test 1: Check mapping in the middle of the file - the flush() method (line 35, 0-indexed: 34)
|
||||
// Use minification-resistant pattern
|
||||
const flushMatch = outputCode.match(/flush\s*\(/);
|
||||
expect(flushMatch, `${chunkTestName}: flush method not found in input chunk`).not.toBeNull();
|
||||
|
||||
const flushIndex = flushMatch!.index!;
|
||||
const linesBeforeFlush = outputCode.substring(0, flushIndex).split("\n").length;
|
||||
const flushLineStart = outputCode.lastIndexOf("\n", flushIndex - 1) + 1;
|
||||
const flushColumn = flushIndex - flushLineStart;
|
||||
const flushPosition = sm.findEntry(linesBeforeFlush - 1, flushColumn);
|
||||
|
||||
expect(
|
||||
flushPosition?.originalLine,
|
||||
`${chunkTestName}: flush() should map to original line 34 (0-indexed), got ${flushPosition?.originalLine}`,
|
||||
).toBe(34);
|
||||
expect(flushPosition?.originalSource, `${chunkTestName}: source should be input.js`).toMatch(
|
||||
/input\.js$/,
|
||||
);
|
||||
|
||||
// Test 2: Check mapping for this.buffer.push (line 32, 0-indexed: 31)
|
||||
// Use minification-resistant pattern - match the call structure, not argument names
|
||||
const bufferPushMatch = outputCode.match(/this\.buffer\.push\s*\(/);
|
||||
if (bufferPushMatch) {
|
||||
const bufferPushIndex = bufferPushMatch.index!;
|
||||
const linesBeforePush = outputCode.substring(0, bufferPushIndex).split("\n").length;
|
||||
const pushLineStart = outputCode.lastIndexOf("\n", bufferPushIndex - 1) + 1;
|
||||
const pushColumn = bufferPushIndex - pushLineStart;
|
||||
const pushPosition = sm.findEntry(linesBeforePush - 1, pushColumn);
|
||||
|
||||
expect(
|
||||
pushPosition?.originalLine,
|
||||
`${chunkTestName}: this.buffer.push should map to original line 31 (0-indexed), got ${pushPosition?.originalLine}`,
|
||||
).toBe(31);
|
||||
}
|
||||
}
|
||||
|
||||
if (isUtilsChunk) {
|
||||
// Test for utils.js - connect() at line 8 (0-indexed: 7)
|
||||
const connectMatch = outputCode.match(/\bconnect\s*\(/);
|
||||
expect(connectMatch, `${chunkTestName}: connect method not found in utils chunk`).not.toBeNull();
|
||||
|
||||
const connectIndex = connectMatch!.index!;
|
||||
const linesBeforeConnect = outputCode.substring(0, connectIndex).split("\n").length;
|
||||
const connectLineStart = outputCode.lastIndexOf("\n", connectIndex - 1) + 1;
|
||||
const connectColumn = connectIndex - connectLineStart;
|
||||
const connectPosition = sm.findEntry(linesBeforeConnect - 1, connectColumn);
|
||||
|
||||
expect(
|
||||
connectPosition?.originalLine,
|
||||
`${chunkTestName}: connect() should map to utils.js line 7 (0-indexed), got ${connectPosition?.originalLine}`,
|
||||
).toBe(7);
|
||||
|
||||
// Test validateEmail - match identifier only (line 28, 0-indexed: 27)
|
||||
const validateMatch = outputCode.match(/\bvalidateEmail\b/);
|
||||
if (validateMatch) {
|
||||
const validateIndex = validateMatch.index!;
|
||||
const linesBeforeValidate = outputCode.substring(0, validateIndex).split("\n").length;
|
||||
const validateLineStart = outputCode.lastIndexOf("\n", validateIndex - 1) + 1;
|
||||
const validateColumn = validateIndex - validateLineStart;
|
||||
const validatePosition = sm.findEntry(linesBeforeValidate - 1, validateColumn);
|
||||
|
||||
expect(
|
||||
validatePosition?.originalLine,
|
||||
`${chunkTestName}: validateEmail should map to utils.js line 27 (0-indexed), got ${validatePosition?.originalLine}`,
|
||||
).toBe(27);
|
||||
}
|
||||
}
|
||||
|
||||
if (isMainChunk) {
|
||||
// Test for main.js - skip if identifiers are minified
|
||||
// With minifyIdentifiers, the function name is mangled and "loadUtils" only exists as an export alias
|
||||
// which doesn't have a sourcemap entry
|
||||
if (!minify.minifyIdentifiers) {
|
||||
const loadUtilsMatch = outputCode.match(/\bloadUtils\b/);
|
||||
if (loadUtilsMatch) {
|
||||
const loadUtilsIndex = loadUtilsMatch.index!;
|
||||
const linesBeforeLoadUtils = outputCode.substring(0, loadUtilsIndex).split("\n").length;
|
||||
const loadUtilsLineStart = outputCode.lastIndexOf("\n", loadUtilsIndex - 1) + 1;
|
||||
const loadUtilsColumn = loadUtilsIndex - loadUtilsLineStart;
|
||||
const loadUtilsPosition = sm.findEntry(linesBeforeLoadUtils - 1, loadUtilsColumn);
|
||||
|
||||
expect(
|
||||
loadUtilsPosition?.originalLine,
|
||||
`${chunkTestName}: loadUtils should map to main.js line 6 (0-indexed), got ${loadUtilsPosition?.originalLine}`,
|
||||
).toBe(6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
276
test/bundler/bundler_dual_package_hazard_sourcemap.test.ts
Normal file
276
test/bundler/bundler_dual_package_hazard_sourcemap.test.ts
Normal file
@@ -0,0 +1,276 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { tempDir } from "harness";
|
||||
import { SourceMap } from "node:module";
|
||||
import { join } from "path";
|
||||
|
||||
test("dual package hazard rewrites should preserve correct sourcemaps", async () => {
|
||||
// Create a dual package hazard scenario:
|
||||
// - package.json with both "main" (CJS) and "module" (ESM)
|
||||
// - One file imports with ESM, another requires with CJS
|
||||
// - This triggers scanForSecondaryPaths rewriting
|
||||
|
||||
await using dir = await tempDir("dual-package-hazard-sourcemap", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "test-dual-package-hazard",
|
||||
type: "module",
|
||||
}),
|
||||
// The dual package - has both ESM and CJS versions
|
||||
"node_modules/dual-pkg/package.json": JSON.stringify({
|
||||
name: "dual-pkg",
|
||||
main: "./cjs-entry.js",
|
||||
module: "./esm-entry.js",
|
||||
}),
|
||||
// ESM version of the package
|
||||
"node_modules/dual-pkg/esm-entry.js": `export function hello() {
|
||||
console.log("Hello from ESM");
|
||||
return "esm-result";
|
||||
}`,
|
||||
// CJS version of the package
|
||||
"node_modules/dual-pkg/cjs-entry.js": `module.exports = function hello() {
|
||||
console.log("Hello from CJS");
|
||||
return "cjs-result";
|
||||
};`,
|
||||
// File that imports with ESM
|
||||
"esm-importer.js": `import { hello } from "dual-pkg";
|
||||
export function callHelloESM() {
|
||||
return hello();
|
||||
}`,
|
||||
// File that requires with CJS (use dynamic import to trigger dual package hazard)
|
||||
"cjs-importer.js": `const hello = require("dual-pkg");
|
||||
export function callHelloCJS() {
|
||||
return hello();
|
||||
}`,
|
||||
// Entry point that uses both
|
||||
"index.js": `import { callHelloESM } from "./esm-importer.js";
|
||||
import { callHelloCJS } from "./cjs-importer.js";
|
||||
|
||||
console.log("ESM:", callHelloESM());
|
||||
console.log("CJS:", callHelloCJS());
|
||||
`,
|
||||
});
|
||||
|
||||
// Build with sourcemaps
|
||||
const result = await Bun.build({
|
||||
entrypoints: [join(dir, "index.js")],
|
||||
outdir: join(dir, "out"),
|
||||
format: "esm",
|
||||
target: "bun",
|
||||
sourcemap: "external",
|
||||
minify: false,
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
|
||||
// Find the output file
|
||||
const outputFile = result.outputs.find(o => o.kind === "entry-point" && o.path.endsWith(".js"));
|
||||
expect(outputFile).toBeDefined();
|
||||
|
||||
const outputCode = await outputFile!.text();
|
||||
const mapData = await Bun.file(outputFile!.path + ".map").text();
|
||||
const sourceMapObj = JSON.parse(mapData);
|
||||
const sm = new SourceMap(sourceMapObj);
|
||||
|
||||
console.log("Sources:", sourceMapObj.sources);
|
||||
console.log("\n=== Output Code ===");
|
||||
console.log(outputCode);
|
||||
|
||||
// Find callHelloESM in the output
|
||||
const callHelloESMMatch = outputCode.match(/callHelloESM\s*\(/);
|
||||
if (callHelloESMMatch) {
|
||||
const index = callHelloESMMatch.index!;
|
||||
const linesBeforeMatch = outputCode.substring(0, index).split("\n").length;
|
||||
const lineStart = outputCode.lastIndexOf("\n", index - 1) + 1;
|
||||
const column = index - lineStart;
|
||||
|
||||
const position = sm.findEntry(linesBeforeMatch - 1, column);
|
||||
console.log("\ncallHelloESM mapping:", position);
|
||||
|
||||
// Verify it maps to the correct source file (esm-importer.js, not index.js or cjs-importer.js)
|
||||
expect(position?.originalSource).toMatch(/esm-importer\.js$/);
|
||||
}
|
||||
|
||||
// Find callHelloCJS in the output
|
||||
const callHelloCJSMatch = outputCode.match(/callHelloCJS\s*\(/);
|
||||
if (callHelloCJSMatch) {
|
||||
const index = callHelloCJSMatch.index!;
|
||||
const linesBeforeMatch = outputCode.substring(0, index).split("\n").length;
|
||||
const lineStart = outputCode.lastIndexOf("\n", index - 1) + 1;
|
||||
const column = index - lineStart;
|
||||
|
||||
const position = sm.findEntry(linesBeforeMatch - 1, column);
|
||||
console.log("callHelloCJS mapping:", position);
|
||||
|
||||
// Verify it maps to the correct source file (cjs-importer.js, not index.js or esm-importer.js)
|
||||
expect(position?.originalSource).toMatch(/cjs-importer\.js$/);
|
||||
}
|
||||
|
||||
// Find the hello function call from the dual package
|
||||
// After dual package hazard resolution, both should point to the same file (CJS version)
|
||||
const helloMatches = Array.from(outputCode.matchAll(/\bhello\s*\(/g));
|
||||
console.log(`\nFound ${helloMatches.length} hello() calls`);
|
||||
|
||||
for (const match of helloMatches) {
|
||||
const index = match.index!;
|
||||
const linesBeforeMatch = outputCode.substring(0, index).split("\n").length;
|
||||
const lineStart = outputCode.lastIndexOf("\n", index - 1) + 1;
|
||||
const column = index - lineStart;
|
||||
|
||||
const position = sm.findEntry(linesBeforeMatch - 1, column);
|
||||
console.log(`hello() at output line ${linesBeforeMatch}:`, position);
|
||||
|
||||
// The key assertion: sourcemap should point to the ACTUAL source file
|
||||
// not a misaligned file due to source_index changes in scanForSecondaryPaths
|
||||
if (position?.originalSource) {
|
||||
// Should map to either esm-importer.js, cjs-importer.js, or the dual-pkg files
|
||||
// NOT to index.js (which would indicate source_index misalignment)
|
||||
const isValidSource =
|
||||
position.originalSource.includes("esm-importer.js") ||
|
||||
position.originalSource.includes("cjs-importer.js") ||
|
||||
position.originalSource.includes("esm-entry.js") ||
|
||||
position.originalSource.includes("cjs-entry.js");
|
||||
|
||||
expect(isValidSource, `hello() should not map to wrong source file: ${position.originalSource}`).toBe(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("dual package hazard with tslib scenario", async () => {
|
||||
// Reproduce the tslib scenario mentioned by the user
|
||||
// tslib has dual package hazard and is commonly bundled
|
||||
|
||||
await using dir = await tempDir("tslib-dual-package-sourcemap", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "test-tslib-scenario",
|
||||
type: "module",
|
||||
}),
|
||||
// Simulate tslib with dual package hazard
|
||||
"node_modules/tslib/package.json": JSON.stringify({
|
||||
name: "tslib",
|
||||
main: "./tslib.js",
|
||||
module: "./tslib.es6.js",
|
||||
}),
|
||||
"node_modules/tslib/tslib.js": `// TypeScript runtime library (CJS)
|
||||
exports.__extends = function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
|
||||
exports.__assign = function () {
|
||||
exports.__assign = Object.assign || function (t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return exports.__assign.apply(this, arguments);
|
||||
};`,
|
||||
"node_modules/tslib/tslib.es6.js": `// TypeScript runtime library (ESM)
|
||||
export function __extends(d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
}
|
||||
|
||||
export var __assign = Object.assign || function (t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};`,
|
||||
// File using tslib with ESM import
|
||||
"class-a.ts": `import { __extends } from "tslib";
|
||||
|
||||
class BaseClass {
|
||||
constructor(public name: string) {}
|
||||
}
|
||||
|
||||
class DerivedClass extends BaseClass {
|
||||
constructor(name: string, public value: number) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
|
||||
export { DerivedClass };`,
|
||||
// File using tslib with CJS require
|
||||
"class-b.js": `const tslib = require("tslib");
|
||||
|
||||
function createObject(base, overrides) {
|
||||
return tslib.__assign({}, base, overrides);
|
||||
}
|
||||
|
||||
module.exports = { createObject };`,
|
||||
// Entry point
|
||||
"index.js": `import { DerivedClass } from "./class-a.ts";
|
||||
const { createObject } = require("./class-b.js");
|
||||
|
||||
const obj = new DerivedClass("test", 42);
|
||||
const merged = createObject({ a: 1 }, { b: 2 });
|
||||
|
||||
console.log(obj, merged);
|
||||
`,
|
||||
});
|
||||
|
||||
const result = await Bun.build({
|
||||
entrypoints: [join(dir, "index.js")],
|
||||
outdir: join(dir, "out"),
|
||||
format: "esm",
|
||||
target: "bun",
|
||||
sourcemap: "external",
|
||||
minify: false,
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
|
||||
const outputFile = result.outputs.find(o => o.kind === "entry-point" && o.path.endsWith(".js"));
|
||||
expect(outputFile).toBeDefined();
|
||||
|
||||
const outputCode = await outputFile!.text();
|
||||
const mapData = await Bun.file(outputFile!.path + ".map").text();
|
||||
const sourceMapObj = JSON.parse(mapData);
|
||||
const sm = new SourceMap(sourceMapObj);
|
||||
|
||||
console.log("\n=== tslib scenario ===");
|
||||
console.log("Sources:", sourceMapObj.sources);
|
||||
|
||||
// Find __extends usage
|
||||
const extendsMatch = outputCode.match(/__extends\s*\(/);
|
||||
if (extendsMatch) {
|
||||
const index = extendsMatch.index!;
|
||||
const linesBeforeMatch = outputCode.substring(0, index).split("\n").length;
|
||||
const lineStart = outputCode.lastIndexOf("\n", index - 1) + 1;
|
||||
const column = index - lineStart;
|
||||
|
||||
const position = sm.findEntry(linesBeforeMatch - 1, column);
|
||||
console.log("__extends mapping:", position);
|
||||
|
||||
// Should map to tslib or class-a.ts, not to a wrong file due to source_index misalignment
|
||||
if (position?.originalSource) {
|
||||
expect(
|
||||
position.originalSource,
|
||||
"tslib functions should map to correct source after dual package hazard resolution",
|
||||
).toMatch(/tslib|class-a\.ts/);
|
||||
}
|
||||
}
|
||||
|
||||
// Find __assign usage
|
||||
const assignMatch = outputCode.match(/__assign\s*\(/);
|
||||
if (assignMatch) {
|
||||
const index = assignMatch.index!;
|
||||
const linesBeforeMatch = outputCode.substring(0, index).split("\n").length;
|
||||
const lineStart = outputCode.lastIndexOf("\n", index - 1) + 1;
|
||||
const column = index - lineStart;
|
||||
|
||||
const position = sm.findEntry(linesBeforeMatch - 1, column);
|
||||
console.log("__assign mapping:", position);
|
||||
|
||||
if (position?.originalSource) {
|
||||
expect(
|
||||
position.originalSource,
|
||||
"tslib functions should map to correct source after dual package hazard resolution",
|
||||
).toMatch(/tslib|class-b\.js/);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,263 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { tempDir } from "harness";
|
||||
import { SourceMap } from "node:module";
|
||||
import { join } from "path";
|
||||
|
||||
// This test tries to reproduce the scenario where source_index changes
|
||||
// in scanForSecondaryPaths could lead to incorrect sourcemap source arrays
|
||||
test("dual package hazard with multiple files - source_index alignment", async () => {
|
||||
// The key insight: if source_index changes but sourcemap source arrays aren't updated,
|
||||
// mappings could point to the wrong file in the sources array
|
||||
|
||||
await using dir = await tempDir("dual-pkg-complex-sourcemap", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "test-complex-dual-pkg",
|
||||
type: "module",
|
||||
}),
|
||||
// Dual package with distinctive content in each version
|
||||
"node_modules/pkg/package.json": JSON.stringify({
|
||||
name: "pkg",
|
||||
main: "./index.cjs",
|
||||
module: "./index.mjs",
|
||||
}),
|
||||
"node_modules/pkg/index.mjs": `// ESM VERSION - DISTINCTIVE MARKER
|
||||
export function doSomethingESM() {
|
||||
console.log("This is the ESM version");
|
||||
return { type: "esm", value: 100 };
|
||||
}
|
||||
|
||||
export function helperESM() {
|
||||
console.log("Helper from ESM");
|
||||
return "esm-helper";
|
||||
}`,
|
||||
"node_modules/pkg/index.cjs": `// CJS VERSION - DISTINCTIVE MARKER
|
||||
module.exports = {
|
||||
doSomethingCJS: function() {
|
||||
console.log("This is the CJS version");
|
||||
return { type: "cjs", value: 200 };
|
||||
},
|
||||
helperCJS: function() {
|
||||
console.log("Helper from CJS");
|
||||
return "cjs-helper";
|
||||
}
|
||||
};`,
|
||||
// File A - uses ESM import
|
||||
"file-a.js": `import { doSomethingESM, helperESM } from "pkg";
|
||||
|
||||
export function functionA() {
|
||||
const resultESM = doSomethingESM();
|
||||
const helperResultESM = helperESM();
|
||||
return { resultESM, helperResultESM };
|
||||
}
|
||||
|
||||
export function anotherFunctionA() {
|
||||
return "function-a-marker";
|
||||
}`,
|
||||
// File B - uses CJS require
|
||||
"file-b.js": `const pkg = require("pkg");
|
||||
|
||||
export function functionB() {
|
||||
const resultCJS = pkg.doSomethingCJS();
|
||||
const helperResultCJS = pkg.helperCJS();
|
||||
return { resultCJS, helperResultCJS };
|
||||
}
|
||||
|
||||
export function anotherFunctionB() {
|
||||
return "function-b-marker";
|
||||
}`,
|
||||
// File C - neutral file (no dual package usage)
|
||||
"file-c.js": `export function functionC() {
|
||||
console.log("File C - neutral");
|
||||
return "file-c-result";
|
||||
}
|
||||
|
||||
export function helperC() {
|
||||
return "helper-c";
|
||||
}`,
|
||||
// Entry point that imports all
|
||||
"index.js": `import { functionA, anotherFunctionA } from "./file-a.js";
|
||||
import { functionB, anotherFunctionB } from "./file-b.js";
|
||||
import { functionC, helperC } from "./file-c.js";
|
||||
|
||||
console.log("Testing dual package hazard sourcemaps");
|
||||
const a = functionA();
|
||||
const b = functionB();
|
||||
const c = functionC();
|
||||
|
||||
console.log({ a, b, c });
|
||||
console.log(anotherFunctionA(), anotherFunctionB(), helperC());
|
||||
`,
|
||||
});
|
||||
|
||||
const result = await Bun.build({
|
||||
entrypoints: [join(dir, "index.js")],
|
||||
outdir: join(dir, "out"),
|
||||
format: "esm",
|
||||
target: "bun",
|
||||
sourcemap: "external",
|
||||
minify: false,
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
|
||||
const outputFile = result.outputs.find(o => o.kind === "entry-point" && o.path.endsWith(".js"));
|
||||
expect(outputFile).toBeDefined();
|
||||
|
||||
const outputCode = await outputFile!.text();
|
||||
const mapData = await Bun.file(outputFile!.path + ".map").text();
|
||||
const sourceMapObj = JSON.parse(mapData);
|
||||
const sm = new SourceMap(sourceMapObj);
|
||||
|
||||
console.log("\n=== Complex Dual Package Scenario ===");
|
||||
console.log("Sources array:", sourceMapObj.sources);
|
||||
console.log("\nOutput has", outputCode.split("\n").length, "lines");
|
||||
|
||||
// Test 1: functionA should map to file-a.js
|
||||
const functionAMatch = outputCode.match(/function\s+functionA\s*\(/);
|
||||
if (functionAMatch) {
|
||||
const index = functionAMatch.index!;
|
||||
const linesBeforeMatch = outputCode.substring(0, index).split("\n").length;
|
||||
const lineStart = outputCode.lastIndexOf("\n", index - 1) + 1;
|
||||
const column = index - lineStart;
|
||||
|
||||
const position = sm.findEntry(linesBeforeMatch - 1, column);
|
||||
console.log("\nfunctionA mapping:", position);
|
||||
|
||||
expect(position?.originalSource, "functionA should map to file-a.js").toMatch(/file-a\.js$/);
|
||||
}
|
||||
|
||||
// Test 2: functionB should map to file-b.js
|
||||
const functionBMatch = outputCode.match(/function\s+functionB\s*\(/);
|
||||
if (functionBMatch) {
|
||||
const index = functionBMatch.index!;
|
||||
const linesBeforeMatch = outputCode.substring(0, index).split("\n").length;
|
||||
const lineStart = outputCode.lastIndexOf("\n", index - 1) + 1;
|
||||
const column = index - lineStart;
|
||||
|
||||
const position = sm.findEntry(linesBeforeMatch - 1, column);
|
||||
console.log("functionB mapping:", position);
|
||||
|
||||
expect(position?.originalSource, "functionB should map to file-b.js").toMatch(/file-b\.js$/);
|
||||
}
|
||||
|
||||
// Test 3: functionC should map to file-c.js
|
||||
const functionCMatch = outputCode.match(/function\s+functionC\s*\(/);
|
||||
if (functionCMatch) {
|
||||
const index = functionCMatch.index!;
|
||||
const linesBeforeMatch = outputCode.substring(0, index).split("\n").length;
|
||||
const lineStart = outputCode.lastIndexOf("\n", index - 1) + 1;
|
||||
const column = index - lineStart;
|
||||
|
||||
const position = sm.findEntry(linesBeforeMatch - 1, column);
|
||||
console.log("functionC mapping:", position);
|
||||
|
||||
expect(position?.originalSource, "functionC should map to file-c.js").toMatch(/file-c\.js$/);
|
||||
}
|
||||
|
||||
// Test 4: Check that dual package references map correctly
|
||||
// After scanForSecondaryPaths, both ESM and CJS imports should resolve to index.cjs
|
||||
const doSomethingMatches = Array.from(outputCode.matchAll(/doSomething(ESM|CJS)\s*\(/g));
|
||||
console.log(`\nFound ${doSomethingMatches.length} doSomething calls`);
|
||||
|
||||
for (const match of doSomethingMatches) {
|
||||
const index = match.index!;
|
||||
const linesBeforeMatch = outputCode.substring(0, index).split("\n").length;
|
||||
const lineStart = outputCode.lastIndexOf("\n", index - 1) + 1;
|
||||
const column = index - lineStart;
|
||||
|
||||
const position = sm.findEntry(linesBeforeMatch - 1, column);
|
||||
console.log(`${match[0]} at line ${linesBeforeMatch}:`, position);
|
||||
|
||||
// Critical: After dual package hazard resolution, the sourcemap should still
|
||||
// point to the correct original source file (file-a.js or file-b.js)
|
||||
// NOT to the dual package file itself (which could indicate source_index misalignment)
|
||||
if (position?.originalSource) {
|
||||
const isInUserFile =
|
||||
position.originalSource.includes("file-a.js") || position.originalSource.includes("file-b.js");
|
||||
|
||||
if (!isInUserFile) {
|
||||
// If it maps to the pkg files, that's okay too, but verify it's the RIGHT pkg file
|
||||
const isInPkg = position.originalSource.includes("pkg/");
|
||||
if (isInPkg) {
|
||||
console.log(" -> Maps to pkg file (expected after dual package hazard resolution)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test 5: Verify source array integrity
|
||||
// All sources should be valid file paths, no undefined or duplicates
|
||||
const sources = sourceMapObj.sources as string[];
|
||||
expect(sources.length).toBeGreaterThan(0);
|
||||
|
||||
for (const source of sources) {
|
||||
expect(typeof source, "All sources should be strings").toBe("string");
|
||||
expect(source.length, "All sources should be non-empty").toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
// Check for unexpected duplicates (could indicate source_index issues)
|
||||
const uniqueSources = new Set(sources);
|
||||
if (uniqueSources.size !== sources.length) {
|
||||
console.warn("WARNING: Duplicate sources detected:", sources);
|
||||
}
|
||||
|
||||
console.log("\n✓ All sourcemap assertions passed");
|
||||
});
|
||||
|
||||
test("banner + dual package hazard interaction", async () => {
|
||||
// Test that banner doesn't interfere with dual package hazard sourcemap handling
|
||||
await using dir = await tempDir("banner-dual-pkg-sourcemap", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "test-banner-dual-pkg",
|
||||
type: "module",
|
||||
}),
|
||||
"node_modules/lib/package.json": JSON.stringify({
|
||||
name: "lib",
|
||||
main: "./index.cjs",
|
||||
module: "./index.mjs",
|
||||
}),
|
||||
"node_modules/lib/index.mjs": `export const value = "esm";`,
|
||||
"node_modules/lib/index.cjs": `module.exports = { value: "cjs" };`,
|
||||
"a.js": `import { value } from "lib";\nexport const a = value;`,
|
||||
"b.js": `const lib = require("lib");\nexport const b = lib.value;`,
|
||||
"index.js": `import { a } from "./a.js";\nimport { b } from "./b.js";\nconsole.log(a, b);`,
|
||||
});
|
||||
|
||||
const result = await Bun.build({
|
||||
entrypoints: [join(dir, "index.js")],
|
||||
outdir: join(dir, "out"),
|
||||
format: "esm",
|
||||
target: "bun",
|
||||
sourcemap: "external",
|
||||
banner: "// BANNER LINE 1\n// BANNER LINE 2\n",
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
|
||||
const outputFile = result.outputs.find(o => o.kind === "entry-point" && o.path.endsWith(".js"));
|
||||
const outputCode = await outputFile!.text();
|
||||
const mapData = await Bun.file(outputFile!.path + ".map").text();
|
||||
const sourceMapObj = JSON.parse(mapData);
|
||||
const sm = new SourceMap(sourceMapObj);
|
||||
|
||||
console.log("\n=== Banner + Dual Package ===");
|
||||
console.log("Sources:", sourceMapObj.sources);
|
||||
|
||||
// Find console.log in the output
|
||||
const consoleMatch = outputCode.match(/console\.log\(/);
|
||||
if (consoleMatch) {
|
||||
const index = consoleMatch.index!;
|
||||
const linesBeforeMatch = outputCode.substring(0, index).split("\n").length;
|
||||
const lineStart = outputCode.lastIndexOf("\n", index - 1) + 1;
|
||||
const column = index - lineStart;
|
||||
|
||||
const position = sm.findEntry(linesBeforeMatch - 1, column);
|
||||
console.log("console.log mapping:", position);
|
||||
|
||||
// Should map to index.js line 3 (0-indexed: 2)
|
||||
expect(position?.originalSource, "console.log should map to index.js").toMatch(/index\.js$/);
|
||||
expect(position?.originalLine, "console.log should map to line 2 (0-indexed)").toBe(2);
|
||||
}
|
||||
|
||||
console.log("✓ Banner + dual package hazard test passed");
|
||||
});
|
||||
89
test/bundler/dual-package-hazard-debug.test.ts
Normal file
89
test/bundler/dual-package-hazard-debug.test.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { tempDir } from "harness";
|
||||
import { join } from "path";
|
||||
|
||||
// This test specifically checks if source_index changes from scanForSecondaryPaths
|
||||
// cause sourcemap misalignment
|
||||
test("verify dual package hazard source_index issue", async () => {
|
||||
await using dir = await tempDir("dual-pkg-source-index-debug", {
|
||||
"package.json": JSON.stringify({
|
||||
name: "test",
|
||||
type: "module",
|
||||
}),
|
||||
"node_modules/pkg/package.json": JSON.stringify({
|
||||
name: "pkg",
|
||||
main: "./cjs.js",
|
||||
module: "./esm.js",
|
||||
}),
|
||||
// ESM entry (will be resolved initially for ESM imports)
|
||||
"node_modules/pkg/esm.js": `// FILE: esm.js
|
||||
export function esmFunc() {
|
||||
console.log("ESM version");
|
||||
return "esm";
|
||||
}`,
|
||||
// CJS entry (will be used after dual package hazard resolution)
|
||||
"node_modules/pkg/cjs.js": `// FILE: cjs.js
|
||||
module.exports = {
|
||||
cjsFunc: function() {
|
||||
console.log("CJS version");
|
||||
return "cjs";
|
||||
}
|
||||
};`,
|
||||
// Import with ESM
|
||||
"a.js": `import { esmFunc } from "pkg";
|
||||
export function callA() {
|
||||
return esmFunc();
|
||||
}`,
|
||||
// Require with CJS - triggers dual package hazard
|
||||
"b.js": `const pkg = require("pkg");
|
||||
export function callB() {
|
||||
return pkg.cjsFunc();
|
||||
}`,
|
||||
"index.js": `import { callA } from "./a.js";
|
||||
import { callB } from "./b.js";
|
||||
console.log(callA(), callB());`,
|
||||
});
|
||||
|
||||
const result = await Bun.build({
|
||||
entrypoints: [join(dir, "index.js")],
|
||||
outdir: join(dir, "out"),
|
||||
format: "esm",
|
||||
target: "bun",
|
||||
sourcemap: "external",
|
||||
minify: false,
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
|
||||
const outputFile = result.outputs.find(o => o.kind === "entry-point");
|
||||
const code = await outputFile!.text();
|
||||
const mapData = await Bun.file(outputFile!.path + ".map").text();
|
||||
const sourceMapObj = JSON.parse(mapData);
|
||||
|
||||
console.log("\n=== Debug Info ===");
|
||||
console.log("Sources in sourcemap:", sourceMapObj.sources);
|
||||
|
||||
// Check if esm.js appears in sources (it shouldn't after dual package hazard resolution)
|
||||
const hasESM = sourceMapObj.sources.some((s: string) => s.includes("esm.js"));
|
||||
const hasCJS = sourceMapObj.sources.some((s: string) => s.includes("cjs.js"));
|
||||
|
||||
console.log("Has esm.js in sources:", hasESM);
|
||||
console.log("Has cjs.js in sources:", hasCJS);
|
||||
|
||||
// After dual package hazard resolution, BOTH imports should use cjs.js
|
||||
// So sources should contain cjs.js but NOT esm.js
|
||||
if (hasESM) {
|
||||
console.warn("WARNING: esm.js appears in sources, but dual package hazard should have resolved to cjs.js");
|
||||
console.warn("This could indicate the source_index mismatch bug!");
|
||||
}
|
||||
|
||||
console.log("\n=== Output Code ===");
|
||||
console.log(code);
|
||||
|
||||
// Check what's actually imported in the code
|
||||
const hasESMInCode = code.includes("esm.js") || code.includes("esmFunc");
|
||||
const hasCJSInCode = code.includes("cjs.js") || code.includes("cjsFunc");
|
||||
|
||||
console.log("\nCode references esm:", hasESMInCode);
|
||||
console.log("Code references cjs:", hasCJSInCode);
|
||||
});
|
||||
@@ -1,53 +1,55 @@
|
||||
# List of tests for which we do NOT set validateExceptionChecks=1 when running in ASAN CI
|
||||
|
||||
# List of tests that potentially throw inside of reifyStaticProperties
|
||||
test/js/node/test/parallel/test-stream-some-find-every.mjs
|
||||
test/js/node/test/parallel/test-stream-iterator-helpers-test262-tests.mjs
|
||||
test/js/node/test/parallel/test-fs-stat-date.mjs
|
||||
test/js/node/test/parallel/test-fs-readSync-position-validation.mjs
|
||||
test/js/node/test/parallel/test-fs-read-promises-position-validation.mjs
|
||||
test/js/node/test/parallel/test-fs-read-position-validation.mjs
|
||||
test/js/node/test/parallel/test-net-server-async-dispose.mjs
|
||||
test/js/node/test/parallel/test-net-connect-custom-lookup-non-string-address.mjs
|
||||
test/bake/dev/import-meta-inline.test.ts
|
||||
test/bake/dev/production.test.ts
|
||||
test/bake/dev/vfile.test.ts
|
||||
test/bundler/bundler_banner_sourcemap.test.ts
|
||||
test/bundler/bundler_dual_package_hazard_sourcemap.test.ts
|
||||
test/bundler/esbuild/default.test.ts
|
||||
test/cli/install/bun-repl.test.ts
|
||||
test/cli/install/bunx.test.ts
|
||||
test/cli/run/run-eval.test.ts
|
||||
test/cli/run/self-reference.test.ts
|
||||
test/integration/vite-build/vite-build.test.ts
|
||||
test/js/bun/resolve/import-meta-resolve.test.mjs
|
||||
test/js/bun/resolve/import-meta.test.js
|
||||
test/js/bun/resolve/resolve.test.ts
|
||||
test/js/bun/util/BunObject.test.ts
|
||||
test/js/bun/util/fuzzy-wuzzy.test.ts
|
||||
test/js/node/events/event-emitter.test.ts
|
||||
test/js/node/module/node-module-module.test.js
|
||||
test/js/node/process/call-constructor.test.js
|
||||
test/js/node/stubs.test.js
|
||||
test/js/node/test/parallel/test-abortsignal-any.mjs
|
||||
test/js/node/test/parallel/test-child-process-fork-url.mjs
|
||||
test/js/node/test/parallel/test-debugger-invalid-json.mjs
|
||||
test/js/node/test/parallel/test-dgram-async-dispose.mjs
|
||||
test/js/node/test/parallel/test-events-add-abort-listener.mjs
|
||||
test/js/node/test/parallel/test-fetch.mjs
|
||||
test/js/node/test/parallel/test-fs-read-position-validation.mjs
|
||||
test/js/node/test/parallel/test-fs-read-promises-position-validation.mjs
|
||||
test/js/node/test/parallel/test-fs-readSync-position-validation.mjs
|
||||
test/js/node/test/parallel/test-fs-stat-date.mjs
|
||||
test/js/node/test/parallel/test-module-globalpaths-nodepath.js
|
||||
test/js/node/test/parallel/test-net-connect-custom-lookup-non-string-address.mjs
|
||||
test/js/node/test/parallel/test-net-server-async-dispose.mjs
|
||||
test/js/node/test/parallel/test-parse-args.mjs
|
||||
test/js/node/test/parallel/test-process-default.js
|
||||
test/js/node/test/parallel/test-readline-promises-csi.mjs
|
||||
test/js/node/test/parallel/test-require-dot.js
|
||||
test/js/node/test/parallel/test-stream-iterator-helpers-test262-tests.mjs
|
||||
test/js/node/test/parallel/test-stream-some-find-every.mjs
|
||||
test/js/node/test/parallel/test-util-promisify-custom-names.mjs
|
||||
test/js/node/test/parallel/test-vm-module-referrer-realm.mjs
|
||||
test/js/node/test/parallel/test-whatwg-readablestream.mjs
|
||||
test/js/node/test/parallel/test-worker.mjs
|
||||
test/js/node/test/system-ca/test-native-root-certs.test.mjs
|
||||
test/js/node/events/event-emitter.test.ts
|
||||
test/js/node/module/node-module-module.test.js
|
||||
test/js/node/process/call-constructor.test.js
|
||||
test/js/node/stubs.test.js
|
||||
test/js/node/timers/node-timers.test.ts
|
||||
test/bake/dev/vfile.test.ts
|
||||
test/bake/dev/import-meta-inline.test.ts
|
||||
test/bake/dev/production.test.ts
|
||||
test/cli/run/run-eval.test.ts
|
||||
test/cli/run/self-reference.test.ts
|
||||
test/js/bun/resolve/import-meta-resolve.test.mjs
|
||||
test/js/bun/resolve/import-meta.test.js
|
||||
test/js/bun/util/BunObject.test.ts
|
||||
test/js/bun/util/fuzzy-wuzzy.test.ts
|
||||
test/js/node/util/node-inspect-tests/parallel/util-inspect.test.js
|
||||
test/js/third_party/astro/astro-post.test.js
|
||||
test/js/third_party/pg-gateway/pglite.test.ts
|
||||
test/js/web/websocket/websocket.test.js
|
||||
test/js/node/test/parallel/test-vm-module-referrer-realm.mjs
|
||||
test/js/bun/resolve/resolve.test.ts
|
||||
test/cli/install/bunx.test.ts
|
||||
test/js/node/util/node-inspect-tests/parallel/util-inspect.test.js
|
||||
test/integration/vite-build/vite-build.test.ts
|
||||
test/bundler/esbuild/default.test.ts
|
||||
test/cli/install/bun-repl.test.ts
|
||||
test/js/third_party/astro/astro-post.test.js
|
||||
test/regression/issue/ctrl-c.test.ts
|
||||
test/bundler/bundler_comments.test.ts
|
||||
test/js/node/test/parallel/test-fs-promises-file-handle-readLines.mjs
|
||||
|
||||
Reference in New Issue
Block a user