@@ -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,56 @@ 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 {
236241 THROW_ERR_INVALID_ARG_TYPE (env,
237- " second argument must be a string or object " );
242+ " second argument must be a string" );
238243 return ;
239244 }
240245
241- // Only remaining argument can be options.
242- if (args.Length () > 2 ) {
246+ // arg2 is options. Per WebIDL, null/undefined for a dictionary
247+ // uses the default value (empty dict).
248+ if (!args[2 ]->IsNullOrUndefined ()) {
243249 if (!args[2 ]->IsObject ()) {
244250 THROW_ERR_INVALID_ARG_TYPE (env, " options must be an object" );
245251 return ;
246252 }
247253 CHECK (!options.has_value ());
248254 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- }
255+ if (!options) return ;
256+ }
257+ } else if (args.Length () == 2 ) {
258+ // Overload resolution: string → overload 1 (baseURL),
259+ // else → overload 2 (options).
260+ if (args[1 ]->IsString ()) {
261+ BufferValue base_url_buffer (env->isolate (), args[1 ]);
262+ CHECK_NOT_NULL (*base_url_buffer);
263+ base_url = base_url_buffer.ToString ();
264+ } else if (args[1 ]->IsNullOrUndefined ()) {
265+ // Overload 2, options uses default → skip
266+ } else if (args[1 ]->IsObject ()) {
267+ CHECK (!options.has_value ());
268+ options = URLPatternOptions::FromJsObject (env, args[1 ].As <Object>());
269+ if (!options) return ;
270+ } else {
271+ THROW_ERR_INVALID_ARG_TYPE (env,
272+ " second argument must be a string or object" );
273+ return ;
255274 }
256275 }
257276
@@ -493,11 +512,8 @@ URLPattern::URLPatternOptions::FromJsObject(Environment* env,
493512 Local<Value> ignore_case;
494513 if (obj->Get (env->context (), env->ignore_case_string ())
495514 .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 ();
515+ // Per WebIDL, boolean dictionary members are coerced (not type-checked).
516+ options.ignore_case = ignore_case->BooleanValue (env->isolate ());
501517 } else {
502518 // If ToLocal returns false, the assumption is that getting the
503519 // ignore_case_string threw an error, let's propagate that now
@@ -564,7 +580,7 @@ void URLPattern::Exec(const FunctionCallbackInfo<Value>& args) {
564580 ada::url_pattern_input input;
565581 std::optional<std::string> baseURL{};
566582 std::string input_base;
567- if (args.Length () == 0 ) {
583+ if (args.Length () == 0 || args[ 0 ]-> IsNullOrUndefined () ) {
568584 input = ada::url_pattern_init{};
569585 } else if (args[0 ]->IsString ()) {
570586 Utf8Value input_value (env->isolate (), args[0 ].As <String>());
@@ -580,13 +596,16 @@ void URLPattern::Exec(const FunctionCallbackInfo<Value>& args) {
580596 return ;
581597 }
582598
583- if (args.Length () > 1 ) {
584- if (!args[1 ]->IsString ()) {
599+ if (args.Length () > 1 && !args[1 ]->IsUndefined ()) {
600+ if (args[1 ]->IsNull ()) {
601+ baseURL = std::string (" null" );
602+ } else if (args[1 ]->IsString ()) {
603+ Utf8Value base_url_value (env->isolate (), args[1 ].As <String>());
604+ baseURL = base_url_value.ToStringView ();
605+ } else {
585606 THROW_ERR_INVALID_ARG_TYPE (env, " baseURL must be a string" );
586607 return ;
587608 }
588- Utf8Value base_url_value (env->isolate (), args[1 ].As <String>());
589- baseURL = base_url_value.ToStringView ();
590609 }
591610
592611 Local<Value> result;
@@ -607,7 +626,7 @@ void URLPattern::Test(const FunctionCallbackInfo<Value>& args) {
607626 ada::url_pattern_input input;
608627 std::optional<std::string> baseURL{};
609628 std::string input_base;
610- if (args.Length () == 0 ) {
629+ if (args.Length () == 0 || args[ 0 ]-> IsNullOrUndefined () ) {
611630 input = ada::url_pattern_init{};
612631 } else if (args[0 ]->IsString ()) {
613632 Utf8Value input_value (env->isolate (), args[0 ].As <String>());
@@ -623,13 +642,16 @@ void URLPattern::Test(const FunctionCallbackInfo<Value>& args) {
623642 return ;
624643 }
625644
626- if (args.Length () > 1 ) {
627- if (!args[1 ]->IsString ()) {
645+ if (args.Length () > 1 && !args[1 ]->IsUndefined ()) {
646+ if (args[1 ]->IsNull ()) {
647+ baseURL = std::string (" null" );
648+ } else if (args[1 ]->IsString ()) {
649+ Utf8Value base_url_value (env->isolate (), args[1 ].As <String>());
650+ baseURL = base_url_value.ToStringView ();
651+ } else {
628652 THROW_ERR_INVALID_ARG_TYPE (env, " baseURL must be a string" );
629653 return ;
630654 }
631- Utf8Value base_url_value (env->isolate (), args[1 ].As <String>());
632- baseURL = base_url_value.ToStringView ();
633655 }
634656
635657 std::optional<std::string_view> baseURL_opt =
0 commit comments