Skip to content

Commit

Permalink
Fixes #7263
Browse files Browse the repository at this point in the history
Loosely based on evanw/esbuild#1385
  • Loading branch information
Jarred-Sumner committed Jun 4, 2024
1 parent 347dc26 commit 8ae0b33
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 18 deletions.
3 changes: 2 additions & 1 deletion src/bun.js/RuntimeTranspilerCache.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// ** Update the version number when any breaking changes are made to the cache format or to the JS parser **
const expected_version = 2;
// Version 2 -> 3: "Infinity" becomes "1/0".
const expected_version = 3;

const bun = @import("root").bun;
const std = @import("std");
Expand Down
3 changes: 3 additions & 0 deletions src/bundler/bundle_v2.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6727,6 +6727,7 @@ const LinkerContext = struct {
const print_options = js_printer.Options{
// TODO: IIFE
.indent = indent,
.has_run_symbol_renamer = true,

.allocator = worker.allocator,
.require_ref = runtimeRequireRef,
Expand Down Expand Up @@ -7615,6 +7616,7 @@ const LinkerContext = struct {
const print_options = js_printer.Options{
// TODO: IIFE
.indent = 0,
.has_run_symbol_renamer = true,

.allocator = allocator,
.to_esm_ref = toESMRef,
Expand Down Expand Up @@ -8902,6 +8904,7 @@ const LinkerContext = struct {
.minify_whitespace = c.options.minify_whitespace,
.minify_syntax = c.options.minify_syntax,
.module_type = c.options.output_format,
.has_run_symbol_renamer = true,

.allocator = allocator,
.to_esm_ref = toESMRef,
Expand Down
52 changes: 38 additions & 14 deletions src/js_printer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ pub const Options = struct {
minify_syntax: bool = false,
transform_only: bool = false,
inline_require_and_import_errors: bool = true,
has_run_symbol_renamer: bool = false,

require_or_import_meta_for_source_callback: RequireOrImportMeta.Callback = .{},

Expand Down Expand Up @@ -2953,29 +2954,54 @@ fn NewPrinter(
},
.e_number => |e| {
const value = e.value;
p.addSourceMapping(expr.loc);

const absValue = @abs(value);

if (std.math.isNan(value)) {
p.printSpaceBeforeIdentifier();
p.addSourceMapping(expr.loc);

p.print("NaN");
} else if (std.math.isPositiveInf(value)) {
p.printSpaceBeforeIdentifier();
p.addSourceMapping(expr.loc);
p.print("Infinity");
} else if (std.math.isNegativeInf(value)) {
if (level.gte(.prefix)) {
p.addSourceMapping(expr.loc);
p.print("(-Infinity)");
} else if (std.math.isPositiveInf(value) or std.math.isNegativeInf(value)) {
const wrap = ((!p.options.has_run_symbol_renamer or p.options.minify_syntax) and level.gte(.multiply)) or
(std.math.isNegativeInf(value) and level.gte(.prefix));

if (wrap) {
p.print("(");
}

if (std.math.isNegativeInf(value)) {
p.printSpaceBeforeOperator(.un_neg);
p.print("-");
} else {
p.printSpaceBeforeIdentifier();
p.addSourceMapping(expr.loc);
p.print("(-Infinity)");
}

// If we are not running the symbol renamer, we must not print "Infinity".
// Some code may assign `Infinity` to another idenitifier.
//
// We do not want:
//
// const Infinity = 1 / 0
//
// to be transformed into:
//
// const Infinity = Infinity
//
if (is_json or (!p.options.minify_syntax and p.options.has_run_symbol_renamer)) {
p.print("Infinity");
} else if (p.options.minify_whitespace) {
p.print("1/0");
} else {
p.print("1 / 0");
}

if (wrap) {
p.print(")");
}
} else if (!std.math.signbit(value)) {
p.printSpaceBeforeIdentifier();
p.addSourceMapping(expr.loc);

p.printNonNegativeFloat(absValue);

// Remember the end of the latest number
Expand All @@ -2986,13 +3012,11 @@ fn NewPrinter(
// "!isNaN(value)" because we need this to be true for "-0" and "-0 < 0"
// is false.
p.print("(-");
p.addSourceMapping(expr.loc);
p.printNonNegativeFloat(absValue);
p.print(")");
} else {
p.printSpaceBeforeOperator(Op.Code.un_neg);
p.print("-");
p.addSourceMapping(expr.loc);
p.printNonNegativeFloat(absValue);

// Remember the end of the latest number
Expand Down
75 changes: 75 additions & 0 deletions test/bundler/bundler_minify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,81 @@ describe("bundler", () => {
assert([...code.matchAll(/var /g)].length === 1, "expected only 1 variable declaration statement");
},
});
itBundled("minify/Infinity", {
files: {
"/entry.js": /* js */ `
capture(Infinity);
capture(-Infinity);
capture(Infinity + 1);
capture(-Infinity - 1);
capture(Infinity / 0);
capture(-Infinity / 0);
capture(Infinity * 0);
capture(-Infinity * 0);
capture(Infinity % 1);
capture(-Infinity % 1);
capture(Infinity ** 1);
capture(-(Infinity ** 1));
capture(~Infinity);
capture(~-Infinity);
`,
},
capture: [
"1 / 0",
"-1 / 0",
"1 / 0",
"-1 / 0",
"1 / 0",
"-1 / 0",
"NaN",
"NaN",
"NaN",
"NaN",
"1 / 0",
"-1 / 0",
"~(1 / 0)",
"~(-1 / 0)",
],
minifySyntax: true,
});
itBundled("minify+whitespace/Infinity", {
files: {
"/entry.js": /* js */ `
capture(Infinity);
capture(-Infinity);
capture(Infinity + 1);
capture(-Infinity - 1);
capture(Infinity / 0);
capture(-Infinity / 0);
capture(Infinity * 0);
capture(-Infinity * 0);
capture(Infinity % 1);
capture(-Infinity % 1);
capture(Infinity ** 1);
capture((-Infinity) ** 2);
capture(~Infinity);
capture(~-Infinity);
`,
},
capture: [
"1/0",
"-1/0",
"1/0",
"-1/0",
"1/0",
"-1/0",
"NaN",
"NaN",
"NaN",
"NaN",
"1/0",
"1/0",
"~(1/0)",
"~(-1/0)",
],
minifySyntax: true,
minifyWhitespace: true,
});
itBundled("minify/InlineArraySpread", {
files: {
"/entry.js": /* js */ `
Expand Down
33 changes: 30 additions & 3 deletions test/bundler/expectBundled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1096,12 +1096,39 @@ for (const [key, blob] of build.outputs) {
options: opts,
captureFile: (file, fnName = "capture") => {
const fileContents = readFile(file);
const regex = new RegExp(`\\b${fnName}\\s*\\(((?:\\(\\))?.*?)\\)`, "g");
const matches = [...fileContents.matchAll(regex)];
let i = 0;
const length = fileContents.length;
const matches = [];
while (i < length) {
i = fileContents.indexOf(fnName, i);
if (i === -1) {
break;
}
const start = i;
let depth = 0;
while (i < length) {
const char = fileContents[i];
if (char === "(") {
depth++;
} else if (char === ")") {
depth--;
if (depth === 0) {
break;
}
}
i++;
}
if (depth !== 0) {
throw new Error(`Could not find closing paren for ${fnName} call in ${file}`);
}
matches.push(fileContents.slice(start + fnName.length + 1, i));
i++;
}

if (matches.length === 0) {
throw new Error(`No ${fnName} calls found in ${file}`);
}
return matches.map(match => match[1]);
return matches;
},
} satisfies BundlerTestBundleAPI;

Expand Down
10 changes: 10 additions & 0 deletions test/transpiler/07263.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { test, expect } from "bun:test";

export const Infinity = 1 / 0;

test("Infinity", async () => {
expect(Infinity).toBe(globalThis.Infinity);
const Mod = await import(import.meta.path);
expect(Mod.Infinity).toBe(1 / 0);
expect(Mod.Infinity).toBe(globalThis.Infinity);
});

0 comments on commit 8ae0b33

Please sign in to comment.