mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
### What does this PR do? This branch: > Ran 1600 tests across 46 files. [63.24s] Main: > Ran 1600 tests across 46 files. [137.05s] This makes the bundler tests run about 60 seconds faster ### How did you verify your code works?
2385 lines
58 KiB
TypeScript
2385 lines
58 KiB
TypeScript
import { describe, expect } from "bun:test";
|
|
import { isBroken, isWindows } from "harness";
|
|
import { join } from "node:path";
|
|
import { itBundled } from "./expectBundled";
|
|
|
|
describe("bundler", () => {
|
|
itBundled("edgecase/EmptyFile", {
|
|
files: {
|
|
"/entry.js": "",
|
|
},
|
|
});
|
|
itBundled("edgecase/EmptyCommonJSModule", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import * as module from './module.cjs';
|
|
console.log(typeof module)
|
|
`,
|
|
"/module.cjs": /* js */ ``,
|
|
},
|
|
run: {
|
|
stdout: "object",
|
|
},
|
|
});
|
|
itBundled("edgecase/NestedRedirectToABuiltin", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import * as path from './module.cjs';
|
|
console.log(path.join('a', 'b'))
|
|
`,
|
|
"/module.cjs": /* js */ `
|
|
module.exports = require('./2nd')
|
|
`,
|
|
"/2nd.js": /* js */ `
|
|
module.exports = require('path')
|
|
`,
|
|
},
|
|
target: "bun",
|
|
run: {
|
|
stdout: join("a", "b"),
|
|
},
|
|
});
|
|
itBundled("edgecase/ImportStarFunction", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import * as foo from "./foo.js";
|
|
console.log(foo.fn());
|
|
`,
|
|
"/foo.js": /* js */ `
|
|
export function fn() {
|
|
return "foo";
|
|
}
|
|
`,
|
|
},
|
|
run: { stdout: "foo" },
|
|
});
|
|
itBundled("edgecase/ImportStarSyntaxErrorBug", {
|
|
// bug: 'import {ns}, * as import_x from "x";'
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
export {ns} from 'x'
|
|
export * as ns2 from 'x'
|
|
`,
|
|
},
|
|
external: ["x"],
|
|
runtimeFiles: {
|
|
"/node_modules/x/index.js": `export const ns = 1`,
|
|
},
|
|
run: true,
|
|
});
|
|
itBundled("edgecase/BunPluginTreeShakeImport", {
|
|
todo: true,
|
|
// This only appears at runtime and not with bun build, even with --no-bundle
|
|
files: {
|
|
"/entry.ts": /* js */ `
|
|
import { A, B } from "./somewhere-else";
|
|
import { plugin } from "bun";
|
|
|
|
plugin(B());
|
|
|
|
new A().chainedMethods();
|
|
`,
|
|
"/somewhere-else.ts": /* js */ `
|
|
export class A {
|
|
chainedMethods() {
|
|
console.log("hey");
|
|
}
|
|
}
|
|
export function B() {
|
|
return { name: 'hey' }
|
|
}
|
|
`,
|
|
},
|
|
minifySyntax: true,
|
|
target: "bun",
|
|
run: { file: "/entry.ts" },
|
|
});
|
|
itBundled("edgecase/TemplateStringIssue622", {
|
|
files: {
|
|
"/entry.ts": /* js */ `
|
|
capture(\`\\?\`);
|
|
capture(hello\`\\?\`);
|
|
`,
|
|
},
|
|
capture: ["`?`", "hello`\\?`"],
|
|
target: "bun",
|
|
});
|
|
// https://github.com/oven-sh/bun/issues/2699
|
|
itBundled("edgecase/ImportNamedFromExportStarCJS", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import { foo } from './foo';
|
|
console.log(foo);
|
|
`,
|
|
"/foo.js": /* js */ `
|
|
export * from './bar.cjs';
|
|
`,
|
|
"/bar.cjs": /* js */ `
|
|
module.exports = { foo: 'bar' };
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "bar",
|
|
},
|
|
});
|
|
itBundled("edgecase/NodeEnvDefaultUnset", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
capture(process.env.NODE_ENV);
|
|
capture(process.env.NODE_ENV === 'production');
|
|
capture(process.env.NODE_ENV === 'development');
|
|
`,
|
|
},
|
|
target: "browser",
|
|
capture: ['"development"', "false", "true"],
|
|
env: {
|
|
// undefined will ensure this variable is not passed to the bundler
|
|
NODE_ENV: undefined,
|
|
},
|
|
});
|
|
itBundled("edgecase/NodeEnvDefaultDevelopment", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
capture(process.env.NODE_ENV);
|
|
capture(process.env.NODE_ENV === 'production');
|
|
capture(process.env.NODE_ENV === 'development');
|
|
`,
|
|
},
|
|
target: "browser",
|
|
capture: ['"development"', "false", "true"],
|
|
env: {
|
|
NODE_ENV: "development",
|
|
},
|
|
});
|
|
itBundled("edgecase/NodeEnvDefaultProduction", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
capture(process.env.NODE_ENV);
|
|
capture(process.env.NODE_ENV === 'production');
|
|
capture(process.env.NODE_ENV === 'development');
|
|
`,
|
|
},
|
|
target: "browser",
|
|
capture: ['"production"', "true", "false"],
|
|
env: {
|
|
NODE_ENV: "production",
|
|
},
|
|
});
|
|
itBundled("edgecase/NodeEnvOptionalChaining", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
capture(process?.env?.NODE_ENV);
|
|
capture(process?.env?.NODE_ENV === 'production');
|
|
capture(process?.env?.NODE_ENV === 'development');
|
|
capture(process.env?.NODE_ENV);
|
|
capture(process.env?.NODE_ENV === 'production');
|
|
capture(process.env?.NODE_ENV === 'development');
|
|
capture(process?.env.NODE_ENV);
|
|
capture(process?.env.NODE_ENV === 'production');
|
|
capture(process?.env.NODE_ENV === 'development');
|
|
`,
|
|
},
|
|
target: "browser",
|
|
capture: ['"development"', "false", "true", '"development"', "false", "true", '"development"', "false", "true"],
|
|
env: {
|
|
NODE_ENV: "development",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/StarExternal", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import { foo } from './foo';
|
|
import { bar } from './bar';
|
|
console.log(foo);
|
|
`,
|
|
},
|
|
external: ["*"],
|
|
});
|
|
itBundled("edgecase/ImportNamespaceAndDefault", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import def2, * as ns2 from './c'
|
|
console.log(def2, JSON.stringify(ns2))
|
|
`,
|
|
"/c.js": /* js */ `
|
|
export const ns = 2
|
|
export const def2 = 3
|
|
export default 1
|
|
`,
|
|
},
|
|
runtimeFiles: {},
|
|
run: {
|
|
stdout: '1 {"ns":2,"default":1,"def2":3}',
|
|
},
|
|
});
|
|
itBundled("edgecase/ExternalES6ConvertedToCommonJSSimplified", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
console.log(JSON.stringify(require('./e')));
|
|
`,
|
|
"/e.js": `export * from 'x'`,
|
|
},
|
|
external: ["x"],
|
|
runtimeFiles: {
|
|
"/node_modules/x/index.js": /* js */ `
|
|
export const ns = 123
|
|
export const ns2 = 456
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: `
|
|
{"ns":123,"ns2":456}
|
|
`,
|
|
},
|
|
});
|
|
itBundled("edgecase/ImportTrailingSlash", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import "slash/"
|
|
`,
|
|
"/node_modules/slash/index.js": /* js */ `console.log(1)`,
|
|
},
|
|
run: {
|
|
stdout: "1",
|
|
},
|
|
});
|
|
itBundled("edgecase/ValidLoaderSeenAsInvalid", {
|
|
files: {
|
|
"/entry.js": /* js */ `console.log(1)`,
|
|
},
|
|
outdir: "/out",
|
|
loader: {
|
|
".a": "file",
|
|
".b": "text",
|
|
".c": "toml",
|
|
".d": "json",
|
|
".e": "js",
|
|
".f": "ts",
|
|
".g": "jsx",
|
|
".h": "tsx",
|
|
// ".i": "wasm",
|
|
// ".j": "napi",
|
|
// ".k": "base64",
|
|
// ".l": "dataurl",
|
|
// ".m": "binary",
|
|
// ".n": "empty",
|
|
// ".o": "copy",
|
|
},
|
|
});
|
|
itBundled("edgecase/InvalidLoaderSegfault", {
|
|
files: {
|
|
"/entry.js": /* js */ `console.log(1)`,
|
|
},
|
|
outdir: "/out",
|
|
backend: "cli",
|
|
loader: {
|
|
".cool": "wtf",
|
|
},
|
|
bundleErrors: {
|
|
"<bun>": ['invalid loader "wtf", expected one of:'],
|
|
},
|
|
});
|
|
itBundled("edgecase/ScriptTagEscape", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
console.log('<script></script>');
|
|
console.log(await import('./text-file.txt'))
|
|
`,
|
|
"/text-file.txt": /* txt */ `
|
|
<script></script>
|
|
`,
|
|
},
|
|
outdir: "/out",
|
|
onAfterBundle(api) {
|
|
try {
|
|
expect(api.readFile("/out/entry.js")).not.toContain("</script>");
|
|
} catch (error) {
|
|
console.error("Bundle contains </script> which will break if this bundle is placed in a script tag.");
|
|
throw error;
|
|
}
|
|
},
|
|
});
|
|
itBundled("edgecase/JSONDefaultImport", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import def from './test.json'
|
|
console.log(JSON.stringify(def))
|
|
`,
|
|
"/test.json": `{ "hello": 234, "world": 123 }`,
|
|
},
|
|
run: {
|
|
stdout: '{"hello":234,"world":123}',
|
|
},
|
|
});
|
|
itBundled("edgecase/JSONDefaultKeyImport", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import def from './test.json'
|
|
console.log(def.hello)
|
|
`,
|
|
"/test.json": `{ "hello": 234, "world": "REMOVE" }`,
|
|
},
|
|
run: {
|
|
stdout: "234",
|
|
},
|
|
});
|
|
itBundled("edgecase/JSONDefaultAndNamedImport", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import def from './test.json'
|
|
import { hello } from './test.json'
|
|
console.log(def.hello, hello)
|
|
`,
|
|
"/test.json": `{ "hello": 234, "world": "REMOVE" }`,
|
|
},
|
|
dce: true,
|
|
run: {
|
|
stdout: "234 234",
|
|
},
|
|
});
|
|
itBundled("edgecase/JSONWithDefaultKey", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import def from './test.json'
|
|
console.log(JSON.stringify(def))
|
|
`,
|
|
"/test.json": `{ "default": 234 }`,
|
|
},
|
|
dce: true,
|
|
run: {
|
|
stdout: '{"default":234}',
|
|
},
|
|
});
|
|
itBundled("edgecase/JSONWithDefaultKeyNamespace", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import * as ns from './test.json'
|
|
console.log(JSON.stringify(ns))
|
|
`,
|
|
"/test.json": `{ "default": 234 }`,
|
|
},
|
|
dce: true,
|
|
run: {
|
|
stdout: '{"default":234}',
|
|
},
|
|
});
|
|
itBundled("edgecase/RequireUnknownExtension", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
require('./x.aaaa')
|
|
`,
|
|
"/x.aaaa": `x`,
|
|
},
|
|
outdir: "/out",
|
|
});
|
|
itBundled("edgecase/PackageJSONDefaultConditionRequire", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
const boop = require('boop')
|
|
console.log(boop)
|
|
`,
|
|
"/node_modules/boop/package.json": /* json */ `
|
|
{
|
|
"name": "boop",
|
|
"exports": {
|
|
".": {
|
|
"boop-server": "./ignore.js",
|
|
"default": "./boop.js"
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
"/node_modules/boop/boop.js": /* js */ `
|
|
module.exports = 123
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "123",
|
|
},
|
|
});
|
|
itBundled("edgecase/PackageJSONDefaultConditionImport", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import React from 'boop'
|
|
console.log(React)
|
|
`,
|
|
// NOTE: this test fails if the package name is "react"
|
|
// most likely an issue with commonjs unwrapping.
|
|
"/node_modules/boop/package.json": /* json */ `
|
|
{
|
|
"name": "boop",
|
|
"exports": {
|
|
".": {
|
|
"react-server": "./ignore.js",
|
|
"default": "./boop.js"
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
"/node_modules/boop/boop.js": /* js */ `
|
|
export default 123
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "123",
|
|
},
|
|
});
|
|
itBundled("edgecase/TSConfigPathsStarOnlyInLeft", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
import test0 from 'test0/hello'
|
|
console.log(test0)
|
|
`,
|
|
"/tsconfig.json": /* json */ `
|
|
{
|
|
"compilerOptions": {
|
|
"baseUrl": ".",
|
|
"paths": {
|
|
"test0/*": ["./test0-success.ts"]
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
"/test0-success.ts": `export default 'success'`,
|
|
},
|
|
run: {
|
|
stdout: "success",
|
|
},
|
|
});
|
|
itBundled("edgecase/TSConfigPathStarAnywhere", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
import test0 from 'test3/foo'
|
|
console.log(test0)
|
|
`,
|
|
"/tsconfig.json": /* json */ `
|
|
{
|
|
"compilerOptions": {
|
|
"baseUrl": ".",
|
|
"paths": {
|
|
"t*t3/foo": ["./test3-succ*s.ts"],
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
"/test3-success.ts": `export default 'success'`,
|
|
},
|
|
run: {
|
|
stdout: "success",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/StaticClassNameIssue2806", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
new class C {
|
|
set baz(x) {
|
|
C.foo = x;
|
|
C.bar;
|
|
}
|
|
static get bar() {
|
|
console.log(C.foo);
|
|
}
|
|
}().baz = "PASS";
|
|
|
|
new class C {
|
|
set baz(x) {
|
|
C.foo = x;
|
|
C.bar;
|
|
}
|
|
static get bar() {
|
|
console.log(C.foo);
|
|
}
|
|
}().baz = "Hello World";
|
|
`,
|
|
},
|
|
minifyIdentifiers: true,
|
|
run: {
|
|
stdout: "PASS\nHello World",
|
|
},
|
|
});
|
|
itBundled("edgecase/DCEVarRedeclarationIssue2814A", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
var a = 1;
|
|
if (false) {
|
|
var a;
|
|
}
|
|
console.log(a);
|
|
`,
|
|
},
|
|
target: "bun",
|
|
run: {
|
|
stdout: `1`,
|
|
},
|
|
});
|
|
itBundled("edgecase/DCEVarRedeclarationIssue2814B", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
var a = 1;
|
|
switch ("foo") {
|
|
case "foo":
|
|
var a;
|
|
}
|
|
console.log(a);
|
|
`,
|
|
},
|
|
target: "bun",
|
|
run: {
|
|
stdout: `1`,
|
|
},
|
|
});
|
|
itBundled("edgecase/DCEVarRedeclarationIssue2814C", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
"use strict";
|
|
var a = 1;
|
|
{
|
|
var a;
|
|
}
|
|
console.log(a);
|
|
`,
|
|
},
|
|
target: "bun",
|
|
run: {
|
|
stdout: `1`,
|
|
},
|
|
});
|
|
itBundled("edgecase/DCEVarRedeclarationIssue2814", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
"use strict";
|
|
var a = 1, b = 2;
|
|
switch (b++) {
|
|
case b:
|
|
var c = a;
|
|
var a;
|
|
break;
|
|
}
|
|
console.log(a);
|
|
|
|
var x = 123, y = 45;
|
|
switch (console) {
|
|
case 456:
|
|
var x = 789, y = 0;
|
|
}
|
|
var y = 67;
|
|
console.log(x, y);
|
|
|
|
var z = 123;
|
|
switch (console) {
|
|
default:
|
|
var z = typeof z;
|
|
}
|
|
console.log(z);
|
|
|
|
var A = 1, B = 2;
|
|
switch (A) {
|
|
case A:
|
|
var B;
|
|
break;
|
|
case B:
|
|
break;
|
|
}
|
|
console.log(B);
|
|
`,
|
|
},
|
|
target: "bun",
|
|
run: {
|
|
stdout: `
|
|
1
|
|
123 67
|
|
number
|
|
2
|
|
`,
|
|
},
|
|
});
|
|
itBundled("edgecase/DCEVarRedeclarationIssue2815", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
var x = 1;
|
|
try {
|
|
console.blog;
|
|
} catch (x) {
|
|
var x = 2;
|
|
}
|
|
console.log(x);
|
|
|
|
var e = 3;
|
|
try {
|
|
console.log("try2");
|
|
} catch (e) {
|
|
var e = 4;
|
|
}
|
|
console.log(e);
|
|
|
|
try {
|
|
var z = 5;
|
|
throw "try3";
|
|
} catch (w) {
|
|
z += w;
|
|
var w = 6;
|
|
}
|
|
console.log(z);
|
|
|
|
var c = 8;
|
|
try {
|
|
"try4";
|
|
} catch (c) {
|
|
var c = 9;
|
|
}
|
|
console.log(c);
|
|
`,
|
|
},
|
|
target: "bun",
|
|
run: {
|
|
stdout: `
|
|
1
|
|
123 67
|
|
number
|
|
2
|
|
`,
|
|
},
|
|
});
|
|
itBundled("edgecase/AbsolutePathShouldNotResolveAsRelative", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
console.log(1);
|
|
`,
|
|
},
|
|
entryPointsRaw: ["/entry.js"],
|
|
bundleErrors: {
|
|
"<bun>": ['ModuleNotFound resolving "/entry.js" (entry point)'],
|
|
},
|
|
});
|
|
itBundled("edgecase/AssetEntryPoint", {
|
|
files: {
|
|
"/entry.zig": `
|
|
const std = @import("std");
|
|
|
|
pub fn main() void {
|
|
std.log.info("Hello, world!\\n", .{});
|
|
}
|
|
`,
|
|
},
|
|
outdir: "/out",
|
|
entryPointsRaw: ["./entry.zig"],
|
|
runtimeFiles: {
|
|
"/exec.js": `
|
|
import assert from 'node:assert';
|
|
import the_path from './out/entry.js';
|
|
assert.strictEqual(the_path, './entry-z5artd5z.zig');
|
|
`,
|
|
},
|
|
run: {
|
|
file: "./exec.js",
|
|
},
|
|
});
|
|
itBundled("edgecase/ExportDefaultUndefined", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
export const a = 1;
|
|
`,
|
|
},
|
|
target: "bun",
|
|
});
|
|
itBundled("edgecase/RuntimeExternalRequire", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
console.log(require("hello-1").type);
|
|
`,
|
|
},
|
|
external: ["hello-1"],
|
|
target: "bun",
|
|
runtimeFiles: {
|
|
"/node_modules/hello-1/require.js": `export const type = "require";`,
|
|
"/node_modules/hello-1/package.json": /* json */ `
|
|
{
|
|
"type": "module",
|
|
"exports": {
|
|
".": {
|
|
"require": "./require.js",
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: `
|
|
require
|
|
`,
|
|
},
|
|
});
|
|
itBundled("edgecase/RuntimeExternalImport", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
import { type as a1 } from 'hello-1';
|
|
import { type as a2 } from 'hello-2';
|
|
import { type as a3 } from 'hello-3';
|
|
console.log(a1, a2, a3);
|
|
|
|
const b1 = require('hello-1').type;
|
|
const b2 = require('hello-2').type;
|
|
const b3 = require('hello-3').type;
|
|
console.log(b1, b2, b3);
|
|
`,
|
|
},
|
|
external: ["hello-1", "hello-2", "hello-3"],
|
|
target: "bun",
|
|
runtimeFiles: {
|
|
"/node_modules/hello-1/node.js": `export const type = "node";`,
|
|
"/node_modules/hello-1/bun.js": `export const type = "bun";`,
|
|
"/node_modules/hello-1/package.json": /* json */ `
|
|
{
|
|
"type": "module",
|
|
"exports": {
|
|
".": {
|
|
"node": "./node.js",
|
|
"bun": "./bun.js"
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
"/node_modules/hello-2/node.js": `export const type = "node";`,
|
|
"/node_modules/hello-2/bun.js": `export const type = "bun";`,
|
|
"/node_modules/hello-2/package.json": /* json */ `
|
|
{
|
|
"type": "module",
|
|
"exports": {
|
|
".": {
|
|
"bun": "./bun.js",
|
|
"node": "./node.js"
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
"/node_modules/hello-3/import.js": `export const type = "import";`,
|
|
"/node_modules/hello-3/require.js": `exports.type = "require";`,
|
|
"/node_modules/hello-3/package.json": /* json */ `
|
|
{
|
|
"type": "module",
|
|
"exports": {
|
|
".": {
|
|
"require": "./require.js",
|
|
"import": "./import.js",
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: `
|
|
bun bun import
|
|
bun bun import
|
|
`,
|
|
},
|
|
});
|
|
itBundled("edgecase/RuntimeExternalImport2", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
import t from 'hello';
|
|
console.log(t);
|
|
`,
|
|
},
|
|
external: ["hello"],
|
|
target: "bun",
|
|
runtimeFiles: {
|
|
"/node_modules/hello/index.js": /* js */ `
|
|
export const hello = "Hello World";
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "Hello World",
|
|
},
|
|
});
|
|
itBundled("edgecase/AssetPublicPath", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
import hello from "./hello.file";
|
|
console.log(hello);
|
|
`,
|
|
"/hello.file": "Hello World",
|
|
},
|
|
outdir: "/out",
|
|
publicPath: "/www",
|
|
run: {},
|
|
});
|
|
itBundled("edgecase/ImportDefaultInDirectory", {
|
|
files: {
|
|
"/a/file.js": `
|
|
import def from './def'
|
|
console.log(def)
|
|
`,
|
|
"/a/def.js": `
|
|
export default 1;
|
|
console.log('inner');
|
|
`,
|
|
},
|
|
run: {
|
|
file: "/out.js",
|
|
stdout: "inner\n1",
|
|
},
|
|
});
|
|
itBundled("edgecase/RequireVarThenExport", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import { version } from './react';
|
|
console.log(version);
|
|
`,
|
|
"/react.js": /* js */ `
|
|
const a = require('./library.js');
|
|
exports.version = a.version;
|
|
`,
|
|
"/library.js": /* js */ `
|
|
exports.version = '0.6.0';
|
|
`,
|
|
},
|
|
target: "bun",
|
|
run: {
|
|
stdout: `0.6.0`,
|
|
},
|
|
});
|
|
itBundled("edgecase/OverwriteInputWithOutdir", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import { version } from './library';
|
|
console.log(version);
|
|
`,
|
|
"/library.js": /* js */ `
|
|
exports.version = '0.6.0';
|
|
`,
|
|
},
|
|
outdir: "/",
|
|
bundleErrors: {
|
|
"<bun>": ['Refusing to overwrite input file "/entry.js"'],
|
|
},
|
|
});
|
|
itBundled("edgecase/OverwriteInputWithOutfile", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import { version } from './library';
|
|
console.log(version);
|
|
`,
|
|
"/library.js": /* js */ `
|
|
exports.version = '0.6.0';
|
|
`,
|
|
},
|
|
outfile: "/entry.js",
|
|
bundleErrors: {
|
|
"<bun>": ['Refusing to overwrite input file "/entry.js"'],
|
|
},
|
|
});
|
|
itBundled("edgecase/OverwriteInputNonEntrypoint", {
|
|
todo: true,
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import { version } from './library';
|
|
console.log(version);
|
|
`,
|
|
"/library.js": /* js */ `
|
|
exports.version = '0.6.0';
|
|
`,
|
|
},
|
|
outfile: "/entry.js",
|
|
bundleErrors: {
|
|
"<bun>": ['Refusing to overwrite input file "/entry.js"'],
|
|
},
|
|
});
|
|
itBundled("edgecase/ModuleExportsFunctionIssue2911", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
const fn = require('fresh');
|
|
console.log(fn());
|
|
const fn2 = require('./not_in_node_modules');
|
|
console.log(fn2());
|
|
import fn3 from 'fresh';
|
|
console.log(fn());
|
|
import fn4 from './not_in_node_modules';
|
|
console.log(fn2());
|
|
`,
|
|
"/node_modules/fresh/index.js": /* js */ `
|
|
module.exports = function() {
|
|
return 'it worked';
|
|
}
|
|
`,
|
|
"/not_in_node_modules.js": /* js */ `
|
|
module.exports = function() {
|
|
return 'it worked';
|
|
}
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "it worked\nit worked\nit worked\nit worked",
|
|
},
|
|
});
|
|
itBundled("edgecase/IsBuffer1", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import isBuffer from 'lodash-es/isBuffer';
|
|
if(isBuffer !== 1) throw 'fail';
|
|
console.log('pass');
|
|
`,
|
|
"/node_modules/lodash-es/isBuffer.js": /* js */ `
|
|
var freeExports = typeof exports == 'object';
|
|
// this is using the 'freeExports' variable but giving a predictable outcome
|
|
const isBuffer = freeExports ? 1 : 1;
|
|
export default isBuffer;
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "pass",
|
|
},
|
|
});
|
|
itBundled("edgecase/TS_LessThanAmbiguity", {
|
|
files: {
|
|
"/entry.ts": `
|
|
function expectArrow(item) {
|
|
if(typeof item !== 'function') {
|
|
throw new Error('Expected arrow function');
|
|
}
|
|
}
|
|
function expectTypeCast(item) {
|
|
if(typeof item !== 'number') {
|
|
throw new Error('Expected arrow function');
|
|
}
|
|
}
|
|
const x = 1;
|
|
expectTypeCast(<A>(x));
|
|
expectTypeCast(<[]>(x));
|
|
expectTypeCast(<A[]>(x));
|
|
|
|
expectArrow(<A>(x) => {})
|
|
expectArrow(<A, B>(x) => {})
|
|
expectArrow(<A = B>(x) => {})
|
|
expectArrow(<A extends B>(x) => {})
|
|
expectArrow(<const A extends B>(x) => {})
|
|
|
|
console.log('pass');
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "pass",
|
|
},
|
|
});
|
|
itBundled("edgecase/TSX_LessThanAmbiguity", {
|
|
files: {
|
|
"/entry.tsx": `
|
|
function expectJSX(item) {
|
|
if(typeof item !== 'object') {
|
|
throw new Error('Expected JSX');
|
|
}
|
|
}
|
|
function expectArrow(item) {
|
|
if(typeof item !== 'function') {
|
|
throw new Error('Expected arrow function');
|
|
}
|
|
}
|
|
|
|
const A = 1;
|
|
expectJSX(<A>(x) ...</A>);
|
|
expectJSX(<A extends>(x) ... </A>);
|
|
expectJSX(<A extends={false}>(x) ... </A>);
|
|
expectJSX(<const A extends>(x) ...</const>);
|
|
expectJSX(<const extends T>(x) ...</const>);
|
|
expectJSX(<const A B>(x) ...</const>);
|
|
expectJSX(<const A B C>(x) ...</const>);
|
|
|
|
expectArrow(<A, B>(x) => {});
|
|
expectArrow(<A extends B>(x) => {});
|
|
expectArrow(<const A extends B>(x) => {});
|
|
|
|
console.log('pass');
|
|
`,
|
|
"/node_modules/react/jsx-dev-runtime.js": `
|
|
export function jsxDEV(type, props, key, isStaticChildren, source, self) {
|
|
return {};
|
|
}
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "pass",
|
|
},
|
|
});
|
|
itBundled("edgecase/IsBuffer2", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import isBuffer from 'lodash-es/isBuffer';
|
|
if(isBuffer !== 1) throw 'fail';
|
|
console.log('pass');
|
|
`,
|
|
"/node_modules/lodash-es/package.json": /* json */ `
|
|
{ "name": "lodash-es", "type": "module"}
|
|
`,
|
|
"/node_modules/lodash-es/isBuffer.js": /* js */ `
|
|
var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
|
|
var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
|
|
|
|
// this is using the 'freeExports' variable but giving a predictable outcome
|
|
const isBuffer = [freeExports, freeModule] ? 1 : 1;
|
|
export default isBuffer;
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "pass",
|
|
},
|
|
});
|
|
itBundled("edgecase/YieldKeyword", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
function* foo() {
|
|
yield 1;
|
|
[yield];
|
|
yield yield yield;
|
|
[yield * 2];
|
|
[yield (yield)];
|
|
{ x: yield };
|
|
(yield).hello
|
|
yield+1
|
|
}
|
|
`,
|
|
},
|
|
});
|
|
itBundled("edgecase/UsingWithSixImports", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
import { Database } from 'bun:sqlite';
|
|
|
|
import 'bun';
|
|
import 'bun:ffi';
|
|
import 'bun:jsc';
|
|
import 'node:assert';
|
|
import 'bun:test';
|
|
|
|
using a = new Database();
|
|
|
|
export { a };
|
|
`,
|
|
},
|
|
target: "bun",
|
|
});
|
|
itBundled("edgecase/EmitInvalidSourceMap1", {
|
|
files: {
|
|
"/src/index.ts": /* ts */ `
|
|
const y = await import("./second.mts");
|
|
import * as z from "./third.mts";
|
|
const v = await import("./third.mts");
|
|
console.log(z, v, y);
|
|
`,
|
|
"/src/second.mts": /* ts */ `
|
|
export default "swag";
|
|
`,
|
|
"/src/third.mts": /* ts */ `
|
|
export default "bun";
|
|
`,
|
|
},
|
|
outdir: "/out",
|
|
target: "bun",
|
|
sourceMap: "external",
|
|
minifySyntax: true,
|
|
minifyIdentifiers: true,
|
|
minifyWhitespace: true,
|
|
splitting: true,
|
|
});
|
|
// chunk-concat weaved mappings together incorrectly causing the `console`
|
|
// token to be -2, thus breaking the rest of the mappings in the file
|
|
itBundled("edgecase/EmitInvalidSourceMap2", {
|
|
files: {
|
|
"/entry.js": `
|
|
import * as react from "react";
|
|
console.log(react);
|
|
`,
|
|
"/node_modules/react/index.js": `
|
|
var _ = module;
|
|
sideEffect(() => {});
|
|
`,
|
|
},
|
|
outdir: "/out",
|
|
sourceMap: "external",
|
|
minifySyntax: true,
|
|
minifyIdentifiers: true,
|
|
minifyWhitespace: true,
|
|
snapshotSourceMap: {
|
|
"entry.js.map": {
|
|
files: ["../node_modules/react/index.js", "../entry.js"],
|
|
mappingsExactMatch: "qYACA,WAAW,IAAQ,EAAE,ICDrB,eACA,QAAQ,IAAI,CAAK",
|
|
},
|
|
},
|
|
});
|
|
// chunk-concat forgets to de-duplicate source indicies
|
|
// chunk-concat ignores all but the first instance of a chunk
|
|
itBundled("edgecase/EmitInvalidSourceMap2", {
|
|
files: {
|
|
"/entry.js": `
|
|
const a = new TextEncoder();
|
|
console.log('hey!')
|
|
const d = new TextEncoder();
|
|
|
|
const b = { hello: 'world' };
|
|
|
|
const c = new Set([
|
|
]);
|
|
console.log('hey!')
|
|
console.log('hey!')
|
|
console.log('hey!')
|
|
console.log('hey!')
|
|
`,
|
|
},
|
|
outdir: "/out",
|
|
sourceMap: "external",
|
|
minifySyntax: true,
|
|
minifyIdentifiers: true,
|
|
minifyWhitespace: true,
|
|
snapshotSourceMap: {
|
|
"entry.js.map": {
|
|
files: ["../entry.js"],
|
|
mappingsExactMatch:
|
|
"AACQ,QAAQ,IAAI,MAAM,EAOlB,QAAQ,IAAI,MAAM,EAClB,QAAQ,IAAI,MAAM,EAClB,QAAQ,IAAI,MAAM,EAClB,QAAQ,IAAI,MAAM",
|
|
},
|
|
},
|
|
});
|
|
itBundled("edgecase/NoUselessConstructorTS", {
|
|
files: {
|
|
"/entry.ts": `
|
|
class A {
|
|
constructor(...args) {
|
|
console.log(JSON.stringify({ args, self: this }));
|
|
}
|
|
field = 1;
|
|
}
|
|
class B extends A {}
|
|
class C extends A { field = 2 }
|
|
class D extends A { public field = 3 }
|
|
class E extends A { constructor(public y: number, a) { super(a); }; public field = 4 }
|
|
new A("arg1", "arg2");
|
|
new B("arg1", "arg2");
|
|
new C("arg1", "arg2");
|
|
new D("arg1", "arg2");
|
|
new E("arg1", "arg2");
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: `
|
|
{"args":["arg1","arg2"],"self":{"field":1}}
|
|
{"args":["arg1","arg2"],"self":{"field":1}}
|
|
{"args":["arg1","arg2"],"self":{"field":1}}
|
|
{"args":["arg1","arg2"],"self":{"field":1}}
|
|
{"args":["arg2"],"self":{"field":1}}
|
|
`,
|
|
},
|
|
onAfterBundle(api) {
|
|
const content = api.readFile("out.js");
|
|
const count = content.split("constructor").length - 1;
|
|
expect(count, "should only emit two constructors: " + content).toBe(2);
|
|
},
|
|
});
|
|
itBundled("edgecase/EnumInliningRopeStringPoison", {
|
|
files: {
|
|
"/entry.ts": `
|
|
const enum A1 {
|
|
B = "1" + "2",
|
|
C = "3" + B,
|
|
};
|
|
console.log(A1.B, A1.C);
|
|
|
|
const enum A2 {
|
|
B = "1" + "2",
|
|
C = ("3" + B) + "4",
|
|
};
|
|
console.log(A2.B, A2.C);
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "12 312\n12 3124",
|
|
},
|
|
});
|
|
itBundled("edgecase/ProtoNullProtoInlining", {
|
|
files: {
|
|
"/entry.ts": `
|
|
console.log({ __proto__: null }.__proto__ !== void 0)
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "false",
|
|
},
|
|
});
|
|
itBundled("edgecase/ImportOptionsArgument", {
|
|
files: {
|
|
"/entry.js": `
|
|
import('ext', { with: { get ''() { KEEP } } })
|
|
.then(function (error) {
|
|
console.log(error);
|
|
});
|
|
`,
|
|
},
|
|
dce: true,
|
|
external: ["ext"],
|
|
target: "bun",
|
|
});
|
|
itBundled("edgecase/ConstantFoldingShiftOperations", {
|
|
files: {
|
|
"/entry.ts": `
|
|
capture(421 >> -542)
|
|
capture(421 >>> -542)
|
|
capture(1 << 32)
|
|
capture(1 >> 32)
|
|
capture(1 >>> 32)
|
|
capture(47849312 << 34)
|
|
capture(-9 >> 1)
|
|
capture(-5 >> 1)
|
|
`,
|
|
},
|
|
minifySyntax: true,
|
|
capture: ["105", "105", "1", "1", "1", "191397248", "-5", "-3"],
|
|
});
|
|
itBundled("edgecase/ConstantFoldingBitwiseCoersion", {
|
|
files: {
|
|
"/entry.ts": `
|
|
capture(0 | 0)
|
|
capture(12582912 | 0)
|
|
capture(0xc00000 | 0)
|
|
capture(Infinity | 0)
|
|
capture(-Infinity | 0)
|
|
capture(NaN | 0)
|
|
// u32 limits
|
|
capture(-4294967295 | 0)
|
|
capture(-4294967296 | 0)
|
|
capture(-4294967297 | 0)
|
|
capture(4294967295 | 0)
|
|
capture(4294967296 | 0)
|
|
capture(4294967297 | 0)
|
|
// i32 limits
|
|
capture(-2147483647 | 0)
|
|
capture(-2147483648 | 0)
|
|
capture(-2147483649 | 0)
|
|
capture(2147483647 | 0)
|
|
capture(2147483648 | 0)
|
|
capture(2147483649 | 0)
|
|
capture(0.5 | 0)
|
|
`,
|
|
},
|
|
minifySyntax: true,
|
|
capture: [
|
|
"0",
|
|
"12582912",
|
|
"12582912",
|
|
"0",
|
|
"0",
|
|
"0",
|
|
"1",
|
|
"0",
|
|
"-1",
|
|
"-1",
|
|
"0",
|
|
"1",
|
|
"-2147483647",
|
|
"-2147483648",
|
|
"2147483647",
|
|
"2147483647",
|
|
"-2147483648",
|
|
"-2147483647",
|
|
"0",
|
|
],
|
|
});
|
|
itBundled("edgecase/EnumInliningNanBoxedEncoding", {
|
|
files: {
|
|
"/main.ts": `
|
|
import { Enum } from './other.ts';
|
|
capture(Enum.a);
|
|
capture(Enum.b);
|
|
capture(Enum.c);
|
|
capture(Enum.d);
|
|
capture(Enum.e);
|
|
capture(Enum.f);
|
|
capture(Enum.g);
|
|
`,
|
|
"/other.ts": `
|
|
export const enum Enum {
|
|
a = 0,
|
|
b = NaN,
|
|
c = (0 / 0) + 1,
|
|
d = Infinity,
|
|
e = -Infinity,
|
|
f = 3e450,
|
|
// https://float.exposed/0xffefffffffffffff
|
|
g = -1.79769313486231570815e+308,
|
|
}
|
|
`,
|
|
},
|
|
minifySyntax: true,
|
|
capture: [
|
|
"0 /* a */",
|
|
"NaN /* b */",
|
|
"NaN /* c */",
|
|
"1 / 0 /* d */",
|
|
"-1 / 0 /* e */",
|
|
"1 / 0 /* f */",
|
|
// should probably fix this
|
|
"-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 /* g */",
|
|
],
|
|
});
|
|
// Stack overflow possibility
|
|
itBundled("edgecase/AwsCdkLib", {
|
|
files: {
|
|
"entry.js": `import * as aws from ${JSON.stringify(require.resolve("aws-cdk-lib"))}; aws;`,
|
|
},
|
|
target: "bun",
|
|
run: true,
|
|
todo: isBroken && isWindows,
|
|
timeoutScale: 5,
|
|
});
|
|
itBundled("edgecase/PackageExternalDoNotBundleNodeModules", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
import { a } from "foo";
|
|
console.log(a);
|
|
`,
|
|
},
|
|
packages: "external",
|
|
target: "bun",
|
|
runtimeFiles: {
|
|
"/node_modules/foo/index.js": `export const a = "Hello World";`,
|
|
"/node_modules/foo/package.json": /* json */ `
|
|
{
|
|
"name": "foo",
|
|
"version": "2.0.0",
|
|
"main": "index.js"
|
|
}
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: `
|
|
Hello World
|
|
`,
|
|
},
|
|
});
|
|
itBundled("edgecase/EntrypointWithoutPrefixSlashOrDotIsNotConsideredExternal#12734", {
|
|
files: {
|
|
"/src/entry.ts": /* ts */ `
|
|
import { helloWorld } from "./second.ts";
|
|
console.log(helloWorld);
|
|
`,
|
|
"/src/second.ts": /* ts */ `
|
|
export const helloWorld = "Hello World";
|
|
`,
|
|
},
|
|
root: "/src",
|
|
entryPointsRaw: ["src/entry.ts"],
|
|
packages: "external",
|
|
target: "bun",
|
|
run: {
|
|
file: "/src/entry.ts",
|
|
stdout: `
|
|
Hello World
|
|
`,
|
|
},
|
|
});
|
|
itBundled("edgecase/IntegerUnderflow#12547", {
|
|
files: {
|
|
"/entry.js": `
|
|
import { a } from 'external';
|
|
|
|
function func() {
|
|
const b = 1 + a.c;
|
|
return b;
|
|
}
|
|
`,
|
|
},
|
|
minifySyntax: true,
|
|
minifyWhitespace: true,
|
|
minifyIdentifiers: true,
|
|
external: ["external"],
|
|
onAfterBundle(api) {
|
|
// DCE is not yet able to eliminate the `a` or even the `as c`. Equivalent to esbuild as of 2024-07-15
|
|
api.expectFile("/out.js").toBe(`import{a as c}from"external";\n`);
|
|
},
|
|
});
|
|
itBundled("edgecase/TypeScriptNamespaceSiblingFunction", {
|
|
files: {
|
|
"/entry.ts": `
|
|
namespace X {
|
|
export function Y() {
|
|
return 2;
|
|
}
|
|
export namespace Y {
|
|
export const Z = 1;
|
|
}
|
|
}
|
|
console.log(X, X.Y(), X.Y.Z);
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "{\n Y: [Function: Y],\n} 2 1",
|
|
},
|
|
});
|
|
itBundled("edgecase/TypeScriptNamespaceSiblingClass", {
|
|
files: {
|
|
"/entry.ts": `
|
|
namespace X {
|
|
export class Y {
|
|
constructor(v) {
|
|
this.value = v;
|
|
}
|
|
|
|
toJSON() {
|
|
return this.value;
|
|
}
|
|
}
|
|
export namespace Y {
|
|
export const Z = 1;
|
|
}
|
|
}
|
|
console.log(X, new X.Y(2).toJSON(), X.Y.Z);
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "{\n Y: [class Y],\n} 2 1",
|
|
},
|
|
});
|
|
itBundled("edgecase/TypeScriptNamespaceSiblingEnum", {
|
|
files: {
|
|
"/entry.ts": `
|
|
namespace X {
|
|
export enum Y {
|
|
A,
|
|
B,
|
|
}
|
|
export namespace Y {
|
|
export const Z = 1;
|
|
}
|
|
}
|
|
console.log(JSON.stringify([X, X.Y.A, X.Y.Z]));
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: '[{"Y":{"0":"A","1":"B","A":0,"B":1,"Z":1}},0,1]',
|
|
},
|
|
});
|
|
itBundled("edgecase/TypeScriptNamespaceSiblingVariable", {
|
|
files: {
|
|
"/entry.ts": `
|
|
namespace X {
|
|
export let Y = {};
|
|
export namespace Y {
|
|
export const Z = 1;
|
|
}
|
|
}
|
|
`,
|
|
},
|
|
bundleErrors: {
|
|
"/entry.ts": [`"Y" has already been declared`],
|
|
},
|
|
});
|
|
// This specifically only happens with 'export { ... } from ...' syntax
|
|
itBundled("edgecase/EsmSideEffectsFalseWithSideEffectsExportFrom", {
|
|
files: {
|
|
"/file1.js": `
|
|
import("./file2.js");
|
|
`,
|
|
"/file2.js": `
|
|
export { a } from './file3.js';
|
|
`,
|
|
"/file3.js": `
|
|
export function a(input) {
|
|
return 42;
|
|
}
|
|
console.log('side effect');
|
|
`,
|
|
"/package.json": `
|
|
{
|
|
"name": "my-package",
|
|
"sideEffects": false
|
|
}
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "side effect",
|
|
},
|
|
});
|
|
itBundled("edgecase/EsmSideEffectsFalseWithSideEffectsExportFromCodeSplitting", {
|
|
files: {
|
|
"/file1.js": `
|
|
import("./file2.js");
|
|
console.log('file1');
|
|
`,
|
|
"/file1b.js": `
|
|
import("./file2.js");
|
|
console.log('file2');
|
|
`,
|
|
"/file2.js": `
|
|
export { a } from './file3.js';
|
|
`,
|
|
"/file3.js": `
|
|
export function a(input) {
|
|
return 42;
|
|
}
|
|
console.log('side effect');
|
|
`,
|
|
"/package.json": `
|
|
{
|
|
"name": "my-package",
|
|
"sideEffects": false
|
|
}
|
|
`,
|
|
},
|
|
splitting: true,
|
|
outdir: "out",
|
|
entryPoints: ["./file1.js", "./file1b.js"],
|
|
run: [
|
|
{
|
|
file: "/out/file1.js",
|
|
stdout: "file1\nside effect",
|
|
},
|
|
{
|
|
file: "/out/file1b.js",
|
|
stdout: "file2\nside effect",
|
|
},
|
|
],
|
|
});
|
|
itBundled("edgecase/RequireSideEffectsFalseWithSideEffectsExportFrom", {
|
|
files: {
|
|
"/file1.js": `
|
|
require("./file2.js");
|
|
`,
|
|
"/file2.js": `
|
|
export { a } from './file3.js';
|
|
`,
|
|
"/file3.js": `
|
|
export function a(input) {
|
|
return 42;
|
|
}
|
|
console.log('side effect');
|
|
`,
|
|
"/package.json": `
|
|
{
|
|
"name": "my-package",
|
|
"sideEffects": false
|
|
}
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "side effect",
|
|
},
|
|
});
|
|
itBundled("edgecase/SideEffectsFalseWithSideEffectsExportFrom", {
|
|
files: {
|
|
"/file1.js": `
|
|
import("./file2.js");
|
|
`,
|
|
"/file2.js": `
|
|
import * as foo from './file3.js';
|
|
export default foo;
|
|
`,
|
|
"/file3.js": `
|
|
export function a(input) {
|
|
return 42;
|
|
}
|
|
console.log('side effect');
|
|
`,
|
|
"/package.json": `
|
|
{
|
|
"name": "my-package",
|
|
"sideEffects": false
|
|
}
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "side effect",
|
|
},
|
|
});
|
|
itBundled("edgecase/BuiltinWithTrailingSlash", {
|
|
files: {
|
|
"/entry.js": `
|
|
import * as process from 'process/';
|
|
console.log(JSON.stringify(process));
|
|
`,
|
|
"/node_modules/process/index.js": `
|
|
export default { hello: 'world' };
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: `{"default":{"hello":"world"}}`,
|
|
},
|
|
});
|
|
itBundled("edgecase/EsmWrapperClassHoisting", {
|
|
files: {
|
|
"/entry.ts": `
|
|
async function hi() {
|
|
const { default: MyInherited } = await import('./hello');
|
|
const myInstance = new MyInherited();
|
|
console.log(myInstance.greet())
|
|
}
|
|
|
|
hi();
|
|
`,
|
|
"/hello.ts": `
|
|
const MyReassignedSuper = class MySuper {
|
|
greet() {
|
|
return 'Hello, world!';
|
|
}
|
|
};
|
|
|
|
class MyInherited extends MyReassignedSuper {};
|
|
|
|
export default MyInherited;
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "Hello, world!",
|
|
},
|
|
});
|
|
itBundled("edgecase/EsmWrapperElimination1", {
|
|
files: {
|
|
"/entry.ts": `
|
|
async function load() {
|
|
return import('./hello');
|
|
}
|
|
load().then(({ default: def }) => console.log(def()));
|
|
`,
|
|
"/hello.ts": `
|
|
export var x = 123;
|
|
export var y = function() { return x; };
|
|
export function z() { return y(); }
|
|
function a() { return z(); }
|
|
export default function c() { return a(); }
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "123",
|
|
},
|
|
});
|
|
itBundled("edgecase/TsEnumTreeShakingUseAndInlineClass", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import { TestEnum } from './enum';
|
|
|
|
class TestClass {
|
|
constructor() {
|
|
console.log(JSON.stringify(TestEnum));
|
|
}
|
|
|
|
testMethod(name: TestEnum) {
|
|
return name === TestEnum.A;
|
|
}
|
|
}
|
|
|
|
// This must use wrapper class
|
|
console.log(new TestClass());
|
|
// This must inline
|
|
console.log(TestClass.prototype.testMethod.toString().includes('TestEnum'));
|
|
`,
|
|
"/enum.ts": `
|
|
export enum TestEnum {
|
|
A,
|
|
B,
|
|
}
|
|
`,
|
|
},
|
|
dce: true,
|
|
run: {
|
|
stdout: `
|
|
{"0":"A","1":"B","A":0,"B":1}
|
|
TestClass {
|
|
testMethod: [Function: testMethod],
|
|
}
|
|
false
|
|
`,
|
|
},
|
|
});
|
|
// this test checks that visit order doesnt matter (inline then use, above is use then inline)
|
|
itBundled("edgecase/TsEnumTreeShakingUseAndInlineClass2", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import { TestEnum } from './enum';
|
|
|
|
class TestClass {
|
|
testMethod(name: TestEnum) {
|
|
return name === TestEnum.A;
|
|
}
|
|
|
|
constructor() {
|
|
console.log(JSON.stringify(TestEnum));
|
|
}
|
|
}
|
|
|
|
// This must use wrapper class
|
|
console.log(new TestClass());
|
|
// This must inline
|
|
console.log(TestClass.prototype.testMethod.toString().includes('TestEnum'));
|
|
`,
|
|
"/enum.ts": `
|
|
export enum TestEnum {
|
|
A,
|
|
B,
|
|
}
|
|
`,
|
|
},
|
|
dce: true,
|
|
run: {
|
|
stdout: `
|
|
{"0":"A","1":"B","A":0,"B":1}
|
|
TestClass {
|
|
testMethod: [Function: testMethod],
|
|
}
|
|
false
|
|
`,
|
|
},
|
|
});
|
|
itBundled("edgecase/TsEnumTreeShakingUseAndInlineNamespace", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import { TestEnum } from './enum';
|
|
|
|
namespace TestClass {
|
|
console.log(JSON.stringify(TestEnum));
|
|
console.log((() => TestEnum.A).toString().includes('TestEnum'));
|
|
}
|
|
`,
|
|
"/enum.ts": `
|
|
export enum TestEnum {
|
|
A,
|
|
B,
|
|
}
|
|
`,
|
|
},
|
|
dce: true,
|
|
run: {
|
|
stdout: `
|
|
{"0":"A","1":"B","A":0,"B":1}
|
|
false
|
|
`,
|
|
},
|
|
});
|
|
itBundled("edgecase/ImportMetaMain", {
|
|
files: {
|
|
"/entry.ts": /* js */ `
|
|
import {other} from './other';
|
|
console.log(capture(import.meta.main), capture(require.main === module), ...other);
|
|
`,
|
|
"/other.ts": `
|
|
globalThis['ca' + 'pture'] = x => x;
|
|
|
|
export const other = [capture(require.main === module), capture(import.meta.main)];
|
|
`,
|
|
},
|
|
capture: ["false", "false", "import.meta.main", "import.meta.main"],
|
|
onAfterBundle(api) {
|
|
// This should not be marked as a CommonJS module
|
|
api.expectFile("/out.js").not.toContain("require");
|
|
api.expectFile("/out.js").not.toContain("module");
|
|
},
|
|
});
|
|
itBundled("edgecase/ImportMetaMainTargetNode", {
|
|
files: {
|
|
"/entry.ts": /* js */ `
|
|
import {other} from './other';
|
|
console.log(capture(import.meta.main), capture(require.main === module), ...other);
|
|
`,
|
|
"/other.ts": `
|
|
globalThis['ca' + 'pture'] = x => x;
|
|
|
|
export const other = [capture(require.main === module), capture(import.meta.main)];
|
|
`,
|
|
},
|
|
target: "node",
|
|
capture: ["false", "false", "__require.main == __require.module", "__require.main == __require.module"],
|
|
onAfterBundle(api) {
|
|
// This should not be marked as a CommonJS module
|
|
api.expectFile("/out.js").not.toMatch(/\brequire\b/); // __require is ok
|
|
api.expectFile("/out.js").not.toMatch(/[^\.:]module/); // `.module` and `node:module` are ok.
|
|
},
|
|
});
|
|
itBundled("edgecase/build-cjs-module#20308", {
|
|
files: {
|
|
"/entry.ts": /* js */ `
|
|
import {other} from './other';
|
|
console.log(capture(import.meta.main), capture(require.main === module), ...other);
|
|
`,
|
|
"/other.ts": /* js */ `
|
|
globalThis['ca' + 'pture'] = x => x;
|
|
|
|
export const other = [capture(require.main === module), capture(import.meta.main)];
|
|
`,
|
|
},
|
|
target: "node",
|
|
format: "cjs",
|
|
capture: ["false", "false", "require.main == module", "require.main == module"],
|
|
onAfterBundle(api) {
|
|
console.log(api.readFile("/out.js"));
|
|
// This should be marked as a CommonJS module
|
|
api.expectFile("/out.js").toMatch(/\brequire\b/); // __require is not ok
|
|
api.expectFile("/out.js").toMatch(/[^\.:]module/); // `.module` and `node:module` are not ok.
|
|
},
|
|
});
|
|
itBundled("edgecase/IdentifierInEnum#13081", {
|
|
files: {
|
|
"/entry.ts": `
|
|
let ZZZZZZZZZ = 1;
|
|
enum B {
|
|
C = ZZZZZZZZZ,
|
|
}
|
|
console.log(B.C);
|
|
`,
|
|
},
|
|
run: { stdout: "1" },
|
|
});
|
|
itBundled("edgecase/DoNotMoveTaggedTemplateLiterals", {
|
|
files: {
|
|
"/entry.ts": `
|
|
globalThis.z = () => console.log(2)
|
|
const y = await import('./second.ts');
|
|
`,
|
|
"/second.ts": `
|
|
console.log(1);
|
|
export const y = z\`zyx\`;
|
|
`,
|
|
},
|
|
run: { stdout: "1\n2" },
|
|
});
|
|
itBundled("edgecase/Latin1StringInImportedJSON", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import x from './second.json';
|
|
console.log(x + 'a');
|
|
`,
|
|
"/second.json": `
|
|
"测试"
|
|
`,
|
|
},
|
|
target: "bun",
|
|
run: { stdout: `测试a` },
|
|
});
|
|
itBundled("edgecase/Latin1StringInImportedJSONBrowser", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import x from './second.json';
|
|
console.log(x + 'a');
|
|
`,
|
|
"/second.json": `
|
|
"测试"
|
|
`,
|
|
},
|
|
target: "browser",
|
|
run: { stdout: `测试a` },
|
|
});
|
|
itBundled("edgecase/Latin1StringKey", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import x from './second.json';
|
|
console.log(x["测试" + "a"]);
|
|
`,
|
|
"/second.json": `
|
|
{"测试a" : 123}
|
|
`,
|
|
},
|
|
target: "bun",
|
|
run: { stdout: `123` },
|
|
});
|
|
itBundled("edgecase/Latin1StringKeyBrowser", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import x from './second.json';
|
|
console.log(x["测试" + "a"]);
|
|
`,
|
|
"/second.json": `
|
|
{"测试a" : 123}
|
|
`,
|
|
},
|
|
target: "browser",
|
|
run: { stdout: `123` },
|
|
});
|
|
|
|
itBundled("edgecase/UninitializedVariablesMoved", {
|
|
files: {
|
|
"/entry.ts": `
|
|
await import('./b.js');
|
|
`,
|
|
"/b.js": `
|
|
export var a = 32;
|
|
export var b;
|
|
(function (c) {
|
|
c.d = 1;
|
|
})(b ?? {});
|
|
+a;
|
|
`,
|
|
},
|
|
minifySyntax: true,
|
|
run: true, // pass if no thrown error
|
|
});
|
|
|
|
itBundled("edgecase/UsingExportDefault", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import module from "./module.ts";
|
|
console.log(module.x);
|
|
`,
|
|
"/module.ts": `
|
|
using a = {
|
|
[Symbol.dispose]: () => {
|
|
console.log("Disposing");
|
|
}
|
|
};
|
|
export default {x: 1};
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "Disposing\n1",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/UsingExportClass", {
|
|
files: {
|
|
"/entry.ts": `
|
|
export class A {
|
|
[Symbol.dispose](){
|
|
console.info("Disposing");
|
|
}
|
|
}
|
|
using a = new A();
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "Disposing",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/UsingExportDefaultThrows", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import("./module.ts").catch(error => {
|
|
console.log("Caught error:", error.message);
|
|
});
|
|
`,
|
|
"/module.ts": `
|
|
function somethingThatThrows() {
|
|
throw new Error("This function throws");
|
|
}
|
|
|
|
using disposable = {
|
|
[Symbol.dispose]: () => {
|
|
console.log("Disposing");
|
|
}
|
|
};
|
|
|
|
export default somethingThatThrows();
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "Disposing\nCaught error: This function throws",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/UsingExportDefaultAsync", {
|
|
files: {
|
|
"/entry.ts": `
|
|
const result = await import("./importer.ts");
|
|
console.log(await result.default);
|
|
`,
|
|
"/importer.ts": `
|
|
async function main() {
|
|
using disposable = {
|
|
[Symbol.dispose]: () => {
|
|
console.log("Disposing");
|
|
}
|
|
};
|
|
return "Success";
|
|
}
|
|
export default main();
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "Disposing\nSuccess",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/UsingDisposeThrowDoesntMask", {
|
|
files: {
|
|
"/entry.ts": `
|
|
using a = {
|
|
[Symbol.dispose]: () => {
|
|
throw new Error("Error");
|
|
}
|
|
};
|
|
using b = {
|
|
[Symbol.dispose]: () => {
|
|
console.log("Disposing");
|
|
}
|
|
}
|
|
`,
|
|
},
|
|
run: {
|
|
error: "error: Error",
|
|
stdout: "Disposing",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/UsingExportFails", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import a from "./import.ts";
|
|
console.log(a.ok);
|
|
`,
|
|
"/import.ts": `
|
|
using a = {
|
|
[Symbol.dispose]: () => {
|
|
console.log("Disposing");
|
|
},
|
|
ok: true,
|
|
};
|
|
export default a;
|
|
`,
|
|
},
|
|
run: {
|
|
stdout: "Disposing\ntrue",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/NoOutWithTwoFiles", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import index from './index.html' with { type: 'file' }
|
|
console.log(index);
|
|
`,
|
|
"/index.html": `
|
|
<head></head>
|
|
`,
|
|
},
|
|
generateOutput: false,
|
|
backend: "api",
|
|
onAfterApiBundle: async build => {
|
|
expect(build.success).toEqual(true);
|
|
expect(build.outputs).toBeArrayOfSize(2);
|
|
|
|
expect(build.outputs[0].path).toEqual("./entry.js");
|
|
expect(build.outputs[0].loader).toEqual("ts");
|
|
expect(build.outputs[0].kind).toEqual("entry-point");
|
|
|
|
expect(build.outputs[1].loader).toEqual("file");
|
|
expect(build.outputs[1].kind).toEqual("asset");
|
|
expect(await build.outputs[1].text()).toEqual("<head></head>");
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/OutWithTwoFiles", {
|
|
backend: "cli",
|
|
files: {
|
|
"/entry.ts": `
|
|
import index from './index.html' with { type: 'file' }
|
|
console.log(index);
|
|
`,
|
|
"/index.html": `
|
|
<head></head>
|
|
`,
|
|
},
|
|
generateOutput: true,
|
|
bundleErrors: {
|
|
"<bun>": ["cannot write multiple output files without an output directory"],
|
|
},
|
|
run: true,
|
|
});
|
|
|
|
// TODO(@paperclover): test every case of this. I had already tested it manually, but it may break later
|
|
const requireTranspilationListESM = [
|
|
// input, output:bun, output:node
|
|
["require", "import.meta.require", "__require"],
|
|
["typeof require", "import.meta.require", "typeof __require"],
|
|
["typeof require", "import.meta.require", "typeof __require"],
|
|
];
|
|
|
|
// // itBundled('edgecase/RequireTranspilation')
|
|
|
|
itBundled("edgecase/TSConfigPathsConfigDir", {
|
|
files: {
|
|
"/src/entry.ts": /* ts */ `
|
|
import { value } from "alias/foo";
|
|
import { other } from "@scope/bar";
|
|
import { nested } from "deep/path";
|
|
import { absolute } from "abs/path";
|
|
console.log(value, other, nested, absolute);
|
|
`,
|
|
"/src/actual/foo.ts": `export const value = "foo";`,
|
|
"/src/lib/bar.ts": `export const other = "bar";`,
|
|
"/src/nested/deep/file.ts": `export const nested = "nested";`,
|
|
"/src/absolute.ts": `export const absolute = "absolute";`,
|
|
"/src/tsconfig.json": /* json */ `{
|
|
"compilerOptions": {
|
|
"baseUrl": "\${configDir}",
|
|
"paths": {
|
|
"alias/*": ["actual/*"],
|
|
"@scope/*": ["lib/*"],
|
|
"deep/path": ["nested/deep/file.ts"],
|
|
"abs/*": ["\${configDir}/absolute.ts"]
|
|
}
|
|
}
|
|
}`,
|
|
},
|
|
run: {
|
|
stdout: "foo bar nested absolute",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/TSConfigBaseUrlConfigDir", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
import { value } from "./src/subdir/module";
|
|
console.log(value);
|
|
`,
|
|
"/src/lib/module.ts": `export const value = "found";`,
|
|
"/src/subdir/module.ts": `
|
|
import { value } from "absolute";
|
|
export { value };
|
|
`,
|
|
"tsconfig.json": /* json */ `{
|
|
"compilerOptions": {
|
|
"baseUrl": "\${configDir}/src/lib",
|
|
"paths": {
|
|
"absolute": ["./module.ts"]
|
|
}
|
|
}
|
|
}`,
|
|
},
|
|
run: {
|
|
stdout: "found",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/TSConfigPathsConfigDirWildcard", {
|
|
files: {
|
|
"/src/entry.ts": /* ts */ `
|
|
import { one } from "prefix/one";
|
|
import { two } from "prefix/two";
|
|
import { three } from "other/three";
|
|
console.log(one, two, three);
|
|
`,
|
|
"/src/modules/one.ts": `export const one = "one";`,
|
|
"/src/modules/two.ts": `export const two = "two";`,
|
|
"/src/alternate/three.ts": `export const three = "three";`,
|
|
"/src/tsconfig.json": /* json */ `{
|
|
"compilerOptions": {
|
|
"baseUrl": "\${configDir}",
|
|
"paths": {
|
|
"prefix/*": ["modules/*"],
|
|
"other/*": ["\${configDir}/alternate/*"]
|
|
}
|
|
}
|
|
}`,
|
|
},
|
|
run: {
|
|
stdout: "one two three",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/TSConfigPathsConfigDirNested", {
|
|
files: {
|
|
"/deeply/nested/src/entry.ts": /* ts */ `
|
|
import { value } from "alias/module";
|
|
console.log(value);
|
|
`,
|
|
"/deeply/nested/src/actual/module.ts": `export const value = "nested";`,
|
|
"/deeply/nested/src/tsconfig.json": /* json */ `{
|
|
"compilerOptions": {
|
|
"baseUrl": "\${configDir}",
|
|
"paths": {
|
|
"alias/*": ["actual/*"]
|
|
}
|
|
}
|
|
}`,
|
|
},
|
|
run: {
|
|
stdout: "nested",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/TSConfigPathsConfigDirMultiple", {
|
|
files: {
|
|
"/src/entry.ts": /* ts */ `
|
|
import { value } from "multi/module";
|
|
console.log(value);
|
|
`,
|
|
"/src/fallback/module.ts": `export const value = "fallback";`,
|
|
"/src/primary/module.ts": `export const value = "primary";`,
|
|
"/src/tsconfig.json": /* json */ `{
|
|
"compilerOptions": {
|
|
"baseUrl": "\${configDir}",
|
|
"paths": {
|
|
"multi/*": [
|
|
"\${configDir}/primary/*",
|
|
"\${configDir}/fallback/*"
|
|
]
|
|
}
|
|
}
|
|
}`,
|
|
},
|
|
run: {
|
|
stdout: "primary",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/TSConfigPathsConfigDirInvalid", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
import { value } from "invalid/module";
|
|
console.log(value);
|
|
`,
|
|
"/tsconfig.json": /* json */ `{
|
|
"compilerOptions": {
|
|
"baseUrl": "\${configDir}",
|
|
"paths": {
|
|
"invalid/*": ["\${configDir}/\${configDir}/*"]
|
|
}
|
|
}
|
|
}`,
|
|
},
|
|
bundleErrors: {
|
|
"/entry.ts": ['Could not resolve: "invalid/module". Maybe you need to "bun install"?'],
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/TSConfigPathsConfigDirBackslash", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
import { value } from "windows/style";
|
|
console.log(value);
|
|
`,
|
|
"/win/style.ts": `export const value = "windows";`,
|
|
"/tsconfig.json": /* json */ `{
|
|
"compilerOptions": {
|
|
"baseUrl": "\${configDir}",
|
|
"paths": {
|
|
"windows/*": ["win\\\\*"]
|
|
}
|
|
}
|
|
}`,
|
|
},
|
|
run: {
|
|
stdout: "windows",
|
|
},
|
|
});
|
|
|
|
itBundled("edgecase/TSPublicFieldMinification", {
|
|
files: {
|
|
"/entry.ts": /* ts */ `
|
|
export class Foo {
|
|
constructor(public name: string) {}
|
|
}
|
|
|
|
const keys = Object.keys(new Foo('test'))
|
|
if (keys.length !== 1) throw new Error('Keys length is not 1')
|
|
if (keys[0] !== 'name') throw new Error('keys[0] is not "name"')
|
|
console.log('success')
|
|
`,
|
|
},
|
|
minifySyntax: true,
|
|
minifyIdentifiers: true,
|
|
target: "bun",
|
|
run: {
|
|
stdout: "success",
|
|
},
|
|
});
|
|
// https://github.com/oven-sh/bun/issues/14585
|
|
itBundled("identifiers/SameNameDifferentModulesWithMinifyIdentifiersDisabled", {
|
|
files: {
|
|
"/foo.js": `
|
|
{
|
|
var d = 0;
|
|
}
|
|
|
|
export const foo = () => {}
|
|
`,
|
|
"/bar.js": `
|
|
// bar.js - The collision happens with this function declaration
|
|
function d() {}
|
|
export function bar() {d.length;}
|
|
`,
|
|
"/index.js": `
|
|
import { foo } from "./foo.js";
|
|
import { bar } from "./bar.js";
|
|
|
|
// Execute in order
|
|
foo();
|
|
bar();
|
|
`,
|
|
},
|
|
entryPoints: ["/index.js"],
|
|
outfile: "/out.js",
|
|
minifyIdentifiers: false,
|
|
run: {
|
|
stdout: "",
|
|
},
|
|
});
|
|
itBundled("edgecase/NodeBuiltinWithoutPrefix", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import * as hello from "node:test";
|
|
import * as world from "node:fs";
|
|
import * as etc from "console";
|
|
import * as blah from "bun:jsc";
|
|
+[hello,world,etc,blah];
|
|
`,
|
|
},
|
|
target: "bun",
|
|
onAfterBundle(api) {
|
|
api.expectFile("out.js").toMatchInlineSnapshot(`
|
|
"// @bun
|
|
// entry.ts
|
|
import * as hello from "node:test";
|
|
import * as world from "fs";
|
|
import * as etc from "console";
|
|
import * as blah from "bun:jsc";
|
|
+[hello, world, etc, blah];
|
|
"
|
|
`);
|
|
},
|
|
});
|
|
itBundled("edgecase/NodeBuiltinWithoutPrefix2", {
|
|
files: {
|
|
"/entry.ts": `
|
|
import * as hello from "node:test";
|
|
import * as world from "node:fs";
|
|
import * as etc from "console";
|
|
+[hello,world,etc];
|
|
`,
|
|
},
|
|
target: "node",
|
|
onAfterBundle(api) {
|
|
api.expectFile("out.js").toMatchInlineSnapshot(`
|
|
"// entry.ts
|
|
import * as hello from "node:test";
|
|
import * as world from "node:fs";
|
|
import * as etc from "console";
|
|
+[hello, world, etc];
|
|
"
|
|
`);
|
|
},
|
|
});
|
|
});
|
|
|
|
for (const backend of ["api", "cli"] as const) {
|
|
describe(`bundler_edgecase/${backend}`, () => {
|
|
itBundled("edgecase/ProcessEnvArbitrary", {
|
|
files: {
|
|
"/entry.js": /* js */ `
|
|
capture(process.env.ARBITRARY);
|
|
`,
|
|
},
|
|
target: "browser",
|
|
backend,
|
|
capture: ["process.env.ARBITRARY"],
|
|
env: {
|
|
ARBITRARY: "secret environment stuff!",
|
|
},
|
|
});
|
|
});
|
|
}
|