Skip to content

Commit de424c6

Browse files
committed
feat: added the no-navigation-without-resolve rule
1 parent 9223298 commit de424c6

File tree

7 files changed

+423
-0
lines changed

7 files changed

+423
-0
lines changed

.changeset/huge-taxis-jog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-svelte': minor
3+
---
4+
5+
feat: added the no-navigation-without-resolve rule

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ These rules relate to SvelteKit and its best Practices.
363363
| Rule ID | Description | |
364364
|:--------|:------------|:---|
365365
| [svelte/no-export-load-in-svelte-module-in-kit-pages](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-export-load-in-svelte-module-in-kit-pages/) | disallow exporting load functions in `*.svelte` module in SvelteKit page components. | :star: |
366+
| [svelte/no-navigation-without-resolve](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-navigation-without-resolve/) | disallow using navigation (links, goto, pushState, replaceState) without a resolve() | |
366367
| [svelte/valid-prop-names-in-kit-pages](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-prop-names-in-kit-pages/) | disallow props other than data or errors in SvelteKit page components. | :star: |
367368

368369
## Experimental

docs/rules.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ These rules relate to SvelteKit and its best Practices.
120120
| Rule ID | Description | |
121121
| :------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------- | :----- |
122122
| [svelte/no-export-load-in-svelte-module-in-kit-pages](./rules/no-export-load-in-svelte-module-in-kit-pages.md) | disallow exporting load functions in `*.svelte` module in SvelteKit page components. | :star: |
123+
| [svelte/no-navigation-without-resolve](./rules/no-navigation-without-resolve.md) | disallow using navigation (links, goto, pushState, replaceState) without a resolve() | |
123124
| [svelte/valid-prop-names-in-kit-pages](./rules/valid-prop-names-in-kit-pages.md) | disallow props other than data or errors in SvelteKit page components. | :star: |
124125

125126
## Experimental
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
pageClass: 'rule-details'
3+
sidebarDepth: 0
4+
title: 'svelte/no-navigation-without-resolve'
5+
description: 'disallow using navigation (links, goto, pushState, replaceState) without a resolve()'
6+
since: 'v2.36.0-next.9'
7+
---
8+
9+
# svelte/no-navigation-without-resolve
10+
11+
> disallow using navigation (links, goto, pushState, replaceState) without a resolve()
12+
13+
## :book: Rule Details
14+
15+
This rule reports navigation using HTML `<a>` tags, SvelteKit's `goto()`, `pushState()` and `replaceState()` functions without resolving a relative URL. All four of these may be used for navigation, with `goto()`, `pushState()` and `replaceState()` being intended solely for iternal navigation (i.e. not leaving the site), while `<a>` tags may be used for both internal and external navigation. When using any way of internal navigation, the URL must be resolved using SvelteKit's `resolve()`, otherwise the site may break. For programmatic navigation to external URLs, using `window.location` is advised.
16+
17+
This rule checks all 4 navigation options for the presence of the `resolve()` fucntion call, with an exception for `<a>` links to absolute URLs (and fragment URLs), which are assumed to be used for external navigation and so do not require the `resolve()` function, and for shallow outing functions with an empty string as the path, which keeps the current URL.
18+
19+
<!--eslint-skip-->
20+
21+
```svelte
22+
<script>
23+
/* eslint svelte/no-navigation-without-resolve: "error" */
24+
25+
import { goto, pushState, replaceState } from '$app/navigation';
26+
import { resolve } from '$app/paths';
27+
28+
// ✓ GOOD
29+
goto(resolve('/foo/'));
30+
31+
pushState(resolve('/foo/'), {});
32+
pushState('', {});
33+
34+
replaceState(resolve('/foo/'), {});
35+
replaceState('', {});
36+
37+
// ✗ BAD
38+
goto('/foo');
39+
goto('/foo' + resolve('/bar'));
40+
goto(resolve('/foo') + '/bar');
41+
42+
pushState('/foo', {});
43+
replaceState('/foo', {});
44+
</script>
45+
46+
<!-- ✓ GOOD -->
47+
<a href={resolve('/foo/')}>Click me!</a>
48+
<a href="https://svelte.dev">Click me!</a>
49+
50+
<!-- ✗ BAD -->
51+
<a href="/foo">Click me!</a>
52+
<a href={'/foo'}>Click me!</a>
53+
```
54+
55+
## :wrench: Options
56+
57+
```json
58+
{
59+
"svelte/no-navigation-without-resolve": [
60+
"error",
61+
{
62+
"ignoreGoto": false,
63+
"ignoreLinks": false,
64+
"ignorePushState": false,
65+
"ignoreReplaceState": false
66+
}
67+
]
68+
}
69+
```
70+
71+
- `ignoreGoto` ... Whether to ignore all `goto()` calls. Default `false`.
72+
- `ignoreLinks` ... Whether to ignore all `<a>` tags. Default `false`.
73+
- `ignorePushState` ... Whether to ignore all `pushState()` calls. Default `false`.
74+
- `ignoreReplaceState` ... Whether to ignore all `replaceState()` calls. Default `false`.
75+
76+
## :books: Further Reading
77+
78+
- [`resolve()` documentation](https://svelte.dev/docs/kit/$app-paths#resolve)
79+
- [Shallow routing](https://svelte.dev/docs/kit/shallow-routing)
80+
- [`goto()` documentation](https://svelte.dev/docs/kit/$app-navigation#goto)
81+
- [`pushState()` documentation](https://svelte.dev/docs/kit/$app-navigation#pushState)
82+
- [`replaceState()` documentation](https://svelte.dev/docs/kit/$app-navigation#replaceState)
83+
84+
## :rocket: Version
85+
86+
This rule was introduced in eslint-plugin-svelte v2.36.0-next.9
87+
88+
## :mag: Implementation
89+
90+
- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/src/rules/no-navigation-without-resolve.ts)
91+
- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/tests/src/rules/no-navigation-without-resolve.ts)

packages/eslint-plugin-svelte/src/rule-types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ export interface RuleOptions {
192192
* @deprecated
193193
*/
194194
'svelte/no-navigation-without-base'?: Linter.RuleEntry<SvelteNoNavigationWithoutBase>
195+
/**
196+
* disallow using navigation (links, goto, pushState, replaceState) without a resolve()
197+
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-navigation-without-resolve/
198+
*/
199+
'svelte/no-navigation-without-resolve'?: Linter.RuleEntry<SvelteNoNavigationWithoutResolve>
195200
/**
196201
* disallow use of not function in event handler
197202
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-not-function-handler/
@@ -519,6 +524,13 @@ type SvelteNoNavigationWithoutBase = []|[{
519524
ignorePushState?: boolean
520525
ignoreReplaceState?: boolean
521526
}]
527+
// ----- svelte/no-navigation-without-resolve -----
528+
type SvelteNoNavigationWithoutResolve = []|[{
529+
ignoreGoto?: boolean
530+
ignoreLinks?: boolean
531+
ignorePushState?: boolean
532+
ignoreReplaceState?: boolean
533+
}]
522534
// ----- svelte/no-reactive-reassign -----
523535
type SvelteNoReactiveReassign = []|[{
524536
props?: boolean

0 commit comments

Comments
 (0)