Skip to content

Commit 5777c8b

Browse files
authored
fix: avoid URL illegal constructor error (#458)
`nodeFileTrace` errors on `const URLParser = typeof window === 'undefined' ? URL : 'b'` with `TypeError: Class constructor URL cannot be invoked without 'new'`. This is because this code: ```ts async function ConditionalExpression() { return { test: 'foo', then: URL, else: 'bar', }; } await ConditionalExpression(); ``` calls `URL()` since `ConditionalExpression` is an async function returning a [thenable](https://masteringjs.io/tutorials/fundamentals/thenable). Solution: rename all `.then` fields to `.ifTrue` since `then` is reserved for thenables. Closes #447
1 parent 7fbb559 commit 5777c8b

File tree

5 files changed

+64
-59
lines changed

5 files changed

+64
-59
lines changed

src/analyze.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -552,8 +552,8 @@ export default async function analyze(
552552
else if (computed.wildcards.length >= 1)
553553
emitWildcardRequire(computed.value);
554554
} else {
555-
if ('then' in computed && typeof computed.then === 'string')
556-
add(computed.then);
555+
if ('ifTrue' in computed && typeof computed.ifTrue === 'string')
556+
add(computed.ifTrue);
557557
if ('else' in computed && typeof computed.else === 'string')
558558
add(computed.else);
559559
}
@@ -585,8 +585,8 @@ export default async function analyze(
585585
if (
586586
('value' in curStaticValue &&
587587
typeof curStaticValue.value !== 'symbol') ||
588-
('then' in curStaticValue &&
589-
typeof curStaticValue.then !== 'symbol' &&
588+
('ifTrue' in curStaticValue &&
589+
typeof curStaticValue.ifTrue !== 'symbol' &&
590590
typeof curStaticValue.else !== 'symbol')
591591
) {
592592
staticChildValue = curStaticValue;
@@ -974,7 +974,7 @@ export default async function analyze(
974974
}
975975
if (
976976
!('value' in computed) &&
977-
isAbsolutePathOrUrl(computed.then) &&
977+
isAbsolutePathOrUrl(computed.ifTrue) &&
978978
isAbsolutePathOrUrl(computed.else)
979979
) {
980980
staticChildValue = computed;
@@ -1196,14 +1196,14 @@ export default async function analyze(
11961196
await emitAssetPath(resolved);
11971197
} catch (e) {}
11981198
} else if (
1199-
'then' in staticChildValue &&
1199+
'ifTrue' in staticChildValue &&
12001200
'else' in staticChildValue &&
1201-
isAbsolutePathOrUrl(staticChildValue.then) &&
1201+
isAbsolutePathOrUrl(staticChildValue.ifTrue) &&
12021202
isAbsolutePathOrUrl(staticChildValue.else)
12031203
) {
12041204
let resolvedThen;
12051205
try {
1206-
resolvedThen = resolveAbsolutePathOrUrl(staticChildValue.then);
1206+
resolvedThen = resolveAbsolutePathOrUrl(staticChildValue.ifTrue);
12071207
} catch (e) {}
12081208
let resolvedElse;
12091209
try {

src/utils/static-eval.ts

+50-50
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export async function evaluate(
1616

1717
// walk returns:
1818
// 1. Single known value: { value: value }
19-
// 2. Conditional value: { test, then, else }
19+
// 2. Conditional value: { test, ifTrue, else }
2020
// 3. Unknown value: undefined
2121
function walk(node: Node) {
2222
const visitor = visitors[node.type];
@@ -130,79 +130,79 @@ const visitors: Record<
130130
if ('test' in l && 'value' in r) {
131131
const v: any = r.value;
132132
if (op === '==')
133-
return { test: l.test, then: l.then == v, else: l.else == v };
133+
return { test: l.test, ifTrue: l.ifTrue == v, else: l.else == v };
134134
if (op === '===')
135-
return { test: l.test, then: l.then === v, else: l.else === v };
135+
return { test: l.test, ifTrue: l.ifTrue === v, else: l.else === v };
136136
if (op === '!=')
137-
return { test: l.test, then: l.then != v, else: l.else != v };
137+
return { test: l.test, ifTrue: l.ifTrue != v, else: l.else != v };
138138
if (op === '!==')
139-
return { test: l.test, then: l.then !== v, else: l.else !== v };
139+
return { test: l.test, ifTrue: l.ifTrue !== v, else: l.else !== v };
140140
if (op === '+')
141-
return { test: l.test, then: l.then + v, else: l.else + v };
141+
return { test: l.test, ifTrue: l.ifTrue + v, else: l.else + v };
142142
if (op === '-')
143-
return { test: l.test, then: l.then - v, else: l.else - v };
143+
return { test: l.test, ifTrue: l.ifTrue - v, else: l.else - v };
144144
if (op === '*')
145-
return { test: l.test, then: l.then * v, else: l.else * v };
145+
return { test: l.test, ifTrue: l.ifTrue * v, else: l.else * v };
146146
if (op === '/')
147-
return { test: l.test, then: l.then / v, else: l.else / v };
147+
return { test: l.test, ifTrue: l.ifTrue / v, else: l.else / v };
148148
if (op === '%')
149-
return { test: l.test, then: l.then % v, else: l.else % v };
149+
return { test: l.test, ifTrue: l.ifTrue % v, else: l.else % v };
150150
if (op === '<')
151-
return { test: l.test, then: l.then < v, else: l.else < v };
151+
return { test: l.test, ifTrue: l.ifTrue < v, else: l.else < v };
152152
if (op === '<=')
153-
return { test: l.test, then: l.then <= v, else: l.else <= v };
153+
return { test: l.test, ifTrue: l.ifTrue <= v, else: l.else <= v };
154154
if (op === '>')
155-
return { test: l.test, then: l.then > v, else: l.else > v };
155+
return { test: l.test, ifTrue: l.ifTrue > v, else: l.else > v };
156156
if (op === '>=')
157-
return { test: l.test, then: l.then >= v, else: l.else >= v };
157+
return { test: l.test, ifTrue: l.ifTrue >= v, else: l.else >= v };
158158
if (op === '|')
159-
return { test: l.test, then: l.then | v, else: l.else | v };
159+
return { test: l.test, ifTrue: l.ifTrue | v, else: l.else | v };
160160
if (op === '&')
161-
return { test: l.test, then: l.then & v, else: l.else & v };
161+
return { test: l.test, ifTrue: l.ifTrue & v, else: l.else & v };
162162
if (op === '^')
163-
return { test: l.test, then: l.then ^ v, else: l.else ^ v };
163+
return { test: l.test, ifTrue: l.ifTrue ^ v, else: l.else ^ v };
164164
if (op === '&&')
165-
return { test: l.test, then: l.then && v, else: l.else && v };
165+
return { test: l.test, ifTrue: l.ifTrue && v, else: l.else && v };
166166
if (op === '||')
167-
return { test: l.test, then: l.then || v, else: l.else || v };
167+
return { test: l.test, ifTrue: l.ifTrue || v, else: l.else || v };
168168
} else if ('test' in r && 'value' in l) {
169169
const v: any = l.value;
170170
if (op === '==')
171-
return { test: r.test, then: v == r.then, else: v == r.else };
171+
return { test: r.test, ifTrue: v == r.ifTrue, else: v == r.else };
172172
if (op === '===')
173-
return { test: r.test, then: v === r.then, else: v === r.else };
173+
return { test: r.test, ifTrue: v === r.ifTrue, else: v === r.else };
174174
if (op === '!=')
175-
return { test: r.test, then: v != r.then, else: v != r.else };
175+
return { test: r.test, ifTrue: v != r.ifTrue, else: v != r.else };
176176
if (op === '!==')
177-
return { test: r.test, then: v !== r.then, else: v !== r.else };
177+
return { test: r.test, ifTrue: v !== r.ifTrue, else: v !== r.else };
178178
if (op === '+')
179-
return { test: r.test, then: v + r.then, else: v + r.else };
179+
return { test: r.test, ifTrue: v + r.ifTrue, else: v + r.else };
180180
if (op === '-')
181-
return { test: r.test, then: v - r.then, else: v - r.else };
181+
return { test: r.test, ifTrue: v - r.ifTrue, else: v - r.else };
182182
if (op === '*')
183-
return { test: r.test, then: v * r.then, else: v * r.else };
183+
return { test: r.test, ifTrue: v * r.ifTrue, else: v * r.else };
184184
if (op === '/')
185-
return { test: r.test, then: v / r.then, else: v / r.else };
185+
return { test: r.test, ifTrue: v / r.ifTrue, else: v / r.else };
186186
if (op === '%')
187-
return { test: r.test, then: v % r.then, else: v % r.else };
187+
return { test: r.test, ifTrue: v % r.ifTrue, else: v % r.else };
188188
if (op === '<')
189-
return { test: r.test, then: v < r.then, else: v < r.else };
189+
return { test: r.test, ifTrue: v < r.ifTrue, else: v < r.else };
190190
if (op === '<=')
191-
return { test: r.test, then: v <= r.then, else: v <= r.else };
191+
return { test: r.test, ifTrue: v <= r.ifTrue, else: v <= r.else };
192192
if (op === '>')
193-
return { test: r.test, then: v > r.then, else: v > r.else };
193+
return { test: r.test, ifTrue: v > r.ifTrue, else: v > r.else };
194194
if (op === '>=')
195-
return { test: r.test, then: v >= r.then, else: v >= r.else };
195+
return { test: r.test, ifTrue: v >= r.ifTrue, else: v >= r.else };
196196
if (op === '|')
197-
return { test: r.test, then: v | r.then, else: v | r.else };
197+
return { test: r.test, ifTrue: v | r.ifTrue, else: v | r.else };
198198
if (op === '&')
199-
return { test: r.test, then: v & r.then, else: v & r.else };
199+
return { test: r.test, ifTrue: v & r.ifTrue, else: v & r.else };
200200
if (op === '^')
201-
return { test: r.test, then: v ^ r.then, else: v ^ r.else };
201+
return { test: r.test, ifTrue: v ^ r.ifTrue, else: v ^ r.else };
202202
if (op === '&&')
203-
return { test: r.test, then: v && r.then, else: l && r.else };
203+
return { test: r.test, ifTrue: v && r.ifTrue, else: l && r.else };
204204
if (op === '||')
205-
return { test: r.test, then: v || r.then, else: l || r.else };
205+
return { test: r.test, ifTrue: v || r.ifTrue, else: l || r.else };
206206
} else if ('value' in l && 'value' in r) {
207207
if (op === '==') return { value: l.value == r.value };
208208
if (op === '===') return { value: l.value === r.value };
@@ -280,7 +280,7 @@ const visitors: Record<
280280
if (predicate) return;
281281
predicate = x.test;
282282
argsElse = args.concat([]);
283-
args.push(x.then);
283+
args.push(x.ifTrue);
284284
argsElse.push(x.else);
285285
} else {
286286
args.push(x.value);
@@ -304,7 +304,7 @@ const visitors: Record<
304304
}
305305
const resultElse = await fn.apply(ctx, argsElse);
306306
if (result === UNKNOWN) return;
307-
return { test: predicate, then: result, else: resultElse };
307+
return { test: predicate, ifTrue: result, else: resultElse };
308308
} catch (e) {
309309
return;
310310
}
@@ -327,7 +327,7 @@ const visitors: Record<
327327

328328
return {
329329
test: node.test,
330-
then: thenValue.value,
330+
ifTrue: thenValue.value,
331331
else: elseValue.value,
332332
};
333333
},
@@ -444,7 +444,7 @@ const visitors: Record<
444444
try {
445445
return {
446446
test,
447-
then: new URL(arg.then, parent.value),
447+
ifTrue: new URL(arg.ifTrue, parent.value),
448448
else: new URL(arg.else, parent.value),
449449
};
450450
} catch {
@@ -454,7 +454,7 @@ const visitors: Record<
454454
try {
455455
return {
456456
test,
457-
then: new URL(arg.then),
457+
ifTrue: new URL(arg.ifTrue),
458458
else: new URL(arg.else),
459459
};
460460
} catch {
@@ -512,7 +512,7 @@ const visitors: Record<
512512
if ('value' in val) {
513513
val.value += node.quasis[i].value.cooked;
514514
} else {
515-
val.then += node.quasis[i].value.cooked;
515+
val.ifTrue += node.quasis[i].value.cooked;
516516
val.else += node.quasis[i].value.cooked;
517517
}
518518
let exprValue = await walk(node.expressions[i]);
@@ -527,7 +527,7 @@ const visitors: Record<
527527
val.wildcards = [...(val.wildcards || []), ...exprValue.wildcards];
528528
} else {
529529
if (exprValue.wildcards) return;
530-
val.then += exprValue.value;
530+
val.ifTrue += exprValue.value;
531531
val.else += exprValue.value;
532532
}
533533
} else if ('value' in val) {
@@ -537,7 +537,7 @@ const visitors: Record<
537537
}
538538
val = {
539539
test: exprValue.test,
540-
then: val.value + exprValue.then,
540+
ifTrue: val.value + exprValue.ifTrue,
541541
else: val.value + exprValue.else,
542542
};
543543
} else {
@@ -548,7 +548,7 @@ const visitors: Record<
548548
if ('value' in val) {
549549
val.value += node.quasis[i].value.cooked;
550550
} else {
551-
val.then += node.quasis[i].value.cooked;
551+
val.ifTrue += node.quasis[i].value.cooked;
552552
val.else += node.quasis[i].value.cooked;
553553
}
554554
return val;
@@ -575,13 +575,13 @@ const visitors: Record<
575575
if (node.operator === '!') return { value: !val.value };
576576
} else if ('test' in val && 'wildcards' in val === false) {
577577
if (node.operator === '+')
578-
return { test: val.test, then: +val.then, else: +val.else };
578+
return { test: val.test, ifTrue: +val.ifTrue, else: +val.else };
579579
if (node.operator === '-')
580-
return { test: val.test, then: -val.then, else: -val.else };
580+
return { test: val.test, ifTrue: -val.ifTrue, else: -val.else };
581581
if (node.operator === '~')
582-
return { test: val.test, then: ~val.then, else: ~val.else };
582+
return { test: val.test, ifTrue: ~val.ifTrue, else: ~val.else };
583583
if (node.operator === '!')
584-
return { test: val.test, then: !val.then, else: !val.else };
584+
return { test: val.test, ifTrue: !val.ifTrue, else: !val.else };
585585
}
586586
return undefined;
587587
},

src/utils/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export interface StaticValue {
88

99
export interface ConditionalValue {
1010
test: string;
11-
then: any;
11+
ifTrue: any;
1212
else: any;
1313
}
1414

test/unit/url-error/input.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const URLParser = typeof window === 'undefined' ? URL : 'b';

test/unit/url-error/output.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[
2+
"package.json",
3+
"test/unit/url-error/input.js"
4+
]

0 commit comments

Comments
 (0)