From adc29ff815ed10804047bb1db6be90f79c54dfac Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Sat, 12 Sep 2026 17:41:11 +0000 Subject: [PATCH 1/2] js_parser: keep the template tag marker when minify-syntax rewrites a["b"] to a.b The rewrite moved call_target and delete_target to the new E::Dot, but not template_tag. So ns["tag"]`x` on a lifted CommonJS export printed as $tag`x`, and the tag function ran with this === undefined. --- src/js_parser/visit/visit_expr.rs | 3 ++ test/bundler/bundler_cjs2esm.test.ts | 62 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/js_parser/visit/visit_expr.rs b/src/js_parser/visit/visit_expr.rs index 5b14083e6f25..3d5f0b4d57da 100644 --- a/src/js_parser/visit/visit_expr.rs +++ b/src/js_parser/visit/visit_expr.rs @@ -872,6 +872,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O if is_call_target { p.call_target = dot.data; } + if is_template_tag { + p.template_tag = dot.data; + } if is_delete_target { p.delete_target = dot.data; } diff --git a/test/bundler/bundler_cjs2esm.test.ts b/test/bundler/bundler_cjs2esm.test.ts index 7c5964726e11..4daf3946dad0 100644 --- a/test/bundler/bundler_cjs2esm.test.ts +++ b/test/bundler/bundler_cjs2esm.test.ts @@ -1410,6 +1410,43 @@ describe("bundler", () => { stdout: "helped:x helped:y helped:z true", }, }); + // `--minify-syntax` rewrites `X["name"]` to `X.name`. The new node is still the + // call target or the template tag, so the call still passes `X` as `this`. + itBundled("cjs2esm/DefaultImportComputedMemberKeepsThisMinifySyntax", { + files: { + "/entry.js": /* js */ ` + import st from "./lib.cjs"; + console.log(st["parse"]("y"), st["tag"]\`z\`); + `, + ...thisReadingLib, + }, + cjs2esm: true, + minifySyntax: true, + onAfterBundle(api) { + expect(api.readFile("/out.js")).toContain('console.log(exports_lib.parse("y"), exports_lib.tag`z`);'); + }, + run: { + stdout: "helped:y helped:z", + }, + }); + itBundled("cjs2esm/StarImportComputedMemberKeepsThisMinifySyntax", { + files: { + "/entry.js": /* js */ ` + import * as ns from "./lib.cjs"; + console.log(ns["parse"]("y"), ns["tag"]\`z\`); + `, + ...thisReadingLib, + }, + cjs2esm: true, + minifySyntax: true, + onAfterBundle(api) { + // Each access keeps a receiver. The printed name of `ns` is not part of this test. + expect(api.readFile("/out.js")).toMatch(/console\.log\(\w+\.parse\("y"\), \w+\.tag`z`\);/); + }, + run: { + stdout: "helped:y helped:z", + }, + }); itBundled("cjs2esm/StarImportMethodCallThroughExportStarKeepsThis", { files: { "/entry.js": /* js */ ` @@ -1532,6 +1569,31 @@ describe("bundler", () => { stdout: "helped:in helped:module helped:tag", }, }); + itBundled("cjs2esm/SelfComputedMemberKeepsThisMinifySyntax", { + files: { + "/entry.js": /* js */ ` + import { internal, viaTag } from "./lib.cjs"; + console.log(internal(), viaTag()); + `, + "/lib.cjs": /* js */ ` + exports.parse = function (s) { return this._helper(s); }; + exports._helper = function (s) { return "helped:" + s; }; + exports.tag = function (strings) { return this._helper(strings[0]); }; + exports.internal = function () { return exports["parse"]("in"); }; + exports.viaTag = function () { return exports["tag"]\`tag\`; }; + `, + }, + cjs2esm: true, + minifySyntax: true, + onAfterBundle(api) { + const out = api.readFile("/out.js"); + expect(out).toContain('return exports_lib.parse("in");'); + expect(out).toContain("return exports_lib.tag`tag`;"); + }, + run: { + stdout: "helped:in helped:tag", + }, + }); itBundled("cjs2esm/SelfMethodCallWithoutThisBindsDirectly", { files: { "/entry.js": /* js */ ` From c4fb19213088f57c3638d409e47f857d9ced4077 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:33:56 +0000 Subject: [PATCH 2/2] ci: retrigger