eslint-plugin-svelte 3.18.0 → 3.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -334,6 +334,7 @@ These rules relate to better ways of doing things to help you avoid problems:
334
334
  | [svelte/block-lang](https://sveltejs.github.io/eslint-plugin-svelte/rules/block-lang/) | disallows the use of languages other than those specified in the configuration for the lang attribute of `<script>` and `<style>` blocks. | :bulb: |
335
335
  | [svelte/button-has-type](https://sveltejs.github.io/eslint-plugin-svelte/rules/button-has-type/) | disallow usage of button without an explicit type attribute | |
336
336
  | [svelte/no-add-event-listener](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-add-event-listener/) | Warns against the use of `addEventListener` | :bulb: |
337
+ | [svelte/no-at-const-tags](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-const-tags/) | disallow the use of `{@const}` in favor of `{const ...}` declaration tags | :wrench: |
337
338
  | [svelte/no-at-debug-tags](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-debug-tags/) | disallow the use of `{@debug}` | :star::bulb: |
338
339
  | [svelte/no-ignored-unsubscribe](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-ignored-unsubscribe/) | disallow ignoring the unsubscribe method returned by the `subscribe()` on Svelte stores. | |
339
340
  | [svelte/no-immutable-reactive-statements](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-immutable-reactive-statements/) | disallow reactive statements that don't reference reactive values. | :star: |
@@ -403,7 +404,7 @@ These rules relate to SvelteKit and its best Practices.
403
404
  |:--------|:------------|:---|
404
405
  | [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: |
405
406
  | [svelte/no-navigation-without-resolve](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-navigation-without-resolve/) | disallow internal navigation (links, `goto()`, `pushState()`, `replaceState()`) without a `resolve()` | :star: |
406
- | [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: |
407
+ | [svelte/valid-prop-names-in-kit-pages](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-prop-names-in-kit-pages/) | disallow invalid props in SvelteKit route components. | :star: |
407
408
 
408
409
  ## Experimental
409
410
 
package/lib/main.d.ts CHANGED
@@ -14,7 +14,7 @@ export declare const configs: {
14
14
  export declare const rules: Record<string, Rule.RuleModule>;
15
15
  export declare const meta: {
16
16
  name: "eslint-plugin-svelte";
17
- version: "3.18.0";
17
+ version: "3.20.0";
18
18
  };
19
19
  export declare const processors: {
20
20
  '.svelte': typeof processor;
package/lib/meta.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export declare const name: "eslint-plugin-svelte";
2
- export declare const version: "3.18.0";
2
+ export declare const version: "3.20.0";
package/lib/meta.js CHANGED
@@ -2,4 +2,4 @@
2
2
  // This file has been automatically generated,
3
3
  // in order to update its content execute "pnpm run update"
4
4
  export const name = 'eslint-plugin-svelte';
5
- export const version = '3.18.0';
5
+ export const version = '3.20.0';
@@ -100,6 +100,11 @@ export interface RuleOptions {
100
100
  * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-add-event-listener/
101
101
  */
102
102
  'svelte/no-add-event-listener'?: Linter.RuleEntry<[]>;
103
+ /**
104
+ * disallow the use of `{@const}` in favor of `{const ...}` declaration tags
105
+ * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-const-tags/
106
+ */
107
+ 'svelte/no-at-const-tags'?: Linter.RuleEntry<[]>;
103
108
  /**
104
109
  * disallow the use of `{@debug}`
105
110
  * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-debug-tags/
@@ -409,7 +414,7 @@ export interface RuleOptions {
409
414
  */
410
415
  'svelte/valid-each-key'?: Linter.RuleEntry<[]>;
411
416
  /**
412
- * disallow props other than data or errors in SvelteKit page components.
417
+ * disallow invalid props in SvelteKit route components.
413
418
  * @see https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-prop-names-in-kit-pages/
414
419
  */
415
420
  'svelte/valid-prop-names-in-kit-pages'?: Linter.RuleEntry<[]>;
@@ -172,6 +172,13 @@ export function defineVisitor(context) {
172
172
  offsets.setOffsetToken(declarationToken, 1, openToken);
173
173
  offsets.setOffsetToken(closeToken, 0, openToken);
174
174
  },
175
+ SvelteDeclarationTag(node) {
176
+ const openToken = sourceCode.getFirstToken(node);
177
+ const declarationToken = sourceCode.getFirstToken(node.declaration);
178
+ const closeToken = sourceCode.getLastToken(node);
179
+ offsets.setOffsetToken(declarationToken, 1, openToken);
180
+ offsets.setOffsetToken(closeToken, 0, openToken);
181
+ },
175
182
  SvelteRenderTag(node) {
176
183
  const openToken = sourceCode.getFirstToken(node);
177
184
  const renderToken = sourceCode.getTokenAfter(openToken);
@@ -151,6 +151,10 @@ export default createRule('mustache-spacing', {
151
151
  const mustacheTokens = getMustacheTokens(node, sourceCode);
152
152
  verifyBraces(mustacheTokens.openToken, mustacheTokens.closeToken, options.tags.openingBrace, options.tags.closingBrace, true);
153
153
  },
154
+ SvelteDeclarationTag(node) {
155
+ const mustacheTokens = getMustacheTokens(node, sourceCode);
156
+ verifyBraces(mustacheTokens.openToken, mustacheTokens.closeToken, options.tags.openingBrace, options.tags.closingBrace, true);
157
+ },
154
158
  SvelteRenderTag(node) {
155
159
  const mustacheTokens = getMustacheTokens(node, sourceCode);
156
160
  verifyBraces(mustacheTokens.openToken, mustacheTokens.closeToken, options.tags.openingBrace, options.tags.closingBrace, true);
@@ -0,0 +1,2 @@
1
+ declare const _default: import("../types.js").RuleModule;
2
+ export default _default;
@@ -0,0 +1,67 @@
1
+ import { createRule } from '../utils/index.js';
2
+ import { getSvelteContext } from '../utils/svelte-context.js';
3
+ import { VERSION as SVELTE_VERSION } from 'svelte/compiler';
4
+ import semver from 'semver';
5
+ const shouldRun = semver.satisfies(SVELTE_VERSION, '>=5.56.0');
6
+ export default createRule('no-at-const-tags', {
7
+ meta: {
8
+ docs: {
9
+ description: 'disallow the use of `{@const}` in favor of `{const ...}` declaration tags',
10
+ category: 'Best Practices',
11
+ recommended: false
12
+ },
13
+ fixable: 'code',
14
+ schema: [],
15
+ messages: {
16
+ unexpected: 'Use `{const ...}` declaration tag instead of legacy `{@const ...}`.'
17
+ },
18
+ type: 'suggestion',
19
+ conditions: [
20
+ {
21
+ svelteVersions: ['5']
22
+ }
23
+ ]
24
+ },
25
+ create(context) {
26
+ if (!shouldRun) {
27
+ return {};
28
+ }
29
+ const sourceCode = context.sourceCode;
30
+ const runes = getSvelteContext(context)?.runes;
31
+ // Only report and fix in runes mode, since preserving reactivity requires
32
+ // `$derived(...)`, which is unavailable outside runes mode.
33
+ if (runes !== true) {
34
+ return {};
35
+ }
36
+ return {
37
+ SvelteConstTag(node) {
38
+ context.report({
39
+ node,
40
+ messageId: 'unexpected',
41
+ *fix(fixer) {
42
+ const text = sourceCode.getText(node);
43
+ const match = /^\{(\s*)@const\b/u.exec(text);
44
+ if (!match) {
45
+ return;
46
+ }
47
+ const atOffset = node.range[0] + 1 + match[1].length;
48
+ yield fixer.removeRange([atOffset, atOffset + 1]);
49
+ const init = node.declarations[0].init;
50
+ if (init == null) {
51
+ return;
52
+ }
53
+ // Preserve the reactivity of legacy `{@const}` by wrapping the
54
+ // initializer in `$derived(...)`. Skip when already wrapped.
55
+ if (init.type === 'CallExpression' &&
56
+ init.callee.type === 'Identifier' &&
57
+ init.callee.name === '$derived') {
58
+ return;
59
+ }
60
+ yield fixer.insertTextBefore(init, '$derived(');
61
+ yield fixer.insertTextAfter(init, ')');
62
+ }
63
+ });
64
+ }
65
+ };
66
+ }
67
+ });
@@ -1,7 +1,9 @@
1
1
  import { createRule } from '../utils/index.js';
2
- import { getSvelteVersion } from '../utils/svelte-context.js';
3
- const EXPECTED_PROP_NAMES = ['data', 'errors', 'form', 'params', 'snapshot'];
4
- const EXPECTED_PROP_NAMES_SVELTE5 = [...EXPECTED_PROP_NAMES, 'children'];
2
+ import { getSvelteContext, getSvelteVersion } from '../utils/svelte-context.js';
3
+ const PAGE_PROP_NAMES = ['data', 'form', 'params', 'snapshot'];
4
+ const LEGACY_PAGE_PROP_NAMES = [...PAGE_PROP_NAMES, 'errors'];
5
+ const LAYOUT_PROP_NAMES = [...PAGE_PROP_NAMES, 'children'];
6
+ const ERROR_PROP_NAMES = ['error'];
5
7
  function checkProp(node, context, expectedPropNames) {
6
8
  if (node.id.type !== 'ObjectPattern')
7
9
  return;
@@ -32,25 +34,35 @@ function isModuleScript(node) {
32
34
  export default createRule('valid-prop-names-in-kit-pages', {
33
35
  meta: {
34
36
  docs: {
35
- description: 'disallow props other than data or errors in SvelteKit page components.',
37
+ description: 'disallow invalid props in SvelteKit route components.',
36
38
  category: 'SvelteKit',
37
39
  recommended: true
38
40
  },
39
41
  schema: [],
40
42
  messages: {
41
- unexpected: 'disallow props other than data or errors in SvelteKit page components.'
43
+ unexpected: 'disallow invalid props in SvelteKit route components.'
42
44
  },
43
45
  type: 'problem',
44
46
  conditions: [
45
47
  {
46
- svelteKitFileTypes: ['+page.svelte', '+error.svelte', '+layout.svelte']
48
+ svelteKitFileTypes: ['+page.svelte', '+layout.svelte', '+error.svelte']
47
49
  }
48
50
  ]
49
51
  },
50
52
  create(context) {
51
53
  let isScript = false;
52
54
  const isSvelte5 = getSvelteVersion() === '5';
53
- const expectedPropNames = isSvelte5 ? EXPECTED_PROP_NAMES_SVELTE5 : EXPECTED_PROP_NAMES;
55
+ const svelteContext = getSvelteContext(context);
56
+ const fileType = svelteContext?.svelteKitFileType;
57
+ let expectedPropNames = PAGE_PROP_NAMES;
58
+ if (isSvelte5) {
59
+ if (fileType === '+layout.svelte') {
60
+ expectedPropNames = LAYOUT_PROP_NAMES;
61
+ }
62
+ else if (fileType === '+error.svelte') {
63
+ expectedPropNames = ERROR_PROP_NAMES;
64
+ }
65
+ }
54
66
  return {
55
67
  // <script>
56
68
  'Program > SvelteScriptElement > SvelteStartTag': (node) => {
@@ -67,7 +79,7 @@ export default createRule('valid-prop-names-in-kit-pages', {
67
79
  return;
68
80
  // export let foo
69
81
  if (node.id.type === 'Identifier') {
70
- if (!expectedPropNames.includes(node.id.name)) {
82
+ if (!LEGACY_PAGE_PROP_NAMES.includes(node.id.name)) {
71
83
  context.report({
72
84
  node,
73
85
  loc: node.loc,
@@ -77,7 +89,7 @@ export default createRule('valid-prop-names-in-kit-pages', {
77
89
  return;
78
90
  }
79
91
  // export let { xxx, yyy } = zzz
80
- checkProp(node, context, expectedPropNames);
92
+ checkProp(node, context, LEGACY_PAGE_PROP_NAMES);
81
93
  },
82
94
  // Svelte5
83
95
  // let { foo, bar } = $props();
@@ -369,6 +369,8 @@ export type ASTNodeListener = {
369
369
  'SvelteDebugTag:exit'?: (node: AST.SvelteDebugTag & ASTNodeWithParent) => void;
370
370
  SvelteConstTag?: (node: AST.SvelteConstTag & ASTNodeWithParent) => void;
371
371
  'SvelteConstTag:exit'?: (node: AST.SvelteConstTag & ASTNodeWithParent) => void;
372
+ SvelteDeclarationTag?: (node: AST.SvelteDeclarationTag & ASTNodeWithParent) => void;
373
+ 'SvelteDeclarationTag:exit'?: (node: AST.SvelteDeclarationTag & ASTNodeWithParent) => void;
372
374
  SvelteRenderTag?: (node: AST.SvelteRenderTag & ASTNodeWithParent) => void;
373
375
  'SvelteRenderTag:exit'?: (node: AST.SvelteRenderTag & ASTNodeWithParent) => void;
374
376
  SvelteIfBlock?: (node: AST.SvelteIfBlock & ASTNodeWithParent) => void;
@@ -757,6 +759,8 @@ export type SvelteNodeListener = {
757
759
  'SvelteDebugTag:exit'?: (node: AST.SvelteDebugTag & ASTNodeWithParent) => void;
758
760
  SvelteConstTag?: (node: AST.SvelteConstTag & ASTNodeWithParent) => void;
759
761
  'SvelteConstTag:exit'?: (node: AST.SvelteConstTag & ASTNodeWithParent) => void;
762
+ SvelteDeclarationTag?: (node: AST.SvelteDeclarationTag & ASTNodeWithParent) => void;
763
+ 'SvelteDeclarationTag:exit'?: (node: AST.SvelteDeclarationTag & ASTNodeWithParent) => void;
760
764
  SvelteRenderTag?: (node: AST.SvelteRenderTag & ASTNodeWithParent) => void;
761
765
  'SvelteRenderTag:exit'?: (node: AST.SvelteRenderTag & ASTNodeWithParent) => void;
762
766
  SvelteIfBlock?: (node: AST.SvelteIfBlock & ASTNodeWithParent) => void;
@@ -91,11 +91,11 @@ export type QuoteAndRange = {
91
91
  };
92
92
  /** Get the quote and range from given attribute values */
93
93
  export declare function getAttributeValueQuoteAndRange(attr: SvAST.SvelteAttribute | SvAST.SvelteDirective | SvAST.SvelteStyleDirective | SvAST.SvelteSpecialDirective, sourceCode: SourceCode): QuoteAndRange | null;
94
- export declare function getMustacheTokens(node: SvAST.SvelteMustacheTag | SvAST.SvelteShorthandAttribute | SvAST.SvelteSpreadAttribute | SvAST.SvelteDebugTag | SvAST.SvelteRenderTag, sourceCode: SourceCode): {
94
+ export declare function getMustacheTokens(node: SvAST.SvelteMustacheTag | SvAST.SvelteShorthandAttribute | SvAST.SvelteSpreadAttribute | SvAST.SvelteDebugTag | SvAST.SvelteDeclarationTag | SvAST.SvelteRenderTag, sourceCode: SourceCode): {
95
95
  openToken: SvAST.Token;
96
96
  closeToken: SvAST.Token;
97
97
  };
98
- export declare function getMustacheTokens(node: SvAST.SvelteDirective | SvAST.SvelteSpecialDirective | SvAST.SvelteMustacheTag | SvAST.SvelteShorthandAttribute | SvAST.SvelteSpreadAttribute | SvAST.SvelteDebugTag | SvAST.SvelteRenderTag, sourceCode: SourceCode): {
98
+ export declare function getMustacheTokens(node: SvAST.SvelteDirective | SvAST.SvelteSpecialDirective | SvAST.SvelteMustacheTag | SvAST.SvelteShorthandAttribute | SvAST.SvelteSpreadAttribute | SvAST.SvelteDebugTag | SvAST.SvelteDeclarationTag | SvAST.SvelteRenderTag, sourceCode: SourceCode): {
99
99
  openToken: SvAST.Token;
100
100
  closeToken: SvAST.Token;
101
101
  } | null;
@@ -333,6 +333,7 @@ function isWrappedInBraces(node) {
333
333
  node.type === 'SvelteShorthandAttribute' ||
334
334
  node.type === 'SvelteSpreadAttribute' ||
335
335
  node.type === 'SvelteDebugTag' ||
336
+ node.type === 'SvelteDeclarationTag' ||
336
337
  node.type === 'SvelteRenderTag');
337
338
  }
338
339
  /** Get attribute key text */
@@ -17,6 +17,7 @@ import maxAttributesPerLine from '../rules/max-attributes-per-line.js';
17
17
  import maxLinesPerBlock from '../rules/max-lines-per-block.js';
18
18
  import mustacheSpacing from '../rules/mustache-spacing.js';
19
19
  import noAddEventListener from '../rules/no-add-event-listener.js';
20
+ import noAtConstTags from '../rules/no-at-const-tags.js';
20
21
  import noAtDebugTags from '../rules/no-at-debug-tags.js';
21
22
  import noAtHtmlTags from '../rules/no-at-html-tags.js';
22
23
  import noDomManipulating from '../rules/no-dom-manipulating.js';
@@ -100,6 +101,7 @@ export const rules = [
100
101
  maxLinesPerBlock,
101
102
  mustacheSpacing,
102
103
  noAddEventListener,
104
+ noAtConstTags,
103
105
  noAtDebugTags,
104
106
  noAtHtmlTags,
105
107
  noDomManipulating,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-svelte",
3
- "version": "3.18.0",
3
+ "version": "3.20.0",
4
4
  "description": "ESLint plugin for Svelte using AST",
5
5
  "repository": {
6
6
  "type": "git",
@@ -45,7 +45,7 @@
45
45
  "postcss-load-config": "^3.1.4",
46
46
  "postcss-safe-parser": "^7.0.0",
47
47
  "semver": "^7.6.3",
48
- "svelte-eslint-parser": "^1.4.0"
48
+ "svelte-eslint-parser": "^1.7.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@babel/core": "^7.28.3",
@@ -79,7 +79,7 @@
79
79
  "sass": "^1.92.0",
80
80
  "source-map-js": "^1.2.1",
81
81
  "stylus": "^0.64.0",
82
- "svelte": "^5.41.0",
82
+ "svelte": "^5.56.0",
83
83
  "svelte-i18n": "^4.0.1",
84
84
  "tsx": "^4.20.5",
85
85
  "type-coverage": "^2.29.7",