Skip to content

feat: add rule no-deprecated-raw-special-elements #918

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lazy-eyes-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'eslint-plugin-svelte': minor
---

Added new `no-deprecated-raw-special-elements` rule
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
| Rule ID | Description | |
|:--------|:------------|:---|
| [svelte/infinite-reactive-loop](https://sveltejs.github.io/eslint-plugin-svelte/rules/infinite-reactive-loop/) | Svelte runtime prevents calling the same reactive statement twice in a microtask. But between different microtask, it doesn't prevent. | |
| [svelte/no-deprecated-raw-special-elements](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-deprecated-raw-special-elements/) | Recommends not using raw special elements in Svelte versions previous to 5. | :wrench: |
| [svelte/no-dom-manipulating](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dom-manipulating/) | disallow DOM manipulating | |
| [svelte/no-dupe-else-if-blocks](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dupe-else-if-blocks/) | disallow duplicate conditions in `{#if}` / `{:else if}` chains | :star: |
| [svelte/no-dupe-on-directives](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dupe-on-directives/) | disallow duplicate `on:` directives | |
Expand Down
1 change: 1 addition & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
| Rule ID | Description | |
| :------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------- | :------------- |
| [svelte/infinite-reactive-loop](./rules/infinite-reactive-loop.md) | Svelte runtime prevents calling the same reactive statement twice in a microtask. But between different microtask, it doesn't prevent. | |
| [svelte/no-deprecated-raw-special-elements](./rules/no-deprecated-raw-special-elements.md) | Recommends not using raw special elements in Svelte versions previous to 5. | :wrench: |
| [svelte/no-dom-manipulating](./rules/no-dom-manipulating.md) | disallow DOM manipulating | |
| [svelte/no-dupe-else-if-blocks](./rules/no-dupe-else-if-blocks.md) | disallow duplicate conditions in `{#if}` / `{:else if}` chains | :star: |
| [svelte/no-dupe-on-directives](./rules/no-dupe-on-directives.md) | disallow duplicate `on:` directives | |
Expand Down
52 changes: 52 additions & 0 deletions docs/rules/no-deprecated-raw-special-elements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
pageClass: 'rule-details'
sidebarDepth: 0
title: 'svelte/no-deprecated-raw-special-elements'
description: 'Recommends not using raw special elements in Svelte versions previous to 5.'
---

# svelte/no-deprecated-raw-special-elements

> Recommends not using raw special elements in Svelte versions previous to 5.

- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>
- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.

## :book: Rule Details

This rule reports the usage of `head`, `body`, `window`, `document`, `element` and `options` HTML elements. These elements were valid in in versions proior to 5, but since Svelte 5 they must be used with `svelte:`.

<ESLintCodeBlock fix>

<!--eslint-skip-->

```svelte
<script>
/* eslint svelte/no-deprecated-raw-special-elements: "error" */
</script>

<!-- ✓ GOOD -->
<svelte:head>
<title>Valid</title>
</svelte:head>

<!-- ✗ BAD -->
<head>
<title>Invalid</title>
</head>
```

</ESLintCodeBlock>

## :wrench: Options

Nothing.

## :books: Further Reading

- See special elements section in [Svelte docs](https://svelte.dev/docs/svelte/svelte-window)

## :mag: Implementation

- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/src/rules/no-deprecated-raw-special-elements.ts)
- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/packages/eslint-plugin-svelte/tests/src/rules/no-deprecated-raw-special-elements.ts)
5 changes: 5 additions & 0 deletions packages/eslint-plugin-svelte/src/rule-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ export interface RuleOptions {
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-html-tags/
*/
'svelte/no-at-html-tags'?: Linter.RuleEntry<[]>
/**
* Recommends not using raw special elements in Svelte versions previous to 5.
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-deprecated-raw-special-elements/
*/
'svelte/no-deprecated-raw-special-elements'?: Linter.RuleEntry<[]>
/**
* disallow DOM manipulating
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dom-manipulating/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type { AST } from 'svelte-eslint-parser';
import { createRule } from '../utils';

const INVALID_HTML_ELEMENTS = ['head', 'body', 'window', 'document', 'element', 'options'];
const VALID_PREFIX = 'svelte:';

export default createRule('no-deprecated-raw-special-elements', {
meta: {
docs: {
description: 'Recommends not using raw special elements in Svelte versions previous to 5.',
category: 'Possible Errors',
// TODO: Switch to recommended in the major version

Check warning on line 12 in packages/eslint-plugin-svelte/src/rules/no-deprecated-raw-special-elements.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected 'todo' comment: 'TODO: Switch to recommended in the major...'
recommended: false
},
schema: [],
messages: {
deprecatedElement:
'Special {{name}} element is deprecated in v5, use svelte:{{name}} instead.'
},
type: 'problem', // 'problem', or 'layout',
fixable: 'code'
},
create(context) {
return {
'SvelteElement[kind="html"]'(node: AST.SvelteHTMLElement) {
const { name } = node.name;
if (INVALID_HTML_ELEMENTS.includes(name)) {
context.report({
node,
messageId: 'deprecatedElement',
data: { name },
*fix(fixer) {
const { endTag } = node;
yield fixer.insertTextBeforeRange([node.range[0] + 1, node.range[1]], VALID_PREFIX);
if (endTag) {
yield fixer.insertTextBeforeRange(
[endTag.range[0] + 2, endTag.range[1]],
VALID_PREFIX
);
}
}
});
}
}
};
}
});
2 changes: 2 additions & 0 deletions packages/eslint-plugin-svelte/src/utils/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import maxAttributesPerLine from '../rules/max-attributes-per-line';
import mustacheSpacing from '../rules/mustache-spacing';
import noAtDebugTags from '../rules/no-at-debug-tags';
import noAtHtmlTags from '../rules/no-at-html-tags';
import noDeprecatedRawSpecialElements from '../rules/no-deprecated-raw-special-elements';
import noDomManipulating from '../rules/no-dom-manipulating';
import noDupeElseIfBlocks from '../rules/no-dupe-else-if-blocks';
import noDupeOnDirectives from '../rules/no-dupe-on-directives';
Expand Down Expand Up @@ -87,6 +88,7 @@ export const rules = [
mustacheSpacing,
noAtDebugTags,
noAtHtmlTags,
noDeprecatedRawSpecialElements,
noDomManipulating,
noDupeElseIfBlocks,
noDupeOnDirectives,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
- message: Special head element is deprecated in v5, use svelte:head instead.
line: 1
column: 1
suggestions: null
- message: Special body element is deprecated in v5, use svelte:body instead.
line: 2
column: 1
suggestions: null
- message: Special window element is deprecated in v5, use svelte:window instead.
line: 3
column: 1
suggestions: null
- message: Special document element is deprecated in v5, use svelte:document instead.
line: 4
column: 1
suggestions: null
- message: Special element element is deprecated in v5, use svelte:element instead.
line: 5
column: 1
suggestions: null
- message: Special options element is deprecated in v5, use svelte:options instead.
line: 6
column: 1
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<head></head>
<body></body>
<window></window>
<document></document>
<element this={{}}></element>
<options></options>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<svelte:head></svelte:head>
<svelte:body></svelte:body>
<svelte:window></svelte:window>
<svelte:document></svelte:document>
<svelte:element this={{}}></svelte:element>
<svelte:options></svelte:options>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<svelte:options />

<svelte:body />
<svelte:document />
<svelte:element this={{}}></svelte:element>
<svelte:head></svelte:head>

<svelte:window />
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { RuleTester } from '../../utils/eslint-compat';
import rule from '../../../src/rules/no-deprecated-raw-special-elements';
import { loadTestCases } from '../../utils/utils';

const tester = new RuleTester({
languageOptions: {
ecmaVersion: 2020,
sourceType: 'module'
}
});

tester.run('no-deprecated-raw-special-elements', rule as any, loadTestCases('no-deprecated-raw-special-elements'));
Loading