url: align default argument handling for URLPattern with webidl · nodejs/node@2d63638
@@ -202,7 +202,11 @@ void URLPattern::New(const FunctionCallbackInfo<Value>& args) {
202202// - new URLPattern(input, baseURL)
203203// - new URLPattern(input, options)
204204// - new URLPattern(input, baseURL, options)
205-if (args[0]->IsString()) {
205+// Per WebIDL, null/undefined for a union type including a dictionary
206+// uses the default value (empty init).
207+if (args[0]->IsNullOrUndefined()) {
208+ init = ada::url_pattern_init{};
209+ } else if (args[0]->IsString()) {
206210 BufferValue input_buffer(env->isolate(), args[0]);
207211CHECK_NOT_NULL(*input_buffer);
208212 input = input_buffer.ToString();
@@ -217,41 +221,55 @@ void URLPattern::New(const FunctionCallbackInfo<Value>& args) {
217221return;
218222 }
219223220-// The next argument can be baseURL or options.
221-if (args.Length() > 1) {
224+// Per WebIDL overload resolution:
225+// With 3+ args, it's always overload 1: (input, baseURL, options)
226+// With 2 args, if arg1 is string, it is overload 1 (baseURL),
227+// otherwise overload 2 (options)
228+if (args.Length() >= 3) {
229+// arg1 is baseURL. Per WebIDL, null/undefined are stringified for
230+// USVString ("null"/"undefined"), which will be rejected as invalid
231+// URLs by ada downstream.
222232if (args[1]->IsString()) {
223233 BufferValue base_url_buffer(env->isolate(), args[1]);
224234CHECK_NOT_NULL(*base_url_buffer);
225235 base_url = base_url_buffer.ToString();
226- } else if (args[1]->IsObject()) {
227-CHECK(!options.has_value());
228- options = URLPatternOptions::FromJsObject(env, args[1].As<Object>());
229-if (!options) {
230-// If options does not have a value, we assume an error was
231-// thrown and scheduled on the isolate. Return early to
232-// propagate it.
233-return;
234- }
236+ } else if (args[1]->IsNull()) {
237+ base_url = std::string("null");
238+ } else if (args[1]->IsUndefined()) {
239+ base_url = std::string("undefined");
235240 } else {
236-THROW_ERR_INVALID_ARG_TYPE(env,
237-"second argument must be a string or object");
241+THROW_ERR_INVALID_ARG_TYPE(env, "second argument must be a string");
238242return;
239243 }
240244241-// Only remaining argument can be options.
242-if (args.Length() > 2) {
245+// arg2 is options. Per WebIDL, null/undefined for a dictionary
246+// uses the default value (empty dict).
247+if (!args[2]->IsNullOrUndefined()) {
243248if (!args[2]->IsObject()) {
244249THROW_ERR_INVALID_ARG_TYPE(env, "options must be an object");
245250return;
246251 }
247252CHECK(!options.has_value());
248253 options = URLPatternOptions::FromJsObject(env, args[2].As<Object>());
249-if (!options) {
250-// If options does not have a value, we assume an error was
251-// thrown and scheduled on the isolate. Return early to
252-// propagate it.
253-return;
254- }
254+if (!options) return;
255+ }
256+ } else if (args.Length() == 2) {
257+// Overload resolution: string is overload 1 (baseURL),
258+// otherwise overload 2 (options).
259+if (args[1]->IsString()) {
260+ BufferValue base_url_buffer(env->isolate(), args[1]);
261+CHECK_NOT_NULL(*base_url_buffer);
262+ base_url = base_url_buffer.ToString();
263+ } else if (args[1]->IsNullOrUndefined()) {
264+// Overload 2, options uses default.
265+ } else if (args[1]->IsObject()) {
266+CHECK(!options.has_value());
267+ options = URLPatternOptions::FromJsObject(env, args[1].As<Object>());
268+if (!options) return;
269+ } else {
270+THROW_ERR_INVALID_ARG_TYPE(env,
271+"second argument must be a string or object");
272+return;
255273 }
256274 }
257275@@ -493,11 +511,8 @@ URLPattern::URLPatternOptions::FromJsObject(Environment* env,
493511 Local<Value> ignore_case;
494512if (obj->Get(env->context(), env->ignore_case_string())
495513 .ToLocal(&ignore_case)) {
496-if (!ignore_case->IsBoolean()) {
497-THROW_ERR_INVALID_ARG_TYPE(env, "options.ignoreCase must be a boolean");
498-return std::nullopt;
499- }
500- options.ignore_case = ignore_case->IsTrue();
514+// Per WebIDL, boolean dictionary members are coerced (not type-checked).
515+ options.ignore_case = ignore_case->BooleanValue(env->isolate());
501516 } else {
502517// If ToLocal returns false, the assumption is that getting the
503518// ignore_case_string threw an error, let's propagate that now
@@ -564,7 +579,7 @@ void URLPattern::Exec(const FunctionCallbackInfo<Value>& args) {
564579 ada::url_pattern_input input;
565580 std::optional<std::string> baseURL{};
566581 std::string input_base;
567-if (args.Length() == 0) {
582+if (args.Length() == 0 || args[0]->IsNullOrUndefined()) {
568583 input = ada::url_pattern_init{};
569584 } else if (args[0]->IsString()) {
570585 Utf8Value input_value(env->isolate(), args[0].As<String>());
@@ -580,13 +595,16 @@ void URLPattern::Exec(const FunctionCallbackInfo<Value>& args) {
580595return;
581596 }
582597583-if (args.Length() > 1) {
584-if (!args[1]->IsString()) {
598+if (args.Length() > 1 && !args[1]->IsUndefined()) {
599+if (args[1]->IsNull()) {
600+ baseURL = std::string("null");
601+ } else if (args[1]->IsString()) {
602+ Utf8Value base_url_value(env->isolate(), args[1].As<String>());
603+ baseURL = base_url_value.ToStringView();
604+ } else {
585605THROW_ERR_INVALID_ARG_TYPE(env, "baseURL must be a string");
586606return;
587607 }
588- Utf8Value base_url_value(env->isolate(), args[1].As<String>());
589- baseURL = base_url_value.ToStringView();
590608 }
591609592610 Local<Value> result;
@@ -607,7 +625,7 @@ void URLPattern::Test(const FunctionCallbackInfo<Value>& args) {
607625 ada::url_pattern_input input;
608626 std::optional<std::string> baseURL{};
609627 std::string input_base;
610-if (args.Length() == 0) {
628+if (args.Length() == 0 || args[0]->IsNullOrUndefined()) {
611629 input = ada::url_pattern_init{};
612630 } else if (args[0]->IsString()) {
613631 Utf8Value input_value(env->isolate(), args[0].As<String>());
@@ -623,13 +641,16 @@ void URLPattern::Test(const FunctionCallbackInfo<Value>& args) {
623641return;
624642 }
625643626-if (args.Length() > 1) {
627-if (!args[1]->IsString()) {
644+if (args.Length() > 1 && !args[1]->IsUndefined()) {
645+if (args[1]->IsNull()) {
646+ baseURL = std::string("null");
647+ } else if (args[1]->IsString()) {
648+ Utf8Value base_url_value(env->isolate(), args[1].As<String>());
649+ baseURL = base_url_value.ToStringView();
650+ } else {
628651THROW_ERR_INVALID_ARG_TYPE(env, "baseURL must be a string");
629652return;
630653 }
631- Utf8Value base_url_value(env->isolate(), args[1].As<String>());
632- baseURL = base_url_value.ToStringView();
633654 }
634655635656 std::optional<std::string_view> baseURL_opt =