-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Expand file tree
/
Copy pathMdxObject.zig
More file actions
105 lines (92 loc) · 3.78 KB
/
MdxObject.zig
File metadata and controls
105 lines (92 loc) · 3.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
pub fn create(globalThis: *jsc.JSGlobalObject) jsc.JSValue {
const object = JSValue.createEmptyObject(globalThis, 1);
object.put(
globalThis,
bun.String.static("compile"),
jsc.JSFunction.create(globalThis, "compile", compile, 2, .{}),
);
return object;
}
pub fn compile(
globalThis: *jsc.JSGlobalObject,
callframe: *jsc.CallFrame,
) bun.JSError!jsc.JSValue {
const input_value, const opts_value = callframe.argumentsAsArray(2);
if (input_value.isEmptyOrUndefinedOrNull()) {
return globalThis.throwInvalidArguments("Expected a string or buffer to compile", .{});
}
var arena: bun.ArenaAllocator = .init(bun.default_allocator);
defer arena.deinit();
const buffer = try jsc.Node.StringOrBuffer.fromJS(globalThis, arena.allocator(), input_value) orelse {
return globalThis.throwInvalidArguments("Expected a string or buffer to compile", .{});
};
const input = buffer.slice();
const options = try parseOptions(globalThis, arena.allocator(), opts_value);
const result = mdx.compile(input, arena.allocator(), options) catch |err| return switch (err) {
error.OutOfMemory => globalThis.throwOutOfMemory(),
error.JSError, error.JSTerminated => |e| e,
error.StackOverflow => globalThis.throwStackOverflow(),
else => globalThis.throwValue(globalThis.createSyntaxErrorInstance("MDX compile error: {s}", .{@errorName(err)})),
};
return bun.String.createUTF8ForJS(globalThis, result);
}
fn parseOptions(globalThis: *jsc.JSGlobalObject, allocator: std.mem.Allocator, opts_value: JSValue) bun.JSError!mdx.MdxOptions {
var options: mdx.MdxOptions = .{};
if (opts_value.isObject()) {
inline for (@typeInfo(md.Options).@"struct".fields) |field| {
comptime if (field.type != bool) continue;
const camel = comptime camelCaseOf(field.name);
if (try opts_value.getBooleanLoose(globalThis, camel)) |val| {
@field(options.md_options, field.name) = val;
} else if (comptime !std.mem.eql(u8, camel, field.name)) {
if (try opts_value.getBooleanLoose(globalThis, field.name)) |val| {
@field(options.md_options, field.name) = val;
}
}
}
if (try opts_value.get(globalThis, "jsxImportSource")) |import_source_value| {
if (!import_source_value.isUndefinedOrNull()) {
if (!import_source_value.isString()) {
return globalThis.throwInvalidArguments("jsxImportSource must be a string", .{});
}
const str = try import_source_value.toBunString(globalThis);
defer str.deref();
if (!str.isEmpty()) {
const utf8 = str.toUTF8(allocator);
defer utf8.deinit();
options.jsx_import_source = try allocator.dupe(u8, utf8.slice());
}
}
}
}
return options;
}
fn camelCaseOf(comptime snake: []const u8) []const u8 {
return comptime brk: {
var count: usize = 0;
for (snake) |c| {
if (c != '_') count += 1;
}
if (count == snake.len) break :brk snake;
var buf: [count]u8 = undefined;
var i: usize = 0;
var cap_next = false;
for (snake) |c| {
if (c == '_') {
cap_next = true;
} else {
buf[i] = if (cap_next and i != 0 and c >= 'a' and c <= 'z') c - 32 else c;
i += 1;
cap_next = false;
}
}
const final = buf;
break :brk &final;
};
}
const bun = @import("bun");
const jsc = bun.jsc;
const md = bun.md;
const mdx = bun.md.mdx;
const std = @import("std");
const JSValue = jsc.JSValue;