diff options
| -rw-r--r-- | src/bundler.zig | 2 | ||||
| -rw-r--r-- | test/transpiler/transpiler.test.js | 200 |
2 files changed, 132 insertions, 70 deletions
diff --git a/src/bundler.zig b/src/bundler.zig index fa3cca0d7..011634b7a 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -1387,7 +1387,7 @@ pub const Bundler = struct { opts.legacy_transform_require_to_import = bundler.options.allow_runtime and !bundler.options.target.isBun(); opts.features.allow_runtime = bundler.options.allow_runtime; opts.features.trim_unused_imports = bundler.options.trim_unused_imports orelse loader.isTypeScript(); - opts.features.should_fold_typescript_constant_expressions = loader.isTypeScript() or target.isBun() or bundler.options.inlining; + opts.features.should_fold_typescript_constant_expressions = loader.isTypeScript() or target.isBun() or bundler.options.minify_syntax; opts.features.dynamic_require = target.isBun(); opts.transform_only = bundler.options.transform_only; diff --git a/test/transpiler/transpiler.test.js b/test/transpiler/transpiler.test.js index bf51adba8..fe40ae66a 100644 --- a/test/transpiler/transpiler.test.js +++ b/test/transpiler/transpiler.test.js @@ -259,7 +259,7 @@ describe("Bun.Transpiler", () => { // TODO: why are there two newlines here? exp("F<{}>()\nclass F<T> {}", "F();\n\nclass F {\n}"); - exp("f<{}>()\nfunction f<T>() {}", "f();\nfunction f() {\n}"); + exp("f<{}>()\nfunction f<T>() {}", "let f = function() {\n};\nf()"); }); // TODO: fix all the cases that report generic "Parse error" @@ -596,7 +596,7 @@ describe("Bun.Transpiler", () => { exp("class Foo<const T extends X> {}", "class Foo {\n}"); exp("Foo = class <const T> {}", "Foo = class {\n}"); exp("Foo = class Bar<const T> {}", "Foo = class Bar {\n}"); - exp("function foo<const T>() {}", "function foo() {\n}"); + exp("function foo<const T>() {}", "let foo = function() {\n}"); exp("foo = function <const T>() {}", "foo = function() {\n}"); exp("foo = function bar<const T>() {}", "foo = function bar() {\n}"); exp("class Foo { bar<const T>() {} }", "class Foo {\n bar() {\n }\n}"); @@ -1099,6 +1099,9 @@ export default class { bacon: `${import.meta.dir}/macro-check.js`, }, }, + minify: { + syntax: true, + }, }); const code = `import { useParams } from "remix"; @@ -1733,8 +1736,12 @@ export const { dead } = { dead: "hello world!" }; }); it("rewrite string to length", () => { - expectPrinted_(`export const foo = "a".length + "b".length;`, `export const foo = 1 + 1`); expectBunPrinted_(`export const foo = "a".length + "b".length;`, `export const foo = 2`); + expectBunPrinted_(`export const foo = ("a" + "b").length;`, `export const foo = 2`); + expectBunPrinted_( + `export const foo = "😋 Get Emoji — All Emojis to ✂️ Copy and 📋 Paste 👌".length;`, + `export const foo = 52`, + ); }); describe("Bun.js", () => { @@ -2163,6 +2170,60 @@ class Foo { }); describe("simplification", () => { + const transpiler = new Bun.Transpiler({ + loader: "tsx", + define: { + "process.env.NODE_ENV": JSON.stringify("development"), + user_undefined: "undefined", + }, + macro: { + react: { + bacon: `${import.meta.dir}/macro-check.js`, + }, + }, + platform: "browser", + minify: { syntax: true }, + }); + + const parsed = (code, trim = true, autoExport = false, transpiler_ = transpiler) => { + if (autoExport) { + code = "export default (" + code + ")"; + } + + var out = transpiler_.transformSync(code, "js"); + if (autoExport && out.startsWith("export default ")) { + out = out.substring("export default ".length); + } + + if (trim) { + out = out.trim(); + + if (out.endsWith(";")) { + out = out.substring(0, out.length - 1); + } + + return out.trim(); + } + + return out; + }; + + const expectPrinted = (code, out) => { + expect(parsed(code, true, true)).toBe(out); + }; + + const expectPrinted_ = (code, out) => { + expect(parsed(code, !out.endsWith(";\n"), false)).toBe(out); + }; + + const expectPrintedNoTrim = (code, out) => { + expect(parsed(code, false, false)).toBe(out); + }; + + const expectBunPrinted_ = (code, out) => { + expect(parsed(code, !out.endsWith(";\n"), false, bunTranspiler)).toBe(out); + }; + it("unary operator", () => { expectPrinted("a = !(b, c)", "a = (b, !c)"); }); @@ -2172,6 +2233,7 @@ class Foo { inline: true, platform: "bun", allowBunRuntime: false, + minify: { syntax: true }, }); function check(input, output) { @@ -2182,6 +2244,7 @@ class Foo { .replaceAll(/^ /gm, ""), ).toBe("export function hello() {\n" + output + "\n}".replaceAll(/^ /gm, "")); } + hideFromStackTrace(check); check("const x = 1; return x", "return 1;"); check("const x = 1; return x + 1", "return 2;"); @@ -2199,9 +2262,7 @@ const d = b + a; console.log(a, b, c, d); `, ` -const c = "ba"; -const b = c + "a"; -const d = b + "a"; +const c = "ba", b = c + "a", d = b + "a"; console.log("a", b, c, d); `.trim(), ); @@ -2253,8 +2314,7 @@ hey(); console.log(foo, array); `, ` -const foo = { bar: true }; -const array = [1]; +const foo = { bar: !0 }, array = [1]; console.log(foo, array); `.trim(), ); @@ -2265,6 +2325,7 @@ console.log(foo, array); inline: true, platform: "bun", allowBunRuntime: false, + minify: { syntax: true }, }); // Check that pushing/popping scopes doesn't cause a crash @@ -2313,6 +2374,7 @@ console.log(foo, array); inline: true, platform: "bun", allowBunRuntime: false, + minify: { syntax: true }, }); function check(input, output) { expect( @@ -2334,7 +2396,7 @@ console.log(foo, array); // Can substitute into normal unary operators check("let x = 1; return +x", "return 1;"); check("let x = 1; return -x", "return -1;"); - check("let x = 1; return !x", "return false;"); + check("let x = 1; return !x", "return !1;"); check("let x = 1; return ~x", "return ~1;"); // TODO: remove needless return undefined; // check("let x = 1; return void x", "let x = 1;"); @@ -2374,10 +2436,10 @@ console.log(foo, array); check("let x = 1; x--", "let x = 1;\nx--;"); check("let x = 1; delete x", "let x = 1;\ndelete x;"); - // Cannot substitute into mutating binary operators - check("let x = 1; x = 2", "let x = 1;\nx = 2;"); - check("let x = 1; x += 2", "let x = 1;\nx += 2;"); - check("let x = 1; x ||= 2", "let x = 1;\nx ||= 2;"); + // Cannot substitute into mutating binary operators unless immediately after the assignment + check("let x = 1; let y; x = 2", "let x = 1, y;\nx = 2;"); + check("let x = 1; let y; x += 2", "let x = 1, y;\nx += 2;"); + check("let x = 1; let y; x ||= 2", "let x = 1, y;\nx ||= 2;"); // Can substitute past mutating binary operators when the left operand has no side effects // check("let x = 1; arg0 = x", "arg0 = 1;"); @@ -2653,7 +2715,7 @@ console.log(foo, array); expectPrinted("null ?? 1", "1"); expectPrinted("undefined ?? 1", "1"); expectPrinted("0 ?? 1", "0"); - expectPrinted("false ?? 1", "false"); + expectPrinted("false ?? 1", "!1"); expectPrinted('"" ?? 1', '""'); expectPrinted("typeof undefined", '"undefined"'); @@ -2672,60 +2734,60 @@ console.log(foo, array); expectPrinted("typeof [null]", '"object"'); expectPrinted("typeof ['boolean']", '"object"'); - expectPrinted('typeof [] === "object"', "true"); - expectPrinted("typeof {foo: 123} === typeof {bar: 123}", "true"); - expectPrinted("typeof {foo: 123} !== typeof 123", "true"); - - expectPrinted("undefined === undefined", "true"); - expectPrinted("undefined !== undefined", "false"); - expectPrinted("undefined == undefined", "true"); - expectPrinted("undefined != undefined", "false"); - - expectPrinted("null === null", "true"); - expectPrinted("null !== null", "false"); - expectPrinted("null == null", "true"); - expectPrinted("null != null", "false"); - - expectPrinted("undefined === null", "undefined === null"); - expectPrinted("undefined !== null", "undefined !== null"); - expectPrinted("undefined == null", "undefined == null"); - expectPrinted("undefined != null", "undefined != null"); - - expectPrinted("true === true", "true"); - expectPrinted("true === false", "false"); - expectPrinted("true !== true", "false"); - expectPrinted("true !== false", "true"); - expectPrinted("true == true", "true"); - expectPrinted("true == false", "false"); - expectPrinted("true != true", "false"); - expectPrinted("true != false", "true"); - - expectPrinted("1 === 1", "true"); - expectPrinted("1 === 2", "false"); + expectPrinted('typeof [] === "object"', "!0"); + expectPrinted("typeof {foo: 123} === typeof {bar: 123}", "!0"); + expectPrinted("typeof {foo: 123} !== typeof 123", "!0"); + + expectPrinted("undefined === undefined", "!0"); + expectPrinted("undefined !== undefined", "!1"); + expectPrinted("undefined == undefined", "!0"); + expectPrinted("undefined != undefined", "!1"); + + expectPrinted("null === null", "!0"); + expectPrinted("null !== null", "!1"); + expectPrinted("null == null", "!0"); + expectPrinted("null != null", "!1"); + + expectPrinted("undefined === null", "!1"); + expectPrinted("undefined !== null", "!0"); + expectPrinted("undefined == null", "!0"); + expectPrinted("undefined != null", "!1"); + + expectPrinted("true === true", "!0"); + expectPrinted("true === false", "!1"); + expectPrinted("true !== true", "!1"); + expectPrinted("true !== false", "!0"); + expectPrinted("true == true", "!0"); + expectPrinted("true == false", "!1"); + expectPrinted("true != true", "!1"); + expectPrinted("true != false", "!0"); + + expectPrinted("1 === 1", "!0"); + expectPrinted("1 === 2", "!1"); expectPrinted("1 === '1'", '1 === "1"'); - expectPrinted("1 == 1", "true"); - expectPrinted("1 == 2", "false"); + expectPrinted("1 == 1", "!0"); + expectPrinted("1 == 2", "!1"); expectPrinted("1 == '1'", '1 == "1"'); - expectPrinted("1 !== 1", "false"); - expectPrinted("1 !== 2", "true"); + expectPrinted("1 !== 1", "!1"); + expectPrinted("1 !== 2", "!0"); expectPrinted("1 !== '1'", '1 !== "1"'); - expectPrinted("1 != 1", "false"); - expectPrinted("1 != 2", "true"); + expectPrinted("1 != 1", "!1"); + expectPrinted("1 != 2", "!0"); expectPrinted("1 != '1'", '1 != "1"'); - expectPrinted("'a' === '\\x61'", "true"); - expectPrinted("'a' === '\\x62'", "false"); - expectPrinted("'a' === 'abc'", "false"); - expectPrinted("'a' !== '\\x61'", "false"); - expectPrinted("'a' !== '\\x62'", "true"); - expectPrinted("'a' !== 'abc'", "true"); - expectPrinted("'a' == '\\x61'", "true"); - expectPrinted("'a' == '\\x62'", "false"); - expectPrinted("'a' == 'abc'", "false"); - expectPrinted("'a' != '\\x61'", "false"); - expectPrinted("'a' != '\\x62'", "true"); - expectPrinted("'a' != 'abc'", "true"); + expectPrinted("'a' === '\\x61'", "!0"); + expectPrinted("'a' === '\\x62'", "!1"); + expectPrinted("'a' === 'abc'", "!1"); + expectPrinted("'a' !== '\\x61'", "!1"); + expectPrinted("'a' !== '\\x62'", "!0"); + expectPrinted("'a' !== 'abc'", "!0"); + expectPrinted("'a' == '\\x61'", "!0"); + expectPrinted("'a' == '\\x62'", "!1"); + expectPrinted("'a' == 'abc'", "!1"); + expectPrinted("'a' != '\\x61'", "!1"); + expectPrinted("'a' != '\\x62'", "!0"); + expectPrinted("'a' != 'abc'", "!0"); expectPrinted("'a' + 'b'", '"ab"'); expectPrinted("'a' + 'bc'", '"abc"'); @@ -2771,19 +2833,19 @@ console.log(foo, array); expectPrinted("(-123).toString()", "(-123).toString()"); expectPrinted("-0", "-0"); expectPrinted("(-0).toString()", "(-0).toString()"); - expectPrinted("-0 === 0", "true"); + expectPrinted("-0 === 0", "!0"); expectPrinted("NaN", "NaN"); expectPrinted("NaN.toString()", "NaN.toString()"); - expectPrinted("NaN === NaN", "false"); + expectPrinted("NaN === NaN", "!1"); expectPrinted("Infinity", "Infinity"); expectPrinted("Infinity.toString()", "Infinity.toString()"); expectPrinted("(-Infinity).toString()", "(-Infinity).toString()"); - expectPrinted("Infinity === Infinity", "true"); - expectPrinted("Infinity === -Infinity", "false"); + expectPrinted("Infinity === Infinity", "!0"); + expectPrinted("Infinity === -Infinity", "!1"); - expectPrinted("123n === 1_2_3n", "true"); + expectPrinted("123n === 1_2_3n", "!0"); }); describe("type coercions", () => { const dead = ` @@ -2830,8 +2892,8 @@ console.log(foo, array); } if (line.includes("should_be_false")) { - if (!line.includes("= false")) throw new Error(`Expected false in "${line}"`); - expect(line.includes("= false")).toBe(true); + if (!line.includes("= !1")) throw new Error(`Expected false in "${line}"`); + expect(line.includes("= !1")).toBe(true); } if (line.includes("TEST_FAIL")) { |
