mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
[TS] Fix bug with import Foo = require("bar")
Closes https://github.com/oven-sh/bun/issues/1045
This commit is contained in:
@@ -739,10 +739,10 @@ pub const ImportScanner = struct {
|
||||
|
||||
// Skip to the underlying reference
|
||||
var value = decl.value;
|
||||
if (decl.value) |val| {
|
||||
if (decl.value != null) {
|
||||
while (true) {
|
||||
if (@as(Expr.Tag, val.data) == .e_dot) {
|
||||
value = val.data.e_dot.target;
|
||||
if (@as(Expr.Tag, value.?.data) == .e_dot) {
|
||||
value = value.?.data.e_dot.target;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -8097,7 +8097,8 @@ fn NewParser_(
|
||||
|
||||
const kind = S.Local.Kind.k_const;
|
||||
const name = p.lexer.identifier;
|
||||
var value = p.e(E.Identifier{ .ref = p.storeNameInRef(name) catch unreachable }, p.lexer.loc());
|
||||
const target = p.e(E.Identifier{ .ref = p.storeNameInRef(name) catch unreachable }, p.lexer.loc());
|
||||
var value = target;
|
||||
try p.lexer.expect(.t_identifier);
|
||||
|
||||
if (strings.eqlComptime(name, "require") and p.lexer.token == .t_open_paren) {
|
||||
@@ -8106,17 +8107,17 @@ fn NewParser_(
|
||||
const path = p.e(p.lexer.toEString(), p.lexer.loc());
|
||||
try p.lexer.expect(.t_string_literal);
|
||||
try p.lexer.expect(.t_close_paren);
|
||||
const args = try ExprNodeList.one(p.allocator, path);
|
||||
value.data = .{ .e_call = Expr.Data.Store.All.append(E.Call, E.Call{ .target = value, .close_paren_loc = p.lexer.loc(), .args = args }) };
|
||||
if (!opts.is_typescript_declare) {
|
||||
const args = try ExprNodeList.one(p.allocator, path);
|
||||
value = p.e(E.Call{ .target = target, .close_paren_loc = p.lexer.loc(), .args = args }, loc);
|
||||
}
|
||||
} else {
|
||||
// "import Foo = Bar"
|
||||
// "import Foo = Bar.Baz"
|
||||
while (p.lexer.token == .t_dot) {
|
||||
var prev_value = value;
|
||||
while (p.lexer.token == .t_dot) : (prev_value = value) {
|
||||
try p.lexer.next();
|
||||
value.data = .{ .e_dot = Expr.Data.Store.All.append(
|
||||
E.Dot,
|
||||
E.Dot{ .target = value, .name = p.lexer.identifier, .name_loc = p.lexer.loc() },
|
||||
) };
|
||||
value = p.e(E.Dot{ .target = prev_value, .name = p.lexer.identifier, .name_loc = p.lexer.loc() }, loc);
|
||||
try p.lexer.expect(.t_identifier);
|
||||
}
|
||||
}
|
||||
@@ -15717,8 +15718,9 @@ fn NewParser_(
|
||||
|
||||
pub fn ignoreUsage(p: *P, ref: Ref) void {
|
||||
if (!p.is_control_flow_dead) {
|
||||
assert(@as(usize, ref.innerIndex()) < p.symbols.items.len);
|
||||
p.symbols.items[ref.innerIndex()].use_count_estimate -|= 1;
|
||||
var use = p.symbol_uses.get(ref) orelse p.panic("Expected symbol_uses to exist {s}\n{s}", .{ ref, p.symbol_uses });
|
||||
var use = p.symbol_uses.get(ref) orelse return;
|
||||
use.count_estimate -|= 1;
|
||||
if (use.count_estimate == 0) {
|
||||
_ = p.symbol_uses.swapRemove(ref);
|
||||
|
||||
@@ -1,6 +1,101 @@
|
||||
import { expect, it, describe } from "bun:test";
|
||||
|
||||
describe("Bun.Transpiler", () => {
|
||||
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",
|
||||
});
|
||||
|
||||
const ts = {
|
||||
parsed: (code, trim = true, autoExport = false) => {
|
||||
if (autoExport) {
|
||||
code = "export default (" + code + ")";
|
||||
}
|
||||
|
||||
var out = transpiler.transformSync(code, "ts");
|
||||
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;
|
||||
},
|
||||
|
||||
expectPrinted: (code, out) => {
|
||||
expect(ts.parsed(code, true, true)).toBe(out);
|
||||
},
|
||||
|
||||
expectPrinted_: (code, out) => {
|
||||
expect(ts.parsed(code, !out.endsWith(";\n"), false)).toBe(out);
|
||||
},
|
||||
|
||||
expectParseError: (code, message) => {
|
||||
try {
|
||||
ts.parsed(code, false, false);
|
||||
} catch (er) {
|
||||
var err = er;
|
||||
if (er instanceof AggregateError) {
|
||||
err = err.errors[0];
|
||||
}
|
||||
|
||||
expect(er.message).toBe(message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error("Expected parse error for code\n\t" + code);
|
||||
},
|
||||
};
|
||||
|
||||
describe("TypeScript", () => {
|
||||
it("import Foo = Baz.Bar", () => {
|
||||
ts.expectPrinted_(
|
||||
"import Foo = Baz.Bar;\nexport default Foo;",
|
||||
"const Foo = Baz.Bar;\nexport default Foo"
|
||||
);
|
||||
});
|
||||
|
||||
it("import Foo = require('bar')", () => {
|
||||
ts.expectPrinted_(
|
||||
"import React = require('react')",
|
||||
'const React = require("react")'
|
||||
);
|
||||
});
|
||||
|
||||
it("import type Foo = require('bar')", () => {
|
||||
ts.expectPrinted_("import type Foo = require('bar')", "");
|
||||
});
|
||||
|
||||
it("unused import = gets removed", () => {
|
||||
ts.expectPrinted_("import Foo = Baz.Bar;", "");
|
||||
});
|
||||
|
||||
it("export import Foo = Baz.Bar", () => {
|
||||
ts.expectPrinted_(
|
||||
"export import Foo = Baz.Bar;",
|
||||
"export const Foo = Baz.Bar"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("exports.replace", () => {
|
||||
const transpiler = new Bun.Transpiler({
|
||||
exports: {
|
||||
@@ -111,19 +206,6 @@ describe("Bun.Transpiler", () => {
|
||||
});
|
||||
});
|
||||
|
||||
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",
|
||||
});
|
||||
const bunTranspiler = new Bun.Transpiler({
|
||||
loader: "tsx",
|
||||
define: {
|
||||
@@ -496,55 +578,6 @@ export var ComponentThatHasSpreadCausesDeopt = jsx(Hello, {
|
||||
|
||||
throw new Error("Expected parse error for code\n\t" + code);
|
||||
};
|
||||
const ts = {
|
||||
parsed: (code, trim = true, autoExport = false) => {
|
||||
if (autoExport) {
|
||||
code = "export default (" + code + ")";
|
||||
}
|
||||
|
||||
var out = transpiler.transformSync(code, "ts");
|
||||
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;
|
||||
},
|
||||
|
||||
expectPrinted: (code, out) => {
|
||||
expect(ts.parsed(code, true, true)).toBe(out);
|
||||
},
|
||||
|
||||
expectPrinted_: (code, out) => {
|
||||
expect(ts.parsed(code, !out.endsWith(";\n"), false)).toBe(out);
|
||||
},
|
||||
|
||||
expectParseError: (code, message) => {
|
||||
try {
|
||||
ts.parsed(code, false, false);
|
||||
} catch (er) {
|
||||
var err = er;
|
||||
if (er instanceof AggregateError) {
|
||||
err = err.errors[0];
|
||||
}
|
||||
|
||||
expect(er.message).toBe(message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error("Expected parse error for code\n\t" + code);
|
||||
},
|
||||
};
|
||||
|
||||
describe("parser", () => {
|
||||
it("arrays", () => {
|
||||
|
||||
Reference in New Issue
Block a user