From 7fd16ebffae4f733ca32c41995adaf33d20d10b2 Mon Sep 17 00:00:00 2001 From: Kai Tamkun <13513421+heimskr@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:06:09 -0800 Subject: [PATCH] Fix incorrect public TS class field name minification (#15411) --- src/js_parser.zig | 14 ++++++++++---- src/js_printer.zig | 2 +- test/bundler/bundler_edgecase.test.ts | 21 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/js_parser.zig b/src/js_parser.zig index ad1ff24c6f..3c27753894 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -21821,8 +21821,9 @@ fn NewParser_( if (arg.is_typescript_ctor_field) { switch (arg.binding.data) { .b_identifier => |id| { - const name = p.symbols.items[id.ref.innerIndex()].original_name; - const ident = p.newExpr(E.Identifier{ .ref = id.ref }, arg.binding.loc); + const arg_symbol = p.symbols.items[id.ref.innerIndex()]; + const name = arg_symbol.original_name; + const arg_ident = p.newExpr(E.Identifier{ .ref = id.ref }, arg.binding.loc); stmts.insert(if (super_index) |k| j + k + 1 else j, Stmt.assign( p.newExpr(E.Dot{ @@ -21830,12 +21831,17 @@ fn NewParser_( .name = name, .name_loc = arg.binding.loc, }, arg.binding.loc), - ident, + arg_ident, )) catch unreachable; // O(N) class_body.items.len += 1; bun.copy(G.Property, class_body.items[j + 1 ..], class_body.items[j .. class_body.items.len - 1]); - class_body.items[j] = G.Property{ .key = ident }; + // Copy the argument name symbol to prevent the class field declaration from being renamed + // but not the constructor argument. + const field_symbol_ref = p.declareSymbol(.other, arg.binding.loc, name) catch id.ref; + field_symbol_ref.getSymbol(p.symbols.items).must_not_be_renamed = true; + const field_ident = p.newExpr(E.Identifier{ .ref = field_symbol_ref }, arg.binding.loc); + class_body.items[j] = G.Property{ .key = field_ident }; j += 1; }, else => {}, diff --git a/src/js_printer.zig b/src/js_printer.zig index eea3b750a1..128cb2d5bc 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -576,7 +576,7 @@ pub const PrintResult = union(enum) { // do not make this a packed struct // stage1 compiler bug: // > /optional-chain-with-function.js: Evaluation failed: TypeError: (intermediate value) is not a function -// this test failure was caused by the packed structi mplementation +// this test failure was caused by the packed struct implementation const ExprFlag = enum { forbid_call, forbid_in, diff --git a/test/bundler/bundler_edgecase.test.ts b/test/bundler/bundler_edgecase.test.ts index 9cffc7cfc6..9d46ebf0b3 100644 --- a/test/bundler/bundler_edgecase.test.ts +++ b/test/bundler/bundler_edgecase.test.ts @@ -2253,4 +2253,25 @@ describe("bundler", () => { stdout: "windows", }, }); + + itBundled("edgecase/TSPublicFieldMinification", { + files: { + "/entry.ts": /* ts */ ` + export class Foo { + constructor(public name: string) {} + } + + const keys = Object.keys(new Foo('test')) + if (keys.length !== 1) throw new Error('Keys length is not 1') + if (keys[0] !== 'name') throw new Error('keys[0] is not "name"') + console.log('success') + `, + }, + minifySyntax: true, + minifyIdentifiers: true, + target: "bun", + run: { + stdout: "success", + }, + }); });