Compare commits

...

2 Commits

Author SHA1 Message Date
Halil Durak
94b003804b URLSearchParams: update tests 2026-03-31 16:01:21 +03:00
Halil Durak
b41c86e104 URLSearchParams: support passing arrays to constructor 2026-03-31 16:01:08 +03:00
2 changed files with 83 additions and 2 deletions

View File

@@ -20,8 +20,8 @@
<script id=urlSearchParams>
const inputs = [
// @ZIGDOM [["over", "9000!!"], ["abc", 123], ["key1", ""], ["key2", ""]],
{over: "9000!!", abc: 123, key1: "", key2: ""},
[["over", "9000!!"], ["abc", "123"], ["key1", ""], ["key2", ""]],
{over: "9000!!", abc: 123, key1: "", key2: ""},
"over=9000!!&abc=123&key1&key2=",
"?over=9000!!&abc=123&key1&key2=",
]
@@ -367,3 +367,49 @@
testing.expectEqual(['3'], ups.getAll('b'));
}
</script>
<script id=arrayOfArrays>
{
const usp = new URLSearchParams([["a", "1"], ["b", "2"], ["a", "3"]]);
testing.expectEqual(3, usp.size);
testing.expectEqual('1', usp.get('a'));
testing.expectEqual(['1', '3'], usp.getAll('a'));
testing.expectEqual('2', usp.get('b'));
testing.expectEqual('a=1&b=2&a=3', usp.toString());
}
</script>
<script id=arrayOfArraysEmpty>
{
const usp = new URLSearchParams([]);
testing.expectEqual(0, usp.size);
testing.expectEqual('', usp.toString());
}
</script>
<script id=arrayOfArraysDuplicateKeys>
{
const usp = new URLSearchParams([["key", "first"], ["key", "second"], ["key", "third"]]);
testing.expectEqual(3, usp.size);
testing.expectEqual('first', usp.get('key'));
testing.expectEqual(['first', 'second', 'third'], usp.getAll('key'));
}
</script>
<script id=arrayOfArraysSpecialChars>
{
const usp = new URLSearchParams([["q", "hello world"], ["url", "https://example.com/?a=1&b=2"]]);
testing.expectEqual(2, usp.size);
testing.expectEqual('hello world', usp.get('q'));
testing.expectEqual('https://example.com/?a=1&b=2', usp.get('url'));
}
</script>
<script id=arrayOfArraysNumericValues>
{
const usp = new URLSearchParams([["count", 42], ["pi", 3.14]]);
testing.expectEqual(2, usp.size);
testing.expectEqual('42', usp.get('count'));
testing.expectEqual('3.14', usp.get('pi'));
}
</script>

View File

@@ -46,6 +46,10 @@ pub fn init(opts_: ?InitOpts, page: *Page) !*URLSearchParams {
.query_string => |qs| break :blk try paramsFromString(arena, qs, &page.buf),
.form_data => |fd| break :blk try KeyValueList.copy(arena, fd._list),
.value => |js_val| {
// Order matters here; Array is also an Object.
if (js_val.isArray()) {
break :blk try paramsFromArray(arena, js_val.toArray());
}
if (js_val.isObject()) {
break :blk try KeyValueList.fromJsObject(arena, js_val.toObject(), null, page);
}
@@ -134,6 +138,37 @@ pub fn sort(self: *URLSearchParams) void {
}.cmp);
}
fn paramsFromArray(allocator: Allocator, array: js.Array) !KeyValueList {
const array_len = array.len();
if (array_len == 0) {
return .empty;
}
var params = KeyValueList.init();
try params.ensureTotalCapacity(allocator, array_len);
// TODO: Release `params` on error.
var i: u32 = 0;
while (i < array_len) : (i += 1) {
const item = try array.get(i);
if (!item.isArray()) return error.InvalidArgument;
const as_array = item.toArray();
// Need 2 items for KV.
if (as_array.len() != 2) return error.InvalidArgument;
const name_val = try as_array.get(0);
const value_val = try as_array.get(1);
params._entries.appendAssumeCapacity(.{
.name = try name_val.toSSOWithAlloc(allocator),
.value = try value_val.toSSOWithAlloc(allocator),
});
}
return params;
}
fn paramsFromString(allocator: Allocator, input_: []const u8, buf: []u8) !KeyValueList {
if (input_.len == 0) {
return .empty;