aboutsummaryrefslogtreecommitdiff
path: root/src/javascript
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-08-06 23:28:13 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-08-06 23:28:13 -0700
commit4b1f89114e02f8472b63794534698ec13929080e (patch)
tree8e038d24c11a8d4b471cb72fc86de135ec3042e5 /src/javascript
parent6e4da63abeb76540bfefa9efcb3d823f8b50eb61 (diff)
downloadbun-4b1f89114e02f8472b63794534698ec13929080e.tar.gz
bun-4b1f89114e02f8472b63794534698ec13929080e.tar.zst
bun-4b1f89114e02f8472b63794534698ec13929080e.zip
Query String parser with JS integration
Former-commit-id: 8542778c30e9757fa87514f46ff5086d7c8f6bfa
Diffstat (limited to 'src/javascript')
-rw-r--r--src/javascript/jsc/api/router.zig55
-rw-r--r--src/javascript/jsc/bindings/bindings.cpp103
-rw-r--r--src/javascript/jsc/bindings/bindings.zig39
-rw-r--r--src/javascript/jsc/bindings/headers-cpp.h2
-rw-r--r--src/javascript/jsc/bindings/headers.h6
-rw-r--r--src/javascript/jsc/bindings/headers.zig4
6 files changed, 201 insertions, 8 deletions
diff --git a/src/javascript/jsc/api/router.zig b/src/javascript/jsc/api/router.zig
index 6e6fea896..f1c892d94 100644
--- a/src/javascript/jsc/api/router.zig
+++ b/src/javascript/jsc/api/router.zig
@@ -4,6 +4,7 @@ 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;
usingnamespace @import("../bindings/bindings.zig");
usingnamespace @import("../webcore/response.zig");
const Router = @This();
@@ -11,8 +12,7 @@ const Router = @This();
const VirtualMachine = JavaScript.VirtualMachine;
route: *const FilesystemRouter.Match,
-file_path_str: js.JSStringRef = null,
-pathname_str: js.JSStringRef = null,
+query_string_map: ?QueryStringMap = null,
pub fn importRoute(
this: *Router,
@@ -231,7 +231,9 @@ pub fn getFilePath(
pub fn finalize(
this: *Router,
) void {
- // this.deinit();
+ if (this.query_string_map) |*map| {
+ map.deinit();
+ }
}
pub fn getPathname(
@@ -283,6 +285,40 @@ pub fn getKind(
return KindEnum.init(this.route.name).toValue(VirtualMachine.vm.global).asRef();
}
+threadlocal var query_string_values_buf: [256]string = undefined;
+threadlocal var query_string_value_refs_buf: [256]ZigString = undefined;
+pub fn createQueryObject(ctx: js.JSContextRef, map: *QueryStringMap, exception: js.ExceptionRef) callconv(.C) js.JSValueRef {
+ const QueryObjectCreator = struct {
+ query: *QueryStringMap,
+ pub fn create(this: *@This(), obj: *JSObject, global: *JSGlobalObject) void {
+ var iter = this.query.iter();
+ var str: ZigString = undefined;
+ while (iter.next(&query_string_values_buf)) |entry| {
+ str = ZigString.init(entry.name);
+
+ std.debug.assert(entry.values.len > 0);
+ if (entry.values.len > 1) {
+ var values = query_string_value_refs_buf[0..entry.values.len];
+ for (entry.values) |value, i| {
+ values[i] = ZigString.init(value);
+ }
+ obj.putRecord(VirtualMachine.vm.global, &str, values.ptr, values.len);
+ } else {
+ query_string_value_refs_buf[0] = ZigString.init(entry.values[0]);
+
+ obj.putRecord(VirtualMachine.vm.global, &str, &query_string_value_refs_buf, 1);
+ }
+ }
+ }
+ };
+
+ var creator = QueryObjectCreator{ .query = map };
+
+ var value = JSObject.createWithInitializer(QueryObjectCreator, &creator, VirtualMachine.vm.global, map.getNameCount());
+
+ return value.asRef();
+}
+
pub fn getQuery(
this: *Router,
ctx: js.JSContextRef,
@@ -290,5 +326,16 @@ pub fn getQuery(
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
- return ZigString.init(this.route.query_string).toValue(VirtualMachine.vm.global).asRef();
+ if (this.query_string_map == null) {
+ if (QueryStringMap.init(getAllocator(ctx), this.route.query_string)) |map| {
+ this.query_string_map = map;
+ } else |err| {}
+ }
+
+ // If it's still null, the query string has no names.
+ if (this.query_string_map) |*map| {
+ return createQueryObject(ctx, map, exception);
+ } else {
+ return JSValue.createEmptyObject(VirtualMachine.vm.global, 0).asRef();
+ }
}
diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp
index 4d8d13483..c66b5c94b 100644
--- a/src/javascript/jsc/bindings/bindings.cpp
+++ b/src/javascript/jsc/bindings/bindings.cpp
@@ -21,6 +21,7 @@
#include <JavaScriptCore/JSObject.h>
#include <JavaScriptCore/JSSet.h>
#include <JavaScriptCore/JSString.h>
+#include <JavaScriptCore/ObjectConstructor.h>
#include <JavaScriptCore/ParserError.h>
#include <JavaScriptCore/ScriptExecutable.h>
#include <JavaScriptCore/StackFrame.h>
@@ -31,9 +32,109 @@
#include <wtf/text/StringCommon.h>
#include <wtf/text/StringImpl.h>
#include <wtf/text/StringView.h>
-
#include <wtf/text/WTFString.h>
extern "C" {
+JSC__JSValue
+JSC__JSObject__create(JSC__JSGlobalObject *globalObject, size_t initialCapacity, void *arg2,
+ void (*ArgFn3)(void *arg0, JSC__JSObject *arg1, JSC__JSGlobalObject *arg2)) {
+ JSC::JSObject *object =
+ JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), initialCapacity);
+
+ ArgFn3(arg2, object, globalObject);
+
+ return JSC::JSValue::encode(object);
+}
+
+JSC__JSValue JSC__JSValue__createEmptyObject(JSC__JSGlobalObject *globalObject,
+ size_t initialCapacity) {
+ return JSC::JSValue::encode(
+ JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), initialCapacity));
+}
+
+void JSC__JSObject__putRecord(JSC__JSObject *object, JSC__JSGlobalObject *global, ZigString *key,
+ ZigString *values, size_t valuesLen) {
+ auto scope = DECLARE_THROW_SCOPE(global->vm());
+ auto ident = Zig::toIdentifier(*key, global);
+ JSC::PropertyDescriptor descriptor;
+
+ descriptor.setEnumerable(1);
+ descriptor.setConfigurable(1);
+ descriptor.setWritable(1);
+
+ if (valuesLen == 1) {
+ descriptor.setValue(JSC::jsString(global->vm(), Zig::toString(values[0])));
+ } else {
+
+ JSC::JSArray *array = nullptr;
+ {
+ JSC::ObjectInitializationScope initializationScope(global->vm());
+ if ((array = JSC::JSArray::tryCreateUninitializedRestricted(
+ initializationScope, nullptr,
+ global->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
+ valuesLen))) {
+
+ for (size_t i = 0; i < valuesLen; ++i) {
+ array->initializeIndexWithoutBarrier(
+ initializationScope, i, JSC::jsString(global->vm(), Zig::toString(values[i])));
+ }
+ }
+ }
+
+ if (!array) {
+ JSC::throwOutOfMemoryError(global, scope);
+ return;
+ }
+
+ descriptor.setValue(array);
+ }
+
+ object->methodTable(global->vm())->defineOwnProperty(object, global, ident, descriptor, true);
+ object->putDirect(global->vm(), ident, descriptor.value());
+ scope.release();
+}
+void JSC__JSValue__putRecord(JSC__JSValue objectValue, JSC__JSGlobalObject *global, ZigString *key,
+ ZigString *values, size_t valuesLen) {
+ JSC::JSValue objValue = JSC::JSValue::decode(objectValue);
+ JSC::JSObject *object = objValue.asCell()->getObject();
+ auto scope = DECLARE_THROW_SCOPE(global->vm());
+ auto ident = Zig::toIdentifier(*key, global);
+ JSC::PropertyDescriptor descriptor;
+
+ descriptor.setEnumerable(1);
+ descriptor.setConfigurable(1);
+ descriptor.setWritable(1);
+
+ if (valuesLen == 1) {
+ descriptor.setValue(JSC::jsString(global->vm(), Zig::toString(values[0])));
+ } else {
+
+ JSC::JSArray *array = nullptr;
+ {
+ JSC::ObjectInitializationScope initializationScope(global->vm());
+ if ((array = JSC::JSArray::tryCreateUninitializedRestricted(
+ initializationScope, nullptr,
+ global->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
+ valuesLen))) {
+
+ for (size_t i = 0; i < valuesLen; ++i) {
+ array->initializeIndexWithoutBarrier(
+ initializationScope, i, JSC::jsString(global->vm(), Zig::toString(values[i])));
+ }
+ }
+ }
+
+ if (!array) {
+ JSC::throwOutOfMemoryError(global, scope);
+ return;
+ }
+
+ descriptor.setValue(array);
+ }
+
+ object->methodTable(global->vm())->defineOwnProperty(object, global, ident, descriptor, true);
+ object->putDirect(global->vm(), ident, descriptor.value());
+ scope.release();
+}
// This is very naive!
JSC__JSInternalPromise *JSC__VM__reloadModule(JSC__VM *vm, JSC__JSGlobalObject *arg1,
diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig
index 9373a00a5..e2b2679ae 100644
--- a/src/javascript/jsc/bindings/bindings.zig
+++ b/src/javascript/jsc/bindings/bindings.zig
@@ -18,6 +18,29 @@ pub const JSObject = extern struct {
});
}
+ const InitializeCallback = fn (ctx: ?*c_void, obj: [*c]JSObject, global: [*c]JSGlobalObject) callconv(.C) void;
+ pub fn create(global_object: *JSGlobalObject, length: usize, ctx: *c_void, initializer: InitializeCallback) JSValue {
+ return cppFn("create", .{
+ global_object,
+ length,
+ ctx,
+ initializer,
+ });
+ }
+
+ pub fn Initializer(comptime Ctx: type, comptime func: fn (*Ctx, obj: *JSObject, global: *JSGlobalObject) void) type {
+ return struct {
+ pub fn call(this: ?*c_void, obj: [*c]JSObject, global: [*c]JSGlobalObject) callconv(.C) void {
+ @call(.{ .modifier = .always_inline }, func, .{ @ptrCast(*Ctx, @alignCast(@alignOf(*Ctx), this.?)), obj.?, global.? });
+ }
+ };
+ }
+
+ pub fn createWithInitializer(comptime Ctx: type, creator: *Ctx, global: *JSGlobalObject, length: usize) JSValue {
+ const Type = Initializer(Ctx, Ctx.create);
+ return create(global, length, creator, Type.call);
+ }
+
pub fn getIndex(this: *JSObject, globalThis: *JSGlobalObject, i: u32) JSValue {
return cppFn("getIndex", .{
this,
@@ -26,6 +49,10 @@ pub const JSObject = extern struct {
});
}
+ pub fn putRecord(this: *JSObject, global: *JSGlobalObject, key: *ZigString, values: [*]ZigString, values_len: usize) void {
+ return cppFn("putRecord", .{ this, global, key, values, values_len });
+ }
+
pub fn getDirect(this: *JSObject, globalThis: *JSGlobalObject, str: ZigString) JSValue {
return cppFn("getDirect", .{
this,
@@ -44,6 +71,8 @@ pub const JSObject = extern struct {
}
pub const Extern = [_][]const u8{
+ "putRecord",
+ "create",
"getArrayLength",
"getIndex",
"putAtIndex",
@@ -1126,6 +1155,14 @@ pub const JSValue = enum(i64) {
return @intToEnum(JSValue, @intCast(i64, @ptrToInt(ptr)));
}
+ pub fn createEmptyObject(global: *JSGlobalObject, len: usize) JSValue {
+ return cppFn("createEmptyObject", .{ global, len });
+ }
+
+ pub fn putRecord(value: JSValue, global: *JSGlobalObject, key: *ZigString, values: [*]ZigString, values_len: usize) void {
+ return cppFn("putRecord", .{ value, global, key, values, values_len });
+ }
+
pub fn getErrorsProperty(this: JSValue, globalObject: *JSGlobalObject) JSValue {
return cppFn("getErrorsProperty", .{ this, globalObject });
}
@@ -1363,7 +1400,7 @@ pub const JSValue = enum(i64) {
return @intToPtr(*c_void, @intCast(usize, @enumToInt(this)));
}
- pub const Extern = [_][]const u8{ "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "get", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt32", "jsNumberFromInt64", "jsNumberFromUint64", "isUndefined", "isNull", "isUndefinedOrNull", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" };
+ pub const Extern = [_][]const u8{ "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "get", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt32", "jsNumberFromInt64", "jsNumberFromUint64", "isUndefined", "isNull", "isUndefinedOrNull", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" };
};
pub const PropertyName = extern struct {
diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h
index 1e578bd0a..e23e9dd84 100644
--- a/src/javascript/jsc/bindings/headers-cpp.h
+++ b/src/javascript/jsc/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1628213116
+//-- AUTOGENERATED FILE -- 1628316335
// clang-format off
#pragma once
diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h
index 813a01750..abafa1279 100644
--- a/src/javascript/jsc/bindings/headers.h
+++ b/src/javascript/jsc/bindings/headers.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1628213116
+//-- AUTOGENERATED FILE -- 1628316335
// clang-format: off
#pragma once
@@ -231,10 +231,12 @@ typedef void* JSClassRef;
#pragma mark - JSC::JSObject
+CPP_DECL JSC__JSValue JSC__JSObject__create(JSC__JSGlobalObject* arg0, size_t arg1, void* arg2, void (* ArgFn3)(void* arg0, JSC__JSObject* arg1, JSC__JSGlobalObject* arg2));
CPP_DECL size_t JSC__JSObject__getArrayLength(JSC__JSObject* arg0);
CPP_DECL JSC__JSValue JSC__JSObject__getDirect(JSC__JSObject* arg0, JSC__JSGlobalObject* arg1, ZigString arg2);
CPP_DECL JSC__JSValue JSC__JSObject__getIndex(JSC__JSObject* arg0, JSC__JSGlobalObject* arg1, uint32_t arg2);
CPP_DECL void JSC__JSObject__putDirect(JSC__JSObject* arg0, JSC__JSGlobalObject* arg1, ZigString arg2, JSC__JSValue JSValue3);
+CPP_DECL void JSC__JSObject__putRecord(JSC__JSObject* arg0, JSC__JSGlobalObject* arg1, ZigString* arg2, ZigString* arg3, size_t arg4);
CPP_DECL JSC__JSValue ZigString__toErrorInstance(const ZigString* arg0, JSC__JSGlobalObject* arg1);
CPP_DECL JSC__JSValue ZigString__toValue(ZigString arg0, JSC__JSGlobalObject* arg1);
@@ -409,6 +411,7 @@ CPP_DECL JSC__JSCell* JSC__JSValue__asCell(JSC__JSValue JSValue0);
CPP_DECL double JSC__JSValue__asNumber(JSC__JSValue JSValue0);
CPP_DECL bJSC__JSObject JSC__JSValue__asObject(JSC__JSValue JSValue0);
CPP_DECL JSC__JSString* JSC__JSValue__asString(JSC__JSValue JSValue0);
+CPP_DECL JSC__JSValue JSC__JSValue__createEmptyObject(JSC__JSGlobalObject* arg0, size_t arg1);
CPP_DECL bool JSC__JSValue__eqlCell(JSC__JSValue JSValue0, JSC__JSCell* arg1);
CPP_DECL bool JSC__JSValue__eqlValue(JSC__JSValue JSValue0, JSC__JSValue JSValue1);
CPP_DECL void JSC__JSValue__forEach(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void (* ArgFn2)(JSC__VM* arg0, JSC__JSGlobalObject* arg1, JSC__JSValue JSValue2));
@@ -452,6 +455,7 @@ CPP_DECL JSC__JSValue JSC__JSValue__jsNumberFromU16(uint16_t arg0);
CPP_DECL JSC__JSValue JSC__JSValue__jsNumberFromUint64(uint64_t arg0);
CPP_DECL JSC__JSValue JSC__JSValue__jsTDZValue();
CPP_DECL JSC__JSValue JSC__JSValue__jsUndefined();
+CPP_DECL void JSC__JSValue__putRecord(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2, ZigString* arg3, size_t arg4);
CPP_DECL bool JSC__JSValue__toBoolean(JSC__JSValue JSValue0);
CPP_DECL int32_t JSC__JSValue__toInt32(JSC__JSValue JSValue0);
CPP_DECL JSC__JSObject* JSC__JSValue__toObject(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1);
diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig
index 901422733..de854fe53 100644
--- a/src/javascript/jsc/bindings/headers.zig
+++ b/src/javascript/jsc/bindings/headers.zig
@@ -97,10 +97,12 @@ pub const JSC__ObjectPrototype = struct_JSC__ObjectPrototype;
pub const JSC__CallFrame = bJSC__CallFrame;
pub const JSC__MapIteratorPrototype = struct_JSC__MapIteratorPrototype;
+pub extern fn JSC__JSObject__create(arg0: [*c]JSC__JSGlobalObject, arg1: usize, arg2: ?*c_void, ArgFn3: ?fn (?*c_void, [*c]JSC__JSObject, [*c]JSC__JSGlobalObject) callconv(.C) void) JSC__JSValue;
pub extern fn JSC__JSObject__getArrayLength(arg0: [*c]JSC__JSObject) usize;
pub extern fn JSC__JSObject__getDirect(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: ZigString) JSC__JSValue;
pub extern fn JSC__JSObject__getIndex(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: u32) JSC__JSValue;
pub extern fn JSC__JSObject__putDirect(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: ZigString, JSValue3: JSC__JSValue) void;
+pub extern fn JSC__JSObject__putRecord(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void;
pub extern fn ZigString__toErrorInstance(arg0: [*c]const ZigString, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
pub extern fn ZigString__toValue(arg0: ZigString, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
pub extern fn JSC__JSCell__getObject(arg0: [*c]JSC__JSCell) [*c]JSC__JSObject;
@@ -233,6 +235,7 @@ pub extern fn JSC__JSValue__asCell(JSValue0: JSC__JSValue) [*c]JSC__JSCell;
pub extern fn JSC__JSValue__asNumber(JSValue0: JSC__JSValue) f64;
pub extern fn JSC__JSValue__asObject(JSValue0: JSC__JSValue) bJSC__JSObject;
pub extern fn JSC__JSValue__asString(JSValue0: JSC__JSValue) [*c]JSC__JSString;
+pub extern fn JSC__JSValue__createEmptyObject(arg0: [*c]JSC__JSGlobalObject, arg1: usize) JSC__JSValue;
pub extern fn JSC__JSValue__eqlCell(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSCell) bool;
pub extern fn JSC__JSValue__eqlValue(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue) bool;
pub extern fn JSC__JSValue__forEach(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, ArgFn2: ?fn ([*c]JSC__VM, [*c]JSC__JSGlobalObject, JSC__JSValue) callconv(.C) void) void;
@@ -276,6 +279,7 @@ pub extern fn JSC__JSValue__jsNumberFromU16(arg0: u16) JSC__JSValue;
pub extern fn JSC__JSValue__jsNumberFromUint64(arg0: u64) JSC__JSValue;
pub extern fn JSC__JSValue__jsTDZValue(...) JSC__JSValue;
pub extern fn JSC__JSValue__jsUndefined(...) JSC__JSValue;
+pub extern fn JSC__JSValue__putRecord(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void;
pub extern fn JSC__JSValue__toBoolean(JSValue0: JSC__JSValue) bool;
pub extern fn JSC__JSValue__toInt32(JSValue0: JSC__JSValue) i32;
pub extern fn JSC__JSValue__toObject(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) [*c]JSC__JSObject;