Skip to content

Commit 07d3698

Browse files
committed
url: align default argument handling for URLPattern with webidl
1 parent dfe438d commit 07d3698

File tree

2 files changed

+102
-7
lines changed

2 files changed

+102
-7
lines changed

src/node_url_pattern.cc

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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();
@@ -218,7 +222,7 @@ void URLPattern::New(const FunctionCallbackInfo<Value>& args) {
218222
}
219223

220224
// The next argument can be baseURL or options.
221-
if (args.Length() > 1) {
225+
if (args.Length() > 1 && !args[1]->IsNullOrUndefined()) {
222226
if (args[1]->IsString()) {
223227
BufferValue base_url_buffer(env->isolate(), args[1]);
224228
CHECK_NOT_NULL(*base_url_buffer);
@@ -239,7 +243,7 @@ void URLPattern::New(const FunctionCallbackInfo<Value>& args) {
239243
}
240244

241245
// Only remaining argument can be options.
242-
if (args.Length() > 2) {
246+
if (args.Length() > 2 && !args[2]->IsNullOrUndefined()) {
243247
if (!args[2]->IsObject()) {
244248
THROW_ERR_INVALID_ARG_TYPE(env, "options must be an object");
245249
return;
@@ -564,7 +568,7 @@ void URLPattern::Exec(const FunctionCallbackInfo<Value>& args) {
564568
ada::url_pattern_input input;
565569
std::optional<std::string> baseURL{};
566570
std::string input_base;
567-
if (args.Length() == 0) {
571+
if (args.Length() == 0 || args[0]->IsNullOrUndefined()) {
568572
input = ada::url_pattern_init{};
569573
} else if (args[0]->IsString()) {
570574
Utf8Value input_value(env->isolate(), args[0].As<String>());
@@ -580,7 +584,7 @@ void URLPattern::Exec(const FunctionCallbackInfo<Value>& args) {
580584
return;
581585
}
582586

583-
if (args.Length() > 1) {
587+
if (args.Length() > 1 && !args[1]->IsNullOrUndefined()) {
584588
if (!args[1]->IsString()) {
585589
THROW_ERR_INVALID_ARG_TYPE(env, "baseURL must be a string");
586590
return;
@@ -607,7 +611,7 @@ void URLPattern::Test(const FunctionCallbackInfo<Value>& args) {
607611
ada::url_pattern_input input;
608612
std::optional<std::string> baseURL{};
609613
std::string input_base;
610-
if (args.Length() == 0) {
614+
if (args.Length() == 0 || args[0]->IsNullOrUndefined()) {
611615
input = ada::url_pattern_init{};
612616
} else if (args[0]->IsString()) {
613617
Utf8Value input_value(env->isolate(), args[0].As<String>());
@@ -623,7 +627,7 @@ void URLPattern::Test(const FunctionCallbackInfo<Value>& args) {
623627
return;
624628
}
625629

626-
if (args.Length() > 1) {
630+
if (args.Length() > 1 && !args[1]->IsNullOrUndefined()) {
627631
if (!args[1]->IsString()) {
628632
THROW_ERR_INVALID_ARG_TYPE(env, "baseURL must be a string");
629633
return;

test/parallel/test-urlpattern-types.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,94 @@ assert.throws(() => pattern.test(1), {
4444
assert.throws(() => pattern.test('', 1), {
4545
code: 'ERR_INVALID_ARG_TYPE',
4646
});
47+
48+
// Per WebIDL, undefined/null for optional arguments with defaults should use
49+
// the default value (empty URLPatternInit {}) rather than throwing.
50+
// For a union type (USVString or URLPatternInit), null resolves to the
51+
// dictionary branch, yielding an empty URLPatternInit.
52+
53+
// Constructor: undefined input should be treated as empty init.
54+
{
55+
const p = new URLPattern(undefined);
56+
assert.strictEqual(p.protocol, '*');
57+
assert.strictEqual(p.hostname, '*');
58+
}
59+
60+
// Constructor: null input should be treated as empty init.
61+
{
62+
const p = new URLPattern(null);
63+
assert.strictEqual(p.protocol, '*');
64+
assert.strictEqual(p.hostname, '*');
65+
}
66+
67+
// Constructor: undefined input with undefined baseURL.
68+
{
69+
const p = new URLPattern(undefined, undefined);
70+
assert.strictEqual(p.protocol, '*');
71+
assert.strictEqual(p.pathname, '*');
72+
}
73+
74+
// Constructor: null input with null baseURL.
75+
{
76+
const p = new URLPattern(null, null);
77+
assert.strictEqual(p.protocol, '*');
78+
assert.strictEqual(p.pathname, '*');
79+
}
80+
81+
// Constructor: valid input with undefined options.
82+
{
83+
const p = new URLPattern({ pathname: '/foo' }, undefined);
84+
assert.strictEqual(p.pathname, '/foo');
85+
}
86+
87+
// Constructor: valid input with null options.
88+
{
89+
const p = new URLPattern({ pathname: '/foo' }, null);
90+
assert.strictEqual(p.pathname, '/foo');
91+
}
92+
93+
// Constructor: string input, undefined baseURL, undefined options.
94+
{
95+
const p = new URLPattern('https://example.com/foo', undefined, undefined);
96+
assert.strictEqual(p.hostname, 'example.com');
97+
assert.strictEqual(p.pathname, '/foo');
98+
}
99+
100+
// Constructor: string input, null baseURL, null options.
101+
{
102+
const p = new URLPattern('https://example.com/foo', null, null);
103+
assert.strictEqual(p.hostname, 'example.com');
104+
assert.strictEqual(p.pathname, '/foo');
105+
}
106+
107+
// exec() and test(): undefined input should be treated as empty init.
108+
{
109+
const p = new URLPattern();
110+
assert.strictEqual(p.test(undefined), true);
111+
assert.strictEqual(p.test(undefined, undefined), true);
112+
assert.notStrictEqual(p.exec(undefined), null);
113+
assert.notStrictEqual(p.exec(undefined, undefined), null);
114+
}
115+
116+
// exec() and test(): null input should be treated as empty init.
117+
{
118+
const p = new URLPattern();
119+
assert.strictEqual(p.test(null), true);
120+
assert.strictEqual(p.test(null, null), true);
121+
assert.notStrictEqual(p.exec(null), null);
122+
assert.notStrictEqual(p.exec(null, null), null);
123+
}
124+
125+
// exec() and test(): valid input with undefined baseURL.
126+
{
127+
const p = new URLPattern({ protocol: 'https' });
128+
assert.strictEqual(p.test('https://example.com', undefined), true);
129+
assert.notStrictEqual(p.exec('https://example.com', undefined), null);
130+
}
131+
132+
// exec() and test(): valid input with null baseURL.
133+
{
134+
const p = new URLPattern({ protocol: 'https' });
135+
assert.strictEqual(p.test('https://example.com', null), true);
136+
assert.notStrictEqual(p.exec('https://example.com', null), null);
137+
}

0 commit comments

Comments
 (0)