@@ -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 ]);
207211 CHECK_NOT_NULL (*input_buffer);
208212 input = input_buffer.ToString ();
@@ -217,41 +221,55 @@ void URLPattern::New(const FunctionCallbackInfo<Value>& args) {
217221 return ;
218222 }
219223
220- // 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 → overload 1 (baseURL),
227+ // else → 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.
222232 if (args[1 ]->IsString ()) {
223233 BufferValue base_url_buffer (env->isolate (), args[1 ]);
224234 CHECK_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" );
238242 return ;
239243 }
240244
241- // 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 ()) {
243248 if (!args[2 ]->IsObject ()) {
244249 THROW_ERR_INVALID_ARG_TYPE (env, " options must be an object" );
245250 return ;
246251 }
247252 CHECK (!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 → overload 1 (baseURL),
258+ // else → 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 → skip
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;
494512 if (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) {
580595 return ;
581596 }
582597
583- 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 {
585605 THROW_ERR_INVALID_ARG_TYPE (env, " baseURL must be a string" );
586606 return ;
587607 }
588- Utf8Value base_url_value (env->isolate (), args[1 ].As <String>());
589- baseURL = base_url_value.ToStringView ();
590608 }
591609
592610 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) {
623641 return ;
624642 }
625643
626- 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 {
628651 THROW_ERR_INVALID_ARG_TYPE (env, " baseURL must be a string" );
629652 return ;
630653 }
631- Utf8Value base_url_value (env->isolate (), args[1 ].As <String>());
632- baseURL = base_url_value.ToStringView ();
633654 }
634655
635656 std::optional<std::string_view> baseURL_opt =
0 commit comments