aboutsummaryrefslogtreecommitdiff
path: root/src/javascript/jsc/api/transpiler.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/javascript/jsc/api/transpiler.zig')
-rw-r--r--src/javascript/jsc/api/transpiler.zig1304
1 files changed, 0 insertions, 1304 deletions
diff --git a/src/javascript/jsc/api/transpiler.zig b/src/javascript/jsc/api/transpiler.zig
deleted file mode 100644
index 69732c643..000000000
--- a/src/javascript/jsc/api/transpiler.zig
+++ /dev/null
@@ -1,1304 +0,0 @@
-const std = @import("std");
-const Api = @import("../../../api/schema.zig").Api;
-const FilesystemRouter = @import("../../../router.zig");
-const http = @import("../../../http.zig");
-const JavaScript = @import("../javascript.zig");
-const QueryStringMap = @import("../../../url.zig").QueryStringMap;
-const CombinedScanner = @import("../../../url.zig").CombinedScanner;
-const bun = @import("../../../global.zig");
-const string = bun.string;
-const JSC = @import("../../../jsc.zig");
-const js = JSC.C;
-const WebCore = @import("../webcore/response.zig");
-const Bundler = @import("../../../bundler.zig");
-const options = @import("../../../options.zig");
-const VirtualMachine = JavaScript.VirtualMachine;
-const ScriptSrcStream = std.io.FixedBufferStream([]u8);
-const ZigString = JSC.ZigString;
-const Fs = @import("../../../fs.zig");
-const Base = @import("../base.zig");
-const getAllocator = Base.getAllocator;
-const JSObject = JSC.JSObject;
-const JSError = Base.JSError;
-const JSValue = JSC.JSValue;
-const JSGlobalObject = JSC.JSGlobalObject;
-const strings = @import("strings");
-const NewClass = Base.NewClass;
-const To = Base.To;
-const Request = WebCore.Request;
-const d = Base.d;
-const FetchEvent = WebCore.FetchEvent;
-const MacroMap = @import("../../../resolver/package_json.zig").MacroMap;
-const TSConfigJSON = @import("../../../resolver/tsconfig_json.zig").TSConfigJSON;
-const PackageJSON = @import("../../../resolver/package_json.zig").PackageJSON;
-const logger = @import("../../../logger.zig");
-const Loader = options.Loader;
-const Platform = options.Platform;
-const JSAst = @import("../../../js_ast.zig");
-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");
-const Runtime = @import("../../../runtime.zig").Runtime;
-const JSLexer = @import("../../../js_lexer.zig");
-const Expr = JSAst.Expr;
-
-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;
- opts.platform = Api.Platform.browser;
- opts.serve = false;
- break :brk opts;
-};
-
-const TranspilerOptions = struct {
- transform: Api.TransformOptions = default_transform_options,
- default_loader: options.Loader = options.Loader.jsx,
- macro_map: MacroMap = MacroMap{},
- tsconfig: ?*TSConfigJSON = null,
- tsconfig_buf: []const u8 = "",
- macros_buf: []const u8 = "",
- log: logger.Log,
- runtime: Runtime.Features = Runtime.Features{ .top_level_await = true },
- tree_shaking: bool = false,
- trim_unused_imports: ?bool = null,
-};
-
-// Mimalloc gets unstable if we try to move this to a different thread
-// threadlocal var transform_buffer: bun.MutableString = undefined;
-// threadlocal var transform_buffer_loaded: bool = false;
-
-// This is going to be hard to not leak
-pub const TransformTask = struct {
- input_code: ZigString = ZigString.init(""),
- protected_input_value: JSC.JSValue = @intToEnum(JSC.JSValue, 0),
- output_code: ZigString = ZigString.init(""),
- bundler: Bundler.Bundler = undefined,
- log: logger.Log,
- err: ?anyerror = null,
- macro_map: MacroMap = MacroMap{},
- tsconfig: ?*TSConfigJSON = null,
- loader: Loader,
- global: *JSGlobalObject,
- replace_exports: Runtime.Features.ReplaceableExport.Map = .{},
-
- 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 {
- 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),
- .bundler = undefined,
- .global = globalThis,
- .macro_map = transpiler.transpiler_options.macro_map,
- .tsconfig = transpiler.transpiler_options.tsconfig,
- .log = logger.Log.init(bun.default_allocator),
- .loader = loader,
- .replace_exports = transpiler.transpiler_options.runtime.replace_exports,
- };
- transform_task.bundler = transpiler.bundler;
- transform_task.bundler.linker.resolver = &transform_task.bundler.resolver;
-
- transform_task.bundler.setLog(&transform_task.log);
- transform_task.bundler.setAllocator(bun.default_allocator);
- return try AsyncTransformTask.createOnJSThread(bun.default_allocator, globalThis, transform_task);
- }
-
- pub fn run(this: *TransformTask) void {
- const name = this.loader.stdinName();
- const source = logger.Source.initPathString(name, this.input_code.slice());
-
- JSAst.Stmt.Data.Store.create(bun.default_allocator);
- JSAst.Expr.Data.Store.create(bun.default_allocator);
-
- var arena = Mimalloc.Arena.init() catch unreachable;
-
- const allocator = arena.allocator();
-
- defer {
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
- arena.deinit();
- }
-
- this.bundler.setAllocator(allocator);
- const jsx = if (this.tsconfig != null)
- this.tsconfig.?.mergeJSX(this.bundler.options.jsx)
- else
- this.bundler.options.jsx;
-
- const parse_options = Bundler.Bundler.ParseOptions{
- .allocator = allocator,
- .macro_remappings = this.macro_map,
- .dirname_fd = 0,
- .file_descriptor = null,
- .loader = this.loader,
- .jsx = jsx,
- .path = source.path,
- .virtual_source = &source,
- .replace_exports = this.replace_exports,
- // .allocator = this.
- };
-
- const parse_result = this.bundler.parse(parse_options, null) orelse {
- this.err = error.ParseError;
- return;
- };
-
- if (parse_result.empty) {
- this.output_code = ZigString.init("");
- return;
- }
-
- var global_allocator = arena.backingAllocator();
- var buffer_writer = JSPrinter.BufferWriter.init(global_allocator) catch |err| {
- this.err = err;
- return;
- };
- buffer_writer.buffer.list.ensureTotalCapacity(global_allocator, 512) catch unreachable;
- buffer_writer.reset();
-
- // defer {
- // transform_buffer = buffer_writer.buffer;
- // }
-
- var printer = JSPrinter.BufferPrinter.init(buffer_writer);
- const printed = this.bundler.print(parse_result, @TypeOf(&printer), &printer, .esm_ascii) catch |err| {
- this.err = err;
- return;
- };
-
- if (printed > 0) {
- buffer_writer = printer.ctx;
- buffer_writer.buffer.list.items = buffer_writer.written;
-
- var output = JSC.ZigString.init(buffer_writer.written);
- output.mark();
- this.output_code = output;
- } else {
- this.output_code = ZigString.init("");
- }
- }
-
- pub fn then(this: *TransformTask, promise: *JSC.JSInternalPromise) void {
- if (this.log.hasAny() or this.err != null) {
- const error_value: JSValue = brk: {
- if (this.err) |err| {
- if (!this.log.hasAny()) {
- break :brk JSC.JSValue.fromRef(JSC.BuildError.create(
- this.global,
- bun.default_allocator,
- logger.Msg{
- .data = logger.Data{ .text = std.mem.span(@errorName(err)) },
- },
- ));
- }
- }
-
- break :brk this.log.toJS(this.global, bun.default_allocator, "Transform failed");
- };
-
- promise.reject(this.global, error_value);
- return;
- }
-
- finish(this.output_code, this.global, promise);
-
- if (@enumToInt(this.protected_input_value) != 0) {
- this.protected_input_value = @intToEnum(JSC.JSValue, 0);
- }
- this.deinit();
- }
-
- noinline fn finish(code: ZigString, global: *JSGlobalObject, promise: *JSC.JSInternalPromise) void {
- promise.resolve(global, code.toValueGC(global));
- }
-
- pub fn deinit(this: *TransformTask) void {
- var should_cleanup = false;
- defer if (should_cleanup) bun.Global.mimalloc_cleanup(false);
-
- this.log.deinit();
- if (this.input_code.isGloballyAllocated()) {
- this.input_code.deinitGlobal();
- }
-
- if (this.output_code.isGloballyAllocated()) {
- should_cleanup = this.output_code.len > 512_000;
- this.output_code.deinitGlobal();
- }
-
- bun.default_allocator.destroy(this);
- }
-};
-
-fn exportReplacementValue(value: JSValue, globalThis: *JSGlobalObject) ?JSAst.Expr {
- if (value.isBoolean()) {
- return Expr{
- .data = .{
- .e_boolean = .{
- .value = value.toBoolean(),
- },
- },
- .loc = logger.Loc.Empty,
- };
- }
-
- if (value.isNumber()) {
- return Expr{
- .data = .{
- .e_number = .{ .value = value.asNumber() },
- },
- .loc = logger.Loc.Empty,
- };
- }
-
- if (value.isNull()) {
- return Expr{
- .data = .{
- .e_null = .{},
- },
- .loc = logger.Loc.Empty,
- };
- }
-
- if (value.isUndefined()) {
- return Expr{
- .data = .{
- .e_undefined = .{},
- },
- .loc = logger.Loc.Empty,
- };
- }
-
- if (value.isString()) {
- var str = JSAst.E.String{
- .data = std.fmt.allocPrint(bun.default_allocator, "{}", .{value.getZigString(globalThis)}) catch unreachable,
- };
- var out = bun.default_allocator.create(JSAst.E.String) catch unreachable;
- out.* = str;
- return Expr{
- .data = .{
- .e_string = out,
- },
- .loc = logger.Loc.Empty,
- };
- }
-
- 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();
- const object = args.next() orelse return TranspilerOptions{ .log = logger.Log.init(temp_allocator) };
- if (object.isUndefinedOrNull()) return TranspilerOptions{ .log = logger.Log.init(temp_allocator) };
-
- args.eat();
- var allocator = args.arena.allocator();
-
- var transpiler = TranspilerOptions{
- .default_loader = .jsx,
- .transform = default_transform_options,
- .log = logger.Log.init(allocator),
- };
- transpiler.log.level = .warn;
-
- if (!object.isObject()) {
- JSC.throwInvalidArguments("Expected an object", .{}, ctx, exception);
- return transpiler;
- }
-
- if (object.getIfPropertyExists(ctx.ptr(), "define")) |define| {
- define: {
- if (define.isUndefinedOrNull()) {
- break :define;
- }
-
- if (!define.isObject()) {
- JSC.throwInvalidArguments("define must be an object", .{}, ctx, exception);
- return transpiler;
- }
-
- var array = JSC.C.JSObjectCopyPropertyNames(globalThis.ref(), define.asObjectRef());
- defer JSC.C.JSPropertyNameArrayRelease(array);
- const count = JSC.C.JSPropertyNameArrayGetCount(array);
- // 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..];
-
- var i: usize = 0;
- while (i < count) : (i += 1) {
- var property_name_ref = JSC.C.JSPropertyNameArrayGetNameAtIndex(
- array,
- i,
- );
- defer JSC.C.JSStringRelease(property_name_ref);
- const prop: []const u8 = JSC.C.JSStringGetCharacters8Ptr(property_name_ref)[0..JSC.C.JSStringGetLength(property_name_ref)];
- const property_value: JSC.JSValue = JSC.JSValue.fromRef(
- JSC.C.JSObjectGetProperty(
- globalThis.ref(),
- define.asObjectRef(),
- property_name_ref,
- null,
- ),
- );
- const value_type = property_value.jsType();
-
- if (!value_type.isStringLike()) {
- JSC.throwInvalidArguments("define \"{s}\" must be a JSON string", .{prop}, ctx, exception);
- return transpiler;
- }
- names[i] = allocator.dupe(u8, prop) catch unreachable;
- var val = JSC.ZigString.init("");
- property_value.toZigString(&val, globalThis);
- if (val.len == 0) {
- val = JSC.ZigString.init("\"\"");
- }
- values[i] = std.fmt.allocPrint(allocator, "{}", .{val}) catch unreachable;
- }
- transpiler.transform.define = Api.StringMap{
- .keys = names,
- .values = values,
- };
- }
- }
-
- if (object.get(globalThis, "external")) |external| {
- external: {
- if (external.isUndefinedOrNull()) break :external;
-
- const toplevel_type = external.jsType();
- if (toplevel_type.isStringLike()) {
- var zig_str = JSC.ZigString.init("");
- external.toZigString(&zig_str, globalThis);
- if (zig_str.len == 0) break :external;
- var single_external = allocator.alloc(string, 1) catch unreachable;
- single_external[0] = std.fmt.allocPrint(allocator, "{}", .{external}) catch unreachable;
- transpiler.transform.external = single_external;
- } else if (toplevel_type.isArray()) {
- const count = external.getLengthOfArray(globalThis);
- if (count == 0) break :external;
-
- var externals = allocator.alloc(string, count) catch unreachable;
- var iter = external.arrayIterator(globalThis);
- var i: usize = 0;
- while (iter.next()) |entry| {
- if (!entry.jsType().isStringLike()) {
- JSC.throwInvalidArguments("external must be a string or string[]", .{}, ctx, exception);
- return transpiler;
- }
-
- var zig_str = JSC.ZigString.init("");
- entry.toZigString(&zig_str, globalThis);
- if (zig_str.len == 0) continue;
- externals[i] = std.fmt.allocPrint(allocator, "{}", .{external}) catch unreachable;
- i += 1;
- }
-
- transpiler.transform.external = externals[0..i];
- } else {
- JSC.throwInvalidArguments("external must be a string or string[]", .{}, ctx, exception);
- return transpiler;
- }
- }
- }
-
- 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);
- return transpiler;
- }
-
- transpiler.default_loader = resolved;
- }
-
- if (exception.* != null) {
- return transpiler;
- }
- }
-
- if (object.get(globalThis, "platform")) |platform| {
- if (Platform.fromJS(globalThis, platform, exception)) |resolved| {
- transpiler.transform.platform = resolved.toAPI();
- }
-
- if (exception.* != null) {
- return transpiler;
- }
- }
-
- if (object.get(globalThis, "tsconfig")) |tsconfig| {
- tsconfig: {
- if (tsconfig.isUndefinedOrNull()) break :tsconfig;
- const kind = tsconfig.jsType();
- var out = JSC.ZigString.init("");
-
- if (kind.isArray()) {
- JSC.throwInvalidArguments("tsconfig must be a string or object", .{}, ctx, exception);
- return transpiler;
- }
-
- if (!kind.isStringLike()) {
- tsconfig.jsonStringify(globalThis, 0, &out);
- } else {
- tsconfig.toZigString(&out, globalThis);
- }
-
- if (out.len == 0) break :tsconfig;
- transpiler.tsconfig_buf = std.fmt.allocPrint(allocator, "{}", .{out}) catch unreachable;
-
- // TODO: JSC -> Ast conversion
- if (TSConfigJSON.parse(
- allocator,
- &transpiler.log,
- logger.Source.initPathString("tsconfig.json", transpiler.tsconfig_buf),
- &VirtualMachine.vm.bundler.resolver.caches.json,
- true,
- ) catch null) |parsed_tsconfig| {
- transpiler.tsconfig = parsed_tsconfig;
- }
- }
- }
-
- transpiler.runtime.allow_runtime = false;
-
- if (object.getIfPropertyExists(globalThis, "macro")) |macros| {
- macros: {
- if (macros.isUndefinedOrNull()) break :macros;
- const kind = macros.jsType();
- const is_object = kind.isObject();
- if (!(kind.isStringLike() or is_object)) {
- JSC.throwInvalidArguments("macro must be an object", .{}, ctx, exception);
- return transpiler;
- }
-
- var out: ZigString = ZigString.init("");
- // TODO: write a converter between JSC types and Bun AST types
- if (is_object) {
- macros.jsonStringify(globalThis, 0, &out);
- } else {
- macros.toZigString(&out, globalThis);
- }
-
- if (out.len == 0) break :macros;
- transpiler.macros_buf = std.fmt.allocPrint(allocator, "{}", .{out}) catch unreachable;
- const source = logger.Source.initPathString("macros.json", transpiler.macros_buf);
- const json = (VirtualMachine.vm.bundler.resolver.caches.json.parseJSON(
- &transpiler.log,
- source,
- allocator,
- ) catch null) orelse break :macros;
- transpiler.macro_map = PackageJSON.parseMacrosJSON(allocator, json, &transpiler.log, &source);
- }
- }
-
- if (object.get(globalThis, "autoImportJSX")) |flag| {
- transpiler.runtime.auto_import_jsx = flag.toBoolean();
- }
-
- if (object.get(globalThis, "allowBunRuntime")) |flag| {
- transpiler.runtime.allow_runtime = flag.toBoolean();
- }
-
- if (object.get(globalThis, "jsxOptimizationInline")) |flag| {
- transpiler.runtime.jsx_optimization_inline = flag.toBoolean();
- }
-
- if (object.get(globalThis, "jsxOptimizationHoist")) |flag| {
- 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);
- return transpiler;
- }
- }
-
- if (object.get(globalThis, "sourcemap")) |flag| {
- if (flag.isBoolean() or flag.isUndefinedOrNull()) {
- if (flag.toBoolean()) {
- transpiler.transform.source_map = Api.SourceMapMode.external;
- } else {
- transpiler.transform.source_map = Api.SourceMapMode.inline_into_file;
- }
- } else {
- var sourcemap = flag.toSlice(globalThis, allocator);
- 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);
- return transpiler;
- }
- }
- }
-
- var tree_shaking: ?bool = null;
- if (object.get(globalThis, "treeShaking")) |treeShaking| {
- tree_shaking = treeShaking.toBoolean();
- }
-
- var trim_unused_imports: ?bool = null;
- if (object.get(globalThis, "trimUnusedImports")) |trimUnusedImports| {
- trim_unused_imports = trimUnusedImports.toBoolean();
- }
-
- if (object.getTruthy(globalThis, "exports")) |exports| {
- if (!exports.isObject()) {
- JSC.throwInvalidArguments("exports must be an object", .{}, ctx, exception);
- return transpiler;
- }
-
- var replacements = Runtime.Features.ReplaceableExport.Map{};
- errdefer replacements.clearAndFree(bun.default_allocator);
-
- if (exports.getTruthy(globalThis, "eliminate")) |eliminate| {
- if (!eliminate.jsType().isArray()) {
- JSC.throwInvalidArguments("exports.eliminate must be an array", .{}, ctx, exception);
- return transpiler;
- }
-
- var total_name_buf_len: u32 = 0;
- var string_count: u32 = 0;
- var iter = JSC.JSArrayIterator.init(eliminate, globalThis);
- {
- var length_iter = iter;
- while (length_iter.next()) |value| {
- if (value.isString()) {
- const length = value.getLengthOfArray(globalThis);
- string_count += @as(u32, @boolToInt(length > 0));
- total_name_buf_len += length;
- }
- }
- }
-
- if (total_name_buf_len > 0) {
- var buf = try std.ArrayListUnmanaged(u8).initCapacity(bun.default_allocator, total_name_buf_len);
- try replacements.ensureUnusedCapacity(bun.default_allocator, string_count);
- {
- var length_iter = iter;
- while (length_iter.next()) |value| {
- if (!value.isString()) continue;
- 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);
- return transpiler;
- };
- buf.items.len += name.len;
- if (name.len > 0) {
- replacements.putAssumeCapacity(name, .{ .delete = .{} });
- }
- }
- }
- }
- }
-
- if (exports.getTruthy(globalThis, "replace")) |replace| {
- if (!replace.isObject()) {
- JSC.throwInvalidArguments("replace must be an object", .{}, ctx, exception);
- return transpiler;
- }
-
- var total_name_buf_len: usize = 0;
-
- var array = js.JSObjectCopyPropertyNames(ctx, replace.asObjectRef());
- defer js.JSPropertyNameArrayRelease(array);
- const property_names_count = @intCast(u32, js.JSPropertyNameArrayGetCount(array));
- var iter = JSC.JSPropertyNameIterator{
- .array = array,
- .count = @intCast(u32, property_names_count),
- };
-
- {
- var key_iter = iter;
- while (key_iter.next()) |item| {
- total_name_buf_len += JSC.C.JSStringGetLength(item);
- }
- }
-
- if (total_name_buf_len > 0) {
- var total_name_buf = try std.ArrayList(u8).initCapacity(bun.default_allocator, total_name_buf_len);
- errdefer total_name_buf.clearAndFree();
-
- try replacements.ensureUnusedCapacity(bun.default_allocator, property_names_count);
- defer {
- if (exception.* != null) {
- total_name_buf.clearAndFree();
- replacements.clearAndFree(bun.default_allocator);
- }
- }
-
- while (iter.next()) |item| {
- const start = total_name_buf.items.len;
- total_name_buf.items.len += @maximum(
- // this returns a null terminated string
- JSC.C.JSStringGetUTF8CString(item, total_name_buf.items.ptr + start, total_name_buf.capacity - start),
- 1,
- ) - 1;
- JSC.C.JSStringRelease(item);
- const key = total_name_buf.items[start..total_name_buf.items.len];
- // if somehow the string is empty, skip it
- if (key.len == 0)
- continue;
-
- const value = replace.get(globalThis, key).?;
- if (value.isEmpty()) continue;
-
- if (!JSLexer.isIdentifier(key)) {
- JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{key}, ctx, exception);
- total_name_buf.deinit();
- return transpiler;
- }
-
- var entry = replacements.getOrPutAssumeCapacity(key);
-
- if (exportReplacementValue(value, globalThis)) |expr| {
- entry.value_ptr.* = .{ .replace = expr };
- continue;
- }
-
- if (value.isObject() and value.getLengthOfArray(ctx.ptr()) == 2) {
- const replacementValue = JSC.JSObject.getIndex(value, globalThis, 1);
- if (exportReplacementValue(replacementValue, globalThis)) |to_replace| {
- const replacementKey = JSC.JSObject.getIndex(value, globalThis, 0);
- var slice = (try replacementKey.toSlice(globalThis, bun.default_allocator).cloneIfNeeded());
- var replacement_name = slice.slice();
-
- if (!JSLexer.isIdentifier(replacement_name)) {
- JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{replacement_name}, ctx, exception);
- total_name_buf.deinit();
- slice.deinit();
- return transpiler;
- }
-
- entry.value_ptr.* = .{
- .inject = .{
- .name = replacement_name,
- .value = to_replace,
- },
- };
- continue;
- }
- }
-
- JSC.throwInvalidArguments("exports.replace values can only be string, null, undefined, number or boolean", .{}, ctx, exception);
- return transpiler;
- }
- }
- }
-
- tree_shaking = tree_shaking orelse (replacements.count() > 0);
- transpiler.runtime.replace_exports = replacements;
- }
-
- transpiler.tree_shaking = tree_shaking orelse false;
- transpiler.trim_unused_imports = trim_unused_imports orelse transpiler.tree_shaking;
-
- return transpiler;
-}
-
-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]);
- defer temp.deinit();
- const transpiler_options: TranspilerOptions = if (arguments.len > 0)
- transformOptionsFromJSC(ctx, temp.allocator(), &args, exception) catch {
- JSC.throwInvalidArguments("Failed to create transpiler", .{}, ctx, exception);
- return null;
- }
- else
- TranspilerOptions{ .log = logger.Log.init(getAllocator(ctx)) };
-
- if (exception.* != null) {
- return null;
- }
-
- 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();
- return null;
- }
-
- var log = getAllocator(ctx).create(logger.Log) catch unreachable;
- log.* = transpiler_options.log;
- var bundler = Bundler.Bundler.init(
- getAllocator(ctx),
- log,
- transpiler_options.transform,
- null,
- JavaScript.VirtualMachine.vm.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();
- return null;
- }
-
- JSC.throwInvalidArguments("Error creating transpiler: {s}", .{@errorName(err)}, ctx, exception);
- return null;
- };
-
- bundler.configureLinkerWithAutoJSX(false);
- 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();
- return null;
- }
-
- JSC.throwInvalidArguments("Failed to load define: {s}", .{@errorName(err)}, ctx, exception);
- return null;
- };
-
- if (transpiler_options.macro_map.count() > 0) {
- bundler.options.macro_remap = transpiler_options.macro_map;
- }
-
- bundler.options.tree_shaking = transpiler_options.tree_shaking;
- bundler.options.trim_unused_imports = transpiler_options.trim_unused_imports;
- bundler.options.allow_runtime = transpiler_options.runtime.allow_runtime;
- bundler.options.auto_import_jsx = transpiler_options.runtime.auto_import_jsx;
- bundler.options.hot_module_reloading = transpiler_options.runtime.hot_module_reloading;
- 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;
- transpiler.* = Transpiler{
- .transpiler_options = transpiler_options,
- .bundler = bundler,
- .arena = args.arena,
- .scan_pass_result = ScanPassResult.init(getAllocator(ctx)),
- };
-
- return Class.make(ctx, transpiler);
-}
-
-pub fn finalize(
- this: *Transpiler,
-) void {
- this.bundler.log.deinit();
- this.scan_pass_result.named_imports.deinit();
- this.scan_pass_result.import_records.deinit();
- this.scan_pass_result.used_symbols.deinit();
- if (this.buffer_writer != null) {
- this.buffer_writer.?.buffer.deinit();
- }
-
- // bun.default_allocator.free(this.transpiler_options.tsconfig_buf);
- // bun.default_allocator.free(this.transpiler_options.macros_buf);
- this.arena.deinit();
-}
-
-fn getParseResult(this: *Transpiler, allocator: std.mem.Allocator, code: []const u8, loader: ?Loader, macro_js_ctx: JSValue) ?Bundler.ParseResult {
- const name = this.transpiler_options.default_loader.stdinName();
- const source = logger.Source.initPathString(name, code);
-
- const jsx = if (this.transpiler_options.tsconfig != null)
- this.transpiler_options.tsconfig.?.mergeJSX(this.bundler.options.jsx)
- else
- this.bundler.options.jsx;
-
- const parse_options = Bundler.Bundler.ParseOptions{
- .allocator = allocator,
- .macro_remappings = this.transpiler_options.macro_map,
- .dirname_fd = 0,
- .file_descriptor = null,
- .loader = loader orelse this.transpiler_options.default_loader,
- .jsx = jsx,
- .path = source.path,
- .virtual_source = &source,
- .replace_exports = this.transpiler_options.runtime.replace_exports,
- .macro_js_ctx = macro_js_ctx,
- // .allocator = this.
- };
-
- var parse_result = this.bundler.parse(parse_options, null);
-
- // necessary because we don't run the linker
- if (parse_result) |*res| {
- for (res.ast.import_records) |*import| {
- if (import.kind.isCommonJS()) {
- import.wrap_with_to_module = true;
- import.module_id = @truncate(u32, std.hash.Wyhash.hash(0, import.path.pretty));
- }
- }
- }
-
- return parse_result;
-}
-
-pub fn scan(
- 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]);
- defer args.arena.deinit();
- const code_arg = args.next() orelse {
- JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- 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 = code_holder.slice();
- args.eat();
- const loader: ?Loader = brk: {
- if (args.next()) |arg| {
- args.eat();
- break :brk Loader.fromJS(ctx.ptr(), arg, exception);
- }
-
- break :brk null;
- };
-
- if (exception.* != null) return null;
-
- var arena = Mimalloc.Arena.init() catch unreachable;
- var prev_allocator = this.bundler.allocator;
- this.bundler.setAllocator(arena.allocator());
- var log = logger.Log.init(arena.backingAllocator());
- defer log.deinit();
- this.bundler.setLog(&log);
- defer {
- this.bundler.setLog(&this.transpiler_options.log);
- this.bundler.setAllocator(prev_allocator);
- arena.deinit();
- }
-
- defer {
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
- }
-
- const parse_result = getParseResult(this, arena.allocator(), code, loader, JSC.JSValue.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;
- }
-
- JSC.throwInvalidArguments("Failed to parse", .{}, ctx, exception);
- return null;
- };
-
- 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;
- }
-
- const exports_label = JSC.ZigString.init("exports");
- const imports_label = JSC.ZigString.init("imports");
- const named_imports_value = namedImportsToJS(
- ctx.ptr(),
- parse_result.ast.import_records,
- exception,
- );
- if (exception.* != null) return null;
- var named_exports_value = namedExportsToJS(
- ctx.ptr(),
- parse_result.ast.named_exports,
- );
- return JSC.JSValue.createObject2(ctx.ptr(), &imports_label, &exports_label, named_imports_value, named_exports_value).asObjectRef();
-}
-
-// pub fn build(
-// this: *Transpiler,
-// ctx: js.JSContextRef,
-// _: js.JSObjectRef,
-// _: js.JSObjectRef,
-// arguments: []const js.JSValueRef,
-// exception: js.ExceptionRef,
-// ) JSC.C.JSObjectRef {}
-
-pub fn transform(
- 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]);
- defer args.arena.deinit();
- const code_arg = args.next() orelse {
- JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- 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 = code_holder.slice();
- args.eat();
- const loader: ?Loader = brk: {
- if (args.next()) |arg| {
- args.eat();
- break :brk Loader.fromJS(ctx.ptr(), arg, exception);
- }
-
- break :brk null;
- };
-
- if (exception.* != null) return null;
- if (code_holder == .string) {
- JSC.C.JSValueProtect(ctx, arguments[0]);
- }
-
- 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;
- task.schedule();
- return task.promise.asObjectRef();
-}
-
-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]);
- defer args.arena.deinit();
- const code_arg = args.next() orelse {
- JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- 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 = code_holder.slice();
- JSC.JSValue.c(arguments[0]).ensureStillAlive();
- defer JSC.JSValue.c(arguments[0]).ensureStillAlive();
-
- args.eat();
- var js_ctx_value: JSC.JSValue = JSC.JSValue.zero;
- const loader: ?Loader = brk: {
- if (args.next()) |arg| {
- args.eat();
- if (arg.isNumber() or arg.isString()) {
- break :brk Loader.fromJS(ctx.ptr(), arg, exception);
- }
-
- if (arg.isObject()) {
- js_ctx_value = arg;
- break :brk null;
- }
- }
-
- break :brk null;
- };
-
- if (args.nextEat()) |arg| {
- if (arg.isObject()) {
- js_ctx_value = arg;
- } else {
- JSC.throwInvalidArguments("Expected a Loader or object", .{}, ctx, exception);
- return null;
- }
- }
- if (!js_ctx_value.isEmpty()) {
- js_ctx_value.ensureStillAlive();
- }
-
- defer {
- if (!js_ctx_value.isEmpty()) {
- js_ctx_value.ensureStillAlive();
- }
- }
-
- if (exception.* != null) return null;
-
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
- defer {
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
- }
-
- var prev_bundler = this.bundler;
- this.bundler.setAllocator(arena.allocator());
- this.bundler.macro_context = null;
- var log = logger.Log.init(arena.backingAllocator());
- this.bundler.setLog(&log);
-
- defer {
- this.bundler = prev_bundler;
- }
-
- var parse_result = getParseResult(
- this,
- arena.allocator(),
- code,
- loader,
- 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;
- }
-
- JSC.throwInvalidArguments("Failed to parse", .{}, ctx, exception);
- return null;
- };
-
- 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;
- }
-
- 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;
- };
-
- writer.buffer.growIfNeeded(code.len) catch unreachable;
- writer.buffer.list.expandToCapacity();
- break :brk writer;
- };
-
- defer {
- this.buffer_writer = buffer_writer;
- }
-
- 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;
- };
-
- // 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();
-
- return out.toValueGC(ctx.ptr()).asObjectRef();
-}
-
-fn namedExportsToJS(global: *JSGlobalObject, named_exports: JSAst.Ast.NamedExports) JSC.JSValue {
- if (named_exports.count() == 0)
- return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArray(global.ref(), 0, null, null));
-
- var named_exports_iter = named_exports.iterator();
- var stack_fallback = std.heap.stackFallback(@sizeOf(JSC.ZigString) * 32, getAllocator(global.ref()));
- var allocator = stack_fallback.get();
- var names = allocator.alloc(
- JSC.ZigString,
- named_exports.count(),
- ) catch unreachable;
- defer allocator.free(names);
- var i: usize = 0;
- while (named_exports_iter.next()) |entry| {
- names[i] = JSC.ZigString.init(entry.key_ptr.*);
- i += 1;
- }
- JSC.ZigString.sortAsc(names[0..i]);
- return JSC.JSValue.createStringArray(global, names.ptr, names.len, true);
-}
-
-const ImportRecord = @import("../../../import_record.zig").ImportRecord;
-
-fn namedImportsToJS(
- global: *JSGlobalObject,
- import_records: []const ImportRecord,
- exception: JSC.C.ExceptionRef,
-) JSC.JSValue {
- var stack_fallback = std.heap.stackFallback(@sizeOf(JSC.C.JSObjectRef) * 32, getAllocator(global.ref()));
- var allocator = stack_fallback.get();
-
- var i: usize = 0;
- const path_label = JSC.ZigString.init("path");
- const kind_label = JSC.ZigString.init("kind");
- var array_items = allocator.alloc(
- JSC.C.JSValueRef,
- import_records.len,
- ) catch unreachable;
- defer allocator.free(array_items);
-
- for (import_records) |record| {
- if (record.is_internal) continue;
-
- 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();
- i += 1;
- }
-
- return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArray(global.ref(), i, array_items.ptr, exception));
-}
-
-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]);
- const code_arg = args.next() orelse {
- JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- 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;
- };
- 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| {
- loader = _loader;
- }
- args.eat();
- }
-
- if (!loader.isJavaScriptLike()) {
- JSC.throwInvalidArguments("Only JavaScript-like files support this fast path", .{}, ctx, exception);
- return null;
- }
-
- if (exception.* != null) return null;
-
- var arena = Mimalloc.Arena.init() catch unreachable;
- var prev_allocator = this.bundler.allocator;
- this.bundler.setAllocator(arena.allocator());
- var log = logger.Log.init(arena.backingAllocator());
- defer log.deinit();
- this.bundler.setLog(&log);
- defer {
- this.bundler.setLog(&this.transpiler_options.log);
- this.bundler.setAllocator(prev_allocator);
- arena.deinit();
- }
-
- const source = logger.Source.initPathString(loader.stdinName(), code);
- var bundler = &this.bundler;
- const jsx = if (this.transpiler_options.tsconfig != null)
- this.transpiler_options.tsconfig.?.mergeJSX(this.bundler.options.jsx)
- else
- this.bundler.options.jsx;
-
- var opts = JSParser.Parser.Options.init(jsx, loader);
- if (this.bundler.macro_context == null) {
- this.bundler.macro_context = JSAst.Macro.MacroContext.init(&this.bundler);
- }
- opts.macro_context = &this.bundler.macro_context.?;
-
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
-
- defer {
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
- }
-
- bundler.resolver.caches.js.scan(
- bundler.allocator,
- &this.scan_pass_result,
- opts,
- bundler.options.define,
- &log,
- &source,
- ) 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;
- }
-
- JSC.throwInvalidArguments("Failed to scan imports: {s}", .{@errorName(err)}, ctx, exception);
- return null;
- };
-
- 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;
- }
-
- const named_imports_value = namedImportsToJS(
- ctx.ptr(),
- this.scan_pass_result.import_records.items,
- exception,
- );
- if (exception.* != null) return null;
- return named_imports_value.asObjectRef();
-}