Skip to content

Commit 9bac02b

Browse files
committed
Merge remote-tracking branch 'origin/main' into no-navigation-without-base
2 parents add6e9b + 117e60d commit 9bac02b

37 files changed

+248
-71
lines changed

.changeset/blue-panthers-run.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-svelte': patch
3+
---
4+
5+
fix: support each blocks without an item

.changeset/hungry-grapes-shave.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-svelte': patch
3+
---
4+
5+
chore: update `svelte-eslint-parser` to v1.0.0-next.4

.changeset/pre.json

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"changesets": [
99
"cool-rockets-allow",
1010
"fast-coins-fly",
11+
"hungry-grapes-shave",
1112
"lazy-eyes-wait",
1213
"olive-wolves-travel",
1314
"quiet-toys-burn",

.changeset/sixty-news-look.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-svelte': minor
3+
---
4+
5+
feat: support Svelte5 of `valid-prop-names-in-kit-pages` rule

README.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ You can check on the [Online DEMO](https://eslint-online-playground.netlify.app/
1010
> For example, <https://github.com/sveltejs/eslint-plugin-svelte/blob/eslint-plugin-svelte%402.46.0/README.md>
1111
> and <https://github.com/sveltejs/eslint-plugin-svelte/blob/eslint-plugin-svelte%402.46.0/docs>
1212
13-
**_We are working on experimental support for Svelte v5, but may break with new versions of Svelte v5._**
14-
1513
[![NPM license](https://img.shields.io/npm/l/eslint-plugin-svelte.svg)](https://www.npmjs.com/package/eslint-plugin-svelte)
1614
[![NPM version](https://img.shields.io/npm/v/eslint-plugin-svelte.svg)](https://www.npmjs.com/package/eslint-plugin-svelte)
1715
[![NPM downloads](https://img.shields.io/badge/dynamic/json.svg?label=downloads&colorB=green&suffix=/day&query=$.downloads&uri=https://api.npmjs.org//downloads/point/last-day/eslint-plugin-svelte&maxAge=3600)](http://www.npmtrends.com/eslint-plugin-svelte)
@@ -46,6 +44,13 @@ We are working on support for Svelte v5, but it is still an experimental feature
4644

4745
<!--DOCS_IGNORE_START-->
4846

47+
## Versioning policy
48+
49+
This plugin follows [Semantic Versioning](https://semver.org/).
50+
However, unlike [ESLint’s Semantic Versioning Policy](https://github.com/eslint/eslint#semantic-versioning-policy), this plugin adds new rules to its configs even in minor releases. For example, if you are using the recommended config, a minor update may add new rules, which could cause new lint errors in your project.
51+
While [ESLint’s Semantic Versioning Policy](https://github.com/eslint/eslint#semantic-versioning-policy) only adds new rules to configs in major releases, most users (myself included) don’t regularly monitor new rules. This makes it challenging to manually add them to projects whenever they are introduced.
52+
By adding new rules to configs in minor releases, this plugin ensures users can adopt them more easily. If any new rules cause issues, you can simply disable them. I believe this approach helps maintain and improve code quality with minimal effort.
53+
4954
## Migration Guide
5055

5156
To migrate from `eslint-plugin-svelte` v1, or [`@ota-meshi/eslint-plugin-svelte`](https://www.npmjs.com/package/@ota-meshi/eslint-plugin-svelte), please refer to the [migration guide](https://sveltejs.github.io/eslint-plugin-svelte/migration/).

docs/README.md

-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ You can check on the [Online DEMO](https://eslint-online-playground.netlify.app/
1414
> For example, <https://github.com/sveltejs/eslint-plugin-svelte/blob/eslint-plugin-svelte%402.46.0/README.md>
1515
> and <https://github.com/sveltejs/eslint-plugin-svelte/blob/eslint-plugin-svelte%402.46.0/docs>
1616
17-
**_We are working on experimental support for Svelte v5, but may break with new versions of Svelte v5._**
18-
1917
[![NPM license](https://img.shields.io/npm/l/eslint-plugin-svelte.svg)](https://www.npmjs.com/package/eslint-plugin-svelte)
2018
[![NPM version](https://img.shields.io/npm/v/eslint-plugin-svelte.svg)](https://www.npmjs.com/package/eslint-plugin-svelte)
2119
[![NPM downloads](https://img.shields.io/badge/dynamic/json.svg?label=downloads&colorB=green&suffix=/day&query=$.downloads&uri=https://api.npmjs.org//downloads/point/last-day/eslint-plugin-svelte&maxAge=3600)](http://www.npmtrends.com/eslint-plugin-svelte)

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"license": "MIT",
66
"funding": "https://github.com/sponsors/ota-meshi",
7-
"packageManager": "pnpm@9.14.4",
7+
"packageManager": "pnpm@9.15.2",
88
"scripts": {
99
"prerelease": "cd packages/eslint-plugin-svelte && pnpm clean && pnpm run build && cd ../.. && cp README.md packages/eslint-plugin-svelte",
1010
"release": "changeset publish",
@@ -24,7 +24,7 @@
2424
"@typescript-eslint/parser": "^8.16.0",
2525
"c8": "^10.1.2",
2626
"env-cmd": "^10.1.0",
27-
"eslint": "~9.16.0",
27+
"eslint": "~9.17.0",
2828
"eslint-config-prettier": "^9.1.0",
2929
"eslint-formatter-friendly": "^7.0.0",
3030
"eslint-plugin-eslint-plugin": "^6.3.2",

packages/eslint-plugin-svelte/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# eslint-plugin-svelte
22

3+
## 3.0.0-next.5
4+
5+
### Patch Changes
6+
7+
- [#956](https://github.com/sveltejs/eslint-plugin-svelte/pull/956) [`157ee1f`](https://github.com/sveltejs/eslint-plugin-svelte/commit/157ee1fade79aab88f01d125b0b01cf375da4cd1) Thanks [@baseballyama](https://github.com/baseballyama)! - chore: update `svelte-eslint-parser` to v1.0.0-next.4
8+
39
## 3.0.0-next.4
410

511
### Major Changes

packages/eslint-plugin-svelte/package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "eslint-plugin-svelte",
3-
"version": "3.0.0-next.4",
3+
"version": "3.0.0-next.5",
44
"description": "ESLint plugin for Svelte using AST",
55
"repository": "git+https://github.com/sveltejs/eslint-plugin-svelte.git",
66
"homepage": "https://sveltejs.github.io/eslint-plugin-svelte",
@@ -30,7 +30,7 @@
3030
"cover": "c8 --reporter=lcov pnpm run test",
3131
"debug": "pnpm run mocha \"tests/src/**/*.ts\" --reporter dot --timeout 60000",
3232
"lint": "run-p lint:*",
33-
"lint-fix": "pnpm run lint:es --fix && pnpm run lint:style --fix",
33+
"lint-fix": "pnpm run lint:es --fix",
3434
"lint:es": "eslint --cache .",
3535
"mocha": "pnpm run ts ./node_modules/mocha/bin/mocha.js",
3636
"new": "pnpm run ts ./tools/new-rule.ts",
@@ -63,10 +63,10 @@
6363
"known-css-properties": "^0.35.0",
6464
"postcss": "^8.4.49",
6565
"postcss-load-config": "^3.1.4",
66-
"postcss-safe-parser": "^6.0.0",
66+
"postcss-safe-parser": "^7.0.0",
6767
"postcss-selector-parser": "^7.0.0",
6868
"semver": "^7.6.3",
69-
"svelte-eslint-parser": "^1.0.0-next.3"
69+
"svelte-eslint-parser": "^1.0.0-next.4"
7070
},
7171
"devDependencies": {
7272
"@babel/core": "^7.26.0",
@@ -91,7 +91,7 @@
9191
"eslint-visitor-keys": "^4.2.0",
9292
"espree": "^10.3.0",
9393
"less": "^4.2.1",
94-
"mocha": "^10.8.2",
94+
"mocha": "^11.0.0",
9595
"postcss-nested": "^7.0.2",
9696
"sass": "^1.81.0",
9797
"source-map-js": "^1.2.1",

packages/eslint-plugin-svelte/src/meta.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
// This file has been automatically generated,
33
// in order to update its content execute "pnpm run update"
44
export const name = 'eslint-plugin-svelte';
5-
export const version = '3.0.0-next.4';
5+
export const version = '3.0.0-next.5';

packages/eslint-plugin-svelte/src/rules/indent-helpers/svelte.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,9 @@ export function defineVisitor(context: IndentContext): NodeListener {
289289
const closeOpenTagToken = sourceCode.getTokenAfter(key.lastToken);
290290
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
291291
} else {
292-
const closeOpenTagToken = sourceCode.getTokenAfter(node.index || node.context);
292+
const closeOpenTagToken = sourceCode.getTokenAfter(
293+
node.index || node.context || node.expression
294+
);
293295
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
294296
}
295297

packages/eslint-plugin-svelte/src/rules/mustache-spacing.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ export default createRule('mustache-spacing', {
272272
SvelteEachBlock(node: AST.SvelteEachBlock) {
273273
const openBlockOpeningToken = sourceCode.getFirstToken(node);
274274
const openBlockClosingToken = sourceCode.getTokenAfter(
275-
node.key || node.index || node.context,
275+
node.key || node.index || node.context || node.expression,
276276
{
277277
includeComments: false,
278278
filter: isClosingBraceToken

packages/eslint-plugin-svelte/src/rules/no-immutable-reactive-statements.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ export default createRule('no-immutable-reactive-statements', {
135135
return parent.kind === 'Binding' && parent.expression === expr;
136136
}
137137
if (parent.type === 'SvelteEachBlock') {
138-
return parent.expression === expr && hasWriteReference(parent.context);
138+
return (
139+
parent.context !== null && parent.expression === expr && hasWriteReference(parent.context)
140+
);
139141
}
140142

141143
return false;

packages/eslint-plugin-svelte/src/rules/require-each-key.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ export default createRule('require-each-key', {
1515
create(context) {
1616
return {
1717
SvelteEachBlock(node: AST.SvelteEachBlock) {
18-
if (node.key == null) {
18+
// No need a `key` if an each blocks without an item
19+
// see: https://svelte.dev/docs/svelte/each#Each-blocks-without-an-item
20+
if (node.context != null && node.key == null) {
1921
context.report({
2022
node,
2123
messageId: 'expectedKey'

packages/eslint-plugin-svelte/src/rules/valid-each-key.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ export default createRule('valid-each-key', {
2727
if (
2828
!variable.defs.some(
2929
(def) =>
30-
(node.context.range[0] <= def.name.range[0] &&
30+
(node.context &&
31+
node.context.range[0] <= def.name.range[0] &&
3132
def.name.range[1] <= node.context.range[1]) ||
3233
(node.index &&
3334
node.index.range[0] <= def.name.range[0] &&
34-
def.name.range[1] <= node.index.range[1])
35+
def.name.range[1] <= node.index.range[1]) ||
36+
(node.expression &&
37+
node.expression.range[0] <= def.name.range[0] &&
38+
def.name.range[1] <= node.expression.range[1])
3539
)
3640
) {
3741
// It's not an iteration variable.

packages/eslint-plugin-svelte/src/rules/valid-prop-names-in-kit-pages.ts

+34-13
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,27 @@ import type { AST } from 'svelte-eslint-parser';
22
import type { TSESTree } from '@typescript-eslint/types';
33
import { createRule } from '../utils/index.js';
44
import { isKitPageComponent } from '../utils/svelte-kit.js';
5+
import type { RuleContext } from '../types.js';
56

67
const EXPECTED_PROP_NAMES = ['data', 'errors', 'form', 'snapshot'];
78

9+
function checkProp(node: TSESTree.VariableDeclarator, context: RuleContext) {
10+
if (node.id.type !== 'ObjectPattern') return;
11+
for (const p of node.id.properties) {
12+
if (
13+
p.type === 'Property' &&
14+
p.value.type === 'Identifier' &&
15+
!EXPECTED_PROP_NAMES.includes(p.value.name)
16+
) {
17+
context.report({
18+
node: p.value,
19+
loc: p.value.loc,
20+
messageId: 'unexpected'
21+
});
22+
}
23+
}
24+
}
25+
826
export default createRule('valid-prop-names-in-kit-pages', {
927
meta: {
1028
docs: {
@@ -39,6 +57,7 @@ export default createRule('valid-prop-names-in-kit-pages', {
3957
isScript = false;
4058
},
4159

60+
// Svelte3,4
4261
'ExportNamedDeclaration > VariableDeclaration > VariableDeclarator': (
4362
node: TSESTree.VariableDeclarator
4463
) => {
@@ -57,20 +76,22 @@ export default createRule('valid-prop-names-in-kit-pages', {
5776
}
5877

5978
// export let { xxx, yyy } = zzz
60-
if (node.id.type !== 'ObjectPattern') return;
61-
for (const p of node.id.properties) {
62-
if (
63-
p.type === 'Property' &&
64-
p.value.type === 'Identifier' &&
65-
!EXPECTED_PROP_NAMES.includes(p.value.name)
66-
) {
67-
context.report({
68-
node: p.value,
69-
loc: p.value.loc,
70-
messageId: 'unexpected'
71-
});
72-
}
79+
checkProp(node, context);
80+
},
81+
82+
// Svelte5
83+
// let { foo, bar } = $props();
84+
'VariableDeclaration > VariableDeclarator': (node: TSESTree.VariableDeclarator) => {
85+
if (!isScript) return;
86+
if (
87+
node.init?.type !== 'CallExpression' ||
88+
node.init.callee?.type !== 'Identifier' ||
89+
node.init.callee?.name !== '$props'
90+
) {
91+
return;
7392
}
93+
94+
checkProp(node, context);
7495
}
7596
};
7697
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"svelte": ">=5.0.0-0"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div class="chess-board">
2+
{#each { length: 8 }, rank}
3+
{#each { length: 8 }}
4+
{rank}
5+
{/each}
6+
{/each}
7+
</div>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
- message: '`<img>` element should have an alt attribute(a11y_missing_attribute)'
1+
- message: |-
2+
`<img>` element should have an alt attribute
3+
https://svelte.dev/e/a11y_missing_attribute(a11y_missing_attribute)
24
line: 5
35
column: 1
46
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
- message: noninteractive element cannot have nonnegative tabIndex
2-
value(a11y_no_noninteractive_tabindex)
1+
- message: |-
2+
noninteractive element cannot have nonnegative tabIndex value
3+
https://svelte.dev/e/a11y_no_noninteractive_tabindex(a11y_no_noninteractive_tabindex)
34
line: 6
45
column: 3
56
suggestions: null
6-
- message: A form label must be associated with a
7-
control(a11y_label_has_associated_control)
7+
- message: |-
8+
A form label must be associated with a control
9+
https://svelte.dev/e/a11y_label_has_associated_control(a11y_label_has_associated_control)
810
line: 6
911
column: 3
1012
suggestions: null
11-
- message: noninteractive element cannot have nonnegative tabIndex
12-
value(a11y_no_noninteractive_tabindex)
13+
- message: |-
14+
noninteractive element cannot have nonnegative tabIndex value
15+
https://svelte.dev/e/a11y_no_noninteractive_tabindex(a11y_no_noninteractive_tabindex)
1316
line: 7
1417
column: 3
1518
suggestions: null

packages/eslint-plugin-svelte/tests/fixtures/rules/valid-compile/invalid/invalid-svelte-ignore01-svelte4-errors.yaml

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
line: 6
44
column: 3
55
suggestions: null
6-
- message: 'A11y: A form label must be associated with a
7-
control.(a11y-label-has-associated-control)'
6+
- message: 'A11y: A form label must be associated with a control.(a11y-label-has-associated-control)'
87
line: 6
98
column: 3
109
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
- message: noninteractive element cannot have nonnegative tabIndex
2-
value(a11y_no_noninteractive_tabindex)
1+
- message: |-
2+
noninteractive element cannot have nonnegative tabIndex value
3+
https://svelte.dev/e/a11y_no_noninteractive_tabindex(a11y_no_noninteractive_tabindex)
34
line: 6
45
column: 3
56
suggestions: null
6-
- message: A form label must be associated with a
7-
control(a11y_label_has_associated_control)
7+
- message: |-
8+
A form label must be associated with a control
9+
https://svelte.dev/e/a11y_label_has_associated_control(a11y_label_has_associated_control)
810
line: 6
911
column: 3
1012
suggestions: null
11-
- message: noninteractive element cannot have nonnegative tabIndex
12-
value(a11y_no_noninteractive_tabindex)
13+
- message: |-
14+
noninteractive element cannot have nonnegative tabIndex value
15+
https://svelte.dev/e/a11y_no_noninteractive_tabindex(a11y_no_noninteractive_tabindex)
1316
line: 7
1417
column: 3
1518
suggestions: null

0 commit comments

Comments
 (0)