Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Added the no-unused-class-name rule using parser services (#489)
- Loading branch information
1 parent
eca2c3d
commit cc321f4
Showing
34 changed files
with
488 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"eslint-plugin-svelte": minor | ||
--- | ||
|
||
feat: added the no-unused-class-name rule |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
--- | ||
pageClass: "rule-details" | ||
sidebarDepth: 0 | ||
title: "svelte/no-unused-class-name" | ||
description: "disallow the use of a class in the template without a corresponding style" | ||
--- | ||
|
||
# svelte/no-unused-class-name | ||
|
||
> disallow the use of a class in the template without a corresponding style | ||
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge> | ||
|
||
## :book: Rule Details | ||
|
||
This rule is aimed at reducing unused classes in the HTML template. While `svelte-check` will produce the `css-unused-selector` if your `<style>` block includes any classes that aren't used in the template, this rule works the other way around - it reports cases wehre the template contains classes that aren't referred to in the `<style>` block. | ||
|
||
<ESLintCodeBlock> | ||
|
||
<!--eslint-skip--> | ||
|
||
```svelte | ||
<script lang="ts"> | ||
/* eslint svelte/no-unused-class-name: "error" */ | ||
</scrip> | ||
<!-- ✓ GOOD --> | ||
<div class="first-class">Hello</div> | ||
<div class="second-class">Hello</div> | ||
<div class="third-class fourth-class">Hello</div> | ||
<!-- ✗ BAD --> | ||
<div class="fifth-class">Hello</div> | ||
<div class="sixth-class first-class">Hello</div> | ||
<style> | ||
.first-class { | ||
color: red; | ||
} | ||
.second-class, | ||
.third-class { | ||
color: blue; | ||
} | ||
.fourth-class { | ||
color: green; | ||
} | ||
</style> | ||
``` | ||
|
||
</ESLintCodeBlock> | ||
|
||
## :wrench: Options | ||
|
||
Nothing. | ||
|
||
## :mag: Implementation | ||
|
||
- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/src/rules/no-unused-class-name.ts) | ||
- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/tests/src/rules/no-unused-class-name.ts) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import { createRule } from "../utils" | ||
import type { | ||
SourceLocation, | ||
SvelteAttribute, | ||
SvelteDirective, | ||
SvelteShorthandAttribute, | ||
SvelteSpecialDirective, | ||
SvelteSpreadAttribute, | ||
SvelteStyleDirective, | ||
} from "svelte-eslint-parser/lib/ast" | ||
import type { AnyNode } from "postcss" | ||
import { | ||
default as selectorParser, | ||
type Node as SelectorNode, | ||
} from "postcss-selector-parser" | ||
|
||
export default createRule("no-unused-class-name", { | ||
meta: { | ||
docs: { | ||
description: | ||
"disallow the use of a class in the template without a corresponding style", | ||
category: "Best Practices", | ||
recommended: false, | ||
}, | ||
schema: [], | ||
messages: {}, | ||
type: "suggestion", | ||
}, | ||
create(context) { | ||
const classesUsedInTemplate: Record<string, SourceLocation> = {} | ||
|
||
return { | ||
SvelteElement(node) { | ||
if (node.kind !== "html") { | ||
return | ||
} | ||
const classes = node.startTag.attributes.flatMap(findClassesInAttribute) | ||
for (const className of classes) { | ||
classesUsedInTemplate[className] = node.startTag.loc | ||
} | ||
}, | ||
"Program:exit"() { | ||
const styleContext = context.parserServices.getStyleContext() | ||
if (["parse-error", "unknown-lang"].includes(styleContext.status)) { | ||
return | ||
} | ||
const classesUsedInStyle = | ||
styleContext.sourceAst != null | ||
? findClassesInPostCSSNode(styleContext.sourceAst) | ||
: [] | ||
for (const className in classesUsedInTemplate) { | ||
if (!classesUsedInStyle.includes(className)) { | ||
context.report({ | ||
loc: classesUsedInTemplate[className], | ||
message: `Unused class "${className}".`, | ||
}) | ||
} | ||
} | ||
}, | ||
} | ||
}, | ||
}) | ||
|
||
/** | ||
* Extract all class names used in a HTML element attribute. | ||
*/ | ||
function findClassesInAttribute( | ||
attribute: | ||
| SvelteAttribute | ||
| SvelteShorthandAttribute | ||
| SvelteSpreadAttribute | ||
| SvelteDirective | ||
| SvelteStyleDirective | ||
| SvelteSpecialDirective, | ||
): string[] { | ||
if (attribute.type === "SvelteAttribute" && attribute.key.name === "class") { | ||
return attribute.value.flatMap((value) => | ||
value.type === "SvelteLiteral" ? value.value.trim().split(/\s+/u) : [], | ||
) | ||
} | ||
if (attribute.type === "SvelteDirective" && attribute.kind === "Class") { | ||
return [attribute.key.name.name] | ||
} | ||
return [] | ||
} | ||
|
||
/** | ||
* Extract all class names used in a PostCSS node. | ||
*/ | ||
function findClassesInPostCSSNode(node: AnyNode): string[] { | ||
if (node.type === "rule") { | ||
let classes = node.nodes.flatMap(findClassesInPostCSSNode) | ||
const processor = selectorParser() | ||
classes = classes.concat( | ||
findClassesInSelector(processor.astSync(node.selector)), | ||
) | ||
return classes | ||
} | ||
if (node.type === "root" || node.type === "atrule") { | ||
return node.nodes.flatMap(findClassesInPostCSSNode) | ||
} | ||
return [] | ||
} | ||
|
||
/** | ||
* Extract all class names used in a PostCSS selector. | ||
*/ | ||
function findClassesInSelector(node: SelectorNode): string[] { | ||
if (node.type === "class") { | ||
return [node.value] | ||
} | ||
if ( | ||
node.type === "pseudo" || | ||
node.type === "root" || | ||
node.type === "selector" | ||
) { | ||
return node.nodes.flatMap(findClassesInSelector) | ||
} | ||
return [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
tests/fixtures/rules/no-unused-class-name/invalid/class-directive01-errors.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
- message: Unused class "first". | ||
line: 1 | ||
column: 1 | ||
suggestions: null | ||
- message: Unused class "second". | ||
line: 3 | ||
column: 1 | ||
suggestions: null |
3 changes: 3 additions & 0 deletions
3
tests/fixtures/rules/no-unused-class-name/invalid/class-directive01-input.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<div class:first={true}>Hello</div> | ||
|
||
<span class:second={false}>World!</span> |
12 changes: 12 additions & 0 deletions
12
tests/fixtures/rules/no-unused-class-name/invalid/multiline-class-names01-errors.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
- message: Unused class "div-class-two". | ||
line: 2 | ||
column: 1 | ||
suggestions: null | ||
- message: Unused class "span-class-two". | ||
line: 4 | ||
column: 1 | ||
suggestions: null | ||
- message: Unused class "span-class-three". | ||
line: 4 | ||
column: 1 | ||
suggestions: null |
19 changes: 19 additions & 0 deletions
19
tests/fixtures/rules/no-unused-class-name/invalid/multiline-class-names01-input.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<!-- eslint-disable prettier/prettier --> | ||
<div class="div-class div-class-two">Hello</div> | ||
|
||
<span | ||
class=" | ||
span-class | ||
span-class-two | ||
span-class-three | ||
">World!</span> | ||
|
||
<style> | ||
.div-class { | ||
color: red; | ||
} | ||
.span-class { | ||
font-weight: bold; | ||
} | ||
</style> |
12 changes: 12 additions & 0 deletions
12
tests/fixtures/rules/no-unused-class-name/invalid/multiple-class-names01-errors.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
- message: Unused class "div-class-two". | ||
line: 1 | ||
column: 1 | ||
suggestions: null | ||
- message: Unused class "span-class-two". | ||
line: 3 | ||
column: 1 | ||
suggestions: null | ||
- message: Unused class "span-class-three". | ||
line: 3 | ||
column: 1 | ||
suggestions: null |
13 changes: 13 additions & 0 deletions
13
tests/fixtures/rules/no-unused-class-name/invalid/multiple-class-names01-input.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<div class="div-class div-class-two">Hello</div> | ||
|
||
<span class="span-class span-class-two span-class-three">World!</span> | ||
|
||
<style> | ||
.div-class { | ||
color: red; | ||
} | ||
.span-class { | ||
font-weight: bold; | ||
} | ||
</style> |
8 changes: 8 additions & 0 deletions
8
tests/fixtures/rules/no-unused-class-name/invalid/same-name-id01-errors.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
- message: Unused class "div-class". | ||
line: 1 | ||
column: 1 | ||
suggestions: null | ||
- message: Unused class "span-class". | ||
line: 3 | ||
column: 1 | ||
suggestions: null |
13 changes: 13 additions & 0 deletions
13
tests/fixtures/rules/no-unused-class-name/invalid/same-name-id01-input.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<div class="div-class">Hello</div> | ||
|
||
<span class="span-class">World!</span> | ||
|
||
<style> | ||
#div-class { | ||
color: red; | ||
} | ||
#span-class { | ||
font-weight: bold; | ||
} | ||
</style> |
8 changes: 8 additions & 0 deletions
8
tests/fixtures/rules/no-unused-class-name/invalid/unused-class-name01-errors.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
- message: Unused class "div-class". | ||
line: 1 | ||
column: 1 | ||
suggestions: null | ||
- message: Unused class "span-class". | ||
line: 3 | ||
column: 1 | ||
suggestions: null |
3 changes: 3 additions & 0 deletions
3
tests/fixtures/rules/no-unused-class-name/invalid/unused-class-name01-input.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<div class="div-class">Hello</div> | ||
|
||
<span class="span-class">World!</span> |
8 changes: 8 additions & 0 deletions
8
tests/fixtures/rules/no-unused-class-name/invalid/used-unrelated-class-name01-errors.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
- message: Unused class "div-class". | ||
line: 1 | ||
column: 1 | ||
suggestions: null | ||
- message: Unused class "span-class". | ||
line: 3 | ||
column: 1 | ||
suggestions: null |
9 changes: 9 additions & 0 deletions
9
tests/fixtures/rules/no-unused-class-name/invalid/used-unrelated-class-name01-input.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<div class="div-class">Hello</div> | ||
|
||
<span class="span-class">World!</span> | ||
|
||
<style> | ||
.unrelated-class { | ||
color: red; | ||
} | ||
</style> |
9 changes: 9 additions & 0 deletions
9
tests/fixtures/rules/no-unused-class-name/valid/adjacent-sibling-combinator01-input.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<div class="div-class">Hello</div> | ||
|
||
<span class="span-class">World!</span> | ||
|
||
<style> | ||
.div-class + .span-class { | ||
color: red; | ||
} | ||
</style> |
9 changes: 9 additions & 0 deletions
9
tests/fixtures/rules/no-unused-class-name/valid/child-combinator01-input.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<div class="container"> | ||
<div class="div-class">Hello</div> | ||
</div> | ||
|
||
<style> | ||
.container > .div-class { | ||
color: red; | ||
} | ||
</style> |
9 changes: 9 additions & 0 deletions
9
tests/fixtures/rules/no-unused-class-name/valid/descendant-combinator01-input.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<div class="container"> | ||
<div class="div-class">Hello</div> | ||
</div> | ||
|
||
<style> | ||
.container .div-class { | ||
color: red; | ||
} | ||
</style> |
Oops, something went wrong.