diff options
-rw-r--r-- | src/bun.js/api/bun.zig | 10 | ||||
-rw-r--r-- | src/bun.js/api/transpiler.classes.ts | 40 | ||||
-rw-r--r-- | src/bun.js/api/transpiler.zig | 394 |
3 files changed, 243 insertions, 201 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index d8506b6b5..d70de3aa9 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -2328,15 +2328,7 @@ pub fn getTranspilerConstructor( _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { - var existing = ctx.ptr().getCachedObject(ZigString.static("BunTranspiler")); - if (existing.isEmpty()) { - return ctx.ptr().putCachedObject( - &ZigString.init("BunTranspiler"), - JSC.JSValue.fromRef(Transpiler.Constructor.constructor(ctx)), - ).asObjectRef(); - } - - return existing.asObjectRef(); + return JSC.API.Bun.Transpiler.getConstructor(ctx).asObjectRef(); } pub fn getFileSystemRouter( diff --git a/src/bun.js/api/transpiler.classes.ts b/src/bun.js/api/transpiler.classes.ts new file mode 100644 index 000000000..d10090f35 --- /dev/null +++ b/src/bun.js/api/transpiler.classes.ts @@ -0,0 +1,40 @@ +import { define } from "../scripts/class-definitions"; + +export default [ + define({ + name: "Transpiler", + construct: true, + finalize: true, + hasPendingActivity: false, + klass: {}, + JSType: "0b11101110", + proto: { + scanImports: { + fn: "scanImports", + length: 2, + }, + scan: { + fn: "scan", + length: 2, + }, + transform: { + fn: "transform", + length: 2, + }, + transformSync: { + fn: "transformSync", + length: 2, + }, + }, + custom: { + onLoadPlugins: { + extraHeaderIncludes: ["BunPlugin.h"], + impl: "JSTranspiler+BunPlugin-impl.h", + type: `WTF::Vector<std::unique_ptr<BunPlugin::OnLoad>>`, + }, + onResolvePlugins: { + type: `WTF::Vector<std::unique_ptr<BunPlugin::OnResolve>>`, + }, + }, + }), +]; diff --git a/src/bun.js/api/transpiler.zig b/src/bun.js/api/transpiler.zig index 715c5137e..eb070b6bc 100644 --- a/src/bun.js/api/transpiler.zig +++ b/src/bun.js/api/transpiler.zig @@ -43,47 +43,14 @@ const Runtime = @import("../../runtime.zig").Runtime; const JSLexer = bun.js_lexer; const Expr = JSAst.Expr; +pub usingnamespace JSC.Codegen.JSTranspiler; + bundler: Bundler.Bundler, arena: std.heap.ArenaAllocator, transpiler_options: TranspilerOptions, scan_pass_result: ScanPassResult, buffer_writer: ?JSPrinter.BufferWriter = null, -pub const Class = NewClass( - Transpiler, - .{ .name = "Transpiler" }, - .{ - .scanImports = .{ - .rfn = scanImports, - }, - .scan = .{ - .rfn = scan, - }, - .transform = .{ - .rfn = transform, - }, - .transformSync = .{ - .rfn = transformSync, - }, - // .resolve = .{ - // .rfn = resolve, - // }, - // .buildSync = .{ - // .rfn = buildSync, - // }, - .finalize = finalize, - }, - .{}, -); - -pub const Constructor = JSC.NewConstructor( - @This(), - .{ - .constructor = .{ .rfn = constructor }, - }, - .{}, -); - const default_transform_options: Api.TransformOptions = brk: { var opts = std.mem.zeroes(Api.TransformOptions); opts.disable_hmr = true; @@ -130,11 +97,11 @@ pub const TransformTask = struct { pub const AsyncTransformTask = JSC.ConcurrentPromiseTask(TransformTask); pub const AsyncTransformEventLoopTask = AsyncTransformTask.EventLoopTask; - pub fn create(transpiler: *Transpiler, protected_input_value: JSC.C.JSValueRef, globalThis: *JSGlobalObject, input_code: ZigString, loader: Loader) !*AsyncTransformTask { + pub fn create(transpiler: *Transpiler, protected_input_value: JSC.JSValue, globalThis: *JSGlobalObject, input_code: ZigString, loader: Loader) !*AsyncTransformTask { var transform_task = try bun.default_allocator.create(TransformTask); transform_task.* = .{ .input_code = input_code, - .protected_input_value = if (protected_input_value != null) JSC.JSValue.fromRef(protected_input_value) else @intToEnum(JSC.JSValue, 0), + .protected_input_value = protected_input_value, .bundler = undefined, .global = globalThis, .macro_map = transpiler.transpiler_options.macro_map, @@ -335,8 +302,8 @@ fn exportReplacementValue(value: JSValue, globalThis: *JSGlobalObject) ?JSAst.Ex return null; } -fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allocator, args: *JSC.Node.ArgumentsSlice, exception: JSC.C.ExceptionRef) !TranspilerOptions { - var globalThis = ctx.ptr(); +fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std.mem.Allocator, args: *JSC.Node.ArgumentsSlice, exception: JSC.C.ExceptionRef) !TranspilerOptions { + var globalThis = globalObject; const object = args.next() orelse return TranspilerOptions{ .log = logger.Log.init(temp_allocator) }; if (object.isUndefinedOrNull()) return TranspilerOptions{ .log = logger.Log.init(temp_allocator) }; @@ -351,18 +318,18 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo transpiler.log.level = .warn; if (!object.isObject()) { - JSC.throwInvalidArguments("Expected an object", .{}, ctx, exception); + JSC.throwInvalidArguments("Expected an object", .{}, globalObject, exception); return transpiler; } - if (object.getIfPropertyExists(ctx.ptr(), "define")) |define| { + if (object.getIfPropertyExists(globalObject, "define")) |define| { define: { if (define.isUndefinedOrNull()) { break :define; } if (!define.isObject()) { - JSC.throwInvalidArguments("define must be an object", .{}, ctx, exception); + JSC.throwInvalidArguments("define must be an object", .{}, globalObject, exception); return transpiler; } @@ -384,7 +351,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo const value_type = property_value.jsType(); if (!value_type.isStringLike()) { - JSC.throwInvalidArguments("define \"{s}\" must be a JSON string", .{prop}, ctx, exception); + JSC.throwInvalidArguments("define \"{s}\" must be a JSON string", .{prop}, globalObject, exception); return transpiler; } @@ -425,7 +392,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo var i: usize = 0; while (iter.next()) |entry| { if (!entry.jsType().isStringLike()) { - JSC.throwInvalidArguments("external must be a string or string[]", .{}, ctx, exception); + JSC.throwInvalidArguments("external must be a string or string[]", .{}, globalObject, exception); return transpiler; } @@ -438,7 +405,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo transpiler.transform.external = externals[0..i]; } else { - JSC.throwInvalidArguments("external must be a string or string[]", .{}, ctx, exception); + JSC.throwInvalidArguments("external must be a string or string[]", .{}, globalObject, exception); return transpiler; } } @@ -447,7 +414,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo if (object.get(globalThis, "loader")) |loader| { if (Loader.fromJS(globalThis, loader, exception)) |resolved| { if (!resolved.isJavaScriptLike()) { - JSC.throwInvalidArguments("only JavaScript-like loaders supported for now", .{}, ctx, exception); + JSC.throwInvalidArguments("only JavaScript-like loaders supported for now", .{}, globalObject, exception); return transpiler; } @@ -476,7 +443,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo var out = JSC.ZigString.init(""); if (kind.isArray()) { - JSC.throwInvalidArguments("tsconfig must be a string or object", .{}, ctx, exception); + JSC.throwInvalidArguments("tsconfig must be a string or object", .{}, globalObject, exception); return transpiler; } @@ -514,7 +481,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo const kind = macros.jsType(); const is_object = kind.isObject(); if (!(kind.isStringLike() or is_object)) { - JSC.throwInvalidArguments("macro must be an object", .{}, ctx, exception); + JSC.throwInvalidArguments("macro must be an object", .{}, globalObject, exception); return transpiler; } @@ -554,7 +521,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo transpiler.runtime.jsx_optimization_hoist = flag.toBoolean(); if (!transpiler.runtime.jsx_optimization_inline and transpiler.runtime.jsx_optimization_hoist) { - JSC.throwInvalidArguments("jsxOptimizationHoist requires jsxOptimizationInline", .{}, ctx, exception); + JSC.throwInvalidArguments("jsxOptimizationHoist requires jsxOptimizationInline", .{}, globalObject, exception); return transpiler; } } @@ -579,7 +546,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo if (options.SourceMapOption.map.get(sourcemap.slice())) |source| { transpiler.transform.source_map = source.toAPI(); } else { - JSC.throwInvalidArguments("sourcemap must be one of \"inline\", \"external\", or \"none\"", .{}, ctx, exception); + JSC.throwInvalidArguments("sourcemap must be one of \"inline\", \"external\", or \"none\"", .{}, globalObject, exception); return transpiler; } } @@ -597,7 +564,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo if (object.getTruthy(globalThis, "exports")) |exports| { if (!exports.isObject()) { - JSC.throwInvalidArguments("exports must be an object", .{}, ctx, exception); + JSC.throwInvalidArguments("exports must be an object", .{}, globalObject, exception); return transpiler; } @@ -606,7 +573,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo if (exports.getTruthy(globalThis, "eliminate")) |eliminate| { if (!eliminate.jsType().isArray()) { - JSC.throwInvalidArguments("exports.eliminate must be an array", .{}, ctx, exception); + JSC.throwInvalidArguments("exports.eliminate must be an array", .{}, globalObject, exception); return transpiler; } @@ -634,7 +601,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo var str = value.getZigString(globalThis); if (str.len == 0) continue; const name = std.fmt.bufPrint(buf.items.ptr[buf.items.len..buf.capacity], "{}", .{str}) catch { - JSC.throwInvalidArguments("Error reading exports.eliminate. TODO: utf-16", .{}, ctx, exception); + JSC.throwInvalidArguments("Error reading exports.eliminate. TODO: utf-16", .{}, globalObject, exception); return transpiler; }; buf.items.len += name.len; @@ -648,7 +615,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo if (exports.getTruthy(globalThis, "replace")) |replace| { if (!replace.isObject()) { - JSC.throwInvalidArguments("replace must be an object", .{}, ctx, exception); + JSC.throwInvalidArguments("replace must be an object", .{}, globalObject, exception); return transpiler; } @@ -678,7 +645,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo var key = try key_.toOwnedSlice(bun.default_allocator); if (!JSLexer.isIdentifier(key)) { - JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{key}, ctx, exception); + JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{key}, globalObject, exception); bun.default_allocator.free(key); return transpiler; } @@ -690,7 +657,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo continue; } - if (value.isObject() and value.getLengthOfArray(ctx.ptr()) == 2) { + if (value.isObject() and value.getLengthOfArray(globalObject) == 2) { const replacementValue = JSC.JSObject.getIndex(value, globalThis, 1); if (exportReplacementValue(replacementValue, globalThis)) |to_replace| { const replacementKey = JSC.JSObject.getIndex(value, globalThis, 0); @@ -698,7 +665,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo var replacement_name = slice.slice(); if (!JSLexer.isIdentifier(replacement_name)) { - JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{replacement_name}, ctx, exception); + JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{replacement_name}, globalObject, exception); slice.deinit(); return transpiler; } @@ -713,7 +680,7 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo } } - JSC.throwInvalidArguments("exports.replace values can only be string, null, undefined, number or boolean", .{}, ctx, exception); + JSC.throwInvalidArguments("exports.replace values can only be string, null, undefined, number or boolean", .{}, globalObject, exception); return transpiler; } } @@ -730,48 +697,60 @@ fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allo } pub fn constructor( - ctx: js.JSContextRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - exception: js.ExceptionRef, -) js.JSObjectRef { - var temp = std.heap.ArenaAllocator.init(getAllocator(ctx)); - var args = JSC.Node.ArgumentsSlice.init(ctx.bunVM(), @ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]); + globalThis: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, +) callconv(.C) ?*Transpiler { + var temp = std.heap.ArenaAllocator.init(getAllocator(globalThis)); + const arguments = callframe.arguments(3); + var args = JSC.Node.ArgumentsSlice.init( + globalThis.bunVM(), + arguments.ptr[0..arguments.len], + ); + defer temp.deinit(); + var exception_ref = [_]JSC.C.JSValueRef{null}; + var exception = &exception_ref[0]; const transpiler_options: TranspilerOptions = if (arguments.len > 0) - transformOptionsFromJSC(ctx, temp.allocator(), &args, exception) catch { - JSC.throwInvalidArguments("Failed to create transpiler", .{}, ctx, exception); + transformOptionsFromJSC(globalThis, temp.allocator(), &args, exception) catch { + JSC.throwInvalidArguments("Failed to create transpiler", .{}, globalThis, exception); return null; } else - TranspilerOptions{ .log = logger.Log.init(getAllocator(ctx)) }; + TranspilerOptions{ .log = logger.Log.init(getAllocator(globalThis)) }; if (exception.* != null) { + globalThis.throwValue(JSC.JSValue.c(exception.*)); return null; } + const allocator = getAllocator(globalThis); + if ((transpiler_options.log.warnings + transpiler_options.log.errors) > 0) { - var out_exception = transpiler_options.log.toJS(ctx.ptr(), getAllocator(ctx), "Failed to create transpiler"); - exception.* = out_exception.asObjectRef(); + globalThis.throwValue( + transpiler_options.log.toJS(globalThis.ptr(), allocator, "Failed to create transpiler"), + ); + return null; } - var log = getAllocator(ctx).create(logger.Log) catch unreachable; + var log = allocator.create(logger.Log) catch unreachable; log.* = transpiler_options.log; var bundler = Bundler.Bundler.init( - getAllocator(ctx), + allocator, log, transpiler_options.transform, null, JavaScript.VirtualMachine.get().bundler.env, ) catch |err| { if ((log.warnings + log.errors) > 0) { - var out_exception = log.toJS(ctx.ptr(), getAllocator(ctx), "Failed to create transpiler"); - exception.* = out_exception.asObjectRef(); + globalThis.throwValue( + log.toJS(globalThis.ptr(), allocator, "Failed to create transpiler"), + ); + return null; } - JSC.throwInvalidArguments("Error creating transpiler: {s}", .{@errorName(err)}, ctx, exception); + globalThis.throwError(err, "Error creating transpiler"); return null; }; @@ -779,12 +758,14 @@ pub fn constructor( bundler.options.env.behavior = .disable; bundler.configureDefines() catch |err| { if ((log.warnings + log.errors) > 0) { - var out_exception = log.toJS(ctx.ptr(), getAllocator(ctx), "Failed to load define"); - exception.* = out_exception.asObjectRef(); + globalThis.throwValue( + log.toJS(globalThis.ptr(), allocator, "Failed to load define"), + ); + return null; } - JSC.throwInvalidArguments("Failed to load define: {s}", .{@errorName(err)}, ctx, exception); + globalThis.throwError(err, "Failed to load define"); return null; }; @@ -802,20 +783,20 @@ pub fn constructor( bundler.options.jsx.supports_fast_refresh = bundler.options.hot_module_reloading and bundler.options.allow_runtime and transpiler_options.runtime.react_fast_refresh; - var transpiler = getAllocator(ctx).create(Transpiler) catch unreachable; + var transpiler = allocator.create(Transpiler) catch unreachable; transpiler.* = Transpiler{ .transpiler_options = transpiler_options, .bundler = bundler, .arena = args.arena, - .scan_pass_result = ScanPassResult.init(getAllocator(ctx)), + .scan_pass_result = ScanPassResult.init(allocator), }; - return Class.make(ctx, transpiler); + return transpiler; } pub fn finalize( this: *Transpiler, -) void { +) callconv(.C) void { this.bundler.log.deinit(); this.scan_pass_result.named_imports.deinit(); this.scan_pass_result.import_records.deinit(); @@ -827,6 +808,7 @@ pub fn finalize( // bun.default_allocator.free(this.transpiler_options.tsconfig_buf); // bun.default_allocator.free(this.transpiler_options.macros_buf); this.arena.deinit(); + JSC.VirtualMachine.get().allocator.destroy(this); } fn getParseResult(this: *Transpiler, allocator: std.mem.Allocator, code: []const u8, loader: ?Loader, macro_js_ctx: Bundler.MacroJSValueType) ?Bundler.ParseResult { @@ -869,37 +851,41 @@ fn getParseResult(this: *Transpiler, allocator: std.mem.Allocator, code: []const pub fn scan( this: *Transpiler, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - exception: js.ExceptionRef, -) JSC.C.JSObjectRef { + globalThis: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, +) callconv(.C) JSC.JSValue { JSC.markBinding(@src()); - var args = JSC.Node.ArgumentsSlice.init(ctx.bunVM(), @ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]); + const arguments = callframe.arguments(3); + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.ptr[0..arguments.len]); defer args.arena.deinit(); const code_arg = args.next() orelse { - JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception); - return null; + globalThis.throwInvalidArgumentType("scan", "code", "string or Uint8Array"); + return .zero; }; - const code_holder = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), args.arena.allocator(), code_arg, exception) orelse { - if (exception.* == null) JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception); - return null; + const code_holder = JSC.Node.SliceOrBuffer.fromJS(globalThis, args.arena.allocator(), code_arg) orelse { + globalThis.throwInvalidArgumentType("scan", "code", "string or Uint8Array"); + return .zero; }; const code = code_holder.slice(); args.eat(); + var exception_ref = [_]JSC.C.JSValueRef{null}; + var exception: JSC.C.ExceptionRef = &exception_ref; + const loader: ?Loader = brk: { if (args.next()) |arg| { args.eat(); - break :brk Loader.fromJS(ctx.ptr(), arg, exception); + break :brk Loader.fromJS(globalThis, arg, exception); } break :brk null; }; - if (exception.* != null) return null; + if (exception.* != null) { + globalThis.throwValue(JSC.JSValue.c(exception.*)); + return .zero; + } var arena = Mimalloc.Arena.init() catch unreachable; var prev_allocator = this.bundler.allocator; @@ -920,34 +906,36 @@ pub fn scan( const parse_result = getParseResult(this, arena.allocator(), code, loader, Bundler.MacroJSValueType.zero) 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(); - return null; + globalThis.throwValue(this.bundler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); + return .zero; } - JSC.throwInvalidArguments("Failed to parse", .{}, ctx, exception); - return null; + globalThis.throw("Failed to parse", .{}); + return .zero; }; 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(); - return null; + globalThis.throwValue(this.bundler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); + return .zero; } - const exports_label = JSC.ZigString.init("exports"); - const imports_label = JSC.ZigString.init("imports"); + const exports_label = JSC.ZigString.static("exports"); + const imports_label = JSC.ZigString.static("imports"); const named_imports_value = namedImportsToJS( - ctx.ptr(), + globalThis, parse_result.ast.import_records, exception, ); - if (exception.* != null) return null; - var named_exports_value = namedExportsToJS( - ctx.ptr(), + if (exception.* != null) { + globalThis.throwValue(JSC.JSValue.c(exception.*)); + return .zero; + } + + const named_exports_value = namedExportsToJS( + globalThis, parse_result.ast.named_exports, ); - return JSC.JSValue.createObject2(ctx.ptr(), &imports_label, &exports_label, named_imports_value, named_exports_value).asObjectRef(); + return JSC.JSValue.createObject2(globalThis, imports_label, exports_label, named_imports_value, named_exports_value); } // pub fn build( @@ -961,24 +949,23 @@ pub fn scan( pub fn transform( this: *Transpiler, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - exception: js.ExceptionRef, -) JSC.C.JSObjectRef { + globalThis: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, +) callconv(.C) JSC.JSValue { JSC.markBinding(@src()); - - var args = JSC.Node.ArgumentsSlice.init(ctx.bunVM(), @ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]); + var exception_ref = [_]JSC.C.JSValueRef{null}; + var exception: JSC.C.ExceptionRef = &exception_ref; + const arguments = callframe.arguments(3); + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.ptr[0..arguments.len]); defer args.arena.deinit(); const code_arg = args.next() orelse { - JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception); - return null; + globalThis.throwInvalidArgumentType("transform", "code", "string or Uint8Array"); + return .zero; }; - const code_holder = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), this.arena.allocator(), code_arg, exception) orelse { - if (exception.* == null) JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception); - return null; + const code_holder = JSC.Node.StringOrBuffer.fromJS(globalThis, this.arena.allocator(), code_arg, exception) orelse { + globalThis.throwInvalidArgumentType("transform", "code", "string or Uint8Array"); + return .zero; }; const code = code_holder.slice(); @@ -986,47 +973,62 @@ pub fn transform( const loader: ?Loader = brk: { if (args.next()) |arg| { args.eat(); - break :brk Loader.fromJS(ctx.ptr(), arg, exception); + break :brk Loader.fromJS(globalThis, arg, exception); } break :brk null; }; - if (exception.* != null) return null; + if (exception.* != null) { + globalThis.throwValue(JSC.JSValue.c(exception.*)); + return .zero; + } + if (code_holder == .string) { - JSC.C.JSValueProtect(ctx, arguments[0]); + arguments.ptr[0].ensureStillAlive(); } - var task = TransformTask.create(this, if (code_holder == .string) arguments[0] else null, ctx.ptr(), ZigString.init(code), loader orelse this.transpiler_options.default_loader) catch return null; + var task = TransformTask.create( + this, + if (code_holder == .string) arguments.ptr[0] else .zero, + globalThis, + ZigString.init(code), + loader orelse this.transpiler_options.default_loader, + ) catch { + globalThis.throw("Out of memory", .{}); + return .zero; + }; task.schedule(); - return task.promise.value().asObjectRef(); + return task.promise.value(); } pub fn transformSync( this: *Transpiler, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - exception: js.ExceptionRef, -) JSC.C.JSObjectRef { - var args = JSC.Node.ArgumentsSlice.init(ctx.bunVM(), @ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]); + globalThis: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, +) callconv(.C) JSC.JSValue { + JSC.markBinding(@src()); + var exception_value = [_]JSC.C.JSValueRef{null}; + var exception: JSC.C.ExceptionRef = &exception_value; + const arguments = callframe.arguments(3); + + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.ptr[0..arguments.len]); defer args.arena.deinit(); const code_arg = args.next() orelse { - JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception); - return null; + globalThis.throwInvalidArgumentType("transformSync", "code", "string or Uint8Array"); + return .zero; }; var arena = Mimalloc.Arena.init() catch unreachable; defer arena.deinit(); - const code_holder = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), arena.allocator(), code_arg, exception) orelse { - if (exception.* == null) JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception); - return null; + const code_holder = JSC.Node.StringOrBuffer.fromJS(globalThis, arena.allocator(), code_arg, exception) orelse { + globalThis.throwInvalidArgumentType("transformSync", "code", "string or Uint8Array"); + return .zero; }; const code = code_holder.slice(); - JSC.JSValue.c(arguments[0]).ensureStillAlive(); - defer JSC.JSValue.c(arguments[0]).ensureStillAlive(); + arguments.ptr[0].ensureStillAlive(); + defer arguments.ptr[0].ensureStillAlive(); args.eat(); var js_ctx_value: JSC.JSValue = JSC.JSValue.zero; @@ -1034,7 +1036,7 @@ pub fn transformSync( if (args.next()) |arg| { args.eat(); if (arg.isNumber() or arg.isString()) { - break :brk Loader.fromJS(ctx.ptr(), arg, exception); + break :brk Loader.fromJS(globalThis, arg, exception); } if (arg.isObject()) { @@ -1050,8 +1052,8 @@ pub fn transformSync( if (arg.isObject()) { js_ctx_value = arg; } else { - JSC.throwInvalidArguments("Expected a Loader or object", .{}, ctx, exception); - return null; + globalThis.throwInvalidArgumentType("transformSync", "context", "object or loader"); + return .zero; } } if (!js_ctx_value.isEmpty()) { @@ -1064,7 +1066,10 @@ pub fn transformSync( } } - if (exception.* != null) return null; + if (exception.* != null) { + globalThis.throwValue(JSC.JSValue.c(exception.*)); + return .zero; + } JSAst.Stmt.Data.Store.reset(); JSAst.Expr.Data.Store.reset(); @@ -1090,25 +1095,23 @@ pub fn transformSync( if (comptime JSC.is_bindgen) Bundler.MacroJSValueType.zero else js_ctx_value, ) 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(); - return null; + globalThis.throwValue(this.bundler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); + return .zero; } - JSC.throwInvalidArguments("Failed to parse", .{}, ctx, exception); - return null; + globalThis.throw("Failed to parse code", .{}); + return .zero; }; 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(); - return null; + globalThis.throwValue(this.bundler.log.toJS(globalThis, globalThis.allocator(), "Parse error")); + return .zero; } 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; + globalThis.throw("Failed to create BufferWriter", .{}); + return .zero; }; writer.buffer.growIfNeeded(code.len) catch unreachable; @@ -1123,18 +1126,16 @@ pub fn transformSync( buffer_writer.reset(); var printer = JSPrinter.BufferPrinter.init(buffer_writer); _ = this.bundler.print(parse_result, @TypeOf(&printer), &printer, .esm_ascii) catch |err| { - JSC.JSError(bun.default_allocator, "Failed to print code: {s}", .{@errorName(err)}, ctx, exception); - - return null; + globalThis.throwError(err, "Failed to print code"); + return .zero; }; // TODO: benchmark if pooling this way is faster or moving is faster buffer_writer = printer.ctx; var out = JSC.ZigString.init(buffer_writer.written); - out.mark(); out.setOutputEncoding(); - return out.toValueGC(ctx.ptr()).asObjectRef(); + return out.toValueGC(globalThis); } fn namedExportsToJS(global: *JSGlobalObject, named_exports: JSAst.Ast.NamedExports) JSC.JSValue { @@ -1169,8 +1170,8 @@ fn namedImportsToJS( var allocator = stack_fallback.get(); var i: usize = 0; - const path_label = JSC.ZigString.init("path"); - const kind_label = JSC.ZigString.init("kind"); + const path_label = JSC.ZigString.static("path"); + const kind_label = JSC.ZigString.static("kind"); var array_items = allocator.alloc( JSC.C.JSValueRef, import_records.len, @@ -1182,7 +1183,7 @@ fn namedImportsToJS( const path = JSC.ZigString.init(record.path.text).toValueGC(global); const kind = JSC.ZigString.init(record.kind.label()).toValue(global); - array_items[i] = JSC.JSValue.createObject2(global, &path_label, &kind_label, path, kind).asObjectRef(); + array_items[i] = JSC.JSValue.createObject2(global, path_label, kind_label, path, kind).asObjectRef(); i += 1; } @@ -1191,39 +1192,47 @@ fn namedImportsToJS( pub fn scanImports( this: *Transpiler, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - exception: js.ExceptionRef, -) JSC.C.JSObjectRef { - var args = JSC.Node.ArgumentsSlice.init(ctx.bunVM(), @ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]); + globalThis: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, +) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(2); + var exception_val = [_]JSC.C.JSValueRef{null}; + var exception: JSC.C.ExceptionRef = &exception_val; + var args = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments.ptr[0..arguments.len]); const code_arg = args.next() orelse { - JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception); - return null; + globalThis.throwInvalidArgumentType("scanImports", "code", "string or Uint8Array"); + return .zero; }; - const code_holder = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), args.arena.allocator(), code_arg, exception) orelse { - if (exception.* == null) JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception); - return null; + const code_holder = JSC.Node.StringOrBuffer.fromJS(globalThis, args.arena.allocator(), code_arg, exception) orelse { + if (exception.* == null) { + globalThis.throwInvalidArgumentType("scanImports", "code", "string or Uint8Array"); + } else { + globalThis.throwValue(JSC.JSValue.c(exception.*)); + } + + return .zero; }; args.eat(); const code = code_holder.slice(); var loader: Loader = this.transpiler_options.default_loader; if (args.next()) |arg| { - if (Loader.fromJS(ctx.ptr(), arg, exception)) |_loader| { + if (Loader.fromJS(globalThis, arg, exception)) |_loader| { loader = _loader; } args.eat(); } if (!loader.isJavaScriptLike()) { - JSC.throwInvalidArguments("Only JavaScript-like files support this fast path", .{}, ctx, exception); - return null; + globalThis.throwInvalidArguments("Only JavaScript-like files support this fast path", .{}); + return .zero; } - if (exception.* != null) return null; + if (exception.* != null) { + globalThis.throwValue(JSC.JSValue.c(exception.*)); + return .zero; + } var arena = Mimalloc.Arena.init() catch unreachable; var prev_allocator = this.bundler.allocator; @@ -1268,28 +1277,29 @@ pub fn scanImports( ) catch |err| { defer this.scan_pass_result.reset(); if ((log.warnings + log.errors) > 0) { - var out_exception = log.toJS(ctx.ptr(), getAllocator(ctx), "Failed to scan imports"); - exception.* = out_exception.asObjectRef(); - return null; + globalThis.throwValue(log.toJS(globalThis, globalThis.allocator(), "Failed to scan imports")); + return .zero; } - JSC.throwInvalidArguments("Failed to scan imports: {s}", .{@errorName(err)}, ctx, exception); - return null; + globalThis.throwError(err, "Failed to scan imports"); + return .zero; }; defer this.scan_pass_result.reset(); if ((log.warnings + log.errors) > 0) { - var out_exception = log.toJS(ctx.ptr(), getAllocator(ctx), "Failed to scan imports"); - exception.* = out_exception.asObjectRef(); - return null; + globalThis.throwValue(log.toJS(globalThis, globalThis.allocator(), "Failed to scan imports")); + return .zero; } const named_imports_value = namedImportsToJS( - ctx.ptr(), + globalThis, this.scan_pass_result.import_records.items, exception, ); - if (exception.* != null) return null; - return named_imports_value.asObjectRef(); + if (exception.* != null) { + globalThis.throwValue(JSC.JSValue.c(exception.*)); + return .zero; + } + return named_imports_value; } |