Skip to content

Commit ce056fa

Browse files
committed
fix(no-navigation-without-resolve): allowing undefined and null in link hrefs
1 parent a757483 commit ce056fa

File tree

5 files changed

+94
-0
lines changed

5 files changed

+94
-0
lines changed

.changeset/public-groups-prove.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-svelte': patch
3+
---
4+
5+
fix(no-navigation-without-resolve): allowing undefined and null in link hrefs

packages/eslint-plugin-svelte/src/rules/no-navigation-without-resolve.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,11 @@ export default createRule('no-navigation-without-resolve', {
123123
}
124124
if (
125125
(node.value[0].type === 'SvelteLiteral' &&
126+
!expressionIsNullish(new FindVariableContext(context), node.value[0]) &&
126127
!expressionIsAbsolute(new FindVariableContext(context), node.value[0]) &&
127128
!expressionIsFragment(new FindVariableContext(context), node.value[0])) ||
128129
(node.value[0].type === 'SvelteMustacheTag' &&
130+
!expressionIsNullish(new FindVariableContext(context), node.value[0].expression) &&
129131
!expressionIsAbsolute(new FindVariableContext(context), node.value[0].expression) &&
130132
!expressionIsFragment(new FindVariableContext(context), node.value[0].expression) &&
131133
!isResolveCall(
@@ -289,6 +291,45 @@ function expressionIsEmpty(url: TSESTree.CallExpressionArgument): boolean {
289291
);
290292
}
291293

294+
function expressionIsNullish(
295+
ctx: FindVariableContext,
296+
url: AST.SvelteLiteral | TSESTree.Expression
297+
): boolean {
298+
switch (url.type) {
299+
case 'Identifier':
300+
return identifierIsNullish(ctx, url);
301+
case 'Literal':
302+
return url.value === null; // Undefined is an Identifier in ESTree, null is a Literal
303+
case 'TemplateLiteral':
304+
return templateLiteralIsNullish(ctx, url);
305+
default:
306+
return false;
307+
}
308+
}
309+
310+
function identifierIsNullish(ctx: FindVariableContext, url: TSESTree.Identifier): boolean {
311+
if (url.name === 'undefined') {
312+
return true;
313+
}
314+
const variable = ctx.findVariable(url);
315+
if (
316+
variable === null ||
317+
variable.identifiers.length === 0 ||
318+
variable.identifiers[0].parent.type !== 'VariableDeclarator' ||
319+
variable.identifiers[0].parent.init === null
320+
) {
321+
return false;
322+
}
323+
return expressionIsNullish(ctx, variable.identifiers[0].parent.init);
324+
}
325+
326+
function templateLiteralIsNullish(
327+
ctx: FindVariableContext,
328+
url: TSESTree.TemplateLiteral
329+
): boolean {
330+
return url.expressions.length === 1 && expressionIsNullish(ctx, url.expressions[0]);
331+
}
332+
292333
function expressionIsAbsolute(
293334
ctx: FindVariableContext,
294335
url: AST.SvelteLiteral | TSESTree.Expression
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
- message: Unexpected href link without resolve().
2+
line: 6
3+
column: 10
4+
suggestions: null
5+
- message: Unexpected href link without resolve().
6+
line: 7
7+
column: 10
8+
suggestions: null
9+
- message: Unexpected href link without resolve().
10+
line: 8
11+
column: 9
12+
suggestions: null
13+
- message: Unexpected href link without resolve().
14+
line: 9
15+
column: 9
16+
suggestions: null
17+
- message: Unexpected href link without resolve().
18+
line: 10
19+
column: 9
20+
suggestions: null
21+
- message: Unexpected href link without resolve().
22+
line: 11
23+
column: 9
24+
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script>
2+
const one = "undefined";
3+
const two = "null";
4+
</script>
5+
6+
<a href="undefined">Click me!</a>
7+
<a href="null">Click me!</a>
8+
<a href={one}>Click me!</a>
9+
<a href={two}>Click me!</a>
10+
<a href={`undefined`}>Click me!</a>
11+
<a href={`null`}>Click me!</a>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
const one = undefined;
3+
const two = null;
4+
</script>
5+
6+
<a href={undefined}>Click me!</a>
7+
<a href={null}>Click me!</a>
8+
<a href={one}>Click me!</a>
9+
<a href={two}>Click me!</a>
10+
<a href={`${undefined}`}>Click me!</a>
11+
<a href={`${null}`}>Click me!</a>
12+
<a href={`${one}`}>Click me!</a>
13+
<a href={`${two}`}>Click me!</a>

0 commit comments

Comments
 (0)