diff --git a/src/env_properties.h b/src/env_properties.h index 7ef519960070c0..f889c2120f29b0 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -467,6 +467,8 @@ V(streambaseoutputstream_constructor_template, v8::ObjectTemplate) \ V(tcp_constructor_template, v8::FunctionTemplate) \ V(tty_constructor_template, v8::FunctionTemplate) \ + V(urlpatterncomponentresult_template, v8::DictionaryTemplate) \ + V(urlpatterninit_template, v8::DictionaryTemplate) \ V(urlpatternresult_template, v8::DictionaryTemplate) \ V(write_wrap_template, v8::ObjectTemplate) \ V(worker_cpu_profile_taker_template, v8::ObjectTemplate) \ diff --git a/src/node_url_pattern.cc b/src/node_url_pattern.cc index f1bddaeab0260e..2294ee43f0a08d 100644 --- a/src/node_url_pattern.cc +++ b/src/node_url_pattern.cc @@ -61,6 +61,7 @@ using v8::FunctionTemplate; using v8::Global; using v8::Isolate; using v8::Local; +using v8::LocalVector; using v8::MaybeLocal; using v8::Name; using v8::NewStringType; @@ -284,27 +285,56 @@ MaybeLocal URLPattern::URLPatternInit::ToJsObject( Environment* env, const ada::url_pattern_init& init) { auto isolate = env->isolate(); auto context = env->context(); - auto result = Object::New(isolate); - const auto trySet = [&](auto name, const std::optional& val) { - if (!val) return true; - Local temp; - return ToV8Value(context, *val).ToLocal(&temp) && - result->Set(context, name, temp).IsJust(); + auto tmpl = env->urlpatterninit_template(); + if (tmpl.IsEmpty()) { + static constexpr std::string_view namesVec[] = { + "protocol", + "username", + "password", + "hostname", + "port", + "pathname", + "search", + "hash", + "baseURL", + }; + tmpl = DictionaryTemplate::New(isolate, namesVec); + env->set_urlpatterninit_template(tmpl); + } + + MaybeLocal values[] = { + Undefined(isolate), // protocol + Undefined(isolate), // username + Undefined(isolate), // password + Undefined(isolate), // hostname + Undefined(isolate), // port + Undefined(isolate), // pathname + Undefined(isolate), // search + Undefined(isolate), // hash + Undefined(isolate), // baseURL + }; + + int idx = 0; + Local temp; + const auto trySet = [&](const std::optional& val) { + if (val.has_value()) { + if (!ToV8Value(context, *val).ToLocal(&temp)) { + return false; + } + values[idx] = temp; + } + idx++; + return true; }; - if (!trySet(env->protocol_string(), init.protocol) || - !trySet(env->username_string(), init.username) || - !trySet(env->password_string(), init.password) || - !trySet(env->hostname_string(), init.hostname) || - !trySet(env->port_string(), init.port) || - !trySet(env->pathname_string(), init.pathname) || - !trySet(env->search_string(), init.search) || - !trySet(env->hash_string(), init.hash) || - !trySet(env->base_url_string(), init.base_url)) { + if (!trySet(init.protocol) || !trySet(init.username) || + !trySet(init.password) || !trySet(init.hostname) || !trySet(init.port) || + !trySet(init.pathname) || !trySet(init.search) || !trySet(init.hash) || + !trySet(init.base_url)) { return {}; } - return result; + return NewDictionaryInstance(env->context(), tmpl, values); } std::optional URLPattern::URLPatternInit::FromJsObject( @@ -364,12 +394,16 @@ MaybeLocal URLPattern::URLPatternComponentResult::ToJSObject( Environment* env, const ada::url_pattern_component_result& result) { auto isolate = env->isolate(); auto context = env->context(); - auto parsed_group = Object::New(isolate); + LocalVector group_names(isolate); + LocalVector group_values(isolate); + group_names.reserve(result.groups.size()); + group_values.reserve(result.groups.size()); for (const auto& [group_key, group_value] : result.groups) { Local key; if (!ToV8Value(context, group_key).ToLocal(&key)) { return {}; } + group_names.push_back(key.As()); Local value; if (group_value) { if (!ToV8Value(env->context(), *group_value).ToLocal(&value)) { @@ -378,19 +412,30 @@ MaybeLocal URLPattern::URLPatternComponentResult::ToJSObject( } else { value = Undefined(isolate); } - if (parsed_group->Set(context, key, value).IsNothing()) { - return {}; - } + group_values.push_back(value); } + auto parsed_group = Object::New(isolate, + Object::New(isolate), + group_names.data(), + group_values.data(), + group_names.size()); + Local input; if (!ToV8Value(env->context(), result.input).ToLocal(&input)) { return {}; } - Local names[] = {env->input_string(), env->groups_string()}; - Local values[] = {input, parsed_group}; - DCHECK_EQ(arraysize(names), arraysize(values)); - return Object::New( - isolate, Object::New(isolate), names, values, arraysize(names)); + + auto tmpl = env->urlpatterncomponentresult_template(); + if (tmpl.IsEmpty()) { + static constexpr std::string_view namesVec[] = { + "input", + "groups", + }; + tmpl = DictionaryTemplate::New(isolate, namesVec); + env->set_urlpatterncomponentresult_template(tmpl); + } + MaybeLocal values[] = {input, parsed_group}; + return NewDictionaryInstance(env->context(), tmpl, values); } MaybeLocal URLPattern::URLPatternResult::ToJSValue(