Skip to content

Commit 3b01537

Browse files
authored
fix(no-navigation-without-base): ignoring fragment links (#1107)
1 parent 2d2007d commit 3b01537

File tree

5 files changed

+71
-2
lines changed

5 files changed

+71
-2
lines changed

.changeset/warm-plums-smile.md

+5
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-base): ignoring fragment links

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

+33-2
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,15 @@ export default createRule('no-navigation-without-base', {
9696
}
9797
const hrefValue = node.value[0];
9898
if (hrefValue.type === 'SvelteLiteral') {
99-
if (!expressionIsAbsolute(hrefValue)) {
99+
if (!expressionIsAbsolute(hrefValue) && !expressionIsFragment(hrefValue)) {
100100
context.report({ loc: hrefValue.loc, messageId: 'linkNotPrefixed' });
101101
}
102102
return;
103103
}
104104
if (
105105
!expressionStartsWithBase(context, hrefValue.expression, basePathNames) &&
106-
!expressionIsAbsolute(hrefValue.expression)
106+
!expressionIsAbsolute(hrefValue.expression) &&
107+
!expressionIsFragment(hrefValue.expression)
107108
) {
108109
context.report({ loc: hrefValue.loc, messageId: 'linkNotPrefixed' });
109110
}
@@ -348,3 +349,33 @@ function templateLiteralIsAbsolute(url: TSESTree.TemplateLiteral): boolean {
348349
function urlValueIsAbsolute(url: string): boolean {
349350
return url.includes('://');
350351
}
352+
353+
function expressionIsFragment(url: SvelteLiteral | TSESTree.Expression): boolean {
354+
switch (url.type) {
355+
case 'BinaryExpression':
356+
return binaryExpressionIsFragment(url);
357+
case 'Literal':
358+
return typeof url.value === 'string' && urlValueIsFragment(url.value);
359+
case 'SvelteLiteral':
360+
return urlValueIsFragment(url.value);
361+
case 'TemplateLiteral':
362+
return templateLiteralIsFragment(url);
363+
default:
364+
return false;
365+
}
366+
}
367+
368+
function binaryExpressionIsFragment(url: TSESTree.BinaryExpression): boolean {
369+
return url.left.type !== 'PrivateIdentifier' && expressionIsFragment(url.left);
370+
}
371+
372+
function templateLiteralIsFragment(url: TSESTree.TemplateLiteral): boolean {
373+
return (
374+
(url.expressions.length >= 1 && expressionIsFragment(url.expressions[0])) ||
375+
(url.quasis.length >= 1 && urlValueIsFragment(url.quasis[0].value.raw))
376+
);
377+
}
378+
379+
function urlValueIsFragment(url: string): boolean {
380+
return url.startsWith('#');
381+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
- message: Found a link with a url that isn't prefixed with the base path.
2+
line: 4
3+
column: 10
4+
suggestions: null
5+
- message: Found a link with a url that isn't prefixed with the base path.
6+
line: 5
7+
column: 9
8+
suggestions: null
9+
- message: Found a link with a url that isn't prefixed with the base path.
10+
line: 6
11+
column: 9
12+
suggestions: null
13+
- message: Found a link with a url that isn't prefixed with the base path.
14+
line: 7
15+
column: 9
16+
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
const value = "/foo#section";
3+
</script>
4+
<a href="/foo#section">Click me!</a>
5+
<a href={'/foo#section'}>Click me!</a>
6+
<a href={'/' + 'foo#section'}>Click me!</a>
7+
<a href={value}>Click me!</a>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
const section = 'sectionName';
3+
</script>
4+
5+
<a href="#">Click me!</a>
6+
<a href="#section">Click me!</a>
7+
<a href={'#section'}>Click me!</a>
8+
<a href={'#' + 'section'}>Click me!</a>
9+
<a href={'#' + section}>Click me!</a>
10+
<a href={`#${section}`}>Click me!</a>

0 commit comments

Comments
 (0)