diff options
| author | 2021-08-06 23:28:13 -0700 | |
|---|---|---|
| committer | 2021-08-06 23:28:13 -0700 | |
| commit | 4b1f89114e02f8472b63794534698ec13929080e (patch) | |
| tree | 8e038d24c11a8d4b471cb72fc86de135ec3042e5 /src/javascript | |
| parent | 6e4da63abeb76540bfefa9efcb3d823f8b50eb61 (diff) | |
| download | bun-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.zig | 55 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/bindings.cpp | 103 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/bindings.zig | 39 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/headers-cpp.h | 2 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/headers.h | 6 | ||||
| -rw-r--r-- | src/javascript/jsc/bindings/headers.zig | 4 |
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; |
