Skip to content

Commit 394ec8d

Browse files
committed
[bun.js] Implement Response.json
1 parent dcb437b commit 394ec8d

File tree

1 file changed

+76
-5
lines changed

1 file changed

+76
-5
lines changed

src/javascript/jsc/webcore/response.zig

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub const Response = struct {
4646
Response,
4747
.{
4848
.@"constructor" = constructor,
49+
.@"json" = .{ .rfn = constructJSON },
4950
},
5051
.{},
5152
);
@@ -219,18 +220,21 @@ pub const Response = struct {
219220
return js.JSValueMakeBoolean(ctx, this.isOK());
220221
}
221222

223+
fn getOrCreateHeaders(this: *Response) *Headers.RefCountedHeaders {
224+
if (this.body.init.headers == null) {
225+
this.body.init.headers = Headers.RefCountedHeaders.init(Headers.empty(this.allocator), this.allocator) catch unreachable;
226+
}
227+
return this.body.init.headers.?;
228+
}
229+
222230
pub fn getHeaders(
223231
this: *Response,
224232
ctx: js.JSContextRef,
225233
_: js.JSValueRef,
226234
_: js.JSStringRef,
227235
_: js.ExceptionRef,
228236
) js.JSValueRef {
229-
if (this.body.init.headers == null) {
230-
this.body.init.headers = Headers.RefCountedHeaders.init(Headers.empty(getAllocator(ctx)), getAllocator(ctx)) catch unreachable;
231-
}
232-
233-
return Headers.Class.make(ctx, this.body.init.headers.?.getRef());
237+
return Headers.Class.make(ctx, this.getOrCreateHeaders().getRef());
234238
}
235239

236240
pub fn doClone(
@@ -325,6 +329,73 @@ pub const Response = struct {
325329
}
326330
}
327331

332+
pub fn constructJSON(
333+
_: void,
334+
ctx: js.JSContextRef,
335+
_: js.JSObjectRef,
336+
_: js.JSObjectRef,
337+
arguments: []const js.JSValueRef,
338+
_: js.ExceptionRef,
339+
) js.JSObjectRef {
340+
// https://github.com/remix-run/remix/blob/db2c31f64affb2095e4286b91306b96435967969/packages/remix-server-runtime/responses.ts#L4
341+
var args = JSC.Node.ArgumentsSlice.from(arguments);
342+
// var response = getAllocator(ctx).create(Response) catch unreachable;
343+
344+
var response = Response{
345+
.body = Body{
346+
.init = Body.Init{
347+
.headers = null,
348+
.status_code = 200,
349+
},
350+
.value = Body.Value.empty,
351+
},
352+
.allocator = getAllocator(ctx),
353+
.url = "",
354+
};
355+
356+
const json_value = args.nextEat() orelse JSC.JSValue.zero;
357+
358+
if (@enumToInt(json_value) != 0) {
359+
var zig_str = JSC.ZigString.init("");
360+
// calling JSON.stringify on an empty string adds extra quotes
361+
// so this is correct
362+
json_value.jsonStringify(ctx.ptr(), 0, &zig_str);
363+
364+
if (zig_str.len > 0) {
365+
var zig_str_slice = zig_str.toSlice(getAllocator(ctx));
366+
367+
if (zig_str_slice.allocated) {
368+
response.body.value = .{
369+
.Blob = Blob.initWithAllASCII(zig_str_slice.mut(), zig_str_slice.allocator, ctx.ptr(), false),
370+
};
371+
} else {
372+
response.body.value = .{
373+
.Blob = Blob.initWithAllASCII(getAllocator(ctx).dupe(u8, zig_str_slice.slice()) catch unreachable, zig_str_slice.allocator, ctx.ptr(), true),
374+
};
375+
}
376+
}
377+
}
378+
379+
if (args.nextEat()) |init| {
380+
if (init.isUndefinedOrNull()) {} else if (init.isNumber()) {
381+
response.body.init.status_code = @intCast(u16, @minimum(@maximum(0, init.toInt32()), std.math.maxInt(u16)));
382+
} else {
383+
if (Body.Init.init(getAllocator(ctx), ctx, init.asObjectRef()) catch null) |_init| {
384+
response.body.init = _init;
385+
if (response.body.init.status_code == 0) {
386+
response.body.init.status_code = 200;
387+
}
388+
}
389+
}
390+
}
391+
392+
var headers_ref = response.getOrCreateHeaders().leak();
393+
headers_ref.putHeaderNormalized("content-type", "application/json", false);
394+
var ptr = response.allocator.create(Response) catch unreachable;
395+
ptr.* = response;
396+
397+
return Response.Class.make(ctx, ptr);
398+
}
328399
pub fn constructor(
329400
ctx: js.JSContextRef,
330401
_: js.JSObjectRef,

0 commit comments

Comments
 (0)