diff --git a/test/bundler/bundler_edgecase.test.ts b/test/bundler/bundler_edgecase.test.ts index d7b9942009a43..cd4b57bc87ce7 100644 --- a/test/bundler/bundler_edgecase.test.ts +++ b/test/bundler/bundler_edgecase.test.ts @@ -168,4 +168,64 @@ describe("bundler", () => { ARBITRARY: "secret environment stuff!", }, }); + itBundled("edgecase/StarExternal", { + files: { + "/entry.js": /* js */ ` + import { foo } from './foo'; + import { bar } from './bar'; + console.log(foo); + `, + }, + external: ["*"], + }); + itBundled("edgecase/ImportNamespaceAndDefault", { + files: { + "/entry.js": /* js */ ` + import def2, * as ns2 from './c' + console.log(def2, JSON.stringify(ns2)) + `, + }, + external: ["*"], + runtimeFiles: { + "/c.js": /* js */ ` + export default 1 + export const ns = 2 + export const def2 = 3 + `, + }, + run: { + stdout: '1 {"def2":3,"default":1,"ns":2}', + }, + }); + itBundled("edgecase/ExternalES6ConvertedToCommonJSSimplified", { + files: { + "/entry.js": /* js */ ` + console.log(JSON.stringify(require('./e'))); + `, + "/e.js": `export * from 'x'`, + }, + external: ["x"], + runtimeFiles: { + "/node_modules/x/index.js": /* js */ ` + export const ns = 123 + export const ns2 = 456 + `, + }, + run: { + stdout: ` + {"ns":123,"ns2":456} + `, + }, + }); + itBundled("edgecase/ImportTrailingSlash", { + files: { + "/entry.js": /* js */ ` + import "slash/" + `, + "/node_modules/slash/index.js": /* js */ `console.log(1)`, + }, + run: { + stdout: "1", + }, + }); }); diff --git a/test/bundler/bundler_plugin.test.ts b/test/bundler/bundler_plugin.test.ts index 69bd221ef5552..bde2f180c5e9b 100644 --- a/test/bundler/bundler_plugin.test.ts +++ b/test/bundler/bundler_plugin.test.ts @@ -390,4 +390,41 @@ describe("bundler", () => { }, }; }); + itBundled("plugin/ManyFiles", ({ root }) => { + const FILES = 200; + const create = (fn: (i: number) => string) => new Array(FILES).fill(0).map((_, i) => fn(i)); + + let onResolveCount = 0; + let importers: string[] = []; + return { + files: { + "index.ts": /* ts */ ` + ${create(i => `import * as foo${i} from "./${i}.magic";`).join("\n")} + ${create(i => `console.log(foo${i}.foo);`).join("\n")} + `, + }, + plugins(builder) { + builder.onResolve({ filter: /\.magic$/ }, async args => { + importers.push(args.importer); + onResolveCount++; + return { + path: args.path, + namespace: "magic", + }; + }); + builder.onLoad({ filter: /\.magic$/, namespace: "magic" }, async args => { + return { + contents: `export const foo = "${args.path}";`, + loader: "js", + }; + }); + }, + run: { + stdout: create(i => `./${i}.magic`).join("\n"), + }, + onAfterBundle(api) {}, + }; + }); }); + +// TODO: add async on resolve stuff diff --git a/test/bundler/esbuild/dce.test.ts b/test/bundler/esbuild/dce.test.ts index 9d4a0c27d6ac8..de68742c6c63d 100644 --- a/test/bundler/esbuild/dce.test.ts +++ b/test/bundler/esbuild/dce.test.ts @@ -1,6 +1,6 @@ import assert from "assert"; import dedent from "dedent"; -import { itBundled, testForFile } from "../expectBundled"; +import { ESBUILD, itBundled, testForFile } from "../expectBundled"; var { describe, test, expect } = testForFile(import.meta.path); // Tests ported from: @@ -88,7 +88,7 @@ describe("bundler", () => { `, }, run: { - stdout: 'hello\n{"default":{"foo":123},"foo":123}', + stdout: 'hello\n{"foo":123}', }, }); itBundled("dce/PackageJsonSideEffectsTrueKeepES6", { @@ -704,7 +704,6 @@ describe("bundler", () => { }, }); itBundled("dce/PackageJsonSideEffectsFalseIntermediateFilesChainAll", { - // GENERATED files: { "/Users/user/project/src/entry.js": /* js */ ` import {foo} from "a" @@ -1038,35 +1037,6 @@ describe("bundler", () => { stdout: `["F",{"children":[null,{"children":["div",{}]}]}]`, }, }); - // TODO: Unsure how to port this: https://github.com/evanw/esbuild/blob/main/internal/bundler_tests/bundler_dce_test.go#L1249 - itBundled("dce/DisableTreeShaking", { - notImplemented: true, - // GENERATED - files: { - "/entry.jsx": /* jsx */ ` - import './remove-me' - function RemoveMe1() {} - let removeMe2 = 0 - class RemoveMe3 {} - - import './keep-me' - function KeepMe1() {} - let keepMe2 = - function keepMe3() { console.log('side effects') } - let keepMe4 = /* @__PURE__ */ keepMe3() - let keepMe5 = pure() - let keepMe6 = some.fn() - `, - "/remove-me.js": `export default 'unused'`, - "/keep-me/index.js": `console.log('side effects')`, - "/keep-me/package.json": `{ "sideEffects": false }`, - }, - ignoreDCEAnnotations: true, - define: { - pure: "???", - "some.fn": "???", - }, - }); itBundled("dce/DeadCodeFollowingJump", { notImplemented: true, files: { @@ -1308,6 +1278,7 @@ describe("bundler", () => { dce: true, }); itBundled("dce/TreeShakingClassStaticProperty", { + notImplemented: true, files: { "/entry.js": /* js */ ` let remove1 = class { static x } @@ -1421,6 +1392,7 @@ describe("bundler", () => { format: "iife", }); itBundled("dce/TreeShakingNoBundleESM", { + notImplemented: true, files: { "/entry.js": /* js */ ` function keep() {} @@ -1434,7 +1406,6 @@ describe("bundler", () => { dce: true, }); itBundled("dce/TreeShakingNoBundleCJS", { - // GENERATED files: { "/entry.js": /* js */ ` function keep() {} @@ -1442,12 +1413,12 @@ describe("bundler", () => { keep() `, }, + dce: true, format: "cjs", treeShaking: true, mode: "transform", }); itBundled("dce/TreeShakingNoBundleIIFE", { - // GENERATED files: { "/entry.js": /* js */ ` function keep() {} @@ -1455,6 +1426,7 @@ describe("bundler", () => { keep() `, }, + dce: true, format: "iife", treeShaking: true, mode: "transform", @@ -1483,7 +1455,6 @@ describe("bundler", () => { }, }); itBundled("dce/DCETypeOf", { - // GENERATED files: { "/entry.js": /* js */ ` // These should be removed because they have no side effects @@ -1690,6 +1661,7 @@ describe("bundler", () => { dce: true, }); itBundled("dce/RemoveUnusedImports", { + notImplemented: true, files: { "/entry.js": /* js */ ` import REMOVE1 from 'a' @@ -1698,8 +1670,8 @@ describe("bundler", () => { `, }, minifySyntax: true, - mode: "transform", dce: true, + external: ["a", "b", "c"], onAfterBundle(api) { api.expectFile("/out.js").toBe( dedent` @@ -1721,6 +1693,7 @@ describe("bundler", () => { }, minifySyntax: true, mode: "transform", + external: ["a", "b", "c"], dce: true, }); itBundled("dce/RemoveUnusedImportsEvalTS", { @@ -2157,6 +2130,7 @@ describe("bundler", () => { }, }); itBundled("dce/InlineFunctionCallBehaviorChanges", { + notImplemented: true, files: { // At the time of writing, using a template string here triggered a bug in bun's transpiler // making it impossible to run the test. @@ -2238,6 +2212,7 @@ describe("bundler", () => { dce: true, }); itBundled("dce/ConstValueInliningNoBundle", { + notImplemented: true, files: { "/top-level.js": /* js */ ` // These should be kept because they are top-level and tree shaking is not enabled @@ -2290,6 +2265,7 @@ describe("bundler", () => { s_keep, s_keep, ) } + console.log(nested()) `, "/namespace-export.ts": /* ts */ ` namespace ns { @@ -2343,10 +2319,12 @@ describe("bundler", () => { function foo() { return y_REMOVE } + console.log(foo) } + console.log(nested()); `, "/disabled-tdz.js": /* js */ ` - foo() + console.log(foo()) const x_keep = 1 function foo() { return x_keep @@ -2369,6 +2347,7 @@ describe("bundler", () => { y, y, ) } + console.log(foo()) `, }, entryPoints: [ @@ -2386,11 +2365,11 @@ describe("bundler", () => { "/backwards-reference-top-level.js", "/backwards-reference-nested-function.js", ], - mode: "transform", minifySyntax: true, dce: true, dceKeepMarkerCount: { - "/out/top-level.js": 7, + "/out/top-level.js": 5, + "/out/nested-function.js": 3, "/out/namespace-export.js": 1, }, }); @@ -2539,6 +2518,7 @@ describe("bundler", () => { }, }); itBundled("dce/ConstValueInliningDirectEval", { + notImplemented: true, files: { "/top-level-no-eval.js": /* js */ ` const keep = 1 @@ -2873,7 +2853,6 @@ describe("bundler", () => { }, }); itBundled("dce/NestedFunctionInliningWithSpread", { - // GENERATED files: { "/entry.js": /* js */ ` function empty1() {} diff --git a/test/bundler/esbuild/default.test.ts b/test/bundler/esbuild/default.test.ts index e178637aaa972..83822411fce5c 100644 --- a/test/bundler/esbuild/default.test.ts +++ b/test/bundler/esbuild/default.test.ts @@ -232,7 +232,8 @@ describe("bundler", () => { "/e.js": "export default class Foo {}", }, entryPoints: ["/a.js", "/b.js", "/c.js", "/d.js", "/e.js"], - mode: "transform", + mode: "bundle", + external: ["*"], runtimeFiles: { "./out/f.js": /* js */ ` export const f = 987; @@ -312,15 +313,15 @@ describe("bundler", () => { run: { file: "/test.js", }, - external: ["node:assert", "./a", "./b", "./c"], + external: ["*"], } as const; itBundled("default/ImportFormsWithNoBundle", { ...importFormsConfig, - }); + } as any); itBundled("default/ImportFormsWithMinifyIdentifiersAndNoBundle", { ...importFormsConfig, minifyIdentifiers: true, - }); + } as any); itBundled("default/ExportFormsCommonJS", { files: { "/entry.js": /* js */ ` @@ -1063,6 +1064,7 @@ describe("bundler", () => { "/entry.js": /* js */ ` try { const supportsColor = require('not-supports-color'); // bun overrides supports-color + exports.colors = false; if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) { exports.colors = []; } @@ -1080,7 +1082,7 @@ describe("bundler", () => { "/test2.js": /* js */ ` globalThis.requireThrows = true; import assert from 'assert'; - assert.deepEqual((await import('./out')).default, { }) + assert.deepEqual((await import('./out')).default, { colors: 'it threw' }) `, "/node_modules/not-supports-color/index.js": /* js */ ` if (requireThrows) { @@ -1420,10 +1422,10 @@ describe("bundler", () => { "/test.js": /* js */ ` import fs from "fs"; import assert from "assert"; - import module from './out.js'; - assert(module.fs === fs, 'exports.fs') - assert(module.readFileSync === fs.readFileSync, 'exports.readFileSync') - assert(module.foo === 123, 'exports.foo') + import * as mod from './out.js'; + assert(mod.fs === fs, 'exports.fs') + assert(mod.readFileSync === fs.readFileSync, 'exports.readFileSync') + assert(mod.foo === 123, 'exports.foo') `, }, platform: "node", @@ -1541,16 +1543,33 @@ describe("bundler", () => { }, }); itBundled("default/TopLevelReturnForbiddenImport", { + notImplemented: true, files: { "/entry.js": /* js */ ` + console.log('A'); return + console.log('B'); import 'foo' `, }, - mode: "transform", - bundleErrors: { - "/entry.js": ["Top-level return cannot be used inside an ECMAScript module"], + external: ["foo"], + runtimeFiles: { + "/node_modules/foo/index.js": "console.log('C')", + }, + run: { + stdout: "C\nA", + }, + }); + itBundled("default/TopLevelReturnForbiddenImportAndModuleExports", { + notImplemented: true, + files: { + "/entry.js": /* js */ ` + module.exports.foo = 123 + return + import 'foo' + `, }, + external: ["foo"], }); itBundled("default/TopLevelReturnForbiddenExport", { files: { @@ -1947,7 +1966,7 @@ describe("bundler", () => { })(1,3,5); `, }, - format: "esm", + format: "iife", outfile: "/out.js", minifyIdentifiers: true, // mode: "transform", @@ -2204,6 +2223,7 @@ describe("bundler", () => { }, }); itBundled("default/ImportWithQueryParameter", { + notImplemented: true, files: { "/entry.js": /* js */ ` // Each of these should have a separate identity (i.e. end up in the output file twice) @@ -2290,7 +2310,7 @@ describe("bundler", () => { }, }); itBundled("default/AutoExternalNode", { - skipOnEsbuild: true, + notImplemented: true, files: { "/entry.js": /* js */ ` // These URLs should be external automatically @@ -2299,7 +2319,36 @@ describe("bundler", () => { // This should be external and should be tree-shaken because it's side-effect free import "node:path"; - import "bun"; + import "querystring"; + + // This should be external too, but shouldn't be tree-shaken because it could be a run-time error + import "node:what-is-this"; + `, + }, + platform: "node", + treeShaking: true, + onAfterBundle(api) { + const file = api.readFile("/out.js"); + const imports = new Bun.Transpiler().scanImports(file); + expect(imports).toStrictEqual([ + { kind: "import-statement", path: "node:fs/promises" }, + { kind: "import-statement", path: "node:what-is-this" }, + ]); + }, + }); + itBundled("default/AutoExternalBun", { + skipOnEsbuild: true, + notImplemented: true, + files: { + "/entry.js": /* js */ ` + // These URLs should be external automatically + import fs from "node:fs/promises"; + fs.readFile(); + import { CryptoHasher } from "bun"; + new CryptoHasher(); + + // This should be external and should be tree-shaken because it's side-effect free + import "node:path"; import "bun:sqlite"; // This should be external too, but shouldn't be tree-shaken because it could be a run-time error @@ -2307,13 +2356,15 @@ describe("bundler", () => { import "bun:what-is-this"; `, }, - platform: "node", + platform: "bun", onAfterBundle(api) { const file = api.readFile("/out.js"); const imports = new Bun.Transpiler().scanImports(file); expect(imports).toStrictEqual([ + // bun is transformed in destructuring the bun global { kind: "import-statement", path: "node:fs/promises" }, { kind: "import-statement", path: "node:what-is-this" }, + { kind: "import-statement", path: "bun:what-is-this" }, ]); }, }); @@ -2457,17 +2508,20 @@ describe("bundler", () => { }}}}}}}}}}}}}}}}}}}}}}}}}}} `; itBundled("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, }, @@ -2477,6 +2531,7 @@ describe("bundler", () => { mode: "transform", }); itBundled("default/MinifyNestedLabelsBundle", { + notImplemented: true, files: { "/entry.js": crazyNestedLabelFile, }, @@ -2618,14 +2673,15 @@ describe("bundler", () => { stdout: "123", }, }); - itBundled("default/RelativeEntryPointError", { + itBundled("default/RelativeFilepathEntryPoint", { files: { "/entry.js": `console.log(123)`, }, - entryPointsRaw: ["entry"], + entryPointsRaw: ["entry.js"], outfile: "/out.js", - bundleErrors: { - "": [`ModuleNotFound resolving "entry". Did you mean: "./entry"`], + run: { + file: "/out.js", + stdout: "123", }, }); itBundled("default/MultipleEntryPointsSameNameCollision", { @@ -2750,7 +2806,7 @@ describe("bundler", () => { file: "/test.js", stdout: "foo bar", }, - mode: "transform", + external: ["*"], }); itBundled("default/ImportMetaCommonJS", { files: { @@ -3452,6 +3508,7 @@ describe("bundler", () => { mode: "transform", }); itBundled("default/TopLevelAwaitForbiddenRequire", { + notImplemented: true, files: { "/entry.js": /* js */ ` require('./a') @@ -3585,6 +3642,7 @@ describe("bundler", () => { }, }); itBundled("default/AssignToImportNoBundle", { + notImplemented: true, files: { "/bad0.js": `import x from "foo"; x = 1`, "/bad1.js": `import x from "foo"; x++`, @@ -4486,6 +4544,7 @@ describe("bundler", () => { }, }); itBundled("default/CharFreqIgnoreComments", { + notImplemented: true, files: { "/a.js": /* js */ ` export default function(one, two, three, four) { @@ -4689,7 +4748,6 @@ describe("bundler", () => { // mode: "transform", // external: ["a", "b", "c", "react/jsx-dev-runtime"], // }); - if (!RUN_UNCHECKED_TESTS) return; // I cant get bun to use `this` as the JSX runtime. It's a pretty silly idea anyways. // itBundled("default/JSXThisValueCommonJS", { // files: { @@ -4928,13 +4986,13 @@ describe("bundler", () => { // `, */ // }); 0; - itBundled("default/BundlingFilesOutsideOfOutbase", { - // GENERATED + notImplemented: true, files: { "/src/entry.js": `console.log('test')`, }, splitting: true, + outdir: "/out", format: "esm", outbase: "/some/nested/directory", }); @@ -5009,17 +5067,14 @@ describe("bundler", () => { const relocateEntries = ["/top-level.js", "/nested.js", "/let.js", "/function.js", "/function-nested.js"]; itBundled("default/VarRelocatingBundle", { - // GENERATED files: relocateFiles, entryPoints: relocateEntries, format: "esm", }); itBundled("default/VarRelocatingNoBundle", { - // GENERATED files: relocateFiles, entryPoints: relocateEntries, format: "esm", - mode: "convertformat", }); itBundled("default/ImportNamespaceThisValue", { // GENERATED @@ -5038,11 +5093,12 @@ describe("bundler", () => { console.log(new def(), new foo()) `, }, + external: ["external"], entryPoints: ["/a.js", "/b.js", "/c.js"], format: "cjs", }); + // esbuild and bun do not give the warning. this is still set to undefined itBundled("default/ThisUndefinedWarningESM", { - // GENERATED files: { "/entry.js": /* js */ ` import x from './file1.js' @@ -5052,35 +5108,42 @@ describe("bundler", () => { "/file1.js": `export default [this, this]`, "/node_modules/pkg/file2.js": `export default [this, this]`, }, - /* TODO FIX expectedScanLog: `file1.js: DEBUG: Top-level "this" will be replaced with undefined since this file is an ECMAScript module - file1.js: NOTE: This file is considered to be an ECMAScript module because of the "export" keyword here: - node_modules/pkg/file2.js: DEBUG: Top-level "this" will be replaced with undefined since this file is an ECMAScript module - node_modules/pkg/file2.js: NOTE: This file is considered to be an ECMAScript module because of the "export" keyword here: - `, */ + run: { + stdout: "[ null, null ] [ null, null ]", + }, }); itBundled("default/QuotedProperty", { - // GENERATED + notImplemented: true, files: { "/entry.js": /* js */ ` import * as ns from 'ext' console.log(ns.mustBeUnquoted, ns['mustBeQuoted']) `, }, - format: "cjs", + external: ["ext"], + onAfterBundle(api) { + const code = api.readFile("/out.js"); + expect(code).not.toContain(`"mustBeUnquoted"`); + expect(code).toContain(`"mustBeQuoted"`); + }, }); itBundled("default/QuotedPropertyMangle", { - // GENERATED files: { "/entry.js": /* js */ ` import * as ns from 'ext' console.log(ns.mustBeUnquoted, ns['mustBeUnquoted2']) `, }, - format: "cjs", minifySyntax: true, + external: ["ext"], + onAfterBundle(api) { + const code = api.readFile("/out.js"); + expect(code).toContain(`.mustBeUnquoted`); + expect(code).toContain(`.mustBeUnquoted2`); + }, }); itBundled("default/DuplicatePropertyWarning", { - // GENERATED + notImplemented: true, files: { "/entry.js": /* js */ ` import './outside-node-modules' @@ -5091,19 +5154,17 @@ describe("bundler", () => { "/node_modules/inside-node-modules/index.jsx": `console.log({ c: 1, c: 2 },
)`, "/node_modules/inside-node-modules/package.json": `{ "d": 1, "d": 2 }`, }, - /* TODO FIX expectedScanLog: `outside-node-modules/index.jsx: WARNING: Duplicate key "a" in object literal - outside-node-modules/index.jsx: NOTE: The original key "a" is here: - outside-node-modules/index.jsx: WARNING: Duplicate "a2" attribute in JSX element - outside-node-modules/index.jsx: NOTE: The original "a2" attribute is here: - outside-node-modules/package.json: WARNING: Duplicate key "b" in object literal - outside-node-modules/package.json: NOTE: The original key "b" is here: - `, */ + external: ["react"], + bundleWarnings: { + "/outside-node-modules/index.jsx": ['Duplicate key "a" in object literal', 'Duplicate key "a2" in JSX element'], + "/outside-node-modules/package.json": ['Duplicate key "b" in object literal'], + }, }); - itBundled("default/RequireShimSubstitution", { - // GENERATED + const RequireShimSubstitutionBrowser = itBundled("default/RequireShimSubstitutionBrowser", { + notImplemented: true, files: { "/entry.js": /* js */ ` - console.log([ + Promise.all([ require, typeof require, require('./example.json'), @@ -5116,14 +5177,84 @@ describe("bundler", () => { require.resolve(window.SOME_PATH), import('some-path'), import(window.SOME_PATH), - ]) + ]).then(results => { + for (let result of results) { + if (typeof result === 'string' && result.startsWith(dirname)) { + result = result.slice(dirname.length) + } + console.log(typeof result, JSON.stringify(result)) + } + }) `, "/example.json": `{ "works": true }`, }, - external: ["some-path"], + runtimeFiles: { + "/test.mjs": ` + import { createRequire } from "module"; + const require = createRequire(import.meta.url); + import { fileURLToPath } from "url"; + import { dirname } from "path"; + globalThis.dirname = dirname(fileURLToPath(import.meta.url)); + globalThis.window = globalThis + window.SOME_PATH = 'second-path' + window.require = require + window.module = { require: (x) => 'dynamic req: ' + x } + await import('./out.mjs') + `, + "/node_modules/some-path/index.js": `module.exports = 123`, + "/node_modules/second-path/index.js": `module.exports = 567`, + }, + external: ["*"], + platform: "browser", + format: "esm", + outfile: "/out.mjs", + run: { + runtime: "node", + file: "/test.mjs", + stdout: ` + function undefined + string "function" + object {"works":true} + object {"works":true} + number 567 + object {"works":true} + object {"works":true} + number 567 + string "/node_modules/some-path/index.js" + string "/node_modules/second-path/index.js" + object {"default":123} + object {"default":567} + `, + }, + }); + itBundled("default/RequireShimSubstitutionNode", { + notImplemented: true, + files: RequireShimSubstitutionBrowser.options.files, + runtimeFiles: RequireShimSubstitutionBrowser.options.runtimeFiles, + external: ["*"], + platform: "node", + format: "esm", + outfile: "/out.mjs", + run: { + runtime: "node", + file: "/test.mjs", + stdout: ` + function undefined + string "function" + object {"works":true} + object {"works":true} + number 567 + object {"works":true} + object {"works":true} + number 567 + string "/node_modules/some-path/index.js" + string "/node_modules/second-path/index.js" + object {"default":123} + object {"default":567} + `, + }, }); itBundled("default/StrictModeNestedFnDeclKeepNamesVariableInliningESBuildIssue1552", { - // GENERATED files: { "/entry.js": /* js */ ` export function outer() { @@ -5139,10 +5270,11 @@ describe("bundler", () => { `, }, keepNames: true, - mode: "passthrough", + minifySyntax: true, }); itBundled("default/BuiltInNodeModulePrecedence", { // GENERATED + notImplemented: true, files: { "/entry.js": /* js */ ` console.log([ @@ -5161,7 +5293,6 @@ describe("bundler", () => { "/node_modules/fs/promises.js": `throw 'DO NOT INCLUDE THIS'`, }, platform: "node", - format: "cjs", }); itBundled("default/EntryNamesNoSlashAfterDir", { // GENERATED @@ -5170,59 +5301,60 @@ describe("bundler", () => { "/src/app2/main.ts": `console.log(2)`, "/src/app3/main.ts": `console.log(3)`, }, - entryPointsAdvanced: [ - { input: "/src/app1/main.ts" }, - { input: "/src/app2/main.ts" }, - { input: "/src/app3/main.ts", output: "customPath" }, - ], + entryPoints: ["/src/app1/main.ts", "/src/app2/main.ts", "/src/app3/main.ts"], + outputPaths: ["/out/app1-main.js", "/out/app2-main.js", "/out/app3-main.js"], entryNames: "[dir]-[name].[ext]", - mode: "passthrough", - }); - itBundled("default/EntryNamesNonPortableCharacter", { - // GENERATED - // TODO: I think this is impossible with the CLI. and also very unsafe with paths. - files: { - "/entry1-*.ts": `console.log(1)`, - "/entry2-*.ts": `console.log(2)`, - }, - entryPointsAdvanced: [ - // The "*" should turn into "_" for cross-platform Windows portability - { input: "/entry1-*.ts" }, - // The "*" should be preserved since the user _really_ wants it - { input: "/entry2-*.ts", output: "entry2-*" }, - ], - mode: "passthrough", - }); - itBundled("default/EntryNamesChunkNamesExtPlaceholder", { - // GENERATED - files: { - "/src/entries/entry1.js": `import "../lib/shared.js"; import "./entry1.css"; console.log('entry1')`, - "/src/entries/entry2.js": `import "../lib/shared.js"; import "./entry2.css"; console.log('entry2')`, - "/src/entries/entry1.css": `a:after { content: "entry1" }`, - "/src/entries/entry2.css": `a:after { content: "entry2" }`, - "/src/lib/shared.js": `console.log('shared')`, - }, - entryPoints: ["/src/entries/entry1.js", "/src/entries/entry2.js"], - outbase: "/src", - splitting: true, - entryNames: "main/[ext]/[name]-[hash].[ext]", }); + // itBundled("default/EntryNamesNonPortableCharacter", { + // // GENERATED + // // TODO: I think this is impossible with the CLI. and also very unsafe with paths. + // files: { + // "/entry1-*.ts": `console.log(1)`, + // "/entry2-*.ts": `console.log(2)`, + // }, + // entryPointsAdvanced: [ + // // The "*" should turn into "_" for cross-platform Windows portability + // { input: "/entry1-*.ts" }, + // // The "*" should be preserved since the user _really_ wants it + // { input: "/entry2-*.ts", output: "entry2-*" }, + // ], + // mode: "passthrough", + // }); + // itBundled("default/EntryNamesChunkNamesExtPlaceholder", { + // files: { + // "/src/entries/entry1.js": `import "../lib/shared.js"; import "./entry1.css"; console.log('entry1')`, + // "/src/entries/entry2.js": `import "../lib/shared.js"; import "./entry2.css"; console.log('entry2')`, + // "/src/entries/entry1.css": `a:after { content: "entry1" }`, + // "/src/entries/entry2.css": `a:after { content: "entry2" }`, + // "/src/lib/shared.js": `console.log('shared')`, + // }, + // entryPoints: ["/src/entries/entry1.js", "/src/entries/entry2.js"], + // outbase: "/src", + // splitting: true, + // entryNames: "main/[ext]/[name]-[hash].[ext]", + // }); itBundled("default/MinifyIdentifiersImportPathFrequencyAnalysis", { - // GENERATED files: { "/import.js": /* js */ ` import foo from "./WWWWWWWWWWXXXXXXXXXXYYYYYYYYYYZZZZZZZZZZ" - console.log(foo, 'no identifier in this file should be named W, X, Y, or Z') + console.log(foo, remove('no identifier in this file should be named W, X, Y, or Z')) `, "/WWWWWWWWWWXXXXXXXXXXYYYYYYYYYYZZZZZZZZZZ.js": `export default 123`, "/require.js": /* js */ ` const foo = require("./AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDD") - console.log(foo, 'no identifier in this file should be named A, B, C, or D') + console.log(foo, remove('no identifier in this file should be named A, B, C, or D')) `, "/AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDD.js": `module.exports = 123`, }, entryPoints: ["/import.js", "/require.js"], minifyWhitespace: true, + minifyIdentifiers: true, + onAfterBundle(api) { + let importFile = api.readFile("/out/import.js").replace(/remove\(.*?\)/g, "remove()"); + let requireFile = api.readFile("/out/require.js").replace(/remove\(.*?\)/g, "remove()"); + assert(!["W", "X", "Y", "Z"].some(x => importFile.includes(x))); + assert(!["A", "B", "C", "D"].some(x => requireFile.includes(x))); + }, }); itBundled("default/ToESMWrapperOmission", { // GENERATED @@ -5260,67 +5392,19 @@ describe("bundler", () => { `, }, format: "cjs", - mode: "convertformat", + external: ["*"], }); itBundled("default/NamedFunctionExpressionArgumentCollision", { - // GENERATED files: { "/entry.js": /* js */ ` let x = function foo(foo) { var foo; return foo; } + console.log(x(123)) `, }, - mode: "passthrough", - }); - itBundled("default/NoWarnCommonJSExportsInESMPassThrough", { - // GENERATED - files: { - "/cjs-in-esm.js": /* js */ ` - export let foo = 1 - exports.foo = 2 - module.exports = 3 - `, - "/import-in-cjs.js": /* js */ ` - import { foo } from 'bar' - exports.foo = foo - module.exports = foo - `, - "/no-warnings-here.js": `console.log(module, exports)`, - }, - entryPoints: ["/cjs-in-esm.js", "/import-in-cjs.js", "/no-warnings-here.js"], - mode: "passthrough", - }); - itBundled("default/WarnCommonJSExportsInESMConvert", { - // GENERATED - files: { - "/cjs-in-esm.js": /* js */ ` - export let foo = 1 - exports.foo = 2 - module.exports = 3 - `, - "/cjs-in-esm2.js": /* js */ ` - export let foo = 1 - module.exports.bar = 3 - `, - "/import-in-cjs.js": /* js */ ` - import { foo } from 'bar' - exports.foo = foo - module.exports = foo - module.exports.bar = foo - `, - "/no-warnings-here.js": `console.log(module, exports)`, - }, - entryPoints: ["/cjs-in-esm.js", "/cjs-in-esm2.js", "/import-in-cjs.js", "/no-warnings-here.js"], - mode: "convertformat", - /* TODO FIX expectedScanLog: `cjs-in-esm.js: WARNING: The CommonJS "exports" variable is treated as a global variable in an ECMAScript module and may not work as expected - cjs-in-esm.js: NOTE: This file is considered to be an ECMAScript module because of the "export" keyword here: - cjs-in-esm.js: WARNING: The CommonJS "module" variable is treated as a global variable in an ECMAScript module and may not work as expected - cjs-in-esm.js: NOTE: This file is considered to be an ECMAScript module because of the "export" keyword here: - cjs-in-esm2.js: WARNING: The CommonJS "module" variable is treated as a global variable in an ECMAScript module and may not work as expected - cjs-in-esm2.js: NOTE: This file is considered to be an ECMAScript module because of the "export" keyword here: - `, */ + minifySyntax: true, }); itBundled("default/WarnCommonJSExportsInESMBundle", { // GENERATED @@ -5344,6 +5428,7 @@ describe("bundler", () => { cjs-in-esm.js: WARNING: The CommonJS "module" variable is treated as a global variable in an ECMAScript module and may not work as expected cjs-in-esm.js: NOTE: This file is considered to be an ECMAScript module because of the "export" keyword here: `, */ + external: ["bar"], }); itBundled("default/MangleProps", { // GENERATED @@ -5389,7 +5474,8 @@ describe("bundler", () => { `, }, entryPoints: ["/entry1.js", "/entry2.js"], - mode: "passthrough", + external: ["*"], + mangleProps: /_$/, }); itBundled("default/ManglePropsMinify", { // GENERATED @@ -5437,7 +5523,7 @@ describe("bundler", () => { entryPoints: ["/entry1.js", "/entry2.js"], mangleProps: /_$/, minifyIdentifiers: true, - mode: "passthrough", + external: ["*"], }); itBundled("default/ManglePropsKeywordPropertyMinify", { // GENERATED @@ -5451,7 +5537,7 @@ describe("bundler", () => { mangleProps: /./, minifyIdentifiers: true, minifySyntax: true, - mode: "passthrough", + external: ["*"], }); itBundled("default/ManglePropsOptionalChain", { // GENERATED @@ -5469,7 +5555,8 @@ describe("bundler", () => { } `, }, - mode: "passthrough", + mangleProps: /_$/, + external: ["*"], }); itBundled("default/ManglePropsLoweredOptionalChain", { // GENERATED @@ -5488,7 +5575,7 @@ describe("bundler", () => { `, }, mangleProps: /_$/, - mode: "passthrough", + external: ["*"], }); itBundled("default/ReserveProps", { // GENERATED @@ -5501,7 +5588,7 @@ describe("bundler", () => { `, }, mangleProps: /_$/, - mode: "passthrough", + external: ["*"], }); itBundled("default/ManglePropsImportExport", { // GENERATED @@ -5516,7 +5603,8 @@ describe("bundler", () => { `, }, entryPoints: ["/esm.js", "/cjs.js"], - mode: "passthrough", + mangleProps: /_$/, + external: ["*"], }); itBundled("default/ManglePropsImportExportBundled", { // GENERATED @@ -5545,9 +5633,11 @@ describe("bundler", () => { "/cjs.js": `exports.cjs_foo_ = 'foo'`, }, entryPoints: ["/entry-esm.js", "/entry-cjs.js"], + mangleProps: /_$/, }); itBundled("default/ManglePropsJSXTransform", { // GENERATED + notImplemented: true, files: { "/entry.jsx": /* jsx */ ` let Foo = { @@ -5566,10 +5656,10 @@ describe("bundler", () => { `, }, mangleProps: /_$/, - mode: "passthrough", }); itBundled("default/ManglePropsJSXPreserve", { // GENERATED + notImplemented: true, files: { "/entry.jsx": /* jsx */ ` let Foo = { @@ -5583,10 +5673,10 @@ describe("bundler", () => { }, outfile: "/out.jsx", mangleProps: /_$/, - mode: "passthrough", }); itBundled("default/ManglePropsJSXTransformNamespace", { // GENERATED + notImplemented: true, files: { "/entry.jsx": /* jsx */ ` export default [ @@ -5596,10 +5686,8 @@ describe("bundler", () => { ] `, }, - mode: "passthrough", }); itBundled("default/ManglePropsAvoidCollisions", { - // GENERATED files: { "/entry.js": /* js */ ` export default { @@ -5611,10 +5699,9 @@ describe("bundler", () => { } `, }, - mode: "passthrough", + mangleProps: /_$/, }); itBundled("default/ManglePropsTypeScriptFeatures", { - // GENERATED files: { "/parameter-properties.ts": /* ts */ ` class Foo { @@ -5694,10 +5781,9 @@ describe("bundler", () => { `, }, entryPoints: ["/parameter-properties.ts", "/namespace-exports.ts", "/enum-values.ts"], - mode: "passthrough", + mangleProps: /_$/, }); itBundled("default/ManglePropsShorthand", { - // GENERATED files: { "/entry.js": /* js */ ` // This should print as "({ y }) => ({ y })" not "({ y: y }) => ({ y: y })" @@ -5705,10 +5791,8 @@ describe("bundler", () => { `, }, mangleProps: /x/, - mode: "passthrough", }); itBundled("default/ManglePropsNoShorthand", { - // GENERATED files: { "/entry.js": /* js */ ` // This should print as "({ y }) => ({ y: y })" not "({ y: y }) => ({ y: y })" @@ -5717,10 +5801,8 @@ describe("bundler", () => { }, mangleProps: /x/, minifyIdentifiers: true, - mode: "passthrough", }); itBundled("default/ManglePropsLoweredClassFields", { - // GENERATED files: { "/entry.js": /* js */ ` class Foo { @@ -5731,10 +5813,9 @@ describe("bundler", () => { `, }, mangleProps: /_$/, - mode: "passthrough", + unsupportedJSFeatures: ["class-field", "class-static-field"], }); itBundled("default/ManglePropsSuperCall", { - // GENERATED files: { "/entry.js": /* js */ ` class Foo {} @@ -5745,10 +5826,9 @@ describe("bundler", () => { } `, }, - mode: "passthrough", + mangleProps: /./, }); itBundled("default/MangleNoQuotedProps", { - // GENERATED files: { "/entry.js": /* js */ ` x['_doNotMangleThis']; @@ -5766,7 +5846,7 @@ describe("bundler", () => { `, }, mangleProps: /_/, - mode: "passthrough", + mangleQuoted: false, }); itBundled("default/MangleNoQuotedPropsMinifySyntax", { // GENERATED @@ -5788,10 +5868,9 @@ describe("bundler", () => { }, mangleProps: /_/, mangleQuoted: false, - mode: "passthrough", + minifySyntax: true, }); itBundled("default/MangleQuotedProps", { - // GENERATED files: { "/keep.js": /* js */ ` foo("_keepThisProperty"); @@ -5830,10 +5909,9 @@ describe("bundler", () => { }, entryPoints: ["/keep.js", "/mangle.js"], mangleProps: /_/, - mode: "passthrough", + mangleQuoted: true, }); itBundled("default/MangleQuotedPropsMinifySyntax", { - // GENERATED files: { "/keep.js": /* js */ ` foo("_keepThisProperty"); @@ -5873,42 +5951,42 @@ describe("bundler", () => { entryPoints: ["/keep.js", "/mangle.js"], mangleProps: /_/, mangleQuoted: true, - mode: "passthrough", - }); - itBundled("default/IndirectRequireMessage", { - // GENERATED - files: { - "/array.js": `let x = [require]`, - "/assign.js": `require = x`, - "/ident.js": `let x = require`, - "/dot.js": `let x = require.cache`, - "/index.js": `let x = require[cache]`, - }, - entryPoints: ["/array.js", "/assign.js", "/dot.js", "/ident.js", "/index.js"], - /* TODO FIX expectedScanLog: `array.js: DEBUG: Indirect calls to "require" will not be bundled - assign.js: DEBUG: Indirect calls to "require" will not be bundled - ident.js: DEBUG: Indirect calls to "require" will not be bundled - `, */ - }); - itBundled("default/AmbiguousReexportMsg", { - // GENERATED - files: { - "/entry.js": /* js */ ` - export * from './a' - export * from './b' - export * from './c' - `, - "/a.js": `export let a = 1, x = 2`, - "/b.js": `export let b = 3; export { b as x }`, - "/c.js": `export let c = 4, x = 5`, - }, - /* TODO FIX expectedCompileLog: `DEBUG: Re-export of "x" in "entry.js" is ambiguous and has been removed - a.js: NOTE: One definition of "x" comes from "a.js" here: - b.js: NOTE: Another definition of "x" comes from "b.js" here: - `, */ + minifySyntax: true, }); + // we dont check debug messages + // itBundled("default/IndirectRequireMessage", { + // // GENERATED + // files: { + // "/array.js": `let x = [require]`, + // "/assign.js": `require = x`, + // "/ident.js": `let x = require`, + // "/dot.js": `let x = require.cache`, + // "/index.js": `let x = require[cache]`, + // }, + // entryPoints: ["/array.js", "/assign.js", "/dot.js", "/ident.js", "/index.js"], + // /* TODO FIX expectedScanLog: `array.js: DEBUG: Indirect calls to "require" will not be bundled + // assign.js: DEBUG: Indirect calls to "require" will not be bundled + // ident.js: DEBUG: Indirect calls to "require" will not be bundled + // `, */ + // }); + // itBundled("default/AmbiguousReexportMsg", { + // // GENERATED + // files: { + // "/entry.js": /* js */ ` + // export * from './a' + // export * from './b' + // export * from './c' + // `, + // "/a.js": `export let a = 1, x = 2`, + // "/b.js": `export let b = 3; export { b as x }`, + // "/c.js": `export let c = 4, x = 5`, + // }, + // /* TODO FIX expectedCompileLog: `DEBUG: Re-export of "x" in "entry.js" is ambiguous and has been removed + // a.js: NOTE: One definition of "x" comes from "a.js" here: + // b.js: NOTE: Another definition of "x" comes from "b.js" here: + // `, */ + // }); itBundled("default/NonDeterminismESBuildIssue2537", { - // GENERATED files: { "/entry.ts": /* ts */ ` export function aap(noot: boolean, wim: number) { @@ -5933,35 +6011,40 @@ describe("bundler", () => { } `, }, + minifyIdentifiers: true, }); - itBundled("default/MinifiedJSXPreserveWithObjectSpread", { - // GENERATED - files: { - "/entry.jsx": /* jsx */ ` - const obj = { - before, - ...{ [key]: value }, - ...{ key: value }, - after, - }; - ; - ; - `, - }, - minifySyntax: true, - }); + // itBundled("default/MinifiedJSXPreserveWithObjectSpread", { + // // GENERATED + // files: { + // "/entry.jsx": /* jsx */ ` + // const obj = { + // before, + // ...{ [key]: value }, + // ...{ key: value }, + // after, + // }; + // ; + // ; + // `, + // }, + // jsx: { + // // preserve: true, + // }, + // // minifySyntax: true, + // external: ["*"], + // }); itBundled("default/PackageAlias", { files: { "/entry.js": /* js */ ` @@ -5991,22 +6074,21 @@ describe("bundler", () => { "/node_modules/prefix-foo/index.js": `console.log(10)`, "/node_modules/@scope/prefix-foo/index.js": `console.log(11)`, }, - bundleErrors: { - "/entry.js": [ - 'Could not resolve: "pkg1". Maybe you need to "bun install"?', - 'Could not resolve: "pkg2/foo". Maybe you need to "bun install"?', - 'Could not resolve: "@scope/pkg4". Maybe you need to "bun install"?', - 'Could not resolve: "@scope/pkg5/foo". Maybe you need to "bun install"?', - 'Could not resolve: "@abs-path/pkg6". Maybe you need to "bun install"?', - 'Could not resolve: "@abs-path/pkg6/foo". Maybe you need to "bun install"?', - 'Could not resolve: "@scope-only/pkg8". Maybe you need to "bun install"?', - 'Could not resolve: "slash/" Maybe. you need to "bun install"?', - 'Could not resolve: "pkg3". Maybe you need to "bun install"?', - ], + alias: { + "pkg1": "alias1", + "pkg2": "alias2", + "pkg3": "alias3", + "@scope/pkg4": "alias4", + "@scope/pkg5": "alias5", + "@abs-path/pkg6": `/alias6/dir`, + "@abs-path/pkg7": `/alias7/dir`, + "@scope-only": "/alias8/dir", + "slash": "/alias9/some/file.js", + "prefix": "alias10", + "@scope/prefix": "alias11", }, }); itBundled("default/PackageAliasMatchLongest", { - // GENERATED files: { "/entry.js": /* js */ ` import "pkg" @@ -6023,100 +6105,101 @@ describe("bundler", () => { "pkg/foo/bar": "alias/pkg_foo_bar", }, }); - itBundled("default/ErrorsForAssertTypeJSON", { - // GENERATED - files: { - "/js-entry.js": /* js */ ` - import all from './foo.json' assert { type: 'json' } - import { default as def } from './foo.json' assert { type: 'json' } - import { unused } from './foo.json' assert { type: 'json' } - import { used } from './foo.json' assert { type: 'json' } - import * as ns from './foo.json' assert { type: 'json' } - use(used, ns.prop) - export { exported } from './foo.json' assert { type: 'json' } - import text from './foo.text' assert { type: 'json' } - import file from './foo.file' assert { type: 'json' } - import copy from './foo.copy' assert { type: 'json' } - `, - "/ts-entry.ts": /* ts */ ` - import all from './foo.json' assert { type: 'json' } - import { default as def } from './foo.json' assert { type: 'json' } - import { unused } from './foo.json' assert { type: 'json' } - import { used } from './foo.json' assert { type: 'json' } - import * as ns from './foo.json' assert { type: 'json' } - use(used, ns.prop) - export { exported } from './foo.json' assert { type: 'json' } - import text from './foo.text' assert { type: 'json' } - import file from './foo.file' assert { type: 'json' } - import copy from './foo.copy' assert { type: 'json' } - `, - "/foo.json": `{}`, - "/foo.text": `{}`, - "/foo.file": `{}`, - "/foo.copy": `{}`, - }, - entryPoints: ["/js-entry.js", "/ts-entry.ts"], - /* TODO FIX expectedScanLog: `js-entry.js: ERROR: Cannot use non-default import "unused" with a standard JSON module - js-entry.js: NOTE: This is considered an import of a standard JSON module because of the import assertion here: - NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "unused" import (which is non-standard behavior). - js-entry.js: ERROR: Cannot use non-default import "used" with a standard JSON module - js-entry.js: NOTE: This is considered an import of a standard JSON module because of the import assertion here: - NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "used" import (which is non-standard behavior). - js-entry.js: WARNING: Non-default import "prop" is undefined with a standard JSON module - js-entry.js: NOTE: This is considered an import of a standard JSON module because of the import assertion here: - NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "prop" import (which is non-standard behavior). - js-entry.js: ERROR: Cannot use non-default import "exported" with a standard JSON module - js-entry.js: NOTE: This is considered an import of a standard JSON module because of the import assertion here: - NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "exported" import (which is non-standard behavior). - js-entry.js: ERROR: The file "foo.text" was loaded with the "text" loader - js-entry.js: NOTE: This import assertion requires the loader to be "json" instead: - NOTE: You need to either reconfigure esbuild to ensure that the loader for this file is "json" or you need to remove this import assertion. - js-entry.js: ERROR: The file "foo.file" was loaded with the "file" loader - js-entry.js: NOTE: This import assertion requires the loader to be "json" instead: - NOTE: You need to either reconfigure esbuild to ensure that the loader for this file is "json" or you need to remove this import assertion. - ts-entry.ts: ERROR: Cannot use non-default import "used" with a standard JSON module - ts-entry.ts: NOTE: This is considered an import of a standard JSON module because of the import assertion here: - NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "used" import (which is non-standard behavior). - ts-entry.ts: WARNING: Non-default import "prop" is undefined with a standard JSON module - ts-entry.ts: NOTE: This is considered an import of a standard JSON module because of the import assertion here: - NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "prop" import (which is non-standard behavior). - ts-entry.ts: ERROR: Cannot use non-default import "exported" with a standard JSON module - ts-entry.ts: NOTE: This is considered an import of a standard JSON module because of the import assertion here: - NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "exported" import (which is non-standard behavior). - `, */ - }); - itBundled("default/OutputForAssertTypeJSON", { - // GENERATED - files: { - "/js-entry.js": /* js */ ` - import all from './foo.json' assert { type: 'json' } - import copy from './foo.copy' assert { type: 'json' } - import { default as def } from './foo.json' assert { type: 'json' } - import * as ns from './foo.json' assert { type: 'json' } - use(all, copy, def, ns.prop) - export { default } from './foo.json' assert { type: 'json' } - `, - "/ts-entry.ts": /* ts */ ` - import all from './foo.json' assert { type: 'json' } - import copy from './foo.copy' assert { type: 'json' } - import { default as def } from './foo.json' assert { type: 'json' } - import { unused } from './foo.json' assert { type: 'json' } - import * as ns from './foo.json' assert { type: 'json' } - use(all, copy, def, ns.prop) - export { default } from './foo.json' assert { type: 'json' } - `, - "/foo.json": `{}`, - "/foo.copy": `{}`, - }, - entryPoints: ["/js-entry.js", "/ts-entry.ts"], - /* TODO FIX expectedScanLog: `js-entry.js: WARNING: Non-default import "prop" is undefined with a standard JSON module - js-entry.js: NOTE: This is considered an import of a standard JSON module because of the import assertion here: - NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "prop" import (which is non-standard behavior). - ts-entry.ts: WARNING: Non-default import "prop" is undefined with a standard JSON module - ts-entry.ts: NOTE: This is considered an import of a standard JSON module because of the import assertion here: - NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "prop" import (which is non-standard behavior). - `, */ - }); + // itBundled("default/ErrorsForAssertTypeJSON", { + // notImplemented: true, + // files: { + // "/js-entry.js": /* js */ ` + // import all from './foo.json' assert { type: 'json' } + // import { default as def } from './foo.json' assert { type: 'json' } + // import { unused } from './foo.json' assert { type: 'json' } + // import { used } from './foo.json' assert { type: 'json' } + // import * as ns from './foo.json' assert { type: 'json' } + // use(used, ns.prop) + // export { exported } from './foo.json' assert { type: 'json' } + // import text from './foo.text' assert { type: 'json' } + // import file from './foo.file' assert { type: 'json' } + // import copy from './foo.copy' assert { type: 'json' } + // `, + // "/ts-entry.ts": /* ts */ ` + // import all from './foo.json' assert { type: 'json' } + // import { default as def } from './foo.json' assert { type: 'json' } + // import { unused } from './foo.json' assert { type: 'json' } + // import { used } from './foo.json' assert { type: 'json' } + // import * as ns from './foo.json' assert { type: 'json' } + // use(used, ns.prop) + // export { exported } from './foo.json' assert { type: 'json' } + // import text from './foo.text' assert { type: 'json' } + // import file from './foo.file' assert { type: 'json' } + // import copy from './foo.copy' assert { type: 'json' } + // `, + // "/foo.json": `{ "used": 0, "unused": 0, "prop": 0, "exported": 0 }`, + // "/foo.text": `{ "used": 0, "unused": 0, "prop": 0, "exported": 0 }`, + // "/foo.file": `{ "used": 0, "unused": 0, "prop": 0, "exported": 0 }`, + // "/foo.copy": `{ "used": 0, "unused": 0, "prop": 0, "exported": 0 }`, + // }, + // entryPoints: ["/js-entry.js", "/ts-entry.ts"], + // /* TODO FIX expectedScanLog: `js-entry.js: ERROR: Cannot use non-default import "unused" with a standard JSON module + // js-entry.js: NOTE: This is considered an import of a standard JSON module because of the import assertion here: + // NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "unused" import (which is non-standard behavior). + // js-entry.js: ERROR: Cannot use non-default import "used" with a standard JSON module + // js-entry.js: NOTE: This is considered an import of a standard JSON module because of the import assertion here: + // NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "used" import (which is non-standard behavior). + // js-entry.js: WARNING: Non-default import "prop" is undefined with a standard JSON module + // js-entry.js: NOTE: This is considered an import of a standard JSON module because of the import assertion here: + // NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "prop" import (which is non-standard behavior). + // js-entry.js: ERROR: Cannot use non-default import "exported" with a standard JSON module + // js-entry.js: NOTE: This is considered an import of a standard JSON module because of the import assertion here: + // NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "exported" import (which is non-standard behavior). + // js-entry.js: ERROR: The file "foo.text" was loaded with the "text" loader + // js-entry.js: NOTE: This import assertion requires the loader to be "json" instead: + // NOTE: You need to either reconfigure esbuild to ensure that the loader for this file is "json" or you need to remove this import assertion. + // js-entry.js: ERROR: The file "foo.file" was loaded with the "file" loader + // js-entry.js: NOTE: This import assertion requires the loader to be "json" instead: + // NOTE: You need to either reconfigure esbuild to ensure that the loader for this file is "json" or you need to remove this import assertion. + // ts-entry.ts: ERROR: Cannot use non-default import "used" with a standard JSON module + // ts-entry.ts: NOTE: This is considered an import of a standard JSON module because of the import assertion here: + // NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "used" import (which is non-standard behavior). + // ts-entry.ts: WARNING: Non-default import "prop" is undefined with a standard JSON module + // ts-entry.ts: NOTE: This is considered an import of a standard JSON module because of the import assertion here: + // NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "prop" import (which is non-standard behavior). + // ts-entry.ts: ERROR: Cannot use non-default import "exported" with a standard JSON module + // ts-entry.ts: NOTE: This is considered an import of a standard JSON module because of the import assertion here: + // NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "exported" import (which is non-standard behavior). + // `, */ + // }); + // itBundled("default/OutputForAssertTypeJSON", { + // // GENERATED + // files: { + // "/js-entry.js": /* js */ ` + // import all from './foo.json' assert { type: 'json' } + // import copy from './foo.copy' assert { type: 'json' } + // import { default as def } from './foo.json' assert { type: 'json' } + // import * as ns from './foo.json' assert { type: 'json' } + // use(all, copy, def, ns.prop) + // export { default } from './foo.json' assert { type: 'json' } + // `, + // "/ts-entry.ts": /* ts */ ` + // import all from './foo.json' assert { type: 'json' } + // import copy from './foo.copy' assert { type: 'json' } + // import { default as def } from './foo.json' assert { type: 'json' } + // import { unused } from './foo.json' assert { type: 'json' } + // import * as ns from './foo.json' assert { type: 'json' } + // use(all, copy, def, ns.prop) + // export { default } from './foo.json' assert { type: 'json' } + // `, + // "/foo.json": `{}`, + // "/foo.copy": `{}`, + // }, + // entryPoints: ["/js-entry.js", "/ts-entry.ts"], + // /* TODO FIX expectedScanLog: `js-entry.js: WARNING: Non-default import "prop" is undefined with a standard JSON module + // js-entry.js: NOTE: This is considered an import of a standard JSON module because of the import assertion here: + // NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "prop" import (which is non-standard behavior). + // ts-entry.ts: WARNING: Non-default import "prop" is undefined with a standard JSON module + // ts-entry.ts: NOTE: This is considered an import of a standard JSON module because of the import assertion here: + // NOTE: You can either keep the import assertion and only use the "default" import, or you can remove the import assertion and use the "prop" import (which is non-standard behavior). + // `, */ + // }); + return; itBundled("default/ExternalPackages", { // GENERATED files: { diff --git a/test/bundler/esbuild/lower.test.ts b/test/bundler/esbuild/lower.test.ts index d03c4a27f6261..df68a6f5187dc 100644 --- a/test/bundler/esbuild/lower.test.ts +++ b/test/bundler/esbuild/lower.test.ts @@ -1,4 +1,4 @@ -import { RUN_UNCHECKED_TESTS, itBundled, testForFile } from "../expectBundled"; +import { itBundled, testForFile } from "../expectBundled"; var { describe, test, expect } = testForFile(import.meta.path); // Tests ported from: @@ -7,7 +7,7 @@ var { describe, test, expect } = testForFile(import.meta.path); // For debug, all files are written to $TEMP/bun-bundle-tests/lower describe("bundler", () => { - if (!RUN_UNCHECKED_TESTS) return; + return; itBundled("lower/LowerOptionalCatchNameCollisionNoBundle", { // GENERATED files: { diff --git a/test/bundler/esbuild/ts.test.ts b/test/bundler/esbuild/ts.test.ts index a3b3ce9252ecd..2eb894cfe1ce0 100644 --- a/test/bundler/esbuild/ts.test.ts +++ b/test/bundler/esbuild/ts.test.ts @@ -1470,7 +1470,6 @@ describe("bundler", () => { }, }); itBundled("ts/ThisInsideFunctionTSNoBundleUseDefineForClassFields", { - // GENERATED files: { "/entry.ts": /* ts */ ` function foo(x = this) { return [x, this]; } diff --git a/test/bundler/expectBundled.ts b/test/bundler/expectBundled.ts index e625cb5004099..e029787c8e512 100644 --- a/test/bundler/expectBundled.ts +++ b/test/bundler/expectBundled.ts @@ -27,7 +27,7 @@ export function testForFile(file: string): BunTestExports { } /** Use `esbuild` instead of `bun build` */ -const ESBUILD = process.env.BUN_BUNDLER_TEST_USE_ESBUILD; +export const ESBUILD = process.env.BUN_BUNDLER_TEST_USE_ESBUILD; /** Write extra files to disk and log extra info. */ const DEBUG = process.env.BUN_BUNDLER_TEST_DEBUG; /** Set this to the id of a bundle test to run just that test */ @@ -95,6 +95,7 @@ export interface BundlerTestInput { fragment?: string; automaticRuntime?: boolean; development?: boolean; + preserve?: boolean; }; outbase?: string; /** Defaults to `/out.js` */ @@ -392,7 +393,7 @@ function expectBundled( const entryPaths = entryPoints.map(file => path.join(root, file)); if (external) { - external = external.map(x => x.replace(/\{\{root\}\}/g, root)); + external = external.map(x => (typeof x !== "string" ? x : x.replace(/\{\{root\}\}/g, root))); } outfile = useOutFile ? path.join(root, outfile ?? "/out.js") : undefined; @@ -404,7 +405,7 @@ function expectBundled( : entryPaths.map(file => path.join(outdir!, path.basename(file))) ).map(x => x.replace(/\.ts$/, ".js")); - if (mode === "transform" && !outfile) { + if (mode === "transform" && !outfile && !ESBUILD) { throw new Error("transform mode requires one single outfile"); } if (cjs2esm && !outfile && !minifySyntax && !minifyWhitespace) { @@ -475,6 +476,7 @@ function expectBundled( minifyWhitespace && `--minify-whitespace`, globalName && `--global-name=${globalName}`, // inject && inject.map(x => ["--inject", path.join(root, x)]), + jsx.preserve && "--jsx=preserve", jsx.automaticRuntime === false && "--jsx=classic", jsx.factory && `--jsx-factory=${jsx.factory}`, jsx.fragment && `--jsx-fragment=${jsx.fragment}`, @@ -508,6 +510,7 @@ function expectBundled( inject && inject.map(x => `--inject:${path.join(root, x)}`), define && Object.entries(define).map(([k, v]) => `--define:${k}=${v}`), jsx.automaticRuntime && "--jsx=automatic", + jsx.preserve && "--jsx=preserve", jsx.factory && `--jsx-factory=${jsx.factory}`, jsx.fragment && `--jsx-fragment=${jsx.fragment}`, jsx.development && `--jsx-dev`, @@ -579,7 +582,7 @@ function expectBundled( } } - const { stdout, stderr, success } = Bun.spawnSync({ + const { stdout, stderr, success, exitCode } = Bun.spawnSync({ cmd, cwd: root, stdio: ["ignore", "pipe", "pipe"], @@ -785,6 +788,7 @@ function expectBundled( writeFileSync(path.join(root, "run.js"), debugFile); } else { console.log("TODO: generate run.js, currently only works if options are wrapped in a function"); + console.log("options:", buildConfig); } }