Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/js_parser/visit/visit_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,10 +581,14 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
match s2_data {
StmtData::SFunction(mut func_ref) => {
let func: &mut S::Function = &mut *func_ref;
// Leave anonymous so SetFunctionName assigns `.name = "default"`;
// React Fast Refresh injects a name for its `$RefreshReg$` binding.
let name: &'a [u8] = if let Some(func_loc) = func.func.name {
p.load_name_from_ref(func_loc.ref_)
} else {
func.func.name = Some(data.default_name);
if p.options.features.react_fast_refresh {
func.func.name = Some(data.default_name);
}
js_ast::ClauseItem::DEFAULT_ALIAS
Comment thread
robobun marked this conversation as resolved.
};

Expand Down
39 changes: 39 additions & 0 deletions test/bundler/transpiler/export-default-name.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { describe, expect, test } from "bun:test";
import { bunEnv, bunExe, tempDir } from "harness";

describe("anonymous export default .name", () => {
Comment thread
robobun marked this conversation as resolved.
test.concurrent.each([
["function", "export default function () {}"],
["async function", "export default async function () {}"],
["function*", "export default function* () {}"],
["async function*", "export default async function* () {}"],
["class", "export default class {}"],
["arrow", "export default () => 1;"],
])("%s: .name is 'default'", async (_label, decl) => {
using dir = tempDir("export-default-name", {
"mod.mjs": `${decl}\nimport self from "./mod.mjs";\nconsole.log(JSON.stringify(self.name));\n`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "mod.mjs"],
env: bunEnv,
cwd: String(dir),
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
expect({ stdout, stderr, exitCode }).toEqual({ stdout: '"default"\n', stderr: "", exitCode: 0 });
});

test.concurrent("named function keeps its own name", async () => {
using dir = tempDir("export-default-named", {
"mod.mjs": `export default function Foo() {}\nimport self from "./mod.mjs";\nconsole.log(JSON.stringify(self.name));\n`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "mod.mjs"],
env: bunEnv,
cwd: String(dir),
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
expect({ stdout, stderr, exitCode }).toEqual({ stdout: '"Foo"\n', stderr: "", exitCode: 0 });
});
});
9 changes: 5 additions & 4 deletions test/regression/issue/31401.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ describe.concurrent("issue 31401: anonymous default export from digit-named modu
expect(exitCode).toBe(0);
});

test("transpile-only output uses a valid identifier for the generated default name", async () => {
using dir = tempDir("issue-31401-transpile", {
test("bundled output uses a valid identifier for the generated default name", async () => {
using dir = tempDir("issue-31401-bundle", {
"1.ts": `export default function () {}\n`,
"entry.ts": `import f from "./1.ts"; console.log(typeof f);\n`,
});

await using proc = Bun.spawn({
cmd: [bunExe(), "build", "--no-bundle", join(String(dir), "1.ts")],
cmd: [bunExe(), "build", join(String(dir), "entry.ts")],
env: bunEnv,
stderr: "pipe",
stdout: "pipe",
Expand All @@ -60,7 +61,7 @@ describe.concurrent("issue 31401: anonymous default export from digit-named modu

expect(stderr).not.toContain("No identifiers allowed directly after numeric literal");
// Must be a valid identifier: the leading digit gets an underscore prefix.
expect(normalizeBunSnapshot(stdout)).toContain("export default function _1_default() {}");
expect(normalizeBunSnapshot(stdout)).toContain("function _1_default() {}");
expect(exitCode).toBe(0);
});
});
Loading