From 8cafa091eb87be0d36fa0399efa90b69e46fff2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Wed, 26 Feb 2025 23:15:08 +0100 Subject: [PATCH] fix(no-navigation-without-base): ignoring fragment links --- .changeset/warm-plums-smile.md | 5 +++ .../src/rules/no-navigation-without-base.ts | 35 +++++++++++++++++-- .../invalid/link-with-fragment01-errors.yaml | 16 +++++++++ .../invalid/link-with-fragment01-input.svelte | 7 ++++ .../valid/link-fragment-url01-input.svelte | 10 ++++++ 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 .changeset/warm-plums-smile.md create mode 100644 packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/invalid/link-with-fragment01-errors.yaml create mode 100644 packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/invalid/link-with-fragment01-input.svelte create mode 100644 packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/valid/link-fragment-url01-input.svelte diff --git a/.changeset/warm-plums-smile.md b/.changeset/warm-plums-smile.md new file mode 100644 index 000000000..5475ec710 --- /dev/null +++ b/.changeset/warm-plums-smile.md @@ -0,0 +1,5 @@ +--- +'eslint-plugin-svelte': patch +--- + +fix(no-navigation-without-base): ignoring fragment links diff --git a/packages/eslint-plugin-svelte/src/rules/no-navigation-without-base.ts b/packages/eslint-plugin-svelte/src/rules/no-navigation-without-base.ts index 6f2a20994..aaeb4c6c6 100644 --- a/packages/eslint-plugin-svelte/src/rules/no-navigation-without-base.ts +++ b/packages/eslint-plugin-svelte/src/rules/no-navigation-without-base.ts @@ -96,14 +96,15 @@ export default createRule('no-navigation-without-base', { } const hrefValue = node.value[0]; if (hrefValue.type === 'SvelteLiteral') { - if (!expressionIsAbsolute(hrefValue)) { + if (!expressionIsAbsolute(hrefValue) && !expressionIsFragment(hrefValue)) { context.report({ loc: hrefValue.loc, messageId: 'linkNotPrefixed' }); } return; } if ( !expressionStartsWithBase(context, hrefValue.expression, basePathNames) && - !expressionIsAbsolute(hrefValue.expression) + !expressionIsAbsolute(hrefValue.expression) && + !expressionIsFragment(hrefValue.expression) ) { context.report({ loc: hrefValue.loc, messageId: 'linkNotPrefixed' }); } @@ -348,3 +349,33 @@ function templateLiteralIsAbsolute(url: TSESTree.TemplateLiteral): boolean { function urlValueIsAbsolute(url: string): boolean { return url.includes('://'); } + +function expressionIsFragment(url: SvelteLiteral | TSESTree.Expression): boolean { + switch (url.type) { + case 'BinaryExpression': + return binaryExpressionIsFragment(url); + case 'Literal': + return typeof url.value === 'string' && urlValueIsFragment(url.value); + case 'SvelteLiteral': + return urlValueIsFragment(url.value); + case 'TemplateLiteral': + return templateLiteralIsFragment(url); + default: + return false; + } +} + +function binaryExpressionIsFragment(url: TSESTree.BinaryExpression): boolean { + return url.left.type !== 'PrivateIdentifier' && expressionIsFragment(url.left); +} + +function templateLiteralIsFragment(url: TSESTree.TemplateLiteral): boolean { + return ( + (url.expressions.length >= 1 && expressionIsFragment(url.expressions[0])) || + (url.quasis.length >= 1 && urlValueIsFragment(url.quasis[0].value.raw)) + ); +} + +function urlValueIsFragment(url: string): boolean { + return url.startsWith('#'); +} diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/invalid/link-with-fragment01-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/invalid/link-with-fragment01-errors.yaml new file mode 100644 index 000000000..e006d4d27 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/invalid/link-with-fragment01-errors.yaml @@ -0,0 +1,16 @@ +- message: Found a link with a url that isn't prefixed with the base path. + line: 4 + column: 10 + suggestions: null +- message: Found a link with a url that isn't prefixed with the base path. + line: 5 + column: 9 + suggestions: null +- message: Found a link with a url that isn't prefixed with the base path. + line: 6 + column: 9 + suggestions: null +- message: Found a link with a url that isn't prefixed with the base path. + line: 7 + column: 9 + suggestions: null diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/invalid/link-with-fragment01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/invalid/link-with-fragment01-input.svelte new file mode 100644 index 000000000..2e6a11df8 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/invalid/link-with-fragment01-input.svelte @@ -0,0 +1,7 @@ + +Click me! +Click me! +Click me! +Click me! diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/valid/link-fragment-url01-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/valid/link-fragment-url01-input.svelte new file mode 100644 index 000000000..eeaa16267 --- /dev/null +++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-navigation-without-base/valid/link-fragment-url01-input.svelte @@ -0,0 +1,10 @@ + + +Click me! +Click me! +Click me! +Click me! +Click me! +Click me!