aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/bundler/migration.md30
-rw-r--r--docs/cli/build.md74
-rw-r--r--packages/bun-types/bun.d.ts83
-rw-r--r--src/bun.js/api/JSBundler.zig113
-rw-r--r--src/bun.js/api/JSTranspiler.zig2
-rw-r--r--src/bun.js/bindings/bindings.zig3
-rw-r--r--src/bun.js/builtins/js/BundlerPlugin.js4
-rw-r--r--src/bundler/bundle_v2.zig1
-rw-r--r--src/cli.zig25
-rw-r--r--src/options.zig48
-rw-r--r--test/bundler/bundler_cjs2esm.test.ts1
-rw-r--r--test/bundler/bundler_edgecase.test.ts236
-rw-r--r--test/bundler/bundler_plugin.test.ts204
-rw-r--r--test/bundler/bundler_string.test.ts137
-rw-r--r--test/bundler/esbuild/dce.test.ts29
-rw-r--r--test/bundler/esbuild/default.test.ts448
-rw-r--r--test/bundler/esbuild/importstar.test.ts8
-rw-r--r--test/bundler/esbuild/importstar_ts.test.ts12
-rw-r--r--test/bundler/esbuild/loader.test.ts4
-rw-r--r--test/bundler/esbuild/lower.test.ts58
-rw-r--r--test/bundler/esbuild/packagejson.test.ts2
-rw-r--r--test/bundler/esbuild/splitting.test.ts2
-rw-r--r--test/bundler/esbuild/ts.test.ts548
-rw-r--r--test/bundler/esbuild/tsconfig.test.ts280
-rw-r--r--test/bundler/expectBundled.ts240
-rw-r--r--test/bundler/report-bundler-test-progress.sh2
26 files changed, 1862 insertions, 732 deletions
diff --git a/docs/bundler/migration.md b/docs/bundler/migration.md
index 260acf1ba..aac37479c 100644
--- a/docs/bundler/migration.md
+++ b/docs/bundler/migration.md
@@ -63,8 +63,8 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
---
-- `--loader`
-- `--loader`
+- `--loader:.ext=loader`
+- `--loader .ext:loader`
- Bun supports a different set of built-in loaders than esbuild; see [Bundler > Loaders](/docs/bundler/loaders) for a complete reference. The esbuild loaders `dataurl`, `binary`, `base64`, `copy`, and `empty` are not yet implemented.
The syntax for `--loader` is slightly different.
@@ -131,7 +131,7 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
- `--watch`
- n/a
-- Not applicable.
+- Not applicable
---
@@ -143,7 +143,7 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
- `--analyze`
- n/a
-- Not supported. Use `--manifest` to generate a manifest file.
+- Not supported
---
@@ -161,7 +161,7 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
- `--certfile`
- n/a
-- Not applicable, Bun's bundler does
+- Not applicable
---
@@ -203,7 +203,7 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
- `--global-name`
- n/a
-- Not applicable, Bun does not support `iife` output at this time.
+- Not applicable, Bun does not support `iife` output at this time
---
@@ -248,7 +248,7 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
- `--jsx-side-effects`
- n/a
-- JSX is always assumed to be side-effect-free.
+- JSX is always assumed to be side-effect-free
---
@@ -313,7 +313,8 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
---
- `--metafile`
-- `--manifest`
+- n/a
+- Not supported
---
@@ -340,7 +341,6 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
- `--outbase`
- `--root`
-- Not supported
---
@@ -515,7 +515,6 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
- `define`
- `define`
-- Not supported in JS API
---
@@ -637,8 +636,8 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
---
- `loader`
-- n/a
-- Not supported in JS API
+- `loader`
+- Bun supports a different set of built-in loaders than esbuild; see [Bundler > Loaders](/docs/bundler/loaders) for a complete reference. The esbuild loaders `dataurl`, `binary`, `base64`, `copy`, and `empty` are not yet implemented.
---
@@ -685,8 +684,11 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
---
- `metafile`
-- `manifest`
-- When `manifest` is `true`, the result of `Bun.build()` will contain a `manifest` property. The manifest is compatible with esbuild's metafile format.
+- n/a
+- Not supported
+
+<!-- - `manifest`
+- When `manifest` is `true`, the result of `Bun.build()` will contain a `manifest` property. The manifest is compatible with esbuild's metafile format. -->
---
diff --git a/docs/cli/build.md b/docs/cli/build.md
index f205969d5..01262944d 100644
--- a/docs/cli/build.md
+++ b/docs/cli/build.md
@@ -324,7 +324,7 @@ Depending on the target, Bun will apply different module resolution rules and op
{% /table %}
-<!-- ### `module`
+### `format`
Specifies the module format to be used in the generated bundles.
@@ -714,6 +714,24 @@ var value = z.string().parse("Hello world!")
console.log(_.upperCase(value));
```
+To mark all imports as external, use the wildcard `*`:
+
+{% codetabs %}
+
+```ts#JavaScript
+await Bun.build({
+ entrypoints: ['./index.tsx'],
+ outdir: './out',
+ external: ['*'],
+})
+```
+
+```bash#CLI
+$ bun build ./index.tsx --outdir ./out --external '*'
+```
+
+{% /codetabs %}
+
### `naming`
Customizes the generated file names. Defaults to `./[dir]/[name].[ext]`.
@@ -988,6 +1006,56 @@ The output file would now look something like this.
+ var logo = 'https://cdn.example.com/logo-a7305bdef.svg';
```
+### `define`
+
+A map of global identifiers to be replaced at build time. Keys of this object are identifier names, and values are JSON strings that will be inlined.
+
+{% callout }
+This is not needed to inline `process.env.NODE_ENV`, as Bun does this automatically.
+{% /callout %}
+
+{% codetabs %}
+
+```ts#JavaScript
+await Bun.build({
+ entrypoints: ['./index.tsx'],
+ outdir: './out',
+ define: {
+ STRING: JSON.stringify("value"),
+ "nested.boolean": "true",
+ },
+})
+```
+
+```bash#CLI
+$ bun build ./index.tsx --outdir ./out --define 'STRING="value"' --define "nested.boolean=true"
+```
+
+{% /codetabs %}
+
+### `loader`
+
+A map of file extensions to [built-in loader names](https://bun.sh/docs/bundler/loaders#built-in-loaders). This can be used to quickly customize how certain file files are loaded.
+
+{% codetabs %}
+
+```ts#JavaScript
+await Bun.build({
+ entrypoints: ['./index.tsx'],
+ outdir: './out',
+ loader: {
+ ".png": "dataurl",
+ ".txt": "file",
+ },
+})
+```
+
+```bash#CLI
+$ bun build ./index.tsx --outdir ./out --loader .png:dataurl --loader .txt:file
+```
+
+{% /codetabs %}
+
## Reference
```ts
@@ -1003,8 +1071,8 @@ interface BuildOptions {
outdir?: string; // default: no write (in-memory only)
target?: "browser" | "bun" | "node"; // "browser"
splitting?: boolean; // true
- plugins?: BunPlugin[]; // []
- loader?: { [k in string]: Loader };
+ plugins?: BunPlugin[]; // [] // See https://bun.sh/docs/bundler/plugins
+ loader?: { [k in string]: Loader }; // See https://bun.sh/docs/bundler/loaders
manifest?: boolean; // false
external?: string[]; // []
sourcemap?: "none" | "inline" | "external"; // "none"
diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts
index 03c17001c..f00c2cd45 100644
--- a/packages/bun-types/bun.d.ts
+++ b/packages/bun-types/bun.d.ts
@@ -933,18 +933,19 @@ declare module "bun" {
scanImports(code: StringOrBuffer): Import[];
}
+ export type ImportKind =
+ | "import-statement"
+ | "require-call"
+ | "require-resolve"
+ | "dynamic-import"
+ | "import-rule"
+ | "url-token"
+ | "internal"
+ | "entry-point";
+
export interface Import {
path: string;
-
- kind:
- | "import-statement"
- | "require-call"
- | "require-resolve"
- | "dynamic-import"
- | "import-rule"
- | "url-token"
- | "internal"
- | "entry-point";
+ kind: ImportKind;
}
type ModuleFormat = "esm"; // later: "cjs", "iife"
@@ -954,7 +955,6 @@ declare module "bun" {
outdir?: string; // output directory
target?: Target; // default: "browser"
format?: ModuleFormat; // later: "cjs", "iife"
-
naming?:
| string
| {
@@ -968,9 +968,10 @@ declare module "bun" {
// manifest?: boolean; // whether to return manifest
external?: Array<string>;
publicPath?: string;
+ define?: Record<string, string>;
// origin?: string; // e.g. http://mydomain.com
- // loaders?: { [k in string]: Loader };
- // sourcemap?: "none" | "inline" | "external"; // default: "none"
+ loader?: { [k in string]: Loader };
+ sourcemap?: "none" | "inline" | "external"; // default: "none"
minify?:
| boolean
| {
@@ -979,6 +980,19 @@ declare module "bun" {
identifiers?: boolean;
};
// treeshaking?: boolean;
+
+ // jsx?:
+ // | "automatic"
+ // | "classic"
+ // | /* later: "preserve" */ {
+ // runtime?: "automatic" | "classic"; // later: "preserve"
+ // /** Only works when runtime=classic */
+ // factory?: string; // default: "React.createElement"
+ // /** Only works when runtime=classic */
+ // fragment?: string; // default: "React.Fragment"
+ // /** Only works when runtime=automatic */
+ // importSource?: string; // default: "react"
+ // };
}
type BuildResult<T = Blob> = {
@@ -2513,7 +2527,19 @@ declare module "bun" {
* The plugin will be applied to browser builds
*/
| "browser";
- type Loader = "js" | "jsx" | "ts" | "tsx" | "json" | "toml";
+ /** https://bun.sh/docs/bundler/loaders */
+ type Loader =
+ | "js"
+ | "jsx"
+ | "ts"
+ | "tsx"
+ | "json"
+ | "toml"
+ | "file"
+ | "napi"
+ | "wasm"
+ | "dataurl"
+ | "text";
interface PluginConstraints {
/**
@@ -2556,7 +2582,7 @@ declare module "bun" {
*
* "css" will be added in a future version of Bun.
*/
- loader: Loader;
+ loader?: Loader;
}
interface OnLoadResultObject {
@@ -2593,6 +2619,14 @@ declare module "bun" {
* ```
*/
path: string;
+ /**
+ * The namespace of the module being loaded
+ */
+ namespace: string;
+ /**
+ * The default loader for this file extension
+ */
+ loader: Loader;
}
type OnLoadResult = OnLoadResultSourceCode | OnLoadResultObject;
@@ -2609,6 +2643,16 @@ declare module "bun" {
* The module that imported the module being resolved
*/
importer: string;
+ /**
+ * The namespace of the importer.
+ */
+ namespace: string;
+ /**
+ * The kind of import this resolve is for.
+ */
+ kind: ImportKind;
+ // resolveDir: string;
+ // pluginData: any;
}
interface OnResolveResult {
@@ -2627,7 +2671,14 @@ declare module "bun" {
namespace?: string;
}
- type OnResolveCallback = (args: OnResolveArgs) => OnResolveResult | void;
+ type OnResolveCallback = (
+ args: OnResolveArgs,
+ ) =>
+ | OnResolveResult
+ | Promise<OnResolveResult | void | undefined | null>
+ | void
+ | undefined
+ | null;
interface PluginBuilder {
/**
diff --git a/src/bun.js/api/JSBundler.zig b/src/bun.js/api/JSBundler.zig
index cccbca9db..55c224726 100644
--- a/src/bun.js/api/JSBundler.zig
+++ b/src/bun.js/api/JSBundler.zig
@@ -51,6 +51,7 @@ pub const JSBundler = struct {
entry_points: bun.StringSet = bun.StringSet.init(bun.default_allocator),
hot: bool = false,
define: bun.StringMap = bun.StringMap.init(bun.default_allocator, true),
+ loaders: ?Api.LoaderMap = null,
dir: OwnedString = OwnedString.initEmpty(bun.default_allocator),
outdir: OwnedString = OwnedString.initEmpty(bun.default_allocator),
serve: Serve = .{},
@@ -60,7 +61,6 @@ pub const JSBundler = struct {
server_components: ServerComponents = ServerComponents{},
names: Names = .{},
- label: OwnedString = OwnedString.initEmpty(bun.default_allocator),
external: bun.StringSet = bun.StringSet.init(bun.default_allocator),
source_map: options.SourceMapOption = .none,
public_path: OwnedString = OwnedString.initEmpty(bun.default_allocator),
@@ -73,7 +73,6 @@ pub const JSBundler = struct {
.external = bun.StringSet.init(allocator),
.define = bun.StringMap.init(allocator, true),
.dir = OwnedString.initEmpty(allocator),
- .label = OwnedString.initEmpty(allocator),
.outdir = OwnedString.initEmpty(allocator),
.names = .{
.owned_entry_point = OwnedString.initEmpty(allocator),
@@ -88,6 +87,20 @@ pub const JSBundler = struct {
this.target = target;
}
+ if (try config.getOptionalEnum(globalThis, "sourcemap", options.SourceMapOption)) |source_map| {
+ this.source_map = source_map;
+ }
+
+ if (try config.getOptionalEnum(globalThis, "format", options.Format)) |format| {
+ switch (format) {
+ .esm => {},
+ else => {
+ globalThis.throwInvalidArguments("Formats besides 'esm' are not implemented", .{});
+ return error.JSException;
+ },
+ }
+ }
+
// if (try config.getOptional(globalThis, "hot", bool)) |hot| {
// this.hot = hot;
// }
@@ -150,17 +163,12 @@ pub const JSBundler = struct {
}
}
- if (try config.getOptional(globalThis, "label", ZigString.Slice)) |slice| {
- defer slice.deinit();
- this.label.appendSliceExact(slice.slice()) catch unreachable;
- }
-
- if (try config.getOptional(globalThis, "dir", ZigString.Slice)) |slice| {
- defer slice.deinit();
- this.dir.appendSliceExact(slice.slice()) catch unreachable;
- } else {
- this.dir.appendSliceExact(globalThis.bunVM().bundler.fs.top_level_dir) catch unreachable;
- }
+ // if (try config.getOptional(globalThis, "dir", ZigString.Slice)) |slice| {
+ // defer slice.deinit();
+ // this.dir.appendSliceExact(slice.slice()) catch unreachable;
+ // } else {
+ // this.dir.appendSliceExact(globalThis.bunVM().bundler.fs.top_level_dir) catch unreachable;
+ // }
if (try config.getOptional(globalThis, "publicPath", ZigString.Slice)) |slice| {
defer slice.deinit();
@@ -198,6 +206,84 @@ pub const JSBundler = struct {
}
}
+ if (try config.getObject(globalThis, "define")) |define| {
+ if (!define.isObject()) {
+ globalThis.throwInvalidArguments("define must be an object", .{});
+ return error.JSException;
+ }
+
+ var define_iter = JSC.JSPropertyIterator(.{
+ .skip_empty_name = true,
+ .include_value = true,
+ }).init(globalThis, define.asObjectRef());
+ defer define_iter.deinit();
+
+ while (define_iter.next()) |prop| {
+ const property_value = define_iter.value;
+ const value_type = property_value.jsType();
+
+ if (!value_type.isStringLike()) {
+ globalThis.throwInvalidArguments("define \"{s}\" must be a JSON string", .{prop});
+ return error.JSException;
+ }
+
+ var val = JSC.ZigString.init("");
+ property_value.toZigString(&val, globalThis);
+ if (val.len == 0) {
+ val = JSC.ZigString.init("\"\"");
+ }
+
+ try this.define.insert(prop.slice(), val.slice());
+ }
+ }
+
+ if (try config.getObject(globalThis, "loader")) |loaders| {
+ if (!loaders.isUndefinedOrNull()) {
+ if (!loaders.isObject()) {
+ globalThis.throwInvalidArguments("loader must be an object", .{});
+ return error.JSException;
+ }
+
+ var loader_iter = JSC.JSPropertyIterator(.{
+ .skip_empty_name = true,
+ .include_value = true,
+ }).init(globalThis, loaders.asObjectRef());
+ defer loader_iter.deinit();
+
+ var loader_names = try allocator.alloc(string, loader_iter.len);
+ var loader_values = try allocator.alloc(Api.Loader, loader_iter.len);
+
+ while (loader_iter.next()) |prop| {
+ if (prop.len == 0 or prop.ptr[0] != '.') {
+ globalThis.throwInvalidArguments("loader property names must be file extensions, such as '.txt'", .{});
+ return error.JSException;
+ }
+
+ loader_names[loader_iter.i] = prop.slice();
+ var property_value = loader_iter.value;
+ var value_type = property_value.jsType();
+ if (!value_type.isStringLike()) {
+ globalThis.throwInvalidArguments("loader \"{s}\" must be a string", .{prop});
+ return error.JSException;
+ }
+
+ var val = JSC.ZigString.init("");
+ property_value.toZigString(&val, globalThis);
+ if (options.Loader.fromString(val.slice())) |loader| {
+ loader_values[loader_iter.i] = loader.toAPI();
+ } else {
+ globalThis.throwInvalidArguments("loader \"{s}\" is not a valid loader", .{val});
+ return error.JSException;
+ }
+ }
+
+ this.loaders = Api.LoaderMap{
+ .extensions = loader_names,
+ .loaders = loader_values,
+ };
+ }
+ }
+
if (try config.getArray(globalThis, "plugins")) |array| {
var iter = array.arrayIterator(globalThis);
while (iter.next()) |plugin| {
@@ -355,7 +441,6 @@ pub const JSBundler = struct {
self.serve.deinit(allocator);
self.server_components.deinit(allocator);
self.names.deinit();
- self.label.deinit();
self.outdir.deinit();
self.public_path.deinit();
}
diff --git a/src/bun.js/api/JSTranspiler.zig b/src/bun.js/api/JSTranspiler.zig
index f1b00f191..2ac6948d1 100644
--- a/src/bun.js/api/JSTranspiler.zig
+++ b/src/bun.js/api/JSTranspiler.zig
@@ -565,7 +565,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std
}
} else {
var sourcemap = flag.toSlice(globalThis, allocator);
- if (options.SourceMapOption.map.get(sourcemap.slice())) |source| {
+ if (options.SourceMapOption.Map.get(sourcemap.slice())) |source| {
transpiler.transform.source_map = source.toAPI();
} else {
JSC.throwInvalidArguments("sourcemap must be one of \"inline\", \"external\", or \"none\"", .{}, globalObject, exception);
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 12cc81118..71409da4f 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -4009,9 +4009,10 @@ pub const JSValue = enum(JSValueReprInt) {
pub fn getOptionalEnum(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8, comptime Enum: type) !?Enum {
if (get(this, globalThis, property_name)) |prop| {
+ if (prop.isEmptyOrUndefinedOrNull())
+ return null;
return try toEnum(prop, globalThis, property_name, Enum);
}
-
return null;
}
diff --git a/src/bun.js/builtins/js/BundlerPlugin.js b/src/bun.js/builtins/js/BundlerPlugin.js
index 64c655bbe..ec8fee397 100644
--- a/src/bun.js/builtins/js/BundlerPlugin.js
+++ b/src/bun.js/builtins/js/BundlerPlugin.js
@@ -66,7 +66,9 @@ function runOnResolvePlugins(
path: inputPath,
importer,
namespace: inputNamespace,
+ // resolveDir
kind,
+ // pluginData
});
while (
@@ -368,6 +370,8 @@ function runOnLoadPlugins(internalID, path, namespace, defaultLoaderId) {
var result = callback({
path,
namespace,
+ // suffix
+ // pluginData
loader: defaultLoader,
});
diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig
index aad40b961..6bb307381 100644
--- a/src/bundler/bundle_v2.zig
+++ b/src/bundler/bundle_v2.zig
@@ -1555,6 +1555,7 @@ pub const BundleV2 = struct {
);
bundler.options.jsx = config.jsx;
+ bundler.options.loaders = try options.loadersFromTransformOptions(allocator, config.loaders, config.target);
bundler.options.entry_naming = config.names.entry_point.data;
bundler.options.chunk_naming = config.names.chunk.data;
bundler.options.asset_naming = config.names.asset.data;
diff --git a/src/cli.zig b/src/cli.zig
index 3f796e798..171593246 100644
--- a/src/cli.zig
+++ b/src/cli.zig
@@ -141,7 +141,6 @@ pub const Arguments = struct {
clap.parseParam("--jsx-factory <STR> Changes the function called when compiling JSX elements using the classic JSX runtime") catch unreachable,
clap.parseParam("--jsx-fragment <STR> Changes the function called when compiling JSX fragments") catch unreachable,
clap.parseParam("--jsx-import-source <STR> Declares the module specifier to be used for importing the jsx and jsxs factory functions. Default: \"react\"") catch unreachable,
- clap.parseParam("--jsx-production Use jsx instead of jsxDEV (default) for the automatic runtime") catch unreachable,
clap.parseParam("--jsx-runtime <STR> \"automatic\" (default) or \"classic\"") catch unreachable,
clap.parseParam("-r, --preload <STR>... Import a module before other modules are loaded") catch unreachable,
clap.parseParam("--main-fields <STR>... Main fields to lookup in package.json. Defaults to --target dependent") catch unreachable,
@@ -194,6 +193,7 @@ pub const Arguments = struct {
pub const params = public_params ++ debug_params;
const build_only_params = [_]ParamType{
+ clap.parseParam("--format <STR> Specifies the module format to build to. Only esm is supported.") catch unreachable,
clap.parseParam("--outdir <STR> Default to \"dist\" if multiple files") catch unreachable,
clap.parseParam("--outfile <STR> Write to a file") catch unreachable,
clap.parseParam("--splitting Enable code splitting") catch unreachable,
@@ -489,6 +489,20 @@ pub const Arguments = struct {
}
}
+ if (args.option("--format")) |format_str| {
+ const format = options.Format.fromString(format_str) orelse {
+ Output.prettyErrorln("<r><red>error<r>: Invalid format - must be esm, cjs, or iife", .{});
+ Global.crash();
+ };
+ switch (format) {
+ .esm => {},
+ else => {
+ Output.prettyErrorln("<r><red>error<r>: Formats besides 'esm' are not implemented", .{});
+ Global.crash();
+ },
+ }
+ }
+
if (args.flag("--splitting")) {
ctx.bundler_options.code_splitting = true;
}
@@ -569,9 +583,8 @@ pub const Arguments = struct {
var jsx_fragment = args.option("--jsx-fragment");
var jsx_import_source = args.option("--jsx-import-source");
var jsx_runtime = args.option("--jsx-runtime");
- var jsx_production = args.flag("--jsx-production");
const react_fast_refresh = switch (comptime cmd) {
- .DevCommand => !(args.flag("--disable-react-fast-refresh") or jsx_production),
+ .DevCommand => !args.flag("--disable-react-fast-refresh"),
else => true,
};
@@ -689,7 +702,7 @@ pub const Arguments = struct {
jsx_fragment != null or
jsx_import_source != null or
jsx_runtime != null or
- jsx_production or !react_fast_refresh)
+ !react_fast_refresh)
{
var default_factory = "".*;
var default_fragment = "".*;
@@ -700,7 +713,7 @@ pub const Arguments = struct {
.fragment = constStrToU8(jsx_fragment orelse &default_fragment),
.import_source = constStrToU8(jsx_import_source orelse &default_import_source),
.runtime = if (jsx_runtime != null) try resolve_jsx_runtime(jsx_runtime.?) else Api.JsxRuntime.automatic,
- .development = !jsx_production,
+ .development = false,
.react_fast_refresh = react_fast_refresh,
};
} else {
@@ -709,7 +722,7 @@ pub const Arguments = struct {
.fragment = constStrToU8(jsx_fragment orelse opts.jsx.?.fragment),
.import_source = constStrToU8(jsx_import_source orelse opts.jsx.?.import_source),
.runtime = if (jsx_runtime != null) try resolve_jsx_runtime(jsx_runtime.?) else opts.jsx.?.runtime,
- .development = !jsx_production,
+ .development = false,
.react_fast_refresh = react_fast_refresh,
};
}
diff --git a/src/options.zig b/src/options.zig
index 958b36874..fee9035c4 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -636,6 +636,52 @@ pub const Target = enum {
};
};
+pub const Format = enum {
+ esm,
+ cjs,
+ iife,
+
+ pub const Map = ComptimeStringMap(
+ Format,
+ .{
+ .{
+ "esm",
+ Format.esm,
+ },
+ .{
+ "cjs",
+ Format.cjs,
+ },
+ .{
+ "iife",
+ Format.iife,
+ },
+ },
+ );
+
+ pub fn fromJS(global: *JSC.JSGlobalObject, format: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Format {
+ if (format.isUndefinedOrNull()) return null;
+
+ if (!format.jsType().isStringLike()) {
+ JSC.throwInvalidArguments("Format must be a string", .{}, global, exception);
+ return null;
+ }
+
+ var zig_str = JSC.ZigString.init("");
+ format.toZigString(&zig_str, global);
+ if (zig_str.len == 0) return null;
+
+ return fromString(zig_str.slice()) orelse {
+ JSC.throwInvalidArguments("Invalid format - must be esm, cjs, or iife", .{}, global, exception);
+ return null;
+ };
+ }
+
+ pub fn fromString(slice: string) ?Format {
+ return Map.getWithEql(slice, strings.eqlComptime);
+ }
+};
+
pub const Loader = enum(u8) {
jsx,
js,
@@ -1271,7 +1317,7 @@ pub const SourceMapOption = enum {
};
}
- pub const map = ComptimeStringMap(SourceMapOption, .{
+ pub const Map = ComptimeStringMap(SourceMapOption, .{
.{ "none", .none },
.{ "inline", .@"inline" },
.{ "external", .external },
diff --git a/test/bundler/bundler_cjs2esm.test.ts b/test/bundler/bundler_cjs2esm.test.ts
index f88700372..58b7846d0 100644
--- a/test/bundler/bundler_cjs2esm.test.ts
+++ b/test/bundler/bundler_cjs2esm.test.ts
@@ -139,7 +139,6 @@ describe("bundler", () => {
},
});
itBundled("cjs2esm/ModuleExportsEqualsRuntimeCondition", {
- notImplemented: true,
files: {
"/entry.js": /* js */ `
import { foo } from 'lib';
diff --git a/test/bundler/bundler_edgecase.test.ts b/test/bundler/bundler_edgecase.test.ts
index 6020ba2ec..30721637f 100644
--- a/test/bundler/bundler_edgecase.test.ts
+++ b/test/bundler/bundler_edgecase.test.ts
@@ -50,6 +50,7 @@ describe("bundler", () => {
run: true,
});
itBundled("edgecase/BunPluginTreeShakeImport", {
+ notImplemented: true,
// This only appears at runtime and not with bun build, even with --transform
files: {
"/entry.ts": /* js */ `
@@ -71,8 +72,7 @@ describe("bundler", () => {
}
`,
},
- external: ["external"],
- mode: "transform",
+ bundling: false,
minifySyntax: true,
target: "bun",
run: { file: "/entry.ts" },
@@ -88,14 +88,6 @@ describe("bundler", () => {
capture: ["`\\\\?`", "hello`\\\\?`"],
target: "bun",
});
- itBundled("edgecase/StringNullBytes", {
- files: {
- "/entry.ts": /* js */ `
- capture("Hello\0");
- `,
- },
- capture: ['"Hello\0"'],
- });
// https://github.com/oven-sh/bun/issues/2699
itBundled("edgecase/ImportNamedFromExportStarCJS", {
files: {
@@ -198,7 +190,7 @@ describe("bundler", () => {
console.log(foo);
`,
},
- external: ["*"],
+ bundling: false,
});
itBundled("edgecase/ImportNamespaceAndDefault", {
files: {
@@ -207,7 +199,7 @@ describe("bundler", () => {
console.log(def2, JSON.stringify(ns2))
`,
},
- external: ["*"],
+ bundling: false,
runtimeFiles: {
"/c.js": /* js */ `
export default 1
@@ -282,11 +274,11 @@ describe("bundler", () => {
".cool": "wtf",
},
bundleErrors: {
- // todo: get the exact error
- "<bun>": ["InvalidLoader"],
+ "<bun>": ['invalid loader "wtf", expected one of:'],
},
});
itBundled("edgecase/ScriptTagEscape", {
+ notImplemented: true,
files: {
"/entry.js": /* js */ `
console.log('<script></script>');
@@ -428,4 +420,220 @@ describe("bundler", () => {
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", {
+ 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", {
+ 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
+ `,
+ },
+ });
});
diff --git a/test/bundler/bundler_plugin.test.ts b/test/bundler/bundler_plugin.test.ts
index 74c5650cc..a22ec49e3 100644
--- a/test/bundler/bundler_plugin.test.ts
+++ b/test/bundler/bundler_plugin.test.ts
@@ -57,6 +57,20 @@ describe("bundler", () => {
stdout: "HELLO WORLD",
},
});
+ itBundled("plugin/LoadImplicitLoader", {
+ files: loadFixture,
+ plugins(builder) {
+ builder.onLoad({ filter: /\.magic$/ }, async args => {
+ const text = await Bun.file(args.path).text();
+ return {
+ contents: `export const foo = ${JSON.stringify(text.toUpperCase())};`,
+ };
+ });
+ },
+ run: {
+ stdout: "HELLO WORLD",
+ },
+ });
// Load Plugin Errors
itBundled("plugin/LoadThrow", {
@@ -66,14 +80,21 @@ describe("bundler", () => {
throw new Error("error here");
});
},
+ bundleErrors: {
+ "/foo.magic": [`error here`],
+ },
});
itBundled("plugin/LoadThrowPrimative", {
files: loadFixture,
+ notImplemented: true,
plugins(builder) {
builder.onLoad({ filter: /\.magic$/ }, args => {
throw "123";
});
},
+ bundleErrors: {
+ "/foo.magic": [`123`],
+ },
});
itBundled("plugin/LoadThrowAsync", {
files: loadFixture,
@@ -82,14 +103,21 @@ describe("bundler", () => {
throw new Error("error here");
});
},
+ bundleErrors: {
+ "/foo.magic": [`error here`],
+ },
});
itBundled("plugin/LoadThrowPrimativeAsync", {
files: loadFixture,
+ notImplemented: true,
plugins(builder) {
builder.onLoad({ filter: /\.magic$/ }, async args => {
throw 123;
});
},
+ bundleErrors: {
+ "/foo.magic": [`123`],
+ },
});
// Load Plugin Errors
@@ -100,14 +128,44 @@ describe("bundler", () => {
throw new Error("error here");
});
},
+ bundleErrors: {
+ "/index.ts": [`error here`],
+ },
});
itBundled("plugin/ResolveThrowPrimative", {
files: resolveFixture,
+ notImplemented: true,
plugins(builder) {
builder.onResolve({ filter: /\.magic$/ }, args => {
throw "123";
});
},
+ bundleErrors: {
+ "/index.ts": [`123`],
+ },
+ });
+ itBundled("plugin/ResolveThrowAsync", {
+ files: resolveFixture,
+ plugins(builder) {
+ builder.onResolve({ filter: /\.magic$/ }, async args => {
+ throw new Error("error here");
+ });
+ },
+ bundleErrors: {
+ "/index.ts": [`error here`],
+ },
+ });
+ itBundled("plugin/ResolveThrowPrimativeAsync", {
+ files: resolveFixture,
+ notImplemented: true,
+ plugins(builder) {
+ builder.onResolve({ filter: /\.magic$/ }, async args => {
+ throw 123;
+ });
+ },
+ bundleErrors: {
+ "/index.ts": [`123`],
+ },
});
//
@@ -223,7 +281,6 @@ describe("bundler", () => {
builder.onLoad({ filter: /namespace_path/, namespace: "my_namespace" }, args => {
expect(args.path).toBe("namespace_path");
expect(args.namespace).toBe("my_namespace");
- expect(args.suffix).toBeFalsy();
return {
contents: "export const foo = 'foo';",
@@ -240,6 +297,8 @@ describe("bundler", () => {
};
});
itBundled("plugin/ResolveAndLoadNamespaceNested", ({ root }) => {
+ let counter1 = 0;
+ let counter2 = 0;
return {
files: {
"index.ts": /* ts */ `
@@ -251,6 +310,9 @@ describe("bundler", () => {
`,
},
plugins(builder) {
+ builder.onResolve({ filter: /.*/ }, args => {
+ counter1++;
+ });
builder.onResolve({ filter: /magic:some_string/ }, args => {
return {
path: "namespace_path",
@@ -259,21 +321,32 @@ describe("bundler", () => {
});
// the path given is already resolved, so it should not re-resolve
builder.onResolve({ filter: /namespace_path/, namespace: "my_namespace" }, args => {
- throw new Error("SHOULD NOT BE CALLED");
+ throw new Error("SHOULD NOT BE CALLED 1, " + JSON.stringify(args));
});
builder.onResolve({ filter: /namespace_path/ }, args => {
- throw new Error("SHOULD NOT BE CALLED");
+ throw new Error("SHOULD NOT BE CALLED 2, " + JSON.stringify(args));
});
- builder.onLoad({ filter: /namespace_path/, namespace: "my_namespace" }, args => {
+ // load
+ builder.onLoad({ filter: /.*/, namespace: "my_namespace" }, args => {
expect(args.path).toBe("namespace_path");
expect(args.namespace).toBe("my_namespace");
- expect(args.suffix).toBeFalsy();
return {
contents: "import 'nested_import';export const foo = 'foo';",
loader: "js",
};
});
+ // nested_import should not be resolved as a file namespace
+ builder.onResolve({ filter: /nested_import/, namespace: "file" }, args => {
+ throw new Error("SHOULD NOT BE CALLED 3, " + JSON.stringify(args));
+ });
+ builder.onResolve({ filter: /nested_import/, namespace: "my_namespace" }, args => {
+ expect(args.path).toBe("nested_import");
+ expect(args.namespace).toBe("my_namespace");
+ // gonna let this passthrough
+ counter2 += 1;
+ });
+ // but it can be resolved with no namespace filter
builder.onResolve({ filter: /nested_import/ }, args => {
expect(args.path).toBe("nested_import");
expect(args.namespace).toBe("my_namespace");
@@ -282,10 +355,20 @@ describe("bundler", () => {
namespace: "file",
};
});
+ builder.onResolve({ filter: /.*/ }, args => {
+ // entrypoint should hit this but this is a catch all
+ if (args.kind === "import-statement") {
+ throw new Error("SHOULD NOT BE CALLED 4, " + JSON.stringify(args));
+ }
+ });
},
run: {
stdout: "foo",
},
+ onAfterBundle(api) {
+ expect(counter1).toBe(3);
+ expect(counter2).toBe(1);
+ },
};
});
itBundled("plugin/ResolveOverrideFile", ({ root }) => {
@@ -314,9 +397,10 @@ describe("bundler", () => {
},
};
});
- itBundled("plugin/ResolveTwoImportsOnce", ({ root }) => {
+ itBundled("plugin/ResolveOnceWhenSameFile", ({ root }) => {
let onResolveCount = 0;
return {
+ notImplemented: true,
files: {
"index.ts": /* ts */ `
import * as foo from "./foo.ts";
@@ -383,7 +467,7 @@ describe("bundler", () => {
stdout: "this string should exist once this string should exist once",
},
onAfterBundle(api) {
- expect(importers).toEqual([root + "/one.ts", root + "/two.ts"]);
+ expect(importers.sort()).toEqual([root + "/one.ts", root + "/two.ts"]);
expect(onResolveCount).toBe(2);
const contents = api.readFile("/out.js");
expect([...contents.matchAll(/this string should exist once/g)].length).toBe(1);
@@ -562,15 +646,111 @@ describe("bundler", () => {
},
},
],
+ run: true,
+ onAfterBundle(api) {
+ expect(resolveCount).toBe(5050);
+ expect(loadCount).toBe(101);
+ },
+ };
+ });
+ itBundled("plugin/ManyPlugins", ({ root }) => {
+ const pluginCount = 4000;
+ let resolveCount = 0;
+ let loadCount = 0;
+ return {
+ files: {
+ "index.ts": /* ts */ `
+ import { foo as foo1 } from "plugin1:file";
+ import { foo as foo2 } from "plugin4000:file";
+ console.log(foo1, foo2);
+ `,
+ },
+ plugins: Array.from({ length: pluginCount }).map((_, i) => ({
+ name: `${i}`,
+ setup(builder) {
+ builder.onResolve({ filter: new RegExp(`^plugin${i}:file$`) }, args => {
+ resolveCount++;
+ return {
+ path: `plugin${i}:file`,
+ namespace: `plugin${i}`,
+ };
+ });
+ builder.onLoad({ filter: new RegExp(`^plugin${i}:file$`), namespace: `plugin${i}` }, args => {
+ loadCount++;
+ return {
+ contents: `export const foo = ${i};`,
+ loader: "js",
+ };
+ });
+ },
+ })),
run: {
- stdout: "101 102",
+ stdout: `${pluginCount - 1} ${pluginCount - 1}`,
},
onAfterBundle(api) {
- expect(resolveCount).toBe(103);
- expect(loadCount).toBe(102);
+ expect(resolveCount).toBe(pluginCount * 2);
+ expect(loadCount).toBe(pluginCount);
+ },
+ };
+ });
+ itBundled("plugin/NamespaceOnLoadBug", () => {
+ return {
+ files: {
+ "index.ts": /* ts */ `
+ import { foo } from "plugin:file";
+ console.log(foo);
+ `,
+ },
+ plugins(build) {
+ build.onResolve({ filter: /^plugin:/ }, args => {
+ return {
+ path: args.path,
+ namespace: "this",
+ };
+ });
+ build.onLoad({ filter: /.*/, namespace: "that" }, args => {
+ return {
+ contents: "export const foo = 'FAILED';",
+ loader: "js",
+ };
+ });
+ build.onLoad({ filter: /.*/, namespace: "this" }, args => {
+ return {
+ contents: `export const foo = '${args.namespace}';`,
+ loader: "js",
+ };
+ });
+ },
+ };
+ });
+ itBundled("plugin/EntrypointResolve", ({ root }) => {
+ return {
+ files: {},
+ entryPointsRaw: ["plugin"],
+ plugins(build) {
+ build.onResolve({ filter: /^plugin$/ }, args => {
+ expect(args.path).toBe("plugin");
+ expect(args.importer).toBe("");
+ expect(args.kind).toBe("entry-point");
+ expect(args.namespace).toBe("");
+ // expect(args.pluginData).toEqual(undefined);
+ // expect(args.resolveDir).toEqual(root);
+ return {
+ path: args.path,
+ namespace: "plugin",
+ };
+ });
+ build.onLoad({ filter: /.*/, namespace: "plugin" }, args => {
+ console.log(args);
+ return {
+ contents: `console.log("it works")`,
+ };
+ });
+ },
+ run: {
+ file: "./out/plugin.js",
+ stdout: "it works",
},
};
});
});
-
-// TODO: add async on resolve stuff
diff --git a/test/bundler/bundler_string.test.ts b/test/bundler/bundler_string.test.ts
new file mode 100644
index 000000000..fadd52a92
--- /dev/null
+++ b/test/bundler/bundler_string.test.ts
@@ -0,0 +1,137 @@
+import assert from "assert";
+import dedent from "dedent";
+import { itBundled, testForFile } from "./expectBundled";
+var { describe, test, expect } = testForFile(import.meta.path);
+
+interface TemplateStringTest {
+ expr: string;
+ print?: string | boolean; // expect stdout
+ capture?: string | boolean; // expect literal transpilation
+ captureRaw?: string; // expect raw transpilation
+}
+
+const templateStringTests: Record<string, TemplateStringTest> = {
+ // note for writing tests: .print is .trim()'ed due to how run.stdout works
+ Empty: { expr: '""', captureRaw: '""' },
+ NullByte: { expr: '"hello\0"', captureRaw: '"hello\0"' },
+ EmptyTemplate: { expr: "``", captureRaw: "``" },
+ ConstantTemplate: { expr: "`asdf`", captureRaw: "`asdf`" },
+ AddConstant: { expr: "`${7 + 6}`", capture: true },
+ AddConstant2: { expr: "`${7 + 6 + 96}`", capture: true },
+ AddConstant3: { expr: "`${0.1 + 0.2}`", print: true },
+ SubtractConstant: { expr: "`${7 - 6}`", capture: true },
+ SubtractConstant2: { expr: "`${7 - 6 - 10}`", capture: true },
+ MultiplyConstant: { expr: "`${7 * 6}`", capture: true },
+ MultiplyConstant2: { expr: "`${7 * 6 * 2}`", capture: true },
+ MultiplyConstant3: { expr: "`${7.5 * 6.02}`", print: true },
+ DivideConstant: { expr: "`${7 / 6}`", print: true },
+ DivideConstant2: { expr: "`${7 / 6 / 2}`", print: true },
+ DivideConstant3: { expr: "`${7.5 / 6.02}`", print: true },
+ Exponent1: { expr: "`${1e0}`", capture: true },
+ Exponent2: { expr: "`${1e1}`", capture: true },
+ Exponent3: { expr: "`${0e1337}`", capture: true },
+ Exponent4: { expr: "`${-1e0}`", capture: true },
+ BigExponent1: { expr: "`${1e20}`", print: "100000000000000000000" },
+ BigExponent2: { expr: "`${1e21}`", print: "1e+21" },
+ BigNumber1: { expr: "`${999999999999999934463.9999999}`", print: "999999999999999900000" },
+ BigNumber2: { expr: "`${999999999999999934464.0000000}`", print: "1e+21" },
+ True: { expr: "`${true}`", capture: true },
+ False: { expr: "`${false}`", capture: true },
+ BigInt: { expr: "`${1n}`", print: "1" },
+ LongBigInt: {
+ expr: "`${-" + "1234".repeat(1000) + "n}`",
+ print: "-" + "1234".repeat(1000),
+ },
+ BigIntAdd: { expr: "`${1n + 2n}`", print: "3" },
+ BigIntSubtract: { expr: "`${1n - 2n}`", print: "-1" },
+ BigIntMultiply: { expr: "`${2n * 3n}`", print: "6" },
+ BigIntDivide: { expr: "`${6n / 2n}`", print: "3" },
+ BigIntModulo: { expr: "`${6n % 4n}`", print: "2" },
+ BigIntExponent: { expr: "`${2n ** 3n}`", print: "8" },
+ ArrowFunction: { expr: "`${() => 123}`", captureRaw: "`${(" }, // capture is weird in this scenario
+ Function: { expr: "`${function() { return 123; }}`", captureRaw: "`${function(" },
+ Identifier: { expr: "`${ident}`", captureRaw: "`${ident}`" },
+ IdentifierAdd: { expr: "`${ident + ident}`", captureRaw: "`${ident+ident}`" },
+ IdentifierConstAdd: { expr: "`${2 + ident}`", captureRaw: "`${ident+ident}`" },
+ EscapeIssue1: {
+ expr: `\`\\abc\${ident}\``,
+ captureRaw: `\`abc\${ident}\``,
+ },
+ EscapeIssue2: {
+ expr: `\`\\abc\${ident}\``,
+ captureRaw: `\`abc\${ident}\``,
+ },
+ TernaryWithEscapeVariable: {
+ expr: '`${"1"}\\${${VARIABLE ? "SOMETHING" : ""}`',
+ captureRaw: '`${"1"}\\${${VARIABLE ? "SOMETHING" : ""}`',
+ },
+ TernaryWithEscapeTrue: {
+ expr: '`${"1"}\\${${true ? "SOMETHING" : ""}`',
+ captureRaw: '`${"1"}\\${${"SOMETHING"}`',
+ },
+ TernaryWithEscapeFalse: {
+ expr: '`${"1"}\\${${false ? "SOMETHING" : ""}`',
+ captureRaw: '`${"1"}\\${${""}`',
+ },
+ Fold: { expr: "`a${'b'}c${'d'}e`", capture: true },
+ FoldNested1: { expr: "`a${`b`}c${`${'d'}`}e`", capture: true },
+ FoldNested2: { expr: "`a${`b`}c${`1${'d'}`}e`", capture: true },
+ FoldNested3: { expr: "`a${`b`}c${`${'1'}${'d'}`}e`", capture: true },
+ FoldNested4: { expr: "`a${`b`}c${`${`${`${'d'}`}`}`}e`", capture: true },
+ FoldNested5: { expr: "`\\$${`d`}`", print: true }, // could be captured
+ FoldNested6: { expr: "`a\0${5}c\\${{$${`d`}e`", capture: true },
+ EscapedDollar: { expr: "`\\${'a'}`", captureRaw: "`\\${'a'}`" },
+ EscapedDollar2: { expr: "`\\${'a'}\\${'b'}`", captureRaw: "`\\${'a'}\\${'b'}`" },
+};
+
+describe("bundler", () => {
+ for (const key in templateStringTests) {
+ const test = templateStringTests[key];
+ if ([test.capture, test.captureRaw, test.print].filter(x => x !== undefined).length !== 1) {
+ throw new Error(`Exactly one of capture or print must be defined for 'template/${key}'`);
+ }
+ let captureRaw = test.captureRaw;
+ if (test.capture === true) captureRaw = JSON.stringify(eval(test.expr)) as string;
+ else if (test.capture !== undefined) captureRaw = JSON.stringify(test.capture);
+ if (test.print === true) test.print = eval(test.expr) as string;
+
+ itBundled(
+ `string/${key}`,
+ captureRaw !== undefined
+ ? {
+ files: {
+ "index.ts": dedent`
+ capture(${test.expr});
+ `,
+ },
+ capture: [captureRaw],
+ minifySyntax: true,
+ minifyWhitespace: true,
+ }
+ : {
+ files: {
+ "index.ts": dedent`
+ const capture = x => x;
+ console.log(capture(${test.expr}));
+ `,
+ },
+ run: {
+ stdout: test.print as string,
+ },
+ minifySyntax: true,
+ minifyWhitespace: true,
+ onAfterBundle(api) {
+ const capture = api.captureFile("out.js");
+ if (capture[0] === JSON.stringify(test.print)) {
+ // this is to tell the dev to change the test to use .capture
+ // as that is a more strict test (checking literal output)
+ // and if the test passes with this, we should be testing for that.
+ throw new Error(
+ `Test 'string/${key}': Passes capture test when the test only defines print. Rename .print to .capture on the test to fix this.`,
+ );
+ }
+ },
+ },
+ );
+ }
+});
diff --git a/test/bundler/esbuild/dce.test.ts b/test/bundler/esbuild/dce.test.ts
index de68742c6..a35fb68ca 100644
--- a/test/bundler/esbuild/dce.test.ts
+++ b/test/bundler/esbuild/dce.test.ts
@@ -889,9 +889,15 @@ describe("bundler", () => {
run: {
stdout: "unused import",
},
+ assetNaming: "[name].[ext]",
+ outdir: "/out",
loader: {
".data": "file",
},
+ onAfterBundle(api) {
+ const fs = require("fs");
+ expect(fs.readdirSync(api.outdir)).toEqual(["entry.js"]);
+ },
});
itBundled("dce/RemoveUnusedImportMeta", {
files: {
@@ -1038,7 +1044,6 @@ describe("bundler", () => {
},
});
itBundled("dce/DeadCodeFollowingJump", {
- notImplemented: true,
files: {
"/entry.js": /* js */ `
function testReturn() {
@@ -1273,7 +1278,7 @@ describe("bundler", () => {
let POSSIBLE_REMOVAL_1 = class { [{ toString() {} }] = 'x' }
`,
},
- mode: "transform",
+ bundling: false,
treeShaking: true,
dce: true,
});
@@ -1309,7 +1314,7 @@ describe("bundler", () => {
let POSSIBLE_REMOVAL_1 = class { static [{ toString() {} }] = 'x' }
`,
},
- mode: "transform",
+ bundling: false,
treeShaking: true,
dce: true,
});
@@ -1392,7 +1397,6 @@ describe("bundler", () => {
format: "iife",
});
itBundled("dce/TreeShakingNoBundleESM", {
- notImplemented: true,
files: {
"/entry.js": /* js */ `
function keep() {}
@@ -1401,7 +1405,7 @@ describe("bundler", () => {
`,
},
format: "esm",
- mode: "transform",
+ bundling: false,
treeShaking: true,
dce: true,
});
@@ -1416,7 +1420,7 @@ describe("bundler", () => {
dce: true,
format: "cjs",
treeShaking: true,
- mode: "transform",
+ bundling: false,
});
itBundled("dce/TreeShakingNoBundleIIFE", {
files: {
@@ -1429,7 +1433,7 @@ describe("bundler", () => {
dce: true,
format: "iife",
treeShaking: true,
- mode: "transform",
+ bundling: false,
});
itBundled("dce/TreeShakingInESMWrapper", {
files: {
@@ -1692,8 +1696,7 @@ describe("bundler", () => {
`,
},
minifySyntax: true,
- mode: "transform",
- external: ["a", "b", "c"],
+ bundling: false,
dce: true,
});
itBundled("dce/RemoveUnusedImportsEvalTS", {
@@ -1707,7 +1710,7 @@ describe("bundler", () => {
},
dce: true,
minifySyntax: true,
- mode: "transform",
+ bundling: false,
});
itBundled("dce/DCEClassStaticBlocks", {
files: {
@@ -2192,7 +2195,7 @@ describe("bundler", () => {
" delete id_REMOVE((foo(), bar())),\n" +
"]",
},
- mode: "transform",
+ bundling: false,
minifySyntax: true,
treeShaking: true,
dce: true,
@@ -2561,7 +2564,7 @@ describe("bundler", () => {
"/ts-namespace-no-eval.ts",
"/ts-namespace-eval.ts",
],
- mode: "transform",
+ bundling: false,
minifySyntax: true,
dce: true,
dceKeepMarkerCount: {
@@ -2683,7 +2686,6 @@ describe("bundler", () => {
dce: true,
});
itBundled("dce/MultipleDeclarationTreeShaking", {
- notImplemented: true,
files: {
"/var2.js": /* js */ `
var x = 1
@@ -2722,7 +2724,6 @@ describe("bundler", () => {
],
});
itBundled("dce/MultipleDeclarationTreeShakingMinifySyntax", {
- notImplemented: true,
files: {
"/var2.js": /* js */ `
var x = 1
diff --git a/test/bundler/esbuild/default.test.ts b/test/bundler/esbuild/default.test.ts
index 03a7f1adf..39cb293be 100644
--- a/test/bundler/esbuild/default.test.ts
+++ b/test/bundler/esbuild/default.test.ts
@@ -233,7 +233,7 @@ describe("bundler", () => {
},
entryPoints: ["/a.js", "/b.js", "/c.js", "/d.js", "/e.js"],
mode: "bundle",
- external: ["*"],
+ bundling: false,
runtimeFiles: {
"./out/f.js": /* js */ `
export const f = 987;
@@ -309,11 +309,10 @@ describe("bundler", () => {
}
`,
},
- // mode: "transform",
run: {
file: "/test.js",
},
- external: ["*"],
+ bundling: false,
} as const;
itBundled("default/ImportFormsWithNoBundle", {
...importFormsConfig,
@@ -435,59 +434,59 @@ describe("bundler", () => {
"/foo.js": [`Detected cycle while resolving import "b"`, `Detected cycle while resolving import "d"`],
},
});
- itBundled("default/JSXImportsCommonJS", {
- notImplemented: true, // jsx in bun is too different to esbuild
- files: {
- "/entry.jsx": /* jsx */ `
- import {elem, frag} from './custom-react'
- console.log(<div/>, <>fragment</>)
- `,
- "/custom-react.js": /* js */ `
- module.exports = {
- elem: (...args) => console.log('elem', ...args),
- frag: 'frag',
- };
- `,
- },
- jsx: {
- factory: "elem",
- fragment: "frag",
- automaticRuntime: true,
- },
- run: {
- stdout: `
- elem div null
- elem frag null fragment
- undefined undefined
- `,
- },
- });
- itBundled("default/JSXImportsES6", {
- notImplemented: true, // jsx in bun is too different to esbuild
- files: {
- "/entry.jsx": /* jsx */ `
- import {elem, frag} from './custom-react'
- console.log(<div/>, <>fragment</>)
- `,
- "/custom-react.js": /* js */ `
- export function elem(...args) {
- console.log('elem', ...args)
- }
- export const frag = "frag";
- `,
- },
- jsx: {
- factory: "elem",
- fragment: "frag",
- },
- run: {
- stdout: `
- elem div null
- elem frag null fragment
- undefined undefined
- `,
- },
- });
+ // itBundled("default/JSXImportsCommonJS", {
+ // notImplemented: true, // jsx in bun is too different to esbuild
+ // files: {
+ // "/entry.jsx": /* jsx */ `
+ // import {elem, frag} from './custom-react'
+ // console.log(<div/>, <>fragment</>)
+ // `,
+ // "/custom-react.js": /* js */ `
+ // module.exports = {
+ // elem: (...args) => console.log('elem', ...args),
+ // frag: 'frag',
+ // };
+ // `,
+ // },
+ // jsx: {
+ // factory: "elem",
+ // fragment: "frag",
+ // automaticRuntime: true,
+ // },
+ // run: {
+ // stdout: `
+ // elem div null
+ // elem frag null fragment
+ // undefined undefined
+ // `,
+ // },
+ // });
+ // itBundled("default/JSXImportsES6", {
+ // notImplemented: true, // jsx in bun is too different to esbuild
+ // files: {
+ // "/entry.jsx": /* jsx */ `
+ // import {elem, frag} from './custom-react'
+ // console.log(<div/>, <>fragment</>)
+ // `,
+ // "/custom-react.js": /* js */ `
+ // export function elem(...args) {
+ // console.log('elem', ...args)
+ // }
+ // export const frag = "frag";
+ // `,
+ // },
+ // jsx: {
+ // factory: "elem",
+ // fragment: "frag",
+ // },
+ // run: {
+ // stdout: `
+ // elem div null
+ // elem frag null fragment
+ // undefined undefined
+ // `,
+ // },
+ // });
// note: esbuild treats .js as non-jsx
// bun treats js as jsx
// so the extension has to be .mjs or .cjs to disable JSX.
@@ -504,105 +503,105 @@ describe("bundler", () => {
outdir: "/out",
entryPoints: ["/entry.mjs", "/entry.cjs"],
});
- itBundled("default/JSXConstantFragments", {
- notImplemented: true, // jsx in bun is too different to esbuild
- files: {
- "/entry.js": /* js */ `
- import './default'
- import './null'
- import './boolean'
- import './number'
- import './string-single-empty'
- import './string-double-empty'
- import './string-single-punctuation'
- import './string-double-punctuation'
- import './string-template'
- `,
- "/default.jsx": `console.log(<></>)`,
- "/null.jsx": `console.log(<></>) // @jsxFrag null`,
- "/boolean.jsx": `console.log(<></>) // @jsxFrag true`,
- "/number.jsx": `console.log(<></>) // @jsxFrag 123`,
- "/string-single-empty.jsx": `console.log(<></>) // @jsxFrag ''`,
- "/string-double-empty.jsx": `console.log(<></>) // @jsxFrag ""`,
- "/string-single-punctuation.jsx": `console.log(<></>) // @jsxFrag '['`,
- "/string-double-punctuation.jsx": `console.log(<></>) // @jsxFrag "["`,
- "/string-template.jsx": "console.log(<></>) // @jsxFrag ``",
+ // itBundled("default/JSXConstantFragments", {
+ // notImplemented: true, // jsx in bun is too different to esbuild
+ // files: {
+ // "/entry.js": /* js */ `
+ // import './default'
+ // import './null'
+ // import './boolean'
+ // import './number'
+ // import './string-single-empty'
+ // import './string-double-empty'
+ // import './string-single-punctuation'
+ // import './string-double-punctuation'
+ // import './string-template'
+ // `,
+ // "/default.jsx": `console.log(<></>)`,
+ // "/null.jsx": `console.log(<></>) // @jsxFrag null`,
+ // "/boolean.jsx": `console.log(<></>) // @jsxFrag true`,
+ // "/number.jsx": `console.log(<></>) // @jsxFrag 123`,
+ // "/string-single-empty.jsx": `console.log(<></>) // @jsxFrag ''`,
+ // "/string-double-empty.jsx": `console.log(<></>) // @jsxFrag ""`,
+ // "/string-single-punctuation.jsx": `console.log(<></>) // @jsxFrag '['`,
+ // "/string-double-punctuation.jsx": `console.log(<></>) // @jsxFrag "["`,
+ // "/string-template.jsx": "console.log(<></>) // @jsxFrag ``",
- "/test.js": /* js */ `
- globalThis.React = {
- createElement: (x) => x,
- Fragment: 'frag'
- }
- await import('./out.js');
- `,
- },
- jsx: {
- fragment: "']'",
- },
- bundleWarnings: {
- "/string-template.jsx": ["Invalid JSX fragment: ``"],
- },
- run: {
- file: "/test.js",
- stdout: "]\nnull\ntrue\n123\n\n\n[\n[\n]",
- },
- });
- itBundled("default/JSXAutomaticImportsCommonJS", {
- files: {
- "/entry.jsx": /* jsx */ `
- import {jsx, Fragment} from './custom-react'
- console.log(<div jsx={jsx}/>, <><Fragment/></>)
- `,
- "/custom-react.js": `module.exports = { jsx: 'jsx', Fragment: 'fragment2' }`,
- },
- jsx: {
- automaticRuntime: true,
- },
- external: ["react"],
- run: {
- stdout: `
- <div jsx="jsx" /> <>
- <fragment2 />
- </>
- `,
- },
- });
- itBundled("default/JSXAutomaticImportsES6", {
- files: {
- "/entry.jsx": /* jsx */ `
- import {jsx, Fragment} from './custom-react'
- console.log(<div jsx={jsx}/>, <><Fragment/></>)
- `,
- "/custom-react.js": /* js */ `
- export const jsx = 'jsx function'
- export const Fragment = 'fragment'
- `,
- },
- jsx: {
- automaticRuntime: true,
- },
- external: ["react"],
- run: {
- stdout: `
- <div jsx="jsx function" /> <>
- <fragment />
- </>
- `,
- },
- });
- itBundled("default/JSXAutomaticSyntaxInJS", {
- files: {
- "/entry.mjs": `console.log(<div/>)`,
- },
- jsx: {
- automaticRuntime: true,
- },
- external: ["react"],
- bundleErrors: {
- // TODO: this could be a nicer error
- "/entry.mjs": [`Unexpected <`],
- },
- });
+ // "/test.js": /* js */ `
+ // globalThis.React = {
+ // createElement: (x) => x,
+ // Fragment: 'frag'
+ // }
+ // await import('./out.js');
+ // `,
+ // },
+ // jsx: {
+ // fragment: "']'",
+ // },
+ // bundleWarnings: {
+ // "/string-template.jsx": ["Invalid JSX fragment: ``"],
+ // },
+ // run: {
+ // file: "/test.js",
+ // stdout: "]\nnull\ntrue\n123\n\n\n[\n[\n]",
+ // },
+ // });
+ // itBundled("default/JSXAutomaticImportsCommonJS", {
+ // files: {
+ // "/entry.jsx": /* jsx */ `
+ // import {jsx, Fragment} from './custom-react'
+ // console.log(<div jsx={jsx}/>, <><Fragment/></>)
+ // `,
+ // "/custom-react.js": `module.exports = { jsx: 'jsx', Fragment: 'fragment2' }`,
+ // },
+ // jsx: {
+ // automaticRuntime: true,
+ // },
+ // external: ["react"],
+ // run: {
+ // stdout: `
+ // <div jsx="jsx" /> <>
+ // <fragment2 />
+ // </>
+ // `,
+ // },
+ // });
+ // itBundled("default/JSXAutomaticImportsES6", {
+ // files: {
+ // "/entry.jsx": /* jsx */ `
+ // import {jsx, Fragment} from './custom-react'
+ // console.log(<div jsx={jsx}/>, <><Fragment/></>)
+ // `,
+ // "/custom-react.js": /* js */ `
+ // export const jsx = 'jsx function'
+ // export const Fragment = 'fragment'
+ // `,
+ // },
+ // jsx: {
+ // automaticRuntime: true,
+ // },
+ // external: ["react"],
+ // run: {
+ // stdout: `
+ // <div jsx="jsx function" /> <>
+ // <fragment />
+ // </>
+ // `,
+ // },
+ // });
+ // itBundled("default/JSXAutomaticSyntaxInJS", {
+ // files: {
+ // "/entry.mjs": `console.log(<div/>)`,
+ // },
+ // jsx: {
+ // automaticRuntime: true,
+ // },
+ // external: ["react"],
+ // bundleErrors: {
+ // // TODO: this could be a nicer error
+ // "/entry.mjs": [`Unexpected <`],
+ // },
+ // });
itBundled("default/NodeModules", {
files: {
"/Users/user/project/src/entry.js": /* js */ `
@@ -784,7 +783,6 @@ describe("bundler", () => {
},
});
itBundled("default/RequireAndDynamicImportInvalidTemplate", {
- notImplemented: true,
files: {
"/entry.cjs": `
require(tag\`./b\`)
@@ -832,7 +830,7 @@ describe("bundler", () => {
`,
},
format: "cjs",
- mode: "transform",
+ bundling: false,
onAfterBundle(api) {
api.expectFile("/out.js").toContain('import("foo")');
api.expectFile("/out.js").toContain("import(foo())");
@@ -846,7 +844,7 @@ describe("bundler", () => {
`,
},
format: "cjs",
- mode: "transform",
+ bundling: false,
minifyWhitespace: true,
onAfterBundle(api) {
api.expectFile("/out.js").toContain('import("foo")');
@@ -1152,11 +1150,31 @@ describe("bundler", () => {
`,
"/Users/user/project/src/bar.js": `export function bar() { console.log('hi') }`,
},
- outfile: "/Users/user/project/out.js",
- sourceMap: true,
+ outdir: "/Users/user/project/out",
+ sourceMap: "external",
onAfterBundle(api) {
- api.assertFileExists("/Users/user/project/out.js.map");
- api.expectFile("/Users/user/project/out.js").toContain("//# sourceMappingURL=out.js.map");
+ const json = JSON.parse(api.readFile("/Users/user/project/out/entry.js.map"));
+ api.expectFile("/Users/user/project/out/entry.js").toContain(`//# debugId=${json.debugId}`);
+ },
+ run: {
+ stdout: "hi",
+ },
+ });
+ itBundled("default/SourceMapInline", {
+ files: {
+ "/Users/user/project/src/entry.js": /* js */ `
+ import {bar} from './bar'
+ function foo() { bar() }
+ foo()
+ `,
+ "/Users/user/project/src/bar.js": `export function bar() { console.log('hi') }`,
+ },
+ outdir: "/Users/user/project/out",
+ sourceMap: "inline",
+ onAfterBundle(api) {
+ api
+ .expectFile("/Users/user/project/out/entry.js")
+ .toContain(`//# sourceMappingURL=data:application/json;base64,`);
},
run: {
stdout: "hi",
@@ -1469,12 +1487,13 @@ describe("bundler", () => {
files: {
"/entry.js": /* js */ `
function __require() { return 123 }
- console.log(__require())
+ console.log(__require(), typeof (require('fs')))
`,
},
- mode: "transform",
+ bundling: false,
+ target: "bun",
run: {
- stdout: "123",
+ stdout: "123 object",
},
});
itBundled("default/TopLevelReturnForbiddenImport", {
@@ -1513,7 +1532,7 @@ describe("bundler", () => {
export var foo
`,
},
- mode: "transform",
+ bundling: false,
bundleErrors: {
"/entry.js": ["Top-level return cannot be used inside an ECMAScript module"],
},
@@ -1522,7 +1541,7 @@ describe("bundler", () => {
files: {
"/entry.js": `return await foo`,
},
- mode: "transform",
+ bundling: false,
bundleErrors: {
"/entry.js": ["Top-level return cannot be used inside an ECMAScript module"],
},
@@ -1774,7 +1793,7 @@ describe("bundler", () => {
`,
},
minifyIdentifiers: true,
- mode: "transform",
+ bundling: false,
onAfterBundle(api) {
assert(!api.readFile("/out.js").includes("foo"), 'bundle shouldnt include "foo"');
assert(!api.readFile("/out.js").includes("let bar"), 'bundle shouldnt include "let bar"');
@@ -1804,7 +1823,7 @@ describe("bundler", () => {
);
},
minifyIdentifiers: true,
- mode: "transform",
+ bundling: false,
});
itBundled("default/ArgumentsSpecialCaseNoBundle", {
files: {
@@ -1904,7 +1923,6 @@ describe("bundler", () => {
format: "iife",
outfile: "/out.js",
minifyIdentifiers: true,
- // mode: "transform",
});
itBundled("default/WithStatementTaintingNoBundle", {
files: {
@@ -1938,7 +1956,7 @@ describe("bundler", () => {
},
format: "iife",
minifyIdentifiers: true,
- mode: "transform",
+ bundling: false,
run: {
runtime: "node",
stdout: `
@@ -1997,7 +2015,7 @@ describe("bundler", () => {
`,
},
minifyIdentifiers: true,
- mode: "transform",
+ bundling: false,
format: "cjs",
onAfterBundle(api) {
const text = api.readFile("/out.js");
@@ -2332,7 +2350,7 @@ describe("bundler", () => {
files: {
"/entry.js": `import "foo"`,
},
- external: ["*"],
+ bundling: false,
});
itBundled("default/ManyEntryPoints", {
files: Object.fromEntries([
@@ -2384,7 +2402,6 @@ describe("bundler", () => {
});
// These labels should all share the same minified names
itBundled("default/MinifySiblingLabelsNoBundle", {
- notImplemented: true,
files: {
"/entry.js": /* js */ `
foo: {
@@ -2442,30 +2459,14 @@ describe("bundler", () => {
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}console.log('a')
}}}}}}}}}}}}}}}}}}}}}}}}}}}
`;
- itBundled("default/NestedLabelsBundle", {
+ // these tests are flaky. at least if i run it just on its own, i get a crash. in a row its fine
+ itBundled.skip("default/NestedLabelsBundle", {
notImplemented: true,
files: {
"/entry.js": crazyNestedLabelFile,
},
});
- itBundled("default/NestedLabelsNoBundle", {
- notImplemented: true,
- files: {
- "/entry.js": crazyNestedLabelFile,
- },
- mode: "transform",
- });
- itBundled("default/MinifyNestedLabelsNoBundle", {
- notImplemented: true,
- files: {
- "/entry.js": crazyNestedLabelFile,
- },
- minifyWhitespace: true,
- minifyIdentifiers: true,
- minifySyntax: true,
- mode: "transform",
- });
- itBundled("default/MinifyNestedLabelsBundle", {
+ itBundled.skip("default/MinifyNestedLabelsBundle", {
notImplemented: true,
files: {
"/entry.js": crazyNestedLabelFile,
@@ -2527,7 +2528,7 @@ describe("bundler", () => {
format: "iife",
minifySyntax: true,
minifyWhitespace: true,
- mode: "transform",
+ bundling: false,
onAfterBundle(api) {
assert(api.readFile("/out.js").includes('"use strict";'), '"use strict"; was emitted');
},
@@ -2741,7 +2742,7 @@ describe("bundler", () => {
file: "/test.js",
stdout: "foo bar",
},
- external: ["*"],
+ bundling: false,
});
itBundled("default/ImportMetaCommonJS", {
files: {
@@ -2769,7 +2770,7 @@ describe("bundler", () => {
files: {
"/entry.js": `console.log(import.meta.url, import.meta.path)`,
},
- mode: "transform",
+ bundling: false,
run: {
stdout: "url_here path_here",
bunArgs: ["--define", 'import.meta.url="url_here"', "--define", 'import.meta.path="path_here"'],
@@ -3440,7 +3441,7 @@ describe("bundler", () => {
for await (foo of bar) ;
`,
},
- mode: "transform",
+ bundling: false,
});
itBundled("default/TopLevelAwaitForbiddenRequire", {
notImplemented: true,
@@ -3902,7 +3903,7 @@ describe("bundler", () => {
},
dce: true,
treeShaking: true,
- mode: "transform",
+ bundling: false,
run: {
stdout: `
side effects
@@ -4085,7 +4086,7 @@ describe("bundler", () => {
export let bar = 123
`,
},
- mode: "transform",
+ bundling: false,
runtimeFiles: {
"/test.js": /* js */ `
import * as mod from './out';
@@ -4571,7 +4572,7 @@ describe("bundler", () => {
`,
},
minifySyntax: true,
- mode: "transform",
+ bundling: false,
onAfterBundle(api) {
const code = api.readFile("/out.js");
expect(code).not.toContain("const");
@@ -4681,7 +4682,6 @@ describe("bundler", () => {
// `,
// },
// entryPoints: ["/js.js", "/ts.ts", "/jsx-components.jsx", "/jsx-a.jsx", "/jsx-b.jsx", "/jsx-c.jsx"],
- // mode: "transform",
// external: ["a", "b", "c", "react/jsx-dev-runtime"],
// });
// I cant get bun to use `this` as the JSX runtime. It's a pretty silly idea anyways.
@@ -5140,7 +5140,7 @@ describe("bundler", () => {
"/node_modules/some-path/index.js": `module.exports = 123`,
"/node_modules/second-path/index.js": `module.exports = 567`,
},
- external: ["*"],
+ bundling: false,
target: "browser",
format: "esm",
outfile: "/out.mjs",
@@ -5167,7 +5167,7 @@ describe("bundler", () => {
notImplemented: true,
files: RequireShimSubstitutionBrowser.options.files,
runtimeFiles: RequireShimSubstitutionBrowser.options.runtimeFiles,
- external: ["*"],
+ bundling: false,
target: "node",
format: "esm",
outfile: "/out.mjs",
@@ -5209,7 +5209,6 @@ describe("bundler", () => {
minifySyntax: true,
});
itBundled("default/BuiltInNodeModulePrecedence", {
- // GENERATED
notImplemented: true,
files: {
"/entry.js": /* js */ `
@@ -5222,13 +5221,28 @@ describe("bundler", () => {
// These are not node core modules
require('fs/abc'),
require('fs/'),
- ])
+ ].map(x => typeof x).join(','))
`,
"/node_modules/fs/abc.js": `console.log('include this')`,
"/node_modules/fs/index.js": `console.log('include this too')`,
"/node_modules/fs/promises.js": `throw 'DO NOT INCLUDE THIS'`,
},
target: "node",
+ runtimeFiles: {
+ "/node_modules/node_foo/index.js": `console.log('include this too')`,
+ },
+ onAfterBundle(api) {
+ api.writeFile("/out.js", api.readFile("/out.js").replace(/node:foo/g, "node_foo"));
+ },
+ run: {
+ runtime: "node",
+ stdout: `
+ include this too
+ include this
+ include this too
+ object,object,object,object,object
+ `,
+ },
});
itBundled("default/EntryNamesNoSlashAfterDir", {
// GENERATED
@@ -5340,7 +5354,7 @@ describe("bundler", () => {
`,
},
format: "cjs",
- external: ["*"],
+ bundling: false,
});
itBundled("default/NamedFunctionExpressionArgumentCollision", {
files: {
@@ -5422,7 +5436,7 @@ describe("bundler", () => {
`,
},
entryPoints: ["/entry1.js", "/entry2.js"],
- external: ["*"],
+ bundling: false,
mangleProps: /_$/,
});
itBundled("default/ManglePropsMinify", {
@@ -5471,7 +5485,7 @@ describe("bundler", () => {
entryPoints: ["/entry1.js", "/entry2.js"],
mangleProps: /_$/,
minifyIdentifiers: true,
- external: ["*"],
+ bundling: false,
});
itBundled("default/ManglePropsKeywordPropertyMinify", {
// GENERATED
@@ -5485,7 +5499,7 @@ describe("bundler", () => {
mangleProps: /./,
minifyIdentifiers: true,
minifySyntax: true,
- external: ["*"],
+ bundling: false,
});
itBundled("default/ManglePropsOptionalChain", {
// GENERATED
@@ -5504,7 +5518,7 @@ describe("bundler", () => {
`,
},
mangleProps: /_$/,
- external: ["*"],
+ bundling: false,
});
itBundled("default/ManglePropsLoweredOptionalChain", {
// GENERATED
@@ -5523,7 +5537,7 @@ describe("bundler", () => {
`,
},
mangleProps: /_$/,
- external: ["*"],
+ bundling: false,
});
itBundled("default/ReserveProps", {
// GENERATED
@@ -5536,7 +5550,7 @@ describe("bundler", () => {
`,
},
mangleProps: /_$/,
- external: ["*"],
+ bundling: false,
});
itBundled("default/ManglePropsImportExport", {
// GENERATED
@@ -5552,7 +5566,7 @@ describe("bundler", () => {
},
entryPoints: ["/esm.js", "/cjs.js"],
mangleProps: /_$/,
- external: ["*"],
+ bundling: false,
});
itBundled("default/ManglePropsImportExportBundled", {
// GENERATED
@@ -5991,7 +6005,7 @@ describe("bundler", () => {
// // preserve: true,
// },
// // minifySyntax: true,
- // external: ["*"],
+ // bundling: false,
// });
itBundled("default/PackageAlias", {
files: {
@@ -6216,7 +6230,7 @@ describe("bundler", () => {
`,
},
entryPoints: ["/project/entry.js", "/project/entry.css"],
- external: ["*"],
+ bundling: false,
metafile: true,
});
itBundled("default/MetafileVeryLongExternalPaths", {
@@ -6425,7 +6439,7 @@ describe("bundler", () => {
}
},
});
- itBundled("default/CommentPreservationImportAssertions", {
+ itBundled.skip("default/CommentPreservationImportAssertions", {
// GENERATED
notImplemented: true,
files: {
@@ -6439,7 +6453,7 @@ describe("bundler", () => {
},
external: ["foo"],
});
- itBundled("default/CommentPreservationTransformJSX", {
+ itBundled.skip("default/CommentPreservationTransformJSX", {
// GENERATED
notImplemented: true,
files: {
@@ -6469,7 +6483,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("default/CommentPreservationPreserveJSX", {
+ itBundled.skip("default/CommentPreservationPreserveJSX", {
// GENERATED
notImplemented: true,
files: {
diff --git a/test/bundler/esbuild/importstar.test.ts b/test/bundler/esbuild/importstar.test.ts
index f65e0f8f4..6c8edee2c 100644
--- a/test/bundler/esbuild/importstar.test.ts
+++ b/test/bundler/esbuild/importstar.test.ts
@@ -247,11 +247,10 @@ describe("bundler", () => {
console.log(foo)
`,
},
- mode: "transform",
runtimeFiles: {
"/foo.js": `console.log('foo')`,
},
- external: ["./foo"],
+ bundling: false,
run: {
stdout: "foo\n234",
},
@@ -264,7 +263,6 @@ describe("bundler", () => {
console.log(JSON.stringify(ns), ns.foo, foo)
`,
},
- mode: "transform",
runtimeFiles: {
"/foo.js": `export const foo = 123`,
},
@@ -282,7 +280,6 @@ describe("bundler", () => {
`,
},
external: ["./foo"],
- mode: "transform",
runtimeFiles: {
"/foo.js": `export const foo = 123`,
},
@@ -300,7 +297,6 @@ describe("bundler", () => {
},
minifySyntax: true,
external: ["./foo"],
- mode: "transform",
runtimeFiles: {
"/foo.js": `console.log('foo')`,
},
@@ -317,7 +313,6 @@ describe("bundler", () => {
`,
},
minifySyntax: true,
- mode: "transform",
external: ["./foo"],
runtimeFiles: {
"/foo.js": `export const foo = 123`,
@@ -335,7 +330,6 @@ describe("bundler", () => {
`,
},
minifySyntax: true,
- mode: "transform",
external: ["./foo"],
runtimeFiles: {
"/foo.js": `export const foo = 123`,
diff --git a/test/bundler/esbuild/importstar_ts.test.ts b/test/bundler/esbuild/importstar_ts.test.ts
index 0e39f0b29..394c4260f 100644
--- a/test/bundler/esbuild/importstar_ts.test.ts
+++ b/test/bundler/esbuild/importstar_ts.test.ts
@@ -211,7 +211,7 @@ describe("bundler", () => {
console.log(foo)
`,
},
- mode: "transform",
+ bundling: false,
});
itBundled("ts/TSImportStarNoBundleCapture", {
// GENERATED
@@ -222,7 +222,7 @@ describe("bundler", () => {
console.log(ns, ns.foo, foo)
`,
},
- mode: "transform",
+ bundling: false,
});
itBundled("ts/TSImportStarNoBundleNoCapture", {
// GENERATED
@@ -233,7 +233,7 @@ describe("bundler", () => {
console.log(ns.foo, ns.foo, foo)
`,
},
- mode: "transform",
+ bundling: false,
});
itBundled("ts/TSImportStarMangleNoBundleUnused", {
// GENERATED
@@ -245,7 +245,7 @@ describe("bundler", () => {
`,
},
minifySyntax: true,
- mode: "transform",
+ bundling: false,
});
itBundled("ts/TSImportStarMangleNoBundleCapture", {
// GENERATED
@@ -257,7 +257,7 @@ describe("bundler", () => {
`,
},
minifySyntax: true,
- mode: "transform",
+ bundling: false,
});
itBundled("ts/TSImportStarMangleNoBundleNoCapture", {
// GENERATED
@@ -269,7 +269,7 @@ describe("bundler", () => {
`,
},
minifySyntax: true,
- mode: "transform",
+ bundling: false,
});
itBundled("ts/TSReExportTypeOnlyFileES6", {
// GENERATED
diff --git a/test/bundler/esbuild/loader.test.ts b/test/bundler/esbuild/loader.test.ts
index 0b946d0b3..628fc4ca8 100644
--- a/test/bundler/esbuild/loader.test.ts
+++ b/test/bundler/esbuild/loader.test.ts
@@ -116,7 +116,7 @@ describe("bundler", () => {
loader: {
".cjs": "jsx",
},
- external: ["*"],
+ bundling: false,
});
// itBundled("loader/JSXPreserveCapitalLetter", {
// // GENERATED
@@ -460,7 +460,7 @@ describe("bundler", () => {
files: {
"/test.json": `{"test": 123, "invalid-identifier": true}`,
},
- mode: "transform",
+ bundling: false,
});
itBundled("loader/JSONNoBundleES6", {
// GENERATED
diff --git a/test/bundler/esbuild/lower.test.ts b/test/bundler/esbuild/lower.test.ts
index df68a6f51..b73c30b08 100644
--- a/test/bundler/esbuild/lower.test.ts
+++ b/test/bundler/esbuild/lower.test.ts
@@ -18,7 +18,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2018",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerObjectSpreadNoBundle", {
// GENERATED
@@ -41,7 +41,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2017",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerExponentiationOperatorNoBundle", {
// GENERATED
@@ -79,7 +79,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2015",
- mode: "transform",
+ bundling: false,
/* TODO FIX expectedScanLog: `entry.js: ERROR: Big integer literals are not available in the configured target environment
`, */
});
@@ -117,7 +117,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2015",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerPrivateFieldAssignments2019NoBundle", {
// GENERATED
@@ -153,7 +153,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2019",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerPrivateFieldAssignments2020NoBundle", {
// GENERATED
@@ -189,7 +189,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2020",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerPrivateFieldAssignmentsNextNoBundle", {
// GENERATED
@@ -224,7 +224,7 @@ describe("bundler", () => {
}
`,
},
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerPrivateFieldOptionalChain2019NoBundle", {
// GENERATED
@@ -241,7 +241,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2019",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerPrivateFieldOptionalChain2020NoBundle", {
// GENERATED
@@ -258,7 +258,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2020",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerPrivateFieldOptionalChainNextNoBundle", {
// GENERATED
@@ -274,7 +274,7 @@ describe("bundler", () => {
}
`,
},
- mode: "transform",
+ bundling: false,
});
itBundled("lower/TSLowerPrivateFieldOptionalChain2015NoBundle", {
// GENERATED
@@ -291,7 +291,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2015",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/TSLowerPrivateStaticMembers2015NoBundle", {
// GENERATED
@@ -311,7 +311,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2015",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/TSLowerPrivateFieldAndMethodAvoidNameCollision2015", {
// GENERATED
@@ -623,7 +623,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2020",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerPrivateMethodWithModifiers2020", {
// GENERATED
@@ -668,7 +668,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2016",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerAsync2017NoBundle", {
// GENERATED
@@ -696,7 +696,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2017",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerAsyncThis2016CommonJS", {
// GENERATED
@@ -790,7 +790,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2017",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerAsyncSuperES2016NoBundle", {
// GENERATED
@@ -833,7 +833,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2016",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerStaticAsyncSuperES2021NoBundle", {
// GENERATED
@@ -876,7 +876,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2021",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerStaticAsyncSuperES2016NoBundle", {
// GENERATED
@@ -919,7 +919,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2016",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerStaticSuperES2021NoBundle", {
// GENERATED
@@ -962,7 +962,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2021",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerStaticSuperES2016NoBundle", {
// GENERATED
@@ -1005,7 +1005,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2016",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerAsyncArrowSuperES2016", {
// GENERATED
@@ -1238,7 +1238,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2020",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerClassFieldNextNoBundle", {
// GENERATED
@@ -1256,7 +1256,7 @@ describe("bundler", () => {
}
`,
},
- mode: "transform",
+ bundling: false,
});
itBundled("lower/TSLowerClassField2020NoBundle", {
// GENERATED
@@ -1275,7 +1275,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2020",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/TSLowerClassPrivateFieldNextNoBundle", {
// GENERATED
@@ -1293,7 +1293,7 @@ describe("bundler", () => {
}
`,
},
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerClassFieldStrictTsconfigJson2020", {
// GENERATED
@@ -1406,7 +1406,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2017",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/TSLowerObjectRest2018NoBundle", {
// GENERATED
@@ -1449,7 +1449,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2018",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/ClassSuperThisESBuildIssue242NoBundle", {
// GENERATED
@@ -1470,7 +1470,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2019",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerExportStarAsNameCollisionNoBundle", {
// GENERATED
@@ -1482,7 +1482,7 @@ describe("bundler", () => {
`,
},
unsupportedJSFeatures: "es2019",
- mode: "transform",
+ bundling: false,
});
itBundled("lower/LowerExportStarAsNameCollision", {
// GENERATED
diff --git a/test/bundler/esbuild/packagejson.test.ts b/test/bundler/esbuild/packagejson.test.ts
index f1bb556a2..3c3a675c4 100644
--- a/test/bundler/esbuild/packagejson.test.ts
+++ b/test/bundler/esbuild/packagejson.test.ts
@@ -73,7 +73,6 @@ describe("bundler", () => {
},
});
itBundled("packagejson/SyntaxErrorTrailingComma", {
- notImplemented: true,
files: {
"/Users/user/project/src/entry.js": /* js */ `
import fn from 'demo-pkg'
@@ -1212,7 +1211,6 @@ describe("bundler", () => {
},
});
itBundled("packagejson/ExportsNode", {
- notImplemented: true,
files: {
"/Users/user/project/src/entry.js": `import 'pkg'`,
"/Users/user/project/node_modules/pkg/package.json": /* json */ `
diff --git a/test/bundler/esbuild/splitting.test.ts b/test/bundler/esbuild/splitting.test.ts
index c10a1a36f..fa38e80ea 100644
--- a/test/bundler/esbuild/splitting.test.ts
+++ b/test/bundler/esbuild/splitting.test.ts
@@ -263,7 +263,7 @@ describe("bundler", () => {
{ file: "/out/b.js", stdout: "[null]" },
],
bundleWarnings: {
- "/empty.js": [`Import "missing" will always be undefined because the file "empty.js" has no exports`],
+ "/common.js": [`Import "missing" will always be undefined because there is no matching export in "empty.js"`],
},
});
itBundled("splitting/ReExportESBuildIssue273", {
diff --git a/test/bundler/esbuild/ts.test.ts b/test/bundler/esbuild/ts.test.ts
index 2eb894cfe..cafba8f5f 100644
--- a/test/bundler/esbuild/ts.test.ts
+++ b/test/bundler/esbuild/ts.test.ts
@@ -391,7 +391,7 @@ describe("bundler", () => {
minifySyntax: true,
minifyWhitespace: true,
minifyIdentifiers: true,
- mode: "transform",
+ bundling: false,
onAfterBundle(api) {
const a = api.readFile("/out.js");
api.writeFile("/out.edited.js", a.replace(/capture\((.*?)\)/, `export const Foo = $1`));
@@ -434,7 +434,7 @@ describe("bundler", () => {
minifySyntax: true,
minifyWhitespace: true,
minifyIdentifiers: true,
- mode: "transform",
+ bundling: false,
onAfterBundle(api) {
const b = api.readFile("/out.js");
@@ -505,7 +505,7 @@ describe("bundler", () => {
minifySyntax: true,
minifyWhitespace: true,
minifyIdentifiers: true,
- mode: "transform",
+ bundling: false,
unsupportedJSFeatures: ["logical-assignment"],
onAfterBundle(api) {
const a = api.readFile("/out/a.js");
@@ -526,7 +526,7 @@ describe("bundler", () => {
minifyWhitespace: true,
minifyIdentifiers: true,
outdir: "/",
- mode: "transform",
+ bundling: false,
unsupportedJSFeatures: ["arrow"],
onAfterBundle(api) {
const a = api.readFile("/a.js");
@@ -596,7 +596,7 @@ describe("bundler", () => {
minifyWhitespace: true,
minifyIdentifiers: true,
outdir: "/",
- mode: "transform",
+ bundling: false,
unsupportedJSFeatures: ["logical-assignment"],
onAfterBundle(api) {
const a = api.readFile("/a.js");
@@ -629,7 +629,7 @@ describe("bundler", () => {
minifyWhitespace: true,
minifyIdentifiers: true,
outdir: "/",
- mode: "transform",
+ bundling: false,
unsupportedJSFeatures: ["arrow"],
onAfterBundle(api) {
const a = api.readFile("/a.js");
@@ -759,7 +759,7 @@ describe("bundler", () => {
},
treeShaking: false,
dce: true,
- mode: "transform",
+ bundling: false,
external: ["pkg"],
});
itBundled("ts/ImportEqualsTreeShakingTrue", {
@@ -774,7 +774,7 @@ describe("bundler", () => {
dce: true,
treeShaking: true,
external: ["pkg"],
- mode: "transform",
+ bundling: false,
});
itBundled("ts/ImportEqualsBundle", {
notImplemented: true,
@@ -1028,7 +1028,7 @@ describe("bundler", () => {
}
`,
},
- mode: "transform",
+ bundling: false,
onAfterBundle(api) {
const capturedCalls = api.captureFile("/out.js", "dec");
expect(capturedCalls).toEqual([
@@ -1457,7 +1457,7 @@ describe("bundler", () => {
}
`,
},
- mode: "transform",
+ bundling: false,
runtimeFiles: {
"/test.js": /* js */ `
globalThis.nested = true;
@@ -1525,7 +1525,7 @@ describe("bundler", () => {
}
`,
},
- mode: "transform",
+ bundling: false,
runtimeFiles: {
"/test.js": /* js */ `
globalThis.nested = true;
@@ -1574,7 +1574,7 @@ describe("bundler", () => {
`,
},
useDefineForClassFields: false,
- mode: "transform",
+ bundling: false,
run: {
stdout: `
[null,{},"x1",null]
@@ -1621,7 +1621,7 @@ describe("bundler", () => {
`,
},
useDefineForClassFields: true,
- mode: "transform",
+ bundling: false,
run: {
stdout: `
[null,{},"x1",null]
@@ -1668,7 +1668,7 @@ describe("bundler", () => {
`,
},
useDefineForClassFields: true,
- mode: "transform",
+ bundling: false,
run: {
stdout: `
[null,{},"x1",null]
@@ -1712,7 +1712,7 @@ describe("bundler", () => {
(() => new Foo())()
`,
},
- mode: "transform",
+ bundling: false,
useDefineForClassFields: true,
});
itBundled("ts/ImportMTS", {
@@ -1781,7 +1781,7 @@ describe("bundler", () => {
`,
},
entryPoints: ["/let.ts", "/function.ts", "/class.ts", "/namespace.ts", "/enum.ts"],
- mode: "transform",
+ bundling: false,
runtimeFiles: {
"/test.js": /* js */ `
import assert from 'assert'
@@ -1802,6 +1802,9 @@ describe("bundler", () => {
// GENERATED
files: {
"/number.ts": /* ts */ `
+ (0, eval)('globalThis.y = 1234');
+ (0, eval)('globalThis.z = 2345');
+
export enum x { y, yy = y }
export enum x { z = y + 1 }
@@ -1810,6 +1813,9 @@ describe("bundler", () => {
console.log(x.y, x.z)
`,
"/string.ts": /* ts */ `
+ (0, eval)('globalThis.y = 1234');
+ (0, eval)('globalThis.z = 2345');
+
export enum x { y = 'a', yy = y }
export enum x { z = y }
@@ -1829,6 +1835,8 @@ describe("bundler", () => {
console.log(a.b, a['b'], x.g, x['g'])
`,
"/nested-number.ts": /* ts */ `
+ (0, eval)('globalThis.y = 1234');
+ (0, eval)('globalThis.z = 2345');
export namespace foo { export enum x { y, yy = y } }
export namespace foo { export enum x { z = y + 1 } }
@@ -1839,6 +1847,9 @@ describe("bundler", () => {
}
`,
"/nested-string.ts": /* ts */ `
+ (0, eval)('globalThis.y = 1234');
+ (0, eval)('globalThis.z = 2345');
+
export namespace foo { export enum x { y = 'a', yy = y } }
export namespace foo { export enum x { z = y } }
@@ -1872,23 +1883,29 @@ describe("bundler", () => {
"/nested-string.ts",
"/nested-propagation.ts",
],
- mode: "passthrough",
+ run: [
+ { file: "/out/number.js", stdout: "1234 2345\n0 1" },
+ { file: "/out/string.js", stdout: "1234 2345\na a" },
+ { file: "/out/propagation.js", stdout: "100 100 625 625" },
+ { file: "/out/nested-number.js", stdout: "1234 2345\n0 1" },
+ { file: "/out/nested-string.js", stdout: "1234 2345\na a" },
+ { file: "/out/nested-propagation.js", stdout: "100 100 100 625 625 625" },
+ ],
});
itBundled("ts/EnumTreeShaking", {
- // GENERATED
files: {
"/simple-member.ts": /* ts */ `
- enum x { y = 123 }
- console.log(x.y)
+ enum x_DROP { y_DROP = 123 }
+ console.log(x_DROP.y_DROP)
`,
"/simple-enum.ts": /* ts */ `
enum x { y = 123 }
- console.log(x)
+ console.log(JSON.stringify(x))
`,
"/sibling-member.ts": /* ts */ `
- enum x { y = 123 }
- enum x { z = y * 2 }
- console.log(x.y, x.z)
+ enum drop_x { drop_y = 123 }
+ enum drop_x { drop_z = drop_y * 2 }
+ console.log(drop_x.drop_y, drop_x.drop_z)
`,
"/sibling-enum-before.ts": /* ts */ `
console.log(x)
@@ -1897,21 +1914,27 @@ describe("bundler", () => {
`,
"/sibling-enum-middle.ts": /* ts */ `
enum x { y = 123 }
- console.log(x)
+ console.log(JSON.stringify(x))
enum x { z = y * 2 }
`,
"/sibling-enum-after.ts": /* ts */ `
enum x { y = 123 }
enum x { z = y * 2 }
- console.log(x)
+ console.log(JSON.stringify(x))
`,
"/namespace-before.ts": /* ts */ `
+ (0, eval)('globalThis.y = 1234');
+ (0, eval)('globalThis.x = 2345');
+
namespace x { console.log(x, y) }
enum x { y = 123 }
`,
"/namespace-after.ts": /* ts */ `
+ (0, eval)('globalThis.y = 1234');
+ (0, eval)('globalThis.x = 2345');
+
enum x { y = 123 }
- namespace x { console.log(x, y) }
+ namespace x { console.log(JSON.stringify(x), y) }
`,
},
entryPoints: [
@@ -1924,91 +1947,138 @@ describe("bundler", () => {
"/namespace-before.ts",
"/namespace-after.ts",
],
+ dce: true,
+ run: [
+ { file: "/out/simple-member.js", stdout: "123" },
+ { file: "/out/simple-enum.js", stdout: '{"123":"y","y":123}' },
+ { file: "/out/sibling-member.js", stdout: "123 246" },
+ { file: "/out/sibling-enum-before.js", stdout: "undefined" },
+ { file: "/out/sibling-enum-middle.js", stdout: '{"123":"y","y":123}' },
+ { file: "/out/sibling-enum-after.js", stdout: '{"123":"y","246":"z","y":123,"z":246}' },
+ { file: "/out/namespace-before.js", stdout: "{} 1234" },
+ { file: "/out/namespace-after.js", stdout: '{"123":"y","y":123} 1234' },
+ ],
});
itBundled("ts/EnumJSX", {
- // GENERATED
+ notImplemented: true,
files: {
"/element.tsx": /* tsx */ `
+ import { create } from 'not-react'
+
export enum Foo { Div = 'div' }
- console.log(<Foo.Div />)
+ console.log(JSON.stringify(<Foo.Div />))
`,
"/fragment.tsx": /* tsx */ `
+ import { create } from 'not-react'
+
export enum React { Fragment = 'div' }
- console.log(<>test</>)
+ console.log(JSON.stringify(<>test</>))
`,
"/nested-element.tsx": /* tsx */ `
+ import { create } from 'not-react'
+
namespace x.y { export enum Foo { Div = 'div' } }
- namespace x.y { console.log(<x.y.Foo.Div />) }
+ namespace x.y { console.log(JSON.stringify(<Foo.Div />)) }
`,
"/nested-fragment.tsx": /* tsx */ `
+ import { create } from 'not-react'
+
namespace x.y { export enum React { Fragment = 'div' } }
- namespace x.y { console.log(<>test</>) }
+ namespace x.y { console.log(JSON.stringify(<>test</>)) }
`,
},
entryPoints: ["/element.tsx", "/fragment.tsx", "/nested-element.tsx", "/nested-fragment.tsx"],
- mode: "passthrough",
+ outputPaths: ["/out/element.js", "/out/fragment.js", "/out/nested-element.js", "/out/nested-fragment.js"],
+ external: ["*"],
+ jsx: {
+ runtime: "classic",
+ factory: "create",
+ },
+ runtimeFiles: {
+ "/node_modules/not-react/index.js": /* js */ `
+ export const create = (tag, props, ...children) => [tag, props, children]
+ `,
+ },
+ run: [
+ { file: "/out/element.js", stdout: '["div",null,[]]' },
+ { file: "/out/fragment.js", stdout: '["div",null,["test"]]' },
+ { file: "/out/nested-element.js", stdout: '["div",null,[]]' },
+ { file: "/out/nested-fragment.js", stdout: '["div",null,["test"]]' },
+ ],
});
itBundled("ts/EnumDefine", {
- // GENERATED
+ notImplemented: true,
files: {
- "/entry.ts": `enum a { b = 123, c = d }`,
+ "/entry.ts": `
+ enum a { b = 123, c = d }
+ console.log(a.b, a.c)
+ `,
},
- mode: "passthrough",
+ define: {
+ d: "b",
+ },
+ run: { stdout: "123 123" },
});
itBundled("ts/EnumSameModuleInliningAccess", {
- // GENERATED
+ notImplemented: true,
files: {
"/entry.ts": /* ts */ `
- enum a { x = 123 }
- enum b { x = 123 }
+ enum a_drop { x = 123 }
+ enum b_drop { x = 123 }
enum c { x = 123 }
enum d { x = 123 }
enum e { x = 123 }
- console.log([
- a.x,
- b['x'],
+ console.log(JSON.stringify([
+ a_drop.x,
+ b_drop['x'],
c?.x,
d?.['x'],
e,
- ])
+ ]))
`,
},
+ dce: true,
+ run: { stdout: '[123,123,123,123,{"123":"x","x":123}]' },
});
itBundled("ts/EnumCrossModuleInliningAccess", {
- // GENERATED
+ notImplemented: true,
files: {
"/entry.ts": /* ts */ `
- import { a, b, c, d, e } from './enums'
- console.log([
- a.x,
- b['x'],
+ import { drop_a, drop_b, c, d, e } from './enums'
+ console.log(JSON.stringify([
+ drop_a.x,
+ drop_b['x'],
c?.x,
d?.['x'],
e,
- ])
+ ]))
`,
"/enums.ts": /* ts */ `
- export enum a { x = 123 }
- export enum b { x = 123 }
+ export enum drop_a { x = 123 }
+ export enum drop_b { x = 123 }
export enum c { x = 123 }
export enum d { x = 123 }
export enum e { x = 123 }
`,
},
+ dce: true,
});
itBundled("ts/EnumCrossModuleInliningDefinitions", {
- // GENERATED
+ notImplemented: true,
files: {
"/entry.ts": /* ts */ `
import { a } from './enums'
- console.log([
- a.implicit_number,
- a.explicit_number,
- a.explicit_string,
+ (0, eval)('globalThis.capture = x => x');
+ console.log(JSON.stringify([
+ capture(a.implicit_number),
+ capture(a.explicit_number),
+ capture(a.explicit_string),
a.non_constant,
- ])
+ ]))
`,
"/enums.ts": /* ts */ `
+ (0, eval)('globalThis.foo = 321');
+
export enum a {
implicit_number,
explicit_number = 123,
@@ -2017,18 +2087,21 @@ describe("bundler", () => {
}
`,
},
+ onAfterBundle(api) {
+ expect(api.captureFile("/out.js").map(x => x.replace(/\/\*.*\*\//g, "").trim())).toEqual(["0", "123", '"xyz"']);
+ },
});
itBundled("ts/EnumCrossModuleInliningReExport", {
- // GENERATED
+ notImplemented: true,
files: {
"/entry.js": /* js */ `
import { a } from './re-export'
import { b } from './re-export-star'
import * as ns from './enums'
console.log([
- a.x,
- b.x,
- ns.c.x,
+ capture(a.x),
+ capture(b.x),
+ capture(ns.c.x),
])
`,
"/re-export.js": `export { a } from './enums'`,
@@ -2039,9 +2112,12 @@ describe("bundler", () => {
export enum c { x = 'c' }
`,
},
+ onAfterBundle(api) {
+ expect(api.captureFile("/out.js").map(x => x.replace(/\/\*.*\*\//g, "").trim())).toEqual(['"a"', '"b"', '"c"']);
+ },
});
itBundled("ts/EnumCrossModuleTreeShaking", {
- // GENERATED
+ notImplemented: true,
files: {
"/entry.ts": /* ts */ `
import {
@@ -2051,25 +2127,19 @@ describe("bundler", () => {
} from './enums'
console.log([
- a_DROP.x,
- b_DROP['x'],
- c_DROP.x,
+ capture(a_DROP.x),
+ capture(b_DROP['x']),
+ capture(c_DROP.x),
])
- import {
- a_keep,
- b_keep,
- c_keep,
- d_keep,
- e_keep,
- } from './enums'
+ import { a, b, c, d, e } from './enums'
console.log([
- a_keep.x,
- b_keep.x,
- c_keep,
- d_keep.y,
- e_keep.x,
+ capture(a.x),
+ capture(b.x),
+ capture(c),
+ capture(d.y),
+ capture(e.x),
])
`,
"/enums.ts": /* ts */ `
@@ -2077,16 +2147,28 @@ describe("bundler", () => {
export enum b_DROP { x = 2 } // test an index access
export enum c_DROP { x = '' } // test a string enum
- export enum a_keep { x = false } // false is not inlinable
- export enum b_keep { x = foo } // foo has side effects
- export enum c_keep { x = 3 } // this enum object is captured
- export enum d_keep { x = 4 } // we access "y" on this object
- export let e_keep = {} // non-enum properties should be kept
+ export enum a { x = false } // false is not inlinable
+ export enum b { x = foo } // foo has side effects
+ export enum c { x = 3 } // this enum object is captured
+ export enum d { x = 4 } // we access "y" on this object
+ export let e = {} // non-enum properties should be kept
`,
},
+ onAfterBundle(api) {
+ expect(api.captureFile("/out.js").map(x => x.replace(/\/\*.*\*\//g, "").trim())).toEqual([
+ "1",
+ "2",
+ '""',
+ "a.x",
+ "b.x",
+ "c",
+ "d.y",
+ "e.x",
+ ]);
+ },
});
itBundled("ts/EnumExportClause", {
- // GENERATED
+ notImplemented: true,
files: {
"/entry.ts": /* ts */ `
import {
@@ -2097,100 +2179,185 @@ describe("bundler", () => {
} from './enums'
console.log([
- A.A,
- B.B,
- c.C,
- dd.D,
+ capture(A.A),
+ capture(B.B),
+ capture(c.C),
+ capture(dd.D),
])
`,
"/enums.ts": /* ts */ `
export enum A { A = 1 }
- enum B { B = 2 }
- export enum C { C = 3 }
- enum D { D = 4 }
- export { B, D as d }
+ enum B { B = 2 }
+ export enum C { C = 3 }
+ enum D { D = 4 }
+ export { B, D as d }
`,
},
- });
- itBundled("ts/ThisIsUndefinedWarning", {
- // GENERATED
- files: {
- "/warning1.ts": `export var foo = this`,
- "/warning2.ts": `export var foo = this || this.foo`,
- "/warning3.ts": `export var foo = this ? this.foo : null`,
- "/silent1.ts": `export var foo = this && this.foo`,
- "/silent2.ts": `export var foo = this && (() => this.foo)`,
- },
- entryPoints: ["/warning1.ts", "/warning2.ts", "/warning3.ts", "/silent1.ts", "/silent2.ts"],
- /* TODO FIX expectedScanLog: `warning1.ts: DEBUG: Top-level "this" will be replaced with undefined since this file is an ECMAScript module
- warning1.ts: NOTE: This file is considered to be an ECMAScript module because of the "export" keyword here:
- warning2.ts: DEBUG: Top-level "this" will be replaced with undefined since this file is an ECMAScript module
- warning2.ts: NOTE: This file is considered to be an ECMAScript module because of the "export" keyword here:
- warning3.ts: DEBUG: Top-level "this" will be replaced with undefined since this file is an ECMAScript module
- warning3.ts: NOTE: This file is considered to be an ECMAScript module because of the "export" keyword here:
- `, */
- });
- itBundled("ts/CommonJSVariableInESMTypeModule", {
- // GENERATED
- files: {
- "/entry.ts": `module.exports = null`,
- "/package.json": `{ "type": "module" }`,
- },
- /* TODO FIX expectedScanLog: `entry.ts: WARNING: The CommonJS "module" variable is treated as a global variable in an ECMAScript module and may not work as expected
- package.json: NOTE: This file is considered to be an ECMAScript module because the enclosing "package.json" file sets the type of this file to "module":
- NOTE: Node's package format requires that CommonJS files in a "type": "module" package use the ".cjs" file extension. If you are using TypeScript, you can use the ".cts" file extension with esbuild instead.
- `, */
- });
+ onAfterBundle(api) {
+ expect(api.captureFile("/out.js").map(x => x.replace(/\/\*.*\*\//g, "").trim())).toEqual(["1", "2", "3", "4"]);
+ },
+ });
+ // itBundled("ts/CommonJSVariableInESMTypeModule", {
+ // // GENERATED
+ // files: {
+ // "/entry.ts": `module.exports = null`,
+ // "/package.json": `{ "type": "module" }`,
+ // },
+ // /* TODO FIX expectedScanLog: `entry.ts: WARNING: The CommonJS "module" variable is treated as a global variable in an ECMAScript module and may not work as expected
+ // package.json: NOTE: This file is considered to be an ECMAScript module because the enclosing "package.json" file sets the type of this file to "module":
+ // NOTE: Node's package format requires that CommonJS files in a "type": "module" package use the ".cjs" file extension. If you are using TypeScript, you can use the ".cts" file extension with esbuild instead.
+ // `, */
+ // });
itBundled("ts/EnumRulesFrom_TypeScript_5_0", {
// GENERATED
files: {
- "/supported.ts": /* ts */ `
+ "/supported.ts":
+ `
// From https://github.com/microsoft/TypeScript/pull/50528:
- // "An expression is considered a constant expression if it is
- const enum Foo {
- // a number or string literal,
- X0 = 123,
- X1 = 'x',
-
- // a unary +, -, or ~ applied to a numeric constant expression,
- X2 = +1,
- X3 = -2,
- X4 = ~3,
-
- // a binary +, -, *, /, %, **, <<, >>, >>>, |, &, ^ applied to two numeric constant expressions,
- X5 = 1 + 2,
- X6 = 1 - 2,
- X7 = 2 * 3,
- X8 = 1 / 2,
- X9 = 3 % 2,
- X10 = 2 ** 3,
- X11 = 1 << 2,
- X12 = -9 >> 1,
- X13 = -9 >>> 1,
- X14 = 5 | 12,
- X15 = 5 & 12,
- X16 = 5 ^ 12,
-
- // a binary + applied to two constant expressions whereof at least one is a string,
- X17 = 'x' + 0,
- X18 = 0 + 'x',
- X19 = 'x' + 'y',
- X20 = '' + NaN,
- X21 = '' + Infinity,
- X22 = '' + -Infinity,
- X23 = '' + -0,
-
- // a template expression where each substitution expression is a constant expression,
- X24 = \` + "\`A\$00}B\$0'x'}C\$01 + 3 - 4 / 2 * 5 ** 6}D\`" +
+ // "An expression is considered a constant expression if it is
+ const enum DROP {
+ // a number or string literal,
+ X0 = 123,
+ X1 = 'x',
+
+ // a unary +, -, or ~ applied to a numeric constant expression,
+ X2 = +1,
+ X3 = -2,
+ X4 = ~3,
+
+ // a binary +, -, *, /, %, **, <<, >>, >>>, |, &, ^ applied to two numeric constant expressions,
+ X5 = 1 + 2,
+ X6 = 1 - 2,
+ X7 = 2 * 3,
+ X8 = 1 / 2,
+ X9 = 3 % 2,
+ X10 = 2 ** 3,
+ X11 = 1 << 2,
+ X12 = -9 >> 1,
+ X13 = -9 >>> 1,
+ X14 = 5 | 12,
+ X15 = 5 & 12,
+ X16 = 5 ^ 12,
+
+ // a binary + applied to two constant expressions whereof at least one is a string,
+ X17 = 'x' + 0,
+ X18 = 0 + 'x',
+ X19 = 'x' + 'y',
+ X20 = '' + NaN,
+ X21 = '' + Infinity,
+ X22 = '' + -Infinity,
+ X23 = '' + -0,
+
+ // a template expression where each substitution expression is a constant expression,
+ X24 = ` +
+ "`A${0}B${'x'}C${1 + 3 - 4 / 2 * 5 ** 6}D`" +
+ `,
+
+ // a parenthesized constant expression,
+ X25 = (321),
+
+ // a dotted name (e.g. x.y.z) that references a const variable with a constant expression initializer and no type annotation,
+ /* (we don't implement this one) */
+
+ // a dotted name that references an enum member with an enum literal type, or
+ X26 = X0,
+ X27 = X0 + 'x',
+ X28 = 'x' + X0,
+ X29 = ` +
+ "`a${X0}b`" +
+ `,
+ X30 = DROP.X0,
+ X31 = DROP.X0 + 'x',
+ X32 = 'x' + DROP.X0,
+ X33 = ` +
+ "`a${DROP.X0}b`" +
+ `,
+
+ // a dotted name indexed by a string literal (e.g. x.y["z"]) that references an enum member with an enum literal type."
+ X34 = X1,
+ X35 = X1 + 'y',
+ X36 = 'y' + X1,
+ X37 = ` +
+ "`a${X1}b`" +
+ `,
+ X38 = DROP['X1'],
+ X39 = DROP['X1'] + 'y',
+ X40 = 'y' + DROP['X1'],
+ X41 = ` +
+ "`a${DROP['X1']}b`" +
+ `,
+ }
+
+ console.log(JSON.stringify([
+ // a number or string literal,
+ DROP.X0,
+ DROP.X1,
+
+ // a unary +, -, or ~ applied to a numeric constant expression,
+ DROP.X2,
+ DROP.X3,
+ DROP.X4,
+
+ // a binary +, -, *, /, %, **, <<, >>, >>>, |, &, ^ applied to two numeric constant expressions,
+ DROP.X5,
+ DROP.X6,
+ DROP.X7,
+ DROP.X8,
+ DROP.X9,
+ DROP.X10,
+ DROP.X11,
+ DROP.X12,
+ DROP.X13,
+ DROP.X14,
+ DROP.X15,
+ DROP.X16,
+
+ // a template expression where each substitution expression is a constant expression,
+ DROP.X17,
+ DROP.X18,
+ DROP.X19,
+ DROP.X20,
+ DROP.X21,
+ DROP.X22,
+ DROP.X23,
+
+ // a template expression where each substitution expression is a constant expression,
+ DROP.X24,
+
+ // a parenthesized constant expression,
+ DROP.X25,
+
+ // a dotted name that references an enum member with an enum literal type, or
+ DROP.X26,
+ DROP.X27,
+ DROP.X28,
+ DROP.X29,
+ DROP.X30,
+ DROP.X31,
+ DROP.X32,
+ DROP.X33,
+
+ // a dotted name indexed by a string literal (e.g. x.y["z"]) that references an enum member with an enum literal type."
+ DROP.X34,
+ DROP.X35,
+ DROP.X36,
+ DROP.X37,
+ DROP.X38,
+ DROP.X39,
+ DROP.X40,
+ DROP.X41,
+ ]))
`,
"/not-supported.ts": /* ts */ `
+ (0, eval)('globalThis.capture = x => x');
+
const enum NonIntegerNumberToString {
SUPPORTED = '' + 1,
UNSUPPORTED = '' + 1.5,
}
console.log(
- NonIntegerNumberToString.SUPPORTED,
- NonIntegerNumberToString.UNSUPPORTED,
+ capture(NonIntegerNumberToString.SUPPORTED),
+ capture(NonIntegerNumberToString.UNSUPPORTED),
)
const enum OutOfBoundsNumberToString {
@@ -2198,8 +2365,8 @@ describe("bundler", () => {
UNSUPPORTED = '' + 1_000_000_000_000,
}
console.log(
- OutOfBoundsNumberToString.SUPPORTED,
- OutOfBoundsNumberToString.UNSUPPORTED,
+ capture(OutOfBoundsNumberToString.SUPPORTED),
+ capture(OutOfBoundsNumberToString.UNSUPPORTED),
)
const enum TemplateExpressions {
@@ -2209,27 +2376,70 @@ describe("bundler", () => {
FALSE = '' + false,
BIGINT = '' + 123n,
}
+
console.log(
- TemplateExpressions.NULL,
- TemplateExpressions.TRUE,
- TemplateExpressions.FALSE,
- TemplateExpressions.BIGINT,
+ capture(TemplateExpressions.NULL),
+ capture(TemplateExpressions.TRUE),
+ capture(TemplateExpressions.FALSE),
+ capture(TemplateExpressions.BIGINT),
)
`,
},
+ // dce: true,
entryPoints: ["/supported.ts", "/not-supported.ts"],
+ run: [
+ {
+ file: "/out/supported.js",
+ stdout:
+ '[123,"x",1,-2,-4,3,-1,6,0.5,1,8,4,-5,2147483643,13,4,9,"x0","0x","xy","NaN","Infinity","-Infinity","0","A0BxC-31246D",321,123,"123x","x123","a123b",123,"123x","x123","a123b","x","xy","yx","axb","x","xy","yx","axb"]',
+ },
+ {
+ file: "/out/not-supported.js",
+ stdout: `
+ 1 1.5
+ 1000000000 1000000000000
+ null true false 123
+ `,
+ },
+ ],
+ onAfterBundle(api) {
+ // expect(api.captureFile("/out/not-supported.js").map(x => x.replace(/\/\*.*\*\//g, "").trim())).toEqual([
+ // '"1"',
+ // "NonIntegerNumberToString.UNSUPPORTED",
+ // '"1000000000"',
+ // "OutOfBoundsNumberToString.UNSUPPORTED",
+ // "TemplateExpressions.NULL",
+ // "TemplateExpressions.TRUE",
+ // "TemplateExpressions.FALSE",
+ // "TemplateExpressions.BIGINT",
+ // ]);
+ },
});
itBundled("ts/EnumUseBeforeDeclare", {
- // GENERATED
+ notImplemented: true,
files: {
"/entry.ts": /* ts */ `
+ before();
+ after();
+
export function before() {
- console.log(Foo.FOO)
+ console.log(JSON.stringify(Foo), Foo.FOO)
}
enum Foo { FOO }
export function after() {
- console.log(Foo.FOO)
+ console.log(JSON.stringify(Foo), Foo.FOO)
}
+
+ before();
+ after();
+ `,
+ },
+ run: {
+ stdout: `
+ undefined 0
+ undefined 0
+ {"0":"FOO","FOO":0} 0
+ {"0":"FOO","FOO":0} 0
`,
},
});
diff --git a/test/bundler/esbuild/tsconfig.test.ts b/test/bundler/esbuild/tsconfig.test.ts
index accd0ca7e..b698ad07a 100644
--- a/test/bundler/esbuild/tsconfig.test.ts
+++ b/test/bundler/esbuild/tsconfig.test.ts
@@ -7,16 +7,14 @@ var { describe, test, expect } = testForFile(import.meta.path);
// For debug, all files are written to $TEMP/bun-bundle-tests/tsconfig
describe("bundler", () => {
- return;
- itBundled("tsconfig/TsConfigPaths", {
- // GENERATED
+ itBundled("tsconfig/Paths", ({ root }) => ({
files: {
- "/Users/user/project/entry.ts": /* ts */ `
+ "/entry.ts": /* ts */ `
import baseurl_dot from './baseurl_dot'
import baseurl_nested from './baseurl_nested'
- console.log(baseurl_dot, baseurl_nested)
+ console.log(JSON.stringify({baseurl_dot, baseurl_nested}))
`,
- "/Users/user/project/baseurl_dot/index.ts": /* ts */ `
+ "/baseurl_dot/index.ts": /* ts */ `
import test0 from 'test0'
import test1 from 'test1/foo'
import test2 from 'test2/foo'
@@ -40,7 +38,7 @@ describe("bundler", () => {
absoluteOutStar,
}
`,
- "/Users/user/project/baseurl_dot/tsconfig.json": /* json */ `
+ "/baseurl_dot/tsconfig.json": /* json */ `
{
"compilerOptions": {
"baseUrl": ".",
@@ -53,24 +51,24 @@ describe("bundler", () => {
"test5/*": ["./test5-first/*", "./test5-second/*"],
"/virtual-in/test": ["./actual/test"],
"/virtual-in-star/*": ["./actual/*"],
- "/virtual-out/test": ["/Users/user/project/baseurl_dot/actual/test"],
- "/virtual-out-star/*": ["/Users/user/project/baseurl_dot/actual/*"],
+ "/virtual-out/test": ["${root}/baseurl_dot/actual/test"],
+ "/virtual-out-star/*": ["${root}/baseurl_dot/actual/*"],
}
}
}
`,
- "/Users/user/project/baseurl_dot/test0-success.ts": `export default 'test0-success'`,
- "/Users/user/project/baseurl_dot/test1-success.ts": `export default 'test1-success'`,
- "/Users/user/project/baseurl_dot/test2-success/foo.ts": `export default 'test2-success'`,
- "/Users/user/project/baseurl_dot/test3-success.ts": `export default 'test3-success'`,
- "/Users/user/project/baseurl_dot/test4-first/foo.ts": `export default 'test4-success'`,
- "/Users/user/project/baseurl_dot/test5-second/foo.ts": `export default 'test5-success'`,
- "/Users/user/project/baseurl_dot/absolute-in.ts": `export {default} from '/virtual-in/test'`,
- "/Users/user/project/baseurl_dot/absolute-in-star.ts": `export {default} from '/virtual-in-star/test'`,
- "/Users/user/project/baseurl_dot/absolute-out.ts": `export {default} from '/virtual-out/test'`,
- "/Users/user/project/baseurl_dot/absolute-out-star.ts": `export {default} from '/virtual-out-star/test'`,
- "/Users/user/project/baseurl_dot/actual/test.ts": `export default 'absolute-success'`,
- "/Users/user/project/baseurl_nested/index.ts": /* ts */ `
+ "/baseurl_dot/test0-success.ts": `export default 'test0-success'`,
+ "/baseurl_dot/test1-success.ts": `export default 'test1-success'`,
+ "/baseurl_dot/test2-success/foo.ts": `export default 'test2-success'`,
+ "/baseurl_dot/test3-success.ts": `export default 'test3-success'`,
+ "/baseurl_dot/test4-first/foo.ts": `export default 'test4-success'`,
+ "/baseurl_dot/test5-second/foo.ts": `export default 'test5-success'`,
+ "/baseurl_dot/absolute-in.ts": `export {default} from '/virtual-in/test'`,
+ "/baseurl_dot/absolute-in-star.ts": `export {default} from '/virtual-in-star/test'`,
+ "/baseurl_dot/absolute-out.ts": `export {default} from '/virtual-out/test'`,
+ "/baseurl_dot/absolute-out-star.ts": `export {default} from '/virtual-out-star/test'`,
+ "/baseurl_dot/actual/test.ts": `export default 'absolute-success'`,
+ "/baseurl_nested/index.ts": /* ts */ `
import test0 from 'test0'
import test1 from 'test1/foo'
import test2 from 'test2/foo'
@@ -94,7 +92,7 @@ describe("bundler", () => {
absoluteOutStar,
}
`,
- "/Users/user/project/baseurl_nested/tsconfig.json": /* json */ `
+ "/baseurl_nested/tsconfig.json": /* json */ `
{
"compilerOptions": {
"baseUrl": "nested",
@@ -107,34 +105,37 @@ describe("bundler", () => {
"test5/*": ["./test5-first/*", "./test5-second/*"],
"/virtual-in/test": ["./actual/test"],
"/virtual-in-star/*": ["./actual/*"],
- "/virtual-out/test": ["/Users/user/project/baseurl_nested/nested/actual/test"],
- "/virtual-out-star/*": ["/Users/user/project/baseurl_nested/nested/actual/*"],
+ "/virtual-out/test": ["${root}/baseurl_nested/nested/actual/test"],
+ "/virtual-out-star/*": ["${root}/baseurl_nested/nested/actual/*"],
}
}
}
`,
- "/Users/user/project/baseurl_nested/nested/test0-success.ts": `export default 'test0-success'`,
- "/Users/user/project/baseurl_nested/nested/test1-success.ts": `export default 'test1-success'`,
- "/Users/user/project/baseurl_nested/nested/test2-success/foo.ts": `export default 'test2-success'`,
- "/Users/user/project/baseurl_nested/nested/test3-success.ts": `export default 'test3-success'`,
- "/Users/user/project/baseurl_nested/nested/test4-first/foo.ts": `export default 'test4-success'`,
- "/Users/user/project/baseurl_nested/nested/test5-second/foo.ts": `export default 'test5-success'`,
- "/Users/user/project/baseurl_nested/absolute-in.ts": `export {default} from '/virtual-in/test'`,
- "/Users/user/project/baseurl_nested/absolute-in-star.ts": `export {default} from '/virtual-in/test'`,
- "/Users/user/project/baseurl_nested/absolute-out.ts": `export {default} from '/virtual-out/test'`,
- "/Users/user/project/baseurl_nested/absolute-out-star.ts": `export {default} from '/virtual-out-star/test'`,
- "/Users/user/project/baseurl_nested/nested/actual/test.ts": `export default 'absolute-success'`,
+ "/baseurl_nested/nested/test0-success.ts": `export default 'test0-success'`,
+ "/baseurl_nested/nested/test1-success.ts": `export default 'test1-success'`,
+ "/baseurl_nested/nested/test2-success/foo.ts": `export default 'test2-success'`,
+ "/baseurl_nested/nested/test3-success.ts": `export default 'test3-success'`,
+ "/baseurl_nested/nested/test4-first/foo.ts": `export default 'test4-success'`,
+ "/baseurl_nested/nested/test5-second/foo.ts": `export default 'test5-success'`,
+ "/baseurl_nested/absolute-in.ts": `export {default} from '/virtual-in/test'`,
+ "/baseurl_nested/absolute-in-star.ts": `export {default} from '/virtual-in/test'`,
+ "/baseurl_nested/absolute-out.ts": `export {default} from '/virtual-out/test'`,
+ "/baseurl_nested/absolute-out-star.ts": `export {default} from '/virtual-out-star/test'`,
+ "/baseurl_nested/nested/actual/test.ts": `export default 'absolute-success'`,
},
- });
- itBundled("tsconfig/TsConfigPathsNoBaseURL", {
- // GENERATED
+ run: {
+ stdout:
+ '{"baseurl_dot":{"test0":"test0-success","test1":"test1-success","test2":"test2-success","test3":"test3-success","test4":"test4-success","test5":"test5-success","absoluteIn":"absolute-success","absoluteInStar":"absolute-success","absoluteOut":"absolute-success","absoluteOutStar":"absolute-success"},"baseurl_nested":{"test0":"test0-success","test1":"test1-success","test2":"test2-success","test3":"test3-success","test4":"test4-success","test5":"test5-success","absoluteIn":"absolute-success","absoluteInStar":"absolute-success","absoluteOut":"absolute-success","absoluteOutStar":"absolute-success"}}',
+ },
+ }));
+ itBundled("tsconfig/PathsNoBaseURL", {
files: {
- "/Users/user/project/entry.ts": /* ts */ `
+ "/entry.ts": /* ts */ `
import simple from './simple'
import extended from './extended'
- console.log(simple, extended)
+ console.log(JSON.stringify({simple, extended}))
`,
- "/Users/user/project/simple/index.ts": /* ts */ `
+ "/simple/index.ts": /* ts */ `
import test0 from 'test0'
import test1 from 'test1/foo'
import test2 from 'test2/foo'
@@ -152,7 +153,7 @@ describe("bundler", () => {
absolute,
}
`,
- "/Users/user/project/simple/tsconfig.json": /* json */ `
+ "/simple/tsconfig.json": /* json */ `
{
"compilerOptions": {
"paths": {
@@ -167,15 +168,15 @@ describe("bundler", () => {
}
}
`,
- "/Users/user/project/simple/test0-success.ts": `export default 'test0-success'`,
- "/Users/user/project/simple/test1-success.ts": `export default 'test1-success'`,
- "/Users/user/project/simple/test2-success/foo.ts": `export default 'test2-success'`,
- "/Users/user/project/simple/test3-success.ts": `export default 'test3-success'`,
- "/Users/user/project/simple/test4-first/foo.ts": `export default 'test4-success'`,
- "/Users/user/project/simple/test5-second/foo.ts": `export default 'test5-success'`,
- "/Users/user/project/simple/absolute.ts": `export {default} from '/virtual/test'`,
- "/Users/user/project/simple/actual/test.ts": `export default 'absolute-success'`,
- "/Users/user/project/extended/index.ts": /* ts */ `
+ "/simple/test0-success.ts": `export default 'test0-success'`,
+ "/simple/test1-success.ts": `export default 'test1-success'`,
+ "/simple/test2-success/foo.ts": `export default 'test2-success'`,
+ "/simple/test3-success.ts": `export default 'test3-success'`,
+ "/simple/test4-first/foo.ts": `export default 'test4-success'`,
+ "/simple/test5-second/foo.ts": `export default 'test5-success'`,
+ "/simple/absolute.ts": `export {default} from '/virtual/test'`,
+ "/simple/actual/test.ts": `export default 'absolute-success'`,
+ "/extended/index.ts": /* ts */ `
import test0 from 'test0'
import test1 from 'test1/foo'
import test2 from 'test2/foo'
@@ -193,12 +194,12 @@ describe("bundler", () => {
absolute,
}
`,
- "/Users/user/project/extended/tsconfig.json": /* json */ `
+ "/extended/tsconfig.json": /* json */ `
{
"extends": "./nested/tsconfig.json"
}
`,
- "/Users/user/project/extended/nested/tsconfig.json": /* json */ `
+ "/extended/nested/tsconfig.json": /* json */ `
{
"compilerOptions": {
"paths": {
@@ -213,18 +214,24 @@ describe("bundler", () => {
}
}
`,
- "/Users/user/project/extended/nested/test0-success.ts": `export default 'test0-success'`,
- "/Users/user/project/extended/nested/test1-success.ts": `export default 'test1-success'`,
- "/Users/user/project/extended/nested/test2-success/foo.ts": `export default 'test2-success'`,
- "/Users/user/project/extended/nested/test3-success.ts": `export default 'test3-success'`,
- "/Users/user/project/extended/nested/test4-first/foo.ts": `export default 'test4-success'`,
- "/Users/user/project/extended/nested/test5-second/foo.ts": `export default 'test5-success'`,
- "/Users/user/project/extended/absolute.ts": `export {default} from '/virtual/test'`,
- "/Users/user/project/extended/nested/actual/test.ts": `export default 'absolute-success'`,
+ "/extended/nested/test0-success.ts": `export default 'test0-success'`,
+ "/extended/nested/test1-success.ts": `export default 'test1-success'`,
+ "/extended/nested/test2-success/foo.ts": `export default 'test2-success'`,
+ "/extended/nested/test3-success.ts": `export default 'test3-success'`,
+ "/extended/nested/test4-first/foo.ts": `export default 'test4-success'`,
+ "/extended/nested/test5-second/foo.ts": `export default 'test5-success'`,
+ "/extended/absolute.ts": `export {default} from '/virtual/test'`,
+ "/extended/nested/actual/test.ts": `export default 'absolute-success'`,
+ },
+ run: {
+ stdout:
+ '{"simple":{"test0":"test0-success","test1":"test1-success","test2":"test2-success","test3":"test3-success","test4":"test4-success","test5":"test5-success","absolute":"absolute-success"},"extended":{"test0":"test0-success","test1":"test1-success","test2":"test2-success","test3":"test3-success","test4":"test4-success","test5":"test5-success","absolute":"absolute-success"}}',
},
});
- itBundled("tsconfig/TsConfigBadPathsNoBaseURL", {
+ // TODO: warnings shouldnt stop build?
+ itBundled("tsconfig/BadPathsNoBaseURL", {
// GENERATED
+ notImplemented: true,
files: {
"/Users/user/project/entry.ts": `import "should-not-be-imported"`,
"/Users/user/project/should-not-be-imported.ts": ``,
@@ -236,22 +243,22 @@ describe("bundler", () => {
".",
"..",
"./good",
- ".\\good",
+ ".\\\\good",
"../good",
- "..\\good",
+ "..\\\\good",
"/good",
- "\\good",
+ "\\\\good",
"c:/good",
- "c:\\good",
+ "c:\\\\good",
"C:/good",
- "C:\\good",
+ "C:\\\\good",
"bad",
"@bad/core",
".*/bad",
"..*/bad",
- "c*:\\bad",
- "c:*\\bad",
+ "c*:\\\\bad",
+ "c:*\\\\bad",
"http://bad"
]
}
@@ -270,7 +277,7 @@ describe("bundler", () => {
Users/user/project/tsconfig.json: WARNING: Non-relative path "http://bad" is not allowed when "baseUrl" is not set (did you forget a leading "./"?)
`, */
});
- itBundled("tsconfig/TsConfigPathsOverriddenBaseURL", {
+ itBundled("tsconfig/PathsOverriddenBaseURL", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -296,9 +303,11 @@ describe("bundler", () => {
}
`,
},
+ run: {
+ stdout: "123",
+ },
});
- itBundled("tsconfig/TsConfigPathsOverriddenBaseURLDifferentDir", {
- // GENERATED
+ itBundled("tsconfig/PathsOverriddenBaseURLDifferentDir", {
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
import test from '#/test'
@@ -323,9 +332,11 @@ describe("bundler", () => {
}
`,
},
+ run: {
+ stdout: "123",
+ },
});
- itBundled("tsconfig/TsConfigPathsMissingBaseURL", {
- // GENERATED
+ itBundled("tsconfig/PathsMissingBaseURL", {
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
import test from '#/test'
@@ -349,11 +360,12 @@ describe("bundler", () => {
}
`,
},
- /* TODO FIX expectedScanLog: `Users/user/project/src/entry.ts: ERROR: Could not resolve "#/test"
- NOTE: You can mark the path "#/test" as external to exclude it from the bundle, which will remove this error.
- `, */
+ bundleErrors: {
+ "/Users/user/project/src/entry.ts": [`Could not resolve: "#/test". Maybe you need to "bun install"?`],
+ },
});
- itBundled("tsconfig/TsConfigPathsTypeOnly", {
+ return;
+ itBundled("tsconfig/PathsTypeOnly", {
// GENERATED
files: {
"/Users/user/project/entry.ts": /* ts */ `
@@ -382,7 +394,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsConfigJSX", {
+ itBundled("tsconfig/JSX", {
// GENERATED
files: {
"/Users/user/project/entry.tsx": `console.log(<><div/><div/></>)`,
@@ -396,7 +408,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsConfigNestedJSX", {
+ itBundled("tsconfig/NestedJSX", {
// GENERATED
files: {
"/Users/user/project/entry.ts": /* ts */ `
@@ -432,7 +444,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsConfigReactJSX", {
+ itBundled("tsconfig/ReactJSX", {
// GENERATED
files: {
"/Users/user/project/entry.tsx": `console.log(<><div/><div/></>)`,
@@ -447,7 +459,7 @@ describe("bundler", () => {
},
outfile: "/Users/user/project/out.js",
});
- itBundled("tsconfig/TsConfigReactJSXDev", {
+ itBundled("tsconfig/ReactJSXDev", {
// GENERATED
files: {
"/Users/user/project/entry.tsx": `console.log(<><div/><div/></>)`,
@@ -461,7 +473,7 @@ describe("bundler", () => {
},
outfile: "/Users/user/project/out.js",
});
- itBundled("tsconfig/TsConfigReactJSXWithDevInMainConfig", {
+ itBundled("tsconfig/ReactJSXWithDevInMainConfig", {
// GENERATED
files: {
"/Users/user/project/entry.tsx": `console.log(<><div/><div/></>)`,
@@ -478,7 +490,7 @@ describe("bundler", () => {
development: true,
},
});
- itBundled("tsconfig/TsconfigJsonBaseUrl", {
+ itBundled("tsconfig/JsonBaseUrl", {
// GENERATED
files: {
"/Users/user/project/src/app/entry.js": /* js */ `
@@ -520,7 +532,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsconfigJsonAbsoluteBaseUrl", {
+ itBundled("tsconfig/JsonAbsoluteBaseUrl", {
// GENERATED
files: {
"/Users/user/project/src/app/entry.js": /* js */ `
@@ -541,7 +553,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsconfigJsonCommentAllowed", {
+ itBundled("tsconfig/JsonCommentAllowed", {
// GENERATED
files: {
"/Users/user/project/src/app/entry.js": /* js */ `
@@ -563,7 +575,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsconfigJsonTrailingCommaAllowed", {
+ itBundled("tsconfig/JsonTrailingCommaAllowed", {
// GENERATED
files: {
"/Users/user/project/src/app/entry.js": /* js */ `
@@ -584,7 +596,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsconfigJsonExtends", {
+ itBundled("tsconfig/JsonExtends", {
// GENERATED
files: {
"/entry.jsx": `console.log(<div/>, <></>)`,
@@ -606,8 +618,8 @@ describe("bundler", () => {
`,
},
});
- bundlerTest.skip("tsconfig/TsconfigJsonExtendsAbsolute", () => {
- expectBundled("tsconfig/TsconfigJsonExtendsAbsoluteUnix", {
+ test.skip("tsconfig/JsonExtendsAbsolute", () => {
+ expectBundled("tsconfig/JsonExtendsAbsoluteUnix", {
// GENERATED
host: "unix",
files: {
@@ -630,7 +642,7 @@ describe("bundler", () => {
`,
},
});
- expectBundled("tsconfig/TsconfigJsonExtendsAbsoluteWindows", {
+ expectBundled("tsconfig/JsonExtendsAbsoluteWindows", {
// GENERATED
host: "windows",
files: {
@@ -654,7 +666,7 @@ describe("bundler", () => {
},
});
});
- itBundled("tsconfig/TsconfigJsonExtendsThreeLevels", {
+ itBundled("tsconfig/JsonExtendsThreeLevels", {
// GENERATED
files: {
"/Users/user/project/src/entry.jsx": /* jsx */ `
@@ -689,7 +701,7 @@ describe("bundler", () => {
"/Users/user/project/src/path2/works/import.js": `console.log('works')`,
},
});
- itBundled("tsconfig/TsconfigJsonExtendsLoop", {
+ itBundled("tsconfig/JsonExtendsLoop", {
// GENERATED
files: {
"/entry.js": `console.log(123)`,
@@ -707,7 +719,7 @@ describe("bundler", () => {
/* TODO FIX expectedScanLog: `base.json: WARNING: Base config file "./tsconfig" forms cycle
`, */
});
- itBundled("tsconfig/TsconfigJsonExtendsPackage", {
+ itBundled("tsconfig/JsonExtendsPackage", {
// GENERATED
files: {
"/Users/user/project/src/app/entry.jsx": `console.log(<div/>)`,
@@ -725,7 +737,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsconfigJsonOverrideMissing", {
+ itBundled("tsconfig/JsonOverrideMissing", {
// GENERATED
files: {
"/Users/user/project/src/app/entry.ts": `import 'foo'`,
@@ -754,7 +766,7 @@ describe("bundler", () => {
},
outfile: "/Users/user/project/out.js",
});
- itBundled("tsconfig/TsconfigJsonOverrideNodeModules", {
+ itBundled("tsconfig/JsonOverrideNodeModules", {
// GENERATED
files: {
"/Users/user/project/src/app/entry.ts": `import 'foo'`,
@@ -784,7 +796,7 @@ describe("bundler", () => {
},
outfile: "/Users/user/project/out.js",
});
- itBundled("tsconfig/TsconfigJsonOverrideInvalid", {
+ itBundled("tsconfig/JsonOverrideInvalid", {
// GENERATED
files: {
"/entry.ts": ``,
@@ -792,7 +804,7 @@ describe("bundler", () => {
/* TODO FIX expectedScanLog: `ERROR: Cannot find tsconfig file "this/file/doesn't/exist/tsconfig.json"
`, */
});
- itBundled("tsconfig/TsconfigJsonNodeModulesImplicitFile", {
+ itBundled("tsconfig/JsonNodeModulesImplicitFile", {
// GENERATED
files: {
"/Users/user/project/src/app/entry.tsx": `console.log(<div/>)`,
@@ -811,7 +823,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsconfigJsonInsideNodeModules", {
+ itBundled("tsconfig/JsonInsideNodeModules", {
// GENERATED
files: {
"/Users/user/project/src/app/entry.tsx": `import 'foo'`,
@@ -825,7 +837,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsconfigWarningsInsideNodeModules", {
+ itBundled("tsconfig/WarningsInsideNodeModules", {
// GENERATED
files: {
"/Users/user/project/src/entry.tsx": /* tsx */ `
@@ -840,7 +852,7 @@ describe("bundler", () => {
/* TODO FIX expectedScanLog: `Users/user/project/src/foo/tsconfig.json: WARNING: Cannot find base config file "extends for foo"
`, */
});
- itBundled("tsconfig/TsconfigRemoveUnusedImports", {
+ itBundled("tsconfig/RemoveUnusedImports", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -856,7 +868,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsconfigPreserveUnusedImports", {
+ itBundled("tsconfig/PreserveUnusedImports", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -873,7 +885,7 @@ describe("bundler", () => {
},
outfile: "/Users/user/project/out.js",
});
- itBundled("tsconfig/TsconfigImportsNotUsedAsValuesPreserve", {
+ itBundled("tsconfig/ImportsNotUsedAsValuesPreserve", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -894,7 +906,7 @@ describe("bundler", () => {
outfile: "/Users/user/project/out.js",
mode: "convertformat",
});
- itBundled("tsconfig/TsconfigPreserveValueImports", {
+ itBundled("tsconfig/PreserveValueImports", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -921,7 +933,7 @@ describe("bundler", () => {
outfile: "/Users/user/project/out.js",
mode: "convertformat",
});
- itBundled("tsconfig/TsconfigPreserveValueImportsAndImportsNotUsedAsValuesPreserve", {
+ itBundled("tsconfig/PreserveValueImportsAndImportsNotUsedAsValuesPreserve", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -949,7 +961,7 @@ describe("bundler", () => {
outfile: "/Users/user/project/out.js",
mode: "convertformat",
});
- itBundled("tsconfig/TsconfigTarget", {
+ itBundled("tsconfig/Target", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -1007,7 +1019,7 @@ describe("bundler", () => {
/* TODO FIX expectedScanLog: `Users/user/project/src/es4/tsconfig.json: WARNING: Unrecognized target environment "ES4"
`, */
});
- itBundled("tsconfig/TsconfigTargetError", {
+ itBundled("tsconfig/TargetError", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": `x = 123n`,
@@ -1024,7 +1036,7 @@ describe("bundler", () => {
Users/user/project/src/tsconfig.json: NOTE: The target environment was set to "ES2019" here:
`, */
});
- itBundled("tsconfig/TsconfigTargetIgnored", {
+ itBundled("tsconfig/TargetIgnored", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": `x = 123n`,
@@ -1038,7 +1050,7 @@ describe("bundler", () => {
},
outfile: "/Users/user/project/out.js",
});
- itBundled("tsconfig/TsconfigUseDefineForClassFieldsES2020", {
+ itBundled("tsconfig/UseDefineForClassFieldsES2020", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -1055,7 +1067,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsconfigUseDefineForClassFieldsESNext", {
+ itBundled("tsconfig/UseDefineForClassFieldsESNext", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -1072,7 +1084,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsconfigUnrecognizedTargetWarning", {
+ itBundled("tsconfig/UnrecognizedTargetWarning", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -1099,7 +1111,7 @@ describe("bundler", () => {
/* TODO FIX expectedScanLog: `Users/user/project/src/a/tsconfig.json: WARNING: Unrecognized target environment "es3"
`, */
});
- itBundled("tsconfig/TsconfigTargetWarning", {
+ itBundled("tsconfig/TargetWarning", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": `await 0`,
@@ -1117,7 +1129,7 @@ describe("bundler", () => {
Users/user/project/src/tsconfig.json: NOTE: The target environment was set to "es6" here:
`, */
});
- itBundled("tsconfig/TsconfigOverriddenTargetWarning", {
+ itBundled("tsconfig/OverriddenTargetWarning", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": `await 0`,
@@ -1135,7 +1147,7 @@ describe("bundler", () => {
/* TODO FIX expectedScanLog: `Users/user/project/src/entry.ts: ERROR: Top-level await is not available in the configured target environment (es2020)
`, */
});
- itBundled("tsconfig/TsConfigNoBaseURLExtendsPaths", {
+ itBundled("tsconfig/NoBaseURLExtendsPaths", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -1163,7 +1175,7 @@ describe("bundler", () => {
NOTE: You can mark the path "foo" as external to exclude it from the bundle, which will remove this error.
`, */
});
- itBundled("tsconfig/TsConfigBaseURLExtendsPaths", {
+ itBundled("tsconfig/BaseURLExtendsPaths", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -1190,7 +1202,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsConfigPathsExtendsBaseURL", {
+ itBundled("tsconfig/PathsExtendsBaseURL", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -1217,7 +1229,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsConfigModuleSuffixesInsert", {
+ itBundled("tsconfig/ModuleSuffixesInsert", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -1243,7 +1255,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsConfigModuleSuffixesNoInsert", {
+ itBundled("tsconfig/ModuleSuffixesNoInsert", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -1267,7 +1279,7 @@ describe("bundler", () => {
`,
},
});
- itBundled("tsconfig/TsConfigModuleSuffixesNoEmpty", {
+ itBundled("tsconfig/ModuleSuffixesNoEmpty", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": /* ts */ `
@@ -1287,7 +1299,7 @@ describe("bundler", () => {
/* TODO FIX expectedScanLog: `Users/user/project/src/entry.ts: ERROR: Could not resolve "./bar"
`, */
});
- itBundled("tsconfig/TsConfigWithStatementAlwaysStrictFalse", {
+ itBundled("tsconfig/WithStatementAlwaysStrictFalse", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": `with (x) y`,
@@ -1301,7 +1313,7 @@ describe("bundler", () => {
},
outfile: "/Users/user/project/out.js",
});
- itBundled("tsconfig/TsConfigWithStatementAlwaysStrictTrue", {
+ itBundled("tsconfig/WithStatementAlwaysStrictTrue", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": `with (x) y`,
@@ -1317,7 +1329,7 @@ describe("bundler", () => {
Users/user/project/tsconfig.json: NOTE: TypeScript's "alwaysStrict" setting was enabled here:
`, */
});
- itBundled("tsconfig/TsConfigWithStatementStrictFalse", {
+ itBundled("tsconfig/WithStatementStrictFalse", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": `with (x) y`,
@@ -1331,7 +1343,7 @@ describe("bundler", () => {
},
outfile: "/Users/user/project/out.js",
});
- itBundled("tsconfig/TsConfigWithStatementStrictTrue", {
+ itBundled("tsconfig/WithStatementStrictTrue", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": `with (x) y`,
@@ -1347,7 +1359,7 @@ describe("bundler", () => {
Users/user/project/tsconfig.json: NOTE: TypeScript's "strict" setting was enabled here:
`, */
});
- itBundled("tsconfig/TsConfigWithStatementStrictFalseAlwaysStrictTrue", {
+ itBundled("tsconfig/WithStatementStrictFalseAlwaysStrictTrue", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": `with (x) y`,
@@ -1364,7 +1376,7 @@ describe("bundler", () => {
Users/user/project/tsconfig.json: NOTE: TypeScript's "alwaysStrict" setting was enabled here:
`, */
});
- itBundled("tsconfig/TsConfigWithStatementStrictTrueAlwaysStrictFalse", {
+ itBundled("tsconfig/WithStatementStrictTrueAlwaysStrictFalse", {
// GENERATED
files: {
"/Users/user/project/src/entry.ts": `with (x) y`,
@@ -1379,7 +1391,7 @@ describe("bundler", () => {
},
outfile: "/Users/user/project/out.js",
});
- itBundled("tsconfig/TsConfigAlwaysStrictTrueEmitDirectivePassThrough", {
+ itBundled("tsconfig/AlwaysStrictTrueEmitDirectivePassThrough", {
// GENERATED
files: {
"/Users/user/project/src/implicit.ts": `console.log('this file should start with "use strict"')`,
@@ -1398,7 +1410,7 @@ describe("bundler", () => {
entryPoints: ["/Users/user/project/src/implicit.ts", "/Users/user/project/src/explicit.ts"],
mode: "passthrough",
});
- itBundled("tsconfig/TsConfigAlwaysStrictTrueEmitDirectiveFormat", {
+ itBundled("tsconfig/AlwaysStrictTrueEmitDirectiveFormat", {
// GENERATED
files: {
"/Users/user/project/src/implicit.ts": `console.log('this file should start with "use strict"')`,
@@ -1417,7 +1429,7 @@ describe("bundler", () => {
entryPoints: ["/Users/user/project/src/implicit.ts", "/Users/user/project/src/explicit.ts"],
mode: "convertformat",
});
- itBundled("tsconfig/TsConfigAlwaysStrictTrueEmitDirectiveBundleIIFE", {
+ itBundled("tsconfig/AlwaysStrictTrueEmitDirectiveBundleIIFE", {
// GENERATED
files: {
"/Users/user/project/src/implicit.ts": `console.log('this file should start with "use strict"')`,
@@ -1436,7 +1448,7 @@ describe("bundler", () => {
entryPoints: ["/Users/user/project/src/implicit.ts", "/Users/user/project/src/explicit.ts"],
outdir: "/Users/user/project/out",
});
- itBundled("tsconfig/TsConfigAlwaysStrictTrueEmitDirectiveBundleCJS", {
+ itBundled("tsconfig/AlwaysStrictTrueEmitDirectiveBundleCJS", {
// GENERATED
files: {
"/Users/user/project/src/implicit.ts": `console.log('this file should start with "use strict"')`,
@@ -1455,7 +1467,7 @@ describe("bundler", () => {
entryPoints: ["/Users/user/project/src/implicit.ts", "/Users/user/project/src/explicit.ts"],
outdir: "/Users/user/project/out",
});
- itBundled("tsconfig/TsConfigAlwaysStrictTrueEmitDirectiveBundleESM", {
+ itBundled("tsconfig/AlwaysStrictTrueEmitDirectiveBundleESM", {
// GENERATED
files: {
"/Users/user/project/src/implicit.ts": `console.log('this file should not start with "use strict"')`,
@@ -1474,7 +1486,7 @@ describe("bundler", () => {
entryPoints: ["/Users/user/project/src/implicit.ts", "/Users/user/project/src/explicit.ts"],
outdir: "/Users/user/project/out",
});
- itBundled("tsconfig/TsConfigExtendsDotWithoutSlash", {
+ itBundled("tsconfig/ExtendsDotWithoutSlash", {
// GENERATED
files: {
"/Users/user/project/src/main.ts": `console.log(123n)`,
@@ -1497,7 +1509,7 @@ describe("bundler", () => {
Users/user/project/src/tsconfig.json: NOTE: The target environment was set to "ES6" here:
`, */
});
- itBundled("tsconfig/TsConfigExtendsDotDotWithoutSlash", {
+ itBundled("tsconfig/ExtendsDotDotWithoutSlash", {
// GENERATED
files: {
"/Users/user/project/src/main.ts": `console.log(123n)`,
@@ -1519,7 +1531,7 @@ describe("bundler", () => {
Users/user/project/tsconfig.json: NOTE: The target environment was set to "ES6" here:
`, */
});
- itBundled("tsconfig/TsConfigExtendsDotWithSlash", {
+ itBundled("tsconfig/ExtendsDotWithSlash", {
// GENERATED
files: {
"/Users/user/project/src/main.ts": `console.log(123n)`,
@@ -1541,7 +1553,7 @@ describe("bundler", () => {
/* TODO FIX expectedScanLog: `Users/user/project/src/foo.json: WARNING: Cannot find base config file "./"
`, */
});
- itBundled("tsconfig/TsConfigExtendsDotDotWithSlash", {
+ itBundled("tsconfig/ExtendsDotDotWithSlash", {
// GENERATED
files: {
"/Users/user/project/src/main.ts": `console.log(123n)`,
diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts
index 9d4d0a33a..63f9f8e30 100644
--- a/test/bundler/expectBundled.ts
+++ b/test/bundler/expectBundled.ts
@@ -12,6 +12,8 @@ import type { Expect } from "bun:test";
import { PluginBuilder } from "bun";
import * as esbuild from "esbuild";
+let currentFile: string | undefined;
+
type BunTestExports = typeof import("bun:test");
export function testForFile(file: string): BunTestExports {
if (file.startsWith("file://")) {
@@ -20,7 +22,42 @@ export function testForFile(file: string): BunTestExports {
var testFile = testFiles.get(file);
if (!testFile) {
- testFile = (Bun as any).jest(file);
+ const native = (Bun as any).jest(file);
+ const notImplemented: BundlerTestRef[] = [];
+ testFile = {
+ it: native.it,
+ test: native.test,
+ expect: native.expect,
+ addNotImplemented: (ref: BundlerTestRef) => notImplemented.push(ref),
+ };
+ testFile.describe = function (name: string, fn: () => void) {
+ native.describe(name, function () {
+ if (currentFile) {
+ throw new Error("please don't nest describe blocks in the bundler tests.");
+ }
+ currentFile = file;
+ fn();
+ currentFile = undefined;
+ if (!FILTER && !process.env.BUN_BUNDLER_TEST_NO_CHECK_SKIPPED) {
+ native.test(`"${path.basename(file)}" has proper notImplemented markers`, async () => {
+ console.log(`\n Checking if any of the ${notImplemented.length} not implemented tests work...`);
+ const implemented = [];
+ for (const ref of notImplemented) {
+ try {
+ await expectBundled(ref.id, { ...ref.options, notImplemented: false }, false, true);
+ implemented.push({ id: ref.id, success: true });
+ } catch (e) {}
+ }
+ if (implemented.length) {
+ throw (
+ '"notImplemented" can only be used on failing tests. the following tests pass:\n' +
+ implemented.map(x => " - " + x.id).join("\n")
+ );
+ }
+ });
+ }
+ });
+ };
testFiles.set(file, testFile);
}
return testFile;
@@ -63,8 +100,8 @@ export interface BundlerTestInput {
entryPointsAdvanced?: Array<{ input: string; output?: string }>;
/** These are not path resolved. Used for `default/RelativeEntryPointError` */
entryPointsRaw?: string[];
- /** Defaults to bundle */
- mode?: "bundle" | "transform";
+ /** Defaults to true */
+ bundling?: boolean;
/** Used for `default/ErrorMessageCrashStdinESBuildIssue2913`. */
stdin?: { contents: string; cwd: string };
/** Use when doing something weird with entryPoints and you need to check other output paths. */
@@ -122,7 +159,7 @@ export interface BundlerTestInput {
unsupportedJSFeatures?: string[];
/** if set to true or false, create or edit tsconfig.json to set compilerOptions.useDefineForClassFields */
useDefineForClassFields?: boolean;
- sourceMap?: boolean | "inline" | "external";
+ sourceMap?: "inline" | "external" | "none";
plugins?: BunPlugin[] | ((builder: PluginBuilder) => void | Promise<void>);
// pass subprocess.env
@@ -203,7 +240,7 @@ export interface BundlerTestBundleAPI {
*/
captureFile(file: string, fnName?: string): string[];
- warnings: Record<string, { file: string; error: string; line?: string; col?: string }[]>;
+ warnings: Record<string, ErrorMeta[]>;
options: BundlerTestInput;
}
@@ -240,6 +277,13 @@ export interface BundlerTestRef {
options: BundlerTestInput;
}
+interface ErrorMeta {
+ file: string;
+ error: string;
+ line?: string;
+ col?: string;
+}
+
var testFiles = new Map();
function testRef(id: string, options: BundlerTestInput): BundlerTestRef {
@@ -252,18 +296,18 @@ function expectBundled(
dryRun = false,
ignoreFilter = false,
): Promise<BundlerTestRef> | BundlerTestRef {
- var { expect, it, test } = testForFile(callerSourceOrigin());
+ var { expect, it, test } = testForFile(currentFile ?? callerSourceOrigin());
if (!ignoreFilter && FILTER && !filterMatches(id)) return testRef(id, opts);
let {
- notImplemented,
- bundleWarnings,
- bundleErrors,
- banner,
- backend,
assertNotPresent,
- capture,
assetNaming,
+ backend,
+ banner,
+ bundleErrors,
+ bundleWarnings,
+ bundling,
+ capture,
chunkNaming,
cjs2esm,
dce,
@@ -286,23 +330,23 @@ function expectBundled(
matchesReference,
metafile,
minifyIdentifiers,
- serverComponents = false,
minifySyntax,
minifyWhitespace,
- mode,
+ notImplemented,
onAfterBundle,
outbase,
outdir,
outfile,
outputPaths,
- target,
plugins,
publicPath,
run,
runtimeFiles,
+ serverComponents = false,
skipOnEsbuild,
sourceMap,
splitting,
+ target,
treeShaking,
unsupportedCSSFeatures,
unsupportedJSFeatures,
@@ -327,7 +371,7 @@ function expectBundled(
}
// Resolve defaults for options and some related things
- mode ??= "bundle";
+ bundling ??= true;
target ??= "browser";
format ??= "esm";
entryPoints ??= entryPointsRaw ? [] : [Object.keys(files)[0]];
@@ -337,6 +381,10 @@ function expectBundled(
if (bundleWarnings === true) bundleWarnings = {};
const useOutFile = outfile ? true : outdir ? false : entryPoints.length === 1;
+ if (bundling === false) {
+ // https://github.com/oven-sh/bun/issues/2821
+ external = ["*"];
+ }
if (!ESBUILD && format !== "esm") {
throw new Error("formats besides esm not implemented in bun build");
}
@@ -353,7 +401,7 @@ function expectBundled(
throw new Error("unsupportedCSSFeatures not implemented in bun build");
}
if (!ESBUILD && outbase) {
- throw new Error("outbase not implemented in bun build");
+ throw new Error("outbase/root not implemented in bun build");
}
if (!ESBUILD && keepNames) {
throw new Error("keepNames not implemented in bun build");
@@ -361,9 +409,6 @@ function expectBundled(
if (!ESBUILD && mainFields) {
throw new Error("mainFields not implemented in bun build");
}
- if (!ESBUILD && sourceMap) {
- throw new Error("sourceMap not implemented in bun build");
- }
if (!ESBUILD && banner) {
throw new Error("banner not implemented in bun build");
}
@@ -372,7 +417,7 @@ function expectBundled(
}
if (!ESBUILD && loader) {
const loaderValues = [...new Set(Object.values(loader))];
- const supportedLoaderTypes = ["js", "jsx", "ts", "tsx", "css", "json", "text", "file"];
+ const supportedLoaderTypes = ["js", "jsx", "ts", "tsx", "css", "json", "text", "file", "wtf"];
const unsupportedLoaderTypes = loaderValues.filter(x => !supportedLoaderTypes.includes(x));
if (unsupportedLoaderTypes.length) {
throw new Error(`loader '${unsupportedLoaderTypes.join("', '")}' not implemented in bun build`);
@@ -408,9 +453,6 @@ function expectBundled(
: entryPaths.map(file => path.join(outdir!, path.basename(file)))
).map(x => x.replace(/\.ts$/, ".js"));
- if (mode === "transform" && !outfile && !ESBUILD) {
- throw new Error("transform mode requires one single outfile");
- }
if (cjs2esm && !outfile && !minifySyntax && !minifyWhitespace) {
throw new Error("cjs2esm=true requires one output file, minifyWhitespace=false, and minifySyntax=false");
}
@@ -456,12 +498,15 @@ function expectBundled(
}
// Run bun build cli. In the future we can move to using `Bun.Bundler`
- let warningReference: Record<string, { file: string; error: string; line?: string; col?: string }[]> = {};
+ let warningReference: Record<string, ErrorMeta[]> = {};
+ const expectedErrors = bundleErrors
+ ? Object.entries(bundleErrors).flatMap(([file, v]) => v.map(error => ({ file, error })))
+ : null;
+
if (backend === "cli") {
if (plugins) {
throw new Error("plugins not possible in backend=CLI");
}
-
const cmd = (
!ESBUILD
? [
@@ -470,40 +515,39 @@ function expectBundled(
"build",
...entryPaths,
...(entryPointsRaw ?? []),
- mode === "bundle" ? [outfile ? `--outfile=${outfile}` : `--outdir=${outdir}`] : [],
+ outfile ? `--outfile=${outfile}` : `--outdir=${outdir}`,
define && Object.entries(define).map(([k, v]) => ["--define", `${k}=${v}`]),
`--target=${target}`,
+ // `--format=${format}`,
external && external.map(x => ["--external", x]),
minifyIdentifiers && `--minify-identifiers`,
minifySyntax && `--minify-syntax`,
minifyWhitespace && `--minify-whitespace`,
globalName && `--global-name=${globalName}`,
- // inject && inject.map(x => ["--inject", path.join(root, x)]),
- // jsx.preserve && "--jsx=preserve",
jsx.runtime && ["--jsx-runtime", jsx.runtime],
jsx.factory && ["--jsx-factory", jsx.factory],
jsx.fragment && ["--jsx-fragment", jsx.fragment],
jsx.importSource && ["--jsx-import-source", jsx.importSource],
// metafile && `--manifest=${metafile}`,
- // sourceMap && `--sourcemap${sourceMap !== true ? `=${sourceMap}` : ""}`,
+ sourceMap && `--sourcemap=${sourceMap}`,
entryNaming && entryNaming !== "[name].[ext]" && [`--entry-naming`, entryNaming],
chunkNaming && chunkNaming !== "[name]-[hash].[ext]" && [`--chunk-naming`, chunkNaming],
assetNaming && assetNaming !== "[name]-[hash].[ext]" && [`--asset-naming`, chunkNaming],
- // `--format=${format}`,
- // legalComments && `--legal-comments=${legalComments}`,
splitting && `--splitting`,
serverComponents && "--server-components",
+ outbase && `--outbase=${outbase}`,
+ // inject && inject.map(x => ["--inject", path.join(root, x)]),
+ // jsx.preserve && "--jsx=preserve",
+ // legalComments && `--legal-comments=${legalComments}`,
// treeShaking === false && `--no-tree-shaking`, // ??
- // outbase && `--outbase=${outbase}`,
// keepNames && `--keep-names`,
// mainFields && `--main-fields=${mainFields}`,
loader && Object.entries(loader).map(([k, v]) => ["--loader", `${k}:${v}`]),
publicPath && `--public-path=${publicPath}`,
- mode === "transform" && "--transform",
]
: [
ESBUILD_PATH,
- mode === "bundle" && "--bundle",
+ bundling && "--bundle",
outfile ? `--outfile=${outfile}` : `--outdir=${outdir}`,
`--format=${format}`,
`--platform=${target === "bun" ? "node" : target}`,
@@ -514,7 +558,7 @@ function expectBundled(
external && external.map(x => `--external:${x}`),
inject && inject.map(x => `--inject:${path.join(root, x)}`),
define && Object.entries(define).map(([k, v]) => `--define:${k}=${v}`),
- `--jsx=${jsx.runtime ?? "automatic"}`,
+ `--jsx=${jsx.runtime === "classic" ? "transform" : "automatic"}`,
// jsx.preserve && "--jsx=preserve",
jsx.factory && `--jsx-factory=${jsx.factory}`,
jsx.fragment && `--jsx-fragment=${jsx.fragment}`,
@@ -527,7 +571,7 @@ function expectBundled(
assetNaming !== "[name]-[hash].[ext]" &&
`--asset-names=${assetNaming.replace(/\.\[ext]$/, "")}`,
metafile && `--metafile=${metafile}`,
- sourceMap && `--sourcemap${sourceMap !== true ? `=${sourceMap}` : ""}`,
+ sourceMap && `--sourcemap=${sourceMap}`,
banner && `--banner:js=${banner}`,
legalComments && `--legal-comments=${legalComments}`,
splitting && `--splitting`,
@@ -598,10 +642,6 @@ function expectBundled(
});
// Check for errors
- const expectedErrors = bundleErrors
- ? Object.entries(bundleErrors).flatMap(([file, v]) => v.map(error => ({ file, error })))
- : null;
-
if (!success) {
if (!ESBUILD) {
const errorText = stderr.toString("utf-8");
@@ -689,11 +729,6 @@ function expectBundled(
throw new Error("Errors were expected while bundling:\n" + expectedErrors.map(formatError).join("\n"));
}
- if (mode === "transform" && !ESBUILD) {
- mkdirSync(path.dirname(outfile!), { recursive: true });
- Bun.write(outfile!, stdout);
- }
-
// Check for warnings
if (!ESBUILD) {
const warningRegex = /^warn: (.*?)\n.*?\n\s*\^\s*\n(.*?)\n/gms;
@@ -773,7 +808,7 @@ function expectBundled(
plugins: pluginArray,
treeShaking,
outdir: buildOutDir,
- sourcemap: sourceMap === true ? "external" : sourceMap || "none",
+ sourcemap: sourceMap,
splitting,
target,
publicPath,
@@ -805,11 +840,90 @@ for (const blob of build.outputs) {
const build = await Bun.build(buildConfig);
Bun.gc(true);
- console.log(build);
+ const buildLogs = (build as any).logs;
+
+ if (buildLogs) {
+ const rawErrors = buildLogs instanceof AggregateError ? buildLogs.errors : [buildLogs];
+ const allErrors: ErrorMeta[] = [];
+ for (const error of rawErrors) {
+ const str = error.message ?? String(error);
+ if (str.startsWith("\u001B[2mexpect(") || str.startsWith("expect(")) {
+ throw error;
+ }
+
+ // undocuemnted types
+ const position = error.position as {
+ lineText: string;
+ file: string;
+ namespace: string;
+ line: number;
+ column: number;
+ offset: number;
+ };
+
+ const filename = position?.file
+ ? position.namespace === "file"
+ ? "/" + path.relative(root, position.file)
+ : `${position.namespace}:${position.file.replace(root, "")}`
+ : "<bun>";
+
+ allErrors.push({
+ file: filename,
+ error: str,
+ col: position?.column !== undefined ? String(position.column) : undefined,
+ line: position?.line !== undefined ? String(position.line) : undefined,
+ });
+ }
- if (build.logs) {
- console.log(build.logs);
- throw new Error("TODO: handle build logs, but we should make this api nicer");
+ if (DEBUG && allErrors.length) {
+ console.log("REFERENCE ERRORS OBJECT");
+ console.log("bundleErrors: {");
+ const files: any = {};
+ for (const err of allErrors) {
+ files[err.file] ??= [];
+ files[err.file].push(err);
+ }
+ for (const [file, errs] of Object.entries(files)) {
+ console.log(' "' + file + '": [');
+ for (const err of errs as any) {
+ console.log(" `" + err.error + "`,");
+ }
+ console.log(" ],");
+ }
+ console.log("},");
+ }
+
+ if (expectedErrors) {
+ const errorsLeft = [...expectedErrors];
+ let unexpectedErrors = [];
+
+ for (const error of allErrors) {
+ const i = errorsLeft.findIndex(item => error.file === item.file && error.error.includes(item.error));
+ if (i === -1) {
+ unexpectedErrors.push(error);
+ } else {
+ errorsLeft.splice(i, 1);
+ }
+ }
+
+ if (unexpectedErrors.length) {
+ throw new Error(
+ "Unexpected errors reported while bundling:\n" +
+ [...unexpectedErrors].map(formatError).join("\n") +
+ "\n\nExpected errors:\n" +
+ expectedErrors.map(formatError).join("\n"),
+ );
+ }
+
+ if (errorsLeft.length) {
+ throw new Error("Errors were expected while bundling:\n" + errorsLeft.map(formatError).join("\n"));
+ }
+
+ return testRef(id, opts);
+ }
+ throw new Error("Bundle Failed\n" + [...allErrors].map(formatError).join("\n"));
+ } else if (expectedErrors && expectedErrors.length > 0) {
+ throw new Error("Errors were expected while bundling:\n" + expectedErrors.map(formatError).join("\n"));
}
} else {
await esbuild.build({
@@ -914,7 +1028,7 @@ for (const blob of build.outputs) {
}
if (dce) {
const content = readFileSync(fullpath, "utf8");
- const dceFails = [...content.matchAll(/FAIL|FAILED|DROP|REMOVE/gi)];
+ const dceFails = [...content.replace(/\/\*.*?\*\//g, "").matchAll(/FAIL|FAILED|DROP|REMOVE/gi)];
const key = fullpath.slice(root.length);
if (dceFails.length) {
throw new Error("DCE test did not remove all expected code in " + key + ".");
@@ -1160,7 +1274,7 @@ export function itBundled(
opts._referenceFn = fn;
}
const ref = testRef(id, opts);
- const { it } = testForFile(callerSourceOrigin());
+ const { it, addNotImplemented } = testForFile(currentFile ?? callerSourceOrigin()) as any;
if (FILTER && !filterMatches(id)) {
return ref;
@@ -1173,19 +1287,11 @@ export function itBundled(
}
}
- if (opts.notImplemented) {
+ if (opts.notImplemented && !FILTER) {
if (!HIDE_SKIP) it.skip(id, () => {});
- // commented out because expectBundled was made async and this is no longer possible in a sense.
- // try {
- // expectBundled(id, opts);
- // it(id, () => {
- // throw new Error(
- // `Test ${id} passes but was marked as "notImplemented"\nPlease remove "notImplemented: true" from this test.`,
- // );
- // });
- // } catch (error: any) {}
+ addNotImplemented({ id, options: opts });
} else {
- it(id, () => expectBundled(id, opts));
+ it(id, () => expectBundled(id, opts as any));
}
return ref;
}
@@ -1193,13 +1299,13 @@ itBundled.skip = (id: string, opts: BundlerTestInput) => {
if (FILTER && !filterMatches(id)) {
return testRef(id, opts);
}
- const { it } = testForFile(callerSourceOrigin());
+ const { it } = testForFile(currentFile ?? callerSourceOrigin());
if (!HIDE_SKIP) it.skip(id, () => expectBundled(id, opts));
return testRef(id, opts);
};
-function formatError(err: { file: string; error: string; line?: string; col?: string }) {
- return `${err.file}${err.line ? " :" + err.line : ""}${err.col ? ":" + err.col : ""}: ${err.error}`;
+function formatError(err: ErrorMeta) {
+ return `${err.file}${err.line ? ":" + err.line : ""}${err.col ? ":" + err.col : ""}: ${err.error}`;
}
function filterMatches(id: string) {
diff --git a/test/bundler/report-bundler-test-progress.sh b/test/bundler/report-bundler-test-progress.sh
index 7c0266c59..52358a7f3 100644
--- a/test/bundler/report-bundler-test-progress.sh
+++ b/test/bundler/report-bundler-test-progress.sh
@@ -12,7 +12,7 @@ total_skip=0
for test in $tests; do
defined=$(grep "^import" $test -v | grep -v expectBundled.md | grep -Ec "expectBundled|itBundled")
- output=$(BUN_BUNDLER_TEST_LOOSE=false bun test $test 2>&1 | tail -n 5)
+ output=$(BUN_BUNDLER_TEST_LOOSE=false BUN_BUNDLER_TEST_NO_CHECK_SKIPPED=true bun test $test 2>&1 | tail -n 5)
pass=$(echo "$output" | grep "pass" | cut -d " " -f 2)
fail=$(echo "$output" | grep "fail" | cut -d " " -f 2)
skip=$(echo "$output" | grep "skip" | cut -d " " -f 2)