aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-01-19 23:07:03 -0800
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-01-19 23:07:03 -0800
commita09b99565138bb4bc73a5328397428fb5025817b (patch)
tree3412ae330b4a6078173d0048665b9d547b3d718b /src
parent4098484ff5d1c66a5f146e773a9be25cbcd2a1f4 (diff)
downloadbun-a09b99565138bb4bc73a5328397428fb5025817b.tar.gz
bun-a09b99565138bb4bc73a5328397428fb5025817b.tar.zst
bun-a09b99565138bb4bc73a5328397428fb5025817b.zip
Bun.Transpiler – API for scanning imports/exports of JSX/TSX/TS/JS files
Diffstat (limited to 'src')
-rw-r--r--src/api/schema.d.ts3
-rw-r--r--src/api/schema.js4
-rw-r--r--src/api/schema.peechy1
-rw-r--r--src/api/schema.zig3
-rw-r--r--src/bundler.zig20
-rw-r--r--src/import_record.zig17
-rw-r--r--src/javascript/jsc/api/transpiler.zig616
-rw-r--r--src/javascript/jsc/base.zig10
-rw-r--r--src/javascript/jsc/bindings/bindings.zig28
-rw-r--r--src/javascript/jsc/javascript.zig17
-rw-r--r--src/javascript/jsc/test/jest.zig42
-rw-r--r--src/logger.zig29
-rw-r--r--src/options.zig89
-rw-r--r--src/resolver/package_json.zig127
-rw-r--r--src/runtime.version2
15 files changed, 934 insertions, 74 deletions
diff --git a/src/api/schema.d.ts b/src/api/schema.d.ts
index 273f8d9d3..490a74421 100644
--- a/src/api/schema.d.ts
+++ b/src/api/schema.d.ts
@@ -120,6 +120,7 @@ export enum Platform {
browser = 1,
node = 2,
bun = 3,
+ bun_macro = 4,
}
export const PlatformKeys = {
1: "browser",
@@ -128,6 +129,8 @@ export const PlatformKeys = {
node: "node",
3: "bun",
bun: "bun",
+ 4: "bun_macro",
+ bun_macro: "bun_macro",
};
export enum CSSInJSBehavior {
facade = 1,
diff --git a/src/api/schema.js b/src/api/schema.js
index 8b2043e9c..8339484da 100644
--- a/src/api/schema.js
+++ b/src/api/schema.js
@@ -534,17 +534,21 @@ const Platform = {
1: 1,
2: 2,
3: 3,
+ 4: 4,
browser: 1,
node: 2,
bun: 3,
+ bun_macro: 4,
};
const PlatformKeys = {
1: "browser",
2: "node",
3: "bun",
+ 4: "bun_macro",
browser: "browser",
node: "node",
bun: "bun",
+ bun_macro: "bun_macro",
};
const CSSInJSBehavior = {
1: 1,
diff --git a/src/api/schema.peechy b/src/api/schema.peechy
index 7c5b482a2..cd5134299 100644
--- a/src/api/schema.peechy
+++ b/src/api/schema.peechy
@@ -109,6 +109,7 @@ smol Platform {
browser = 1;
node = 2;
bun = 3;
+ bun_macro = 4;
}
smol CSSInJSBehavior {
diff --git a/src/api/schema.zig b/src/api/schema.zig
index 8a850c8f1..4fe8d8acb 100644
--- a/src/api/schema.zig
+++ b/src/api/schema.zig
@@ -797,6 +797,9 @@ pub const Api = struct {
/// bun
bun,
+ /// bun_macro
+ bun_macro,
+
_,
pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
diff --git a/src/bundler.zig b/src/bundler.zig
index 8127a4dc5..a4633421e 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -237,7 +237,7 @@ pub const Bundler = struct {
};
}
- pub fn configureLinker(bundler: *ThisBundler) void {
+ pub fn configureLinkerWithAutoJSX(bundler: *ThisBundler, auto_jsx: bool) void {
bundler.linker = Linker.init(
bundler.allocator,
bundler.log,
@@ -248,17 +248,23 @@ pub const Bundler = struct {
bundler.fs,
);
- // If we don't explicitly pass JSX, try to get it from the root tsconfig
- if (bundler.options.transform_options.jsx == null) {
- // Most of the time, this will already be cached
- if (bundler.resolver.readDirInfo(bundler.fs.top_level_dir) catch null) |root_dir| {
- if (root_dir.tsconfig_json) |tsconfig| {
- bundler.options.jsx = tsconfig.jsx;
+ if (auto_jsx) {
+ // If we don't explicitly pass JSX, try to get it from the root tsconfig
+ if (bundler.options.transform_options.jsx == null) {
+ // Most of the time, this will already be cached
+ if (bundler.resolver.readDirInfo(bundler.fs.top_level_dir) catch null) |root_dir| {
+ if (root_dir.tsconfig_json) |tsconfig| {
+ bundler.options.jsx = tsconfig.jsx;
+ }
}
}
}
}
+ pub fn configureLinker(bundler: *ThisBundler) void {
+ bundler.configureLinkerWithAutoJSX(true);
+ }
+
pub fn runEnvLoader(this: *ThisBundler) !void {
switch (this.options.env.behavior) {
.prefix, .load_all => {
diff --git a/src/import_record.zig b/src/import_record.zig
index 66bfc128d..c73896a0b 100644
--- a/src/import_record.zig
+++ b/src/import_record.zig
@@ -31,6 +31,23 @@ pub const ImportKind = enum(u8) {
internal,
+ pub const Label = std.EnumArray(ImportKind, []const u8);
+ pub const all_labels: Label = brk: {
+ var labels = Label.initFill("internal");
+ labels.set(ImportKind.entry_point, "entry-point");
+ labels.set(ImportKind.stmt, "import-statement");
+ labels.set(ImportKind.require, "require-call");
+ labels.set(ImportKind.dynamic, "dynamic-import");
+ labels.set(ImportKind.require_resolve, "require-resolve");
+ labels.set(ImportKind.at, "import-rule");
+ labels.set(ImportKind.url, "url-token");
+ break :brk labels;
+ };
+
+ pub inline fn label(this: ImportKind) []const u8 {
+ return all_labels.get(this);
+ }
+
pub inline fn isCommonJS(this: ImportKind) bool {
return switch (this) {
.require, .require_resolve => true,
diff --git a/src/javascript/jsc/api/transpiler.zig b/src/javascript/jsc/api/transpiler.zig
new file mode 100644
index 000000000..07d07763e
--- /dev/null
+++ b/src/javascript/jsc/api/transpiler.zig
@@ -0,0 +1,616 @@
+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("../../../query_string_map.zig").QueryStringMap;
+const CombinedScanner = @import("../../../query_string_map.zig").CombinedScanner;
+const _global = @import("../../../global.zig");
+const string = _global.string;
+const JSC = @import("javascript_core");
+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 ScanPassResult = JSParser.ScanPassResult;
+
+bundler: Bundler.Bundler,
+arena: std.heap.ArenaAllocator,
+transpiler_options: TranspilerOptions,
+scan_pass_result: ScanPassResult,
+
+pub const Class = NewClass(
+ Transpiler,
+ .{ .name = "Transpiler" },
+ .{
+ .scanImports = .{
+ .rfn = scanImports,
+ },
+ .scan = .{
+ .rfn = scan,
+ },
+ .finalize = finalize,
+ },
+ .{},
+);
+
+pub const TranspilerConstructor = NewClass(
+ void,
+ .{ .name = "Transpiler" },
+ .{
+ .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,
+};
+
+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);
+ var map_entries = temp_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;
+ }
+ }
+ }
+
+ if (object.getIfPropertyExists(globalThis, "macro")) |macros| {
+ macros: {
+ if (macros.isUndefinedOrNull()) break :macros;
+ const kind = macros.jsType();
+ const is_object = kind == JSC.JSValue.JSType.Object;
+ 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);
+ }
+ }
+
+ 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(@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)
+ 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.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;
+ };
+
+ 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)),
+ };
+
+ transpiler.bundler.macro_context = JSAst.Macro.MacroContext.init(&transpiler.bundler);
+ if (transpiler_options.macro_map.count() > 0) {
+ transpiler.bundler.macro_context.?.remap = transpiler_options.macro_map;
+ }
+
+ 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();
+
+ // _global.default_allocator.free(this.transpiler_options.tsconfig_buf);
+ // _global.default_allocator.free(this.transpiler_options.macros_buf);
+ this.arena.deinit();
+}
+
+fn getParseResult(this: *Transpiler, allocator: std.mem.Allocator, code: []const u8, loader: ?Loader) ?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,
+ // .allocator = this.
+ };
+
+ return this.bundler.parse(parse_options, null);
+}
+
+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(@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(), 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;
+
+ defer {
+ JSAst.Stmt.Data.Store.reset();
+ JSAst.Expr.Data.Store.reset();
+ }
+
+ const parse_result = getParseResult(this, args.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();
+ return null;
+ }
+
+ JSC.throwInvalidArguments("Failed to parse", .{}, ctx, exception);
+ return null;
+ };
+ defer {
+ if (parse_result.ast.symbol_pool) |symbols| {
+ symbols.release();
+ }
+ }
+
+ 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();
+}
+
+fn namedExportsToJS(global: *JSGlobalObject, named_exports: JSAst.Ast.NamedExports) JSC.JSValue {
+ 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(@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(), 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;
+
+ 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);
+ opts.macro_context = &this.bundler.macro_context.?;
+ var log = logger.Log.init(getAllocator(ctx));
+ defer log.deinit();
+
+ 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();
+}
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig
index cf2ed1bad..4d61fb33a 100644
--- a/src/javascript/jsc/base.zig
+++ b/src/javascript/jsc/base.zig
@@ -1263,7 +1263,7 @@ pub fn NewClass(
if (comptime property_name_refs.len > 0) {
comptime var i: usize = 0;
if (!property_name_refs_set) {
- property_name_refs_set =true;
+ property_name_refs_set = true;
inline while (i < property_name_refs.len) : (i += 1) {
property_name_refs[i] = js.JSStringCreateStatic(property_names[i].ptr, property_names[i].len);
}
@@ -1687,7 +1687,8 @@ pub const ArrayBuffer = struct {
return ArrayBuffer{
.byte_len = @truncate(u32, JSC.C.JSObjectGetTypedArrayByteLength(ctx, value.asObjectRef(), exception)),
.offset = @truncate(u32, JSC.C.JSObjectGetTypedArrayByteOffset(ctx, value.asObjectRef(), exception)),
- .ptr = @ptrCast([*]u8, JSC.C.JSObjectGetTypedArrayBytesPtr(ctx, value.asObjectRef(), exception).?),
+ .ptr = @ptrCast([*]u8, JSC.C.JSObjectGetArrayBufferBytesPtr(ctx, value.asObjectRef(), exception) orelse
+ JSC.C.JSObjectGetTypedArrayBytesPtr(ctx, value.asObjectRef(), exception).?),
// TODO
.typed_array_type = js.JSTypedArrayType.kJSTypedArrayTypeUint8Array,
.len = @truncate(u32, JSC.C.JSObjectGetTypedArrayLength(ctx, value.asObjectRef(), exception)),
@@ -1697,7 +1698,8 @@ pub const ArrayBuffer = struct {
pub fn fromArrayBuffer(ctx: JSC.C.JSContextRef, value: JSC.JSValue, exception: JSC.C.ExceptionRef) ArrayBuffer {
var buffer = ArrayBuffer{
.byte_len = @truncate(u32, JSC.C.JSObjectGetArrayBufferByteLength(ctx, value.asObjectRef(), exception)),
- .ptr = @ptrCast([*]u8, JSC.C.JSObjectGetArrayBufferBytesPtr(ctx, value.asObjectRef(), exception).?),
+ .ptr = @ptrCast([*]u8, JSC.C.JSObjectGetArrayBufferBytesPtr(ctx, value.asObjectRef(), exception) orelse
+ JSC.C.JSObjectGetTypedArrayBytesPtr(ctx, value.asObjectRef(), exception).?),
// TODO
.typed_array_type = js.JSTypedArrayType.kJSTypedArrayTypeUint8Array,
.len = 0,
@@ -1804,6 +1806,7 @@ const NodeFS = JSC.Node.NodeFS;
const DirEnt = JSC.Node.DirEnt;
const Stats = JSC.Node.Stats;
const BigIntStats = JSC.Node.BigIntStats;
+const Transpiler = @import("./api/transpiler.zig");
pub const JSPrivateDataPtr = TaggedPointerUnion(.{
ResolveError,
BuildError,
@@ -1824,6 +1827,7 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
Stats,
BigIntStats,
DirEnt,
+ Transpiler,
});
pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {
diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig
index a28717400..4dad9a926 100644
--- a/src/javascript/jsc/bindings/bindings.zig
+++ b/src/javascript/jsc/bindings/bindings.zig
@@ -107,6 +107,22 @@ pub const ZigString = extern struct {
};
}
+ pub fn sortDesc(slice_: []ZigString) void {
+ std.sort.sort(ZigString, slice_, {}, cmpDesc);
+ }
+
+ pub fn cmpDesc(_: void, a: ZigString, b: ZigString) bool {
+ return strings.cmpStringsDesc(void{}, a.slice(), b.slice());
+ }
+
+ pub fn sortAsc(slice_: []ZigString) void {
+ std.sort.sort(ZigString, slice_, {}, cmpAsc);
+ }
+
+ pub fn cmpAsc(_: void, a: ZigString, b: ZigString) bool {
+ return strings.cmpStringsAsc(void{}, a.slice(), b.slice());
+ }
+
pub fn init(slice_: []const u8) ZigString {
return ZigString{ .ptr = slice_.ptr, .len = slice_.len };
}
@@ -1446,6 +1462,13 @@ pub const JSValue = enum(i64) {
else => false,
};
}
+
+ pub inline fn isArray(this: JSType) bool {
+ return switch (this) {
+ .Array, .DerivedArray => true,
+ else => false,
+ };
+ }
};
pub inline fn cast(ptr: anytype) JSValue {
@@ -1735,11 +1758,14 @@ pub const JSValue = enum(i64) {
return cppFn("getIfPropertyExistsImpl", .{ this, global, ptr, len });
}
- pub fn getIfPropertyExists(this: JSValue, global: *JSGlobalObject, property: []const u8) ?JSValue {
+ pub fn get(this: JSValue, global: *JSGlobalObject, property: []const u8) ?JSValue {
const value = getIfPropertyExistsImpl(this, global, property.ptr, @intCast(u32, property.len));
return if (@enumToInt(value) != 0) value else return null;
}
+ /// Alias for getIfPropertyExists
+ pub const getIfPropertyExists = get;
+
pub fn createTypeError(message: *const ZigString, code: *const ZigString, global: *JSGlobalObject) JSValue {
return cppFn("createTypeError", .{ message, code, global });
}
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 64147bc5c..2299e9339 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -77,6 +77,7 @@ const ZigGlobalObject = @import("../../jsc.zig").ZigGlobalObject;
const VM = @import("../../jsc.zig").VM;
const Config = @import("./config.zig");
const URL = @import("../../query_string_map.zig").URL;
+const Transpiler = @import("./api/transpiler.zig");
pub const GlobalClasses = [_]type{
Request.Class,
Response.Class,
@@ -746,9 +747,23 @@ pub const Bun = struct {
.enableANSIColors = .{
.get = enableANSIColors,
},
+ .Transpiler = .{
+ .get = getTranspilerConstructor,
+ .ts = d.ts{ .name = "Transpiler", .@"return" = "Transpiler.prototype" },
+ },
},
);
+ pub fn getTranspilerConstructor(
+ _: void,
+ ctx: js.JSContextRef,
+ _: js.JSValueRef,
+ _: js.JSStringRef,
+ _: js.ExceptionRef,
+ ) js.JSValueRef {
+ return js.JSObjectMake(ctx, Transpiler.TranspilerConstructor.get().?[0], null);
+ }
+
// For testing the segfault handler
pub fn __debug__doSegfault(
_: void,
@@ -1702,7 +1717,7 @@ pub const VirtualMachine = struct {
}
const main_file_name: string = "bun:main";
- threadlocal var errors_stack: [256]*anyopaque = undefined;
+ pub threadlocal var errors_stack: [256]*anyopaque = undefined;
pub fn fetch(ret: *ErrorableResolvedSource, global: *JSGlobalObject, specifier: ZigString, source: ZigString) callconv(.C) void {
var log = logger.Log.init(vm.bundler.allocator);
const spec = specifier.slice();
diff --git a/src/javascript/jsc/test/jest.zig b/src/javascript/jsc/test/jest.zig
index 1398e9058..2ffc8bd01 100644
--- a/src/javascript/jsc/test/jest.zig
+++ b/src/javascript/jsc/test/jest.zig
@@ -365,6 +365,47 @@ pub const Expect = struct {
}
return thisObject;
}
+
+ pub fn toHaveLength(
+ this: *Expect,
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ if (arguments.len != 1) {
+ JSC.JSError(
+ getAllocator(ctx),
+ ".toHaveLength() takes 1 argument",
+ .{},
+ ctx,
+ exception,
+ );
+ return js.JSValueMakeUndefined(ctx);
+ }
+ this.scope.tests.items[this.test_id].counter.actual += 1;
+
+ const expected = JSC.JSValue.fromRef(arguments[0]).toU32();
+ const actual = JSC.JSValue.fromRef(this.value).getLengthOfArray(ctx.ptr());
+ if (expected != actual) {
+ JSC.JSError(
+ getAllocator(ctx),
+ "Expected length to equal {d} but received {d}\n Expected: {d}\n Actual: {d}\n",
+ .{
+ expected,
+ actual,
+ expected,
+ actual,
+ },
+ ctx,
+ exception,
+ );
+ return null;
+ }
+ return thisObject;
+ }
+
pub const toHaveBeenCalledTimes = notImplementedFn;
pub const toHaveBeenCalledWith = notImplementedFn;
pub const toHaveBeenLastCalledWith = notImplementedFn;
@@ -373,7 +414,6 @@ pub const Expect = struct {
pub const toHaveReturnedWith = notImplementedFn;
pub const toHaveLastReturnedWith = notImplementedFn;
pub const toHaveNthReturnedWith = notImplementedFn;
- pub const toHaveLength = notImplementedFn;
pub const toHaveProperty = notImplementedFn;
pub const toBeCloseTo = notImplementedFn;
pub const toBeGreaterThan = notImplementedFn;
diff --git a/src/logger.zig b/src/logger.zig
index 5ac17f13c..1de5dcf9e 100644
--- a/src/logger.zig
+++ b/src/logger.zig
@@ -12,7 +12,7 @@ const MutableString = _global.MutableString;
const stringZ = _global.stringZ;
const default_allocator = _global.default_allocator;
const C = _global.C;
-
+const JSC = @import("./jsc.zig");
const fs = @import("fs.zig");
const unicode = std.unicode;
@@ -522,6 +522,33 @@ pub const Log = struct {
});
}
+ pub fn toJS(this: Log, global: *JSC.JSGlobalObject, allocator: std.mem.Allocator, comptime fmt: string) JSC.JSValue {
+ const msgs: []const Msg = this.msgs.items;
+ const count = @intCast(u16, @minimum(msgs.len, JSC.VirtualMachine.errors_stack.len));
+ switch (count) {
+ 0 => return JSC.JSValue.jsUndefined(),
+ 1 => {
+ const msg = msgs[0];
+ return JSC.JSValue.fromRef(JSC.BuildError.create(global, allocator, msg));
+ },
+ else => {
+ for (msgs[0..count]) |msg, i| {
+ switch (msg.metadata) {
+ .build => {
+ JSC.VirtualMachine.errors_stack[i] = JSC.BuildError.create(global, allocator, msg).?;
+ },
+ .resolve => {
+ JSC.VirtualMachine.errors_stack[i] = JSC.ResolveError.create(global, allocator, msg, "").?;
+ },
+ }
+ }
+ const out = JSC.ZigString.init(fmt);
+ const agg = global.createAggregateError(JSC.VirtualMachine.errors_stack[0..count].ptr, count, &out);
+ return agg;
+ },
+ }
+ }
+
pub fn appendTo(self: *Log, other: *Log) !void {
var notes_count: usize = 0;
diff --git a/src/options.zig b/src/options.zig
index 48fa6c0c5..2e2f684b6 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -24,6 +24,7 @@ const stringZ = _global.stringZ;
const default_allocator = _global.default_allocator;
const C = _global.C;
const StoredFileDescriptorType = _global.StoredFileDescriptorType;
+const JSC = @import("./jsc.zig");
const Analytics = @import("./analytics/analytics_thread.zig");
@@ -259,7 +260,6 @@ pub const ExternalModules = struct {
"dns",
"domain",
"events",
- "fs",
"http",
"http2",
"https",
@@ -368,6 +368,43 @@ pub const Platform = enum {
bun_macro,
node,
+ pub fn fromJS(global: *JSC.JSGlobalObject, value: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Platform {
+ if (!value.jsType().isStringLike()) {
+ JSC.throwInvalidArguments("platform must be a string", .{}, global.ref(), exception);
+
+ return null;
+ }
+ var zig_str = JSC.ZigString.init("");
+ value.toZigString(&zig_str, global);
+
+ var slice = zig_str.slice();
+
+ const Eight = strings.ExactSizeMatcher(8);
+
+ return switch (Eight.match(slice)) {
+ Eight.case("deno"), Eight.case("browser") => Platform.browser,
+ Eight.case("bun") => Platform.bun,
+ Eight.case("macro") => Platform.bun_macro,
+ Eight.case("node") => Platform.node,
+ Eight.case("neutral") => Platform.neutral,
+ else => {
+ JSC.throwInvalidArguments("platform must be one of: deno, browser, bun, macro, node, neutral", .{}, global.ref(), exception);
+
+ return null;
+ },
+ };
+ }
+
+ pub fn toAPI(this: Platform) Api.Platform {
+ return switch (this) {
+ .node => .node,
+ .browser => .browser,
+ .bun => .bun,
+ .bun_macro => .bun_macro,
+ else => ._none,
+ };
+ }
+
pub inline fn isServerSide(this: Platform) bool {
return switch (this) {
.bun_macro, .node, .bun => true,
@@ -461,6 +498,7 @@ pub const Platform = enum {
.node => .node,
.browser => .browser,
.bun => .bun,
+ .bun_macro => .bun_macro,
else => .browser,
};
}
@@ -584,6 +622,55 @@ pub const Loader = enum(u3) {
css,
file,
json,
+ pub const Map = std.EnumArray(Loader, string);
+ pub const stdin_name: Map = brk: {
+ var map = Map.initFill("");
+ map.set(Loader.jsx, "input.jsx");
+ map.set(Loader.js, "input.js");
+ map.set(Loader.ts, "input.ts");
+ map.set(Loader.tsx, "input.tsx");
+ map.set(Loader.css, "input.css");
+ map.set(Loader.file, "input");
+ map.set(Loader.json, "input.json");
+ break :brk map;
+ };
+
+ pub inline fn stdinName(this: Loader) string {
+ return stdin_name.get(this);
+ }
+
+ pub fn fromJS(global: *JSC.JSGlobalObject, loader: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Loader {
+ if (loader.isUndefinedOrNull()) return null;
+
+ if (!loader.jsType().isStringLike()) {
+ JSC.throwInvalidArguments("loader must be a string", .{}, global.ref(), exception);
+ return null;
+ }
+
+ var zig_str = JSC.ZigString.init("");
+ loader.toZigString(&zig_str, global);
+ if (zig_str.len == 0) return null;
+
+ const LoaderMatcher = strings.ExactSizeMatcher(4);
+ var slice = zig_str.slice();
+ if (slice.len > 0 and slice[0] == '.') {
+ slice = slice[1..];
+ }
+
+ return switch (LoaderMatcher.matchLower(slice)) {
+ LoaderMatcher.case("js") => Loader.js,
+ LoaderMatcher.case("jsx") => Loader.jsx,
+ LoaderMatcher.case("ts") => Loader.ts,
+ LoaderMatcher.case("tsx") => Loader.tsx,
+ LoaderMatcher.case("css") => Loader.css,
+ LoaderMatcher.case("file") => Loader.file,
+ LoaderMatcher.case("json") => Loader.json,
+ else => {
+ JSC.throwInvalidArguments("invalid loader – must be js, jsx, tsx, ts, css, file, or json", .{}, global.ref(), exception);
+ return null;
+ },
+ };
+ }
pub fn supportsClientEntryPoint(this: Loader) bool {
return switch (this) {
diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig
index f2918cffa..eefb5474b 100644
--- a/src/resolver/package_json.zig
+++ b/src/resolver/package_json.zig
@@ -448,6 +448,74 @@ pub const PackageJSON = struct {
}
}
+ pub fn parseMacrosJSON(
+ allocator: std.mem.Allocator,
+ macros: js_ast.Expr,
+ log: *logger.Log,
+ json_source: *const logger.Source,
+ ) MacroMap {
+ var macro_map = MacroMap{};
+ if (macros.data != .e_object) return macro_map;
+
+ const properties = macros.data.e_object.properties;
+
+ for (properties) |property| {
+ const key = property.key.?.asString(allocator) orelse continue;
+ if (!resolver.isPackagePath(key)) {
+ log.addRangeWarningFmt(
+ json_source,
+ json_source.rangeOfString(property.key.?.loc),
+ allocator,
+ "\"{s}\" is not a package path. \"macros\" remaps package paths to macros. Skipping.",
+ .{key},
+ ) catch unreachable;
+ continue;
+ }
+
+ const value = property.value.?;
+ if (value.data != .e_object) {
+ log.addWarningFmt(
+ json_source,
+ value.loc,
+ allocator,
+ "Invalid macro remapping in \"{s}\": expected object where the keys are import names and the value is a string path to replace",
+ .{key},
+ ) catch unreachable;
+ continue;
+ }
+
+ const remap_properties = value.data.e_object.properties;
+ if (remap_properties.len == 0) continue;
+
+ var map = MacroImportReplacementMap.init(allocator);
+ map.ensureUnusedCapacity(remap_properties.len) catch unreachable;
+ for (remap_properties) |remap| {
+ const import_name = remap.key.?.asString(allocator) orelse continue;
+ const remap_value = remap.value.?;
+ if (remap_value.data != .e_string or remap_value.data.e_string.utf8.len == 0) {
+ log.addWarningFmt(
+ json_source,
+ remap_value.loc,
+ allocator,
+ "Invalid macro remapping for import \"{s}\": expected string to remap to. e.g. \"graphql\": \"bun-macro-relay\" ",
+ .{import_name},
+ ) catch unreachable;
+ continue;
+ }
+
+ const remap_value_str = remap_value.data.e_string.utf8;
+
+ map.putAssumeCapacityNoClobber(import_name, remap_value_str);
+ }
+
+ if (map.count() > 0) {
+ macro_map.put(allocator, key, map) catch unreachable;
+ }
+ }
+
+ return macro_map;
+ }
+
pub fn parse(
comptime ResolverType: type,
r: *ResolverType,
@@ -569,64 +637,7 @@ pub const PackageJSON = struct {
}
if (bun_json.expr.asProperty("macros")) |macros| {
- if (macros.expr.data == .e_object) {
- const properties = macros.expr.data.e_object.properties;
-
- for (properties) |property| {
- const key = property.key.?.asString(r.allocator) orelse continue;
- if (!resolver.isPackagePath(key)) {
- r.log.addRangeWarningFmt(
- &json_source,
- json_source.rangeOfString(property.key.?.loc),
- r.allocator,
- "\"{s}\" is not a package path. \"macros\" remaps package paths to macros. Skipping.",
- .{key},
- ) catch unreachable;
- continue;
- }
-
- const value = property.value.?;
- if (value.data != .e_object) {
- r.log.addWarningFmt(
- &json_source,
- value.loc,
- r.allocator,
- "Invalid macro remapping in \"{s}\": expected object where the keys are import names and the value is a string path to replace",
- .{key},
- ) catch unreachable;
- continue;
- }
-
- const remap_properties = value.data.e_object.properties;
- if (remap_properties.len == 0) continue;
-
- var map = MacroImportReplacementMap.init(r.allocator);
- map.ensureUnusedCapacity(remap_properties.len) catch unreachable;
- for (remap_properties) |remap| {
- const import_name = remap.key.?.asString(r.allocator) orelse continue;
- const remap_value = remap.value.?;
- if (remap_value.data != .e_string or remap_value.data.e_string.utf8.len == 0) {
- r.log.addWarningFmt(
- &json_source,
- remap_value.loc,
- r.allocator,
- "Invalid macro remapping for import \"{s}\": expected string to remap to. e.g. \"graphql\": \"bun-macro-relay\" ",
- .{import_name},
- ) catch unreachable;
- continue;
- }
-
- const remap_value_str = remap_value.data.e_string.utf8;
-
- map.putAssumeCapacityNoClobber(import_name, remap_value_str);
- }
-
- if (map.count() > 0) {
- package_json.macros.put(r.allocator, key, map) catch unreachable;
- }
- }
- // for (var i = 0; i < bundle_.expr.data.e_array.len; i++) {
- }
+ package_json.macros = parseMacrosJSON(r.allocator, macros.expr, r.log, &json_source);
}
}
diff --git a/src/runtime.version b/src/runtime.version
index 5a9880de4..3fabcd4a7 100644
--- a/src/runtime.version
+++ b/src/runtime.version
@@ -1 +1 @@
-21bcc5d5dcff77b6 \ No newline at end of file
+f7965245ee95858c \ No newline at end of file