aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--integration/bunjs-only-snippets/macro-check.js3
-rw-r--r--integration/bunjs-only-snippets/transpiler.test.js31
-rw-r--r--src/javascript/jsc/api/transpiler.zig45
-rw-r--r--src/javascript/jsc/node/types.zig8
4 files changed, 67 insertions, 20 deletions
diff --git a/integration/bunjs-only-snippets/macro-check.js b/integration/bunjs-only-snippets/macro-check.js
new file mode 100644
index 000000000..2ea3fb8bd
--- /dev/null
+++ b/integration/bunjs-only-snippets/macro-check.js
@@ -0,0 +1,3 @@
+export function keepSecondArgument(args) {
+ return args.arguments[1];
+}
diff --git a/integration/bunjs-only-snippets/transpiler.test.js b/integration/bunjs-only-snippets/transpiler.test.js
index 8480dd091..34ec9f4aa 100644
--- a/integration/bunjs-only-snippets/transpiler.test.js
+++ b/integration/bunjs-only-snippets/transpiler.test.js
@@ -51,15 +51,42 @@ describe("Bun.Transpiler", () => {
});
describe("transform", () => {
+ it("supports macros", async () => {
+ const out = await transpiler.transform(`
+ import {keepSecondArgument} from 'macro:${
+ import.meta.dir
+ }/macro-check.js';
+
+ export default keepSecondArgument("Test failed", "Test passed");
+ `);
+ expect(out.includes("Test failed")).toBe(false);
+ expect(out.includes("Test passed")).toBe(true);
+
+ // ensure both the import and the macro function call are removed
+ expect(out.includes("keepSecondArgument")).toBe(false);
+ });
+
+ it("sync supports macros", async () => {
+ const out = transpiler.transformSync(`
+ import {keepSecondArgument} from 'macro:${
+ import.meta.dir
+ }/macro-check.js';
+
+ export default keepSecondArgument("Test failed", "Test passed");
+ `);
+ expect(out.includes("Test failed")).toBe(false);
+ expect(out.includes("Test passed")).toBe(true);
+
+ expect(out.includes("keepSecondArgument")).toBe(false);
+ });
+
it("removes types", () => {
expect(code.includes("ActionFunction")).toBe(true);
expect(code.includes("LoaderFunction")).toBe(true);
-
const out = transpiler.transformSync(code);
expect(out.includes("ActionFunction")).toBe(false);
expect(out.includes("LoaderFunction")).toBe(false);
-
const { exports } = transpiler.scan(out);
expect(exports[0]).toBe("action");
diff --git a/src/javascript/jsc/api/transpiler.zig b/src/javascript/jsc/api/transpiler.zig
index 0390be154..10d7bf72a 100644
--- a/src/javascript/jsc/api/transpiler.zig
+++ b/src/javascript/jsc/api/transpiler.zig
@@ -39,7 +39,7 @@ const Transpiler = @This();
const JSParser = @import("../../../js_parser.zig");
const JSPrinter = @import("../../../js_printer.zig");
const ScanPassResult = JSParser.ScanPassResult;
-
+const Mimalloc = @import("../../../mimalloc_arena.zig");
bundler: Bundler.Bundler,
arena: std.heap.ArenaAllocator,
transpiler_options: TranspilerOptions,
@@ -139,7 +139,6 @@ pub const TransformTask = struct {
pub fn run(this: *TransformTask) void {
const name = this.loader.stdinName();
const source = logger.Source.initPathString(name, this.input_code.slice());
- const Mimalloc = @import("../../../mimalloc_arena.zig");
JSAst.Stmt.Data.Store.create(_global.default_allocator);
JSAst.Expr.Data.Store.create(_global.default_allocator);
@@ -299,7 +298,8 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo
var array = JSC.C.JSObjectCopyPropertyNames(globalThis.ref(), define.asObjectRef());
defer JSC.C.JSPropertyNameArrayRelease(array);
const count = JSC.C.JSPropertyNameArrayGetCount(array);
- var map_entries = temp_allocator.alloc([]u8, count * 2) catch unreachable;
+ // cannot be a temporary because it may be loaded on different threads.
+ var map_entries = allocator.alloc([]u8, count * 2) catch unreachable;
var names = map_entries[0..count];
var values = map_entries[count..];
@@ -729,6 +729,18 @@ pub fn transformSync(
};
const code = code_holder.slice();
+ JSC.C.JSValueProtect(ctx, arguments[0]);
+ defer JSC.C.JSValueUnprotect(ctx, arguments[0]);
+ var arena = Mimalloc.Arena.init() catch unreachable;
+ this.bundler.setAllocator(arena.allocator());
+ var log = logger.Log.init(arena.backingAllocator());
+ this.bundler.setLog(&log);
+ defer {
+ this.bundler.setLog(&this.transpiler_options.log);
+ this.bundler.setAllocator(_global.default_allocator);
+ arena.deinit();
+ }
+
args.eat();
const loader: ?Loader = brk: {
if (args.next()) |arg| {
@@ -746,7 +758,7 @@ pub fn transformSync(
JSAst.Expr.Data.Store.reset();
}
- const parse_result = getParseResult(this, args.arena.allocator(), code, loader) orelse {
+ const parse_result = getParseResult(this, arena.allocator(), code, loader) orelse {
if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) {
var out_exception = this.bundler.log.toJS(ctx.ptr(), getAllocator(ctx), "Parse error");
exception.* = out_exception.asObjectRef();
@@ -767,26 +779,31 @@ pub fn transformSync(
exception.* = out_exception.asObjectRef();
return null;
}
- if (this.buffer_writer == null) {
- this.buffer_writer = JSPrinter.BufferWriter.init(_global.default_allocator) catch {
+
+ var buffer_writer = this.buffer_writer orelse brk: {
+ var writer = JSPrinter.BufferWriter.init(arena.backingAllocator()) catch {
JSC.throwInvalidArguments("Failed to create BufferWriter", .{}, ctx, exception);
return null;
};
- this.buffer_writer.?.buffer.growIfNeeded(code.len) catch unreachable;
- this.buffer_writer.?.buffer.list.expandToCapacity();
+ writer.buffer.growIfNeeded(code.len) catch unreachable;
+ writer.buffer.list.expandToCapacity();
+ break :brk writer;
+ };
+
+ defer {
+ this.buffer_writer = buffer_writer;
}
- this.buffer_writer.?.reset();
- var printer = JSPrinter.BufferPrinter.init(this.buffer_writer.?);
- const printed = this.bundler.print(parse_result, @TypeOf(printer), printer, .esm_ascii) catch |err| {
+ buffer_writer.reset();
+ var printer = JSPrinter.BufferPrinter.init(buffer_writer);
+ _ = this.bundler.print(parse_result, @TypeOf(&printer), &printer, .esm_ascii) catch |err| {
JSC.JSError(_global.default_allocator, "Failed to print code: {s}", .{@errorName(err)}, ctx, exception);
return null;
};
// TODO: benchmark if pooling this way is faster or moving is faster
- this.buffer_writer = printer.ctx;
- this.buffer_writer.?.buffer.list.expandToCapacity();
- var out = JSC.ZigString.init(this.buffer_writer.?.buffer.list.items[0..printed]);
+ buffer_writer = printer.ctx;
+ var out = JSC.ZigString.init(buffer_writer.written);
out.mark();
return out.toValueGC(ctx.ptr()).asObjectRef();
diff --git a/src/javascript/jsc/node/types.zig b/src/javascript/jsc/node/types.zig
index 31b467cd4..7e4927e78 100644
--- a/src/javascript/jsc/node/types.zig
+++ b/src/javascript/jsc/node/types.zig
@@ -151,10 +151,10 @@ pub const StringOrBuffer = union(Tag) {
JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject, JSC.JSValue.JSType.Object => {
var zig_str = JSC.ZigString.init("");
value.toZigString(&zig_str, global);
- if (zig_str.len == 0) {
- JSC.throwInvalidArguments("Expected string to have length > 0", .{}, global.ref(), exception);
- return null;
- }
+ // if (zig_str.len == 0) {
+ // JSC.throwInvalidArguments("Expected string to have length > 0", .{}, global.ref(), exception);
+ // return null;
+ // }
return StringOrBuffer{
.string = zig_str.slice(),