Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 44 additions & 26 deletions src/node_url_pattern.cc
Original file line number Diff line number Diff line change
Expand Up @@ -409,22 +409,28 @@ std::optional<ada::url_pattern_init> URLPattern::URLPatternInit::FromJsObject(
}

MaybeLocal<Object> URLPattern::URLPatternComponentResult::ToJSObject(
Environment* env, const ada::url_pattern_component_result& result) {
Environment* env,
const ada::url_pattern_component_result& result,
const std::vector<std::string>& ordered_group_names) {
auto isolate = env->isolate();
auto context = env->context();
LocalVector<Name> group_names(isolate);
LocalVector<Name> js_group_names(isolate);
LocalVector<Value> group_values(isolate);
group_names.reserve(result.groups.size());
js_group_names.reserve(result.groups.size());
group_values.reserve(result.groups.size());
for (const auto& [group_key, group_value] : result.groups) {
for (const auto& group_key : ordered_group_names) {
const auto group = result.groups.find(group_key);
if (group == result.groups.end()) {
continue;
}
Local<Value> key;
if (!ToV8Value(context, group_key).ToLocal(&key)) {
return {};
}
group_names.push_back(key.As<Name>());
js_group_names.push_back(key.As<Name>());
Local<Value> value;
if (group_value) {
if (!ToV8Value(env->context(), *group_value).ToLocal(&value)) {
if (group->second) {
if (!ToV8Value(env->context(), *group->second).ToLocal(&value)) {
return {};
}
} else {
Expand All @@ -434,9 +440,9 @@ MaybeLocal<Object> URLPattern::URLPatternComponentResult::ToJSObject(
}
auto parsed_group = Object::New(isolate,
Object::New(isolate),
group_names.data(),
js_group_names.data(),
group_values.data(),
group_names.size());
js_group_names.size());

Local<Value> input;
if (!ToV8Value(env->context(), result.input).ToLocal(&input)) {
Expand All @@ -446,39 +452,45 @@ MaybeLocal<Object> URLPattern::URLPatternComponentResult::ToJSObject(
auto tmpl = env->urlpatterncomponentresult_template();
if (tmpl.IsEmpty()) {
static constexpr std::string_view namesVec[] = {
"input",
"groups",
"input",
};
tmpl = DictionaryTemplate::New(isolate, namesVec);
env->set_urlpatterncomponentresult_template(tmpl);
}
MaybeLocal<Value> values[] = {input, parsed_group};
MaybeLocal<Value> values[] = {parsed_group, input};
return NewDictionaryInstance(env->context(), tmpl, values);
}

MaybeLocal<Value> URLPattern::URLPatternResult::ToJSValue(
Environment* env, const ada::url_pattern_result& result) {
Environment* env,
const ada::url_pattern_result& result,
const ada::url_pattern<URLPatternRegexProvider>& url_pattern) {
auto isolate = env->isolate();

auto tmpl = env->urlpatternresult_template();
if (tmpl.IsEmpty()) {
static constexpr std::string_view namesVec[] = {
"hash",
"hostname",
"inputs",
"protocol",
"username",
"password",
"hostname",
"port",
"pathname",
"port",
"protocol",
"search",
"hash",
"username",
};
tmpl = DictionaryTemplate::New(isolate, namesVec);
env->set_urlpatternresult_template(tmpl);
}

size_t index = 0;
MaybeLocal<Value> vals[] = {
URLPatternComponentResult::ToJSObject(
env, result.hash, url_pattern.hash_component.group_name_list),
URLPatternComponentResult::ToJSObject(
env, result.hostname, url_pattern.hostname_component.group_name_list),
Array::New(env->context(),
result.inputs.size(),
[&index, &inputs = result.inputs, env]() {
Expand All @@ -493,14 +505,20 @@ MaybeLocal<Value> URLPattern::URLPatternResult::ToJSValue(
return URLPatternInit::ToJsObject(env, init);
}
}),
URLPatternComponentResult::ToJSObject(env, result.protocol),
URLPatternComponentResult::ToJSObject(env, result.username),
URLPatternComponentResult::ToJSObject(env, result.password),
URLPatternComponentResult::ToJSObject(env, result.hostname),
URLPatternComponentResult::ToJSObject(env, result.port),
URLPatternComponentResult::ToJSObject(env, result.pathname),
URLPatternComponentResult::ToJSObject(env, result.search),
URLPatternComponentResult::ToJSObject(env, result.hash)};
URLPatternComponentResult::ToJSObject(
env, result.password, url_pattern.password_component.group_name_list),
URLPatternComponentResult::ToJSObject(
env, result.pathname, url_pattern.pathname_component.group_name_list),
URLPatternComponentResult::ToJSObject(
env, result.port, url_pattern.port_component.group_name_list),
URLPatternComponentResult::ToJSObject(
env, result.protocol, url_pattern.protocol_component.group_name_list),
URLPatternComponentResult::ToJSObject(
env, result.search, url_pattern.search_component.group_name_list),
URLPatternComponentResult::ToJSObject(
env,
result.username,
url_pattern.username_component.group_name_list)};
return NewDictionaryInstanceNullProto(env->context(), tmpl, vals);
}

Expand Down Expand Up @@ -552,7 +570,7 @@ MaybeLocal<Value> URLPattern::Exec(Environment* env,
std::optional<std::string_view>& baseURL) {
if (auto result = url_pattern_.exec(input, baseURL ? &*baseURL : nullptr)) {
if (result->has_value()) {
return URLPatternResult::ToJSValue(env, result->value());
return URLPatternResult::ToJSValue(env, result->value(), url_pattern_);
}
return Null(env->isolate());
}
Expand Down
10 changes: 8 additions & 2 deletions src/node_url_pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
#include <v8.h>

#include <optional>
#include <string>
#include <string_view>
#include <vector>

namespace node::url_pattern {

Expand Down Expand Up @@ -81,13 +83,17 @@ class URLPattern : public BaseObject {
class URLPatternResult {
public:
static v8::MaybeLocal<v8::Value> ToJSValue(
Environment* env, const ada::url_pattern_result& result);
Environment* env,
const ada::url_pattern_result& result,
const ada::url_pattern<URLPatternRegexProvider>& url_pattern);
};

class URLPatternComponentResult {
public:
static v8::MaybeLocal<v8::Object> ToJSObject(
Environment* env, const ada::url_pattern_component_result& result);
Environment* env,
const ada::url_pattern_component_result& result,
const std::vector<std::string>& ordered_group_names);
};

private:
Expand Down
35 changes: 35 additions & 0 deletions test/parallel/test-urlpattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,38 @@ assert.throws(() => {
}, {
message: 'boom'
});

{
const result = new URLPattern({ pathname: '/:value' })
.exec('https://example.com/test');

assert.deepStrictEqual(Object.keys(result), [
'hash',
'hostname',
'inputs',
'password',
'pathname',
'port',
'protocol',
'search',
'username',
]);
assert.deepStrictEqual(Object.keys(result.pathname), [
'groups',
'input',
]);
assert.strictEqual(result.hostname.input, 'example.com');
assert.strictEqual(result.pathname.input, '/test');
assert.strictEqual(result.pathname.groups.value, 'test');
}

{
const result = new URLPattern({ pathname: '/:one/:two/:three' })
.exec('https://example.com/a/b/c');

assert.deepStrictEqual(Object.entries(result.pathname.groups), [
['one', 'a'],
['two', 'b'],
['three', 'c'],
]);
}