-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #405 from bchanez/feat/no-important
feat(no-important): add rule !important is used
- Loading branch information
Showing
9 changed files
with
207 additions
and
2 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
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,65 @@ | ||
# No Direct Dom Access | ||
|
||
Checks if a component's styles are using the `!important` declaration to enforce styles. | ||
|
||
## ❓ Why it's good to follow this rule? | ||
|
||
Direct DOM manipulation in Vue components can lead to several issues: | ||
|
||
Using `!important` in CSS can lead to several issues: | ||
|
||
1. It complicates the cascade of styles, making it harder to understand which styles are being applied. | ||
2. It increases the specificity of rules, leading to maintenance challenges when updating styles. | ||
3. It can make debugging more difficult, as the usual cascade and inheritance rules of CSS are bypassed. | ||
4. It promotes poor coding practices by encouraging developers to rely on `!important` rather than properly managing specificity. | ||
|
||
## 😱 Examples of code for which this rule will throw a warning | ||
|
||
::: warning | ||
The following code contains the use of `!important`, which is discouraged: | ||
::: | ||
|
||
|
||
```vue | ||
<template> | ||
<div class="button">Click Me</div> | ||
</template> | ||
<style scoped> | ||
.button { | ||
background-color: blue !important; /* Disallowed */ | ||
color: white; | ||
} | ||
</style> | ||
``` | ||
|
||
## 🤩 How to fix it? | ||
|
||
::: tip | ||
Refactor your CSS to avoid using `!important` by managing specificity through proper selectors. Here's how to fix the previous examples: | ||
::: | ||
|
||
```vue | ||
<template> | ||
<div class="button">Click Me</div> | ||
</template> | ||
<style scoped> | ||
.button { | ||
background-color: blue; /* Removed !important */ | ||
color: white; | ||
} | ||
.special-button { | ||
background-color: red; /* More specific selector */ | ||
} | ||
</style> | ||
``` | ||
|
||
In this fixed example: | ||
|
||
1. We removed the `!important` declaration from the `.button` class. | ||
2. We created a more specific selector (`.special-button`) to override styles when necessary. | ||
3. By relying on proper specificity and structure, we maintain clearer and more manageable CSS. | ||
|
||
This approach enhances maintainability, readability, and performance while ensuring that styles are applied correctly without unnecessary overrides. |
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,90 @@ | ||
import type { SFCTemplateBlock } from '@vue/compiler-sfc' | ||
import { describe, expect, it } from 'vitest' | ||
import { checkNoImportant, reportNoImportant } from './noImportant' | ||
|
||
describe('importantUsed', () => { | ||
it('should not report templates when there is no use of !important', () => { | ||
const template = { | ||
content: ` | ||
<template> | ||
<div style="color: blue"></div> | ||
</template> | ||
<style scoped> | ||
div { | ||
border: solid; | ||
} | ||
</style> | ||
`, | ||
} as SFCTemplateBlock | ||
const filename = 'no-important.vue' | ||
checkNoImportant(template, filename) | ||
const result = reportNoImportant() | ||
expect(result.length).toBe(0) | ||
expect(result).toStrictEqual([]) | ||
}) | ||
|
||
it('should not report css files when there is no use of !important', () => { | ||
const template = { | ||
content: ` | ||
div { | ||
color: blue; | ||
} | ||
`, | ||
} as SFCTemplateBlock | ||
const filename = 'no-important.css' | ||
checkNoImportant(template, filename) | ||
const result = reportNoImportant() | ||
expect(result.length).toBe(0) | ||
expect(result).toStrictEqual([]) | ||
}) | ||
|
||
it('should report templates when there is use of !important', () => { | ||
const template = { | ||
content: ` | ||
<template> | ||
<div style="color: blue !important"></div> | ||
</template> | ||
<style scoped> | ||
div { | ||
border: solid !important; | ||
} | ||
</style> | ||
`, | ||
} as SFCTemplateBlock | ||
const filename = 'no-important.vue' | ||
checkNoImportant(template, filename) | ||
const result = reportNoImportant() | ||
expect(result.length).toBe(2) | ||
expect(result).toStrictEqual([{ | ||
file: filename, | ||
rule: `<text_info>rdd ~ no !important</text_info>`, | ||
description: `👉 <text_warn>Avoid !important as it complicates CSS management and disrupts natural cascading.</text_warn>`, | ||
message: `line #${2} <bg_warn>Found !important</bg_warn> 🚨`, | ||
}, { | ||
file: filename, | ||
rule: `<text_info>rdd ~ no !important</text_info>`, | ||
description: `👉 <text_warn>Avoid !important as it complicates CSS management and disrupts natural cascading.</text_warn>`, | ||
message: `line #${6} <bg_warn>Found !important</bg_warn> 🚨`, | ||
}]) | ||
}) | ||
|
||
it('should report css files when there is use of !important', () => { | ||
const template = { | ||
content: ` | ||
div { | ||
color: blue !important; | ||
} | ||
`, | ||
} as SFCTemplateBlock | ||
const filename = 'no-important.css' | ||
checkNoImportant(template, filename) | ||
const result = reportNoImportant() | ||
expect(result.length).toBe(1) | ||
expect(result).toStrictEqual([{ | ||
file: filename, | ||
rule: `<text_info>rdd ~ no !important</text_info>`, | ||
description: `👉 <text_warn>Avoid !important as it complicates CSS management and disrupts natural cascading.</text_warn>`, | ||
message: `line #${2} <bg_warn>Found !important</bg_warn> 🚨`, | ||
}]) | ||
}) | ||
}) |
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,44 @@ | ||
import type { SFCTemplateBlock } from '@vue/compiler-sfc' | ||
import type { FileCheckResult, Offense } from '../../types' | ||
import getLineNumber from '../getLineNumber' | ||
|
||
const results: FileCheckResult[] = [] | ||
|
||
const resetResults = () => (results.length = 0) | ||
|
||
const checkNoImportant = (template: SFCTemplateBlock | null, filePath: string) => { | ||
if (!template) { | ||
return | ||
} | ||
|
||
const regex = /!important/g | ||
|
||
const matches = [...template.content.matchAll(regex)] | ||
let from = 0 | ||
matches.forEach((match) => { | ||
const lineNumber = getLineNumber(template.content.trim(), match[0], from) | ||
results.push({ filePath, message: `line #${lineNumber} <bg_warn>Found !important</bg_warn>` }) | ||
from = lineNumber | ||
}) | ||
} | ||
|
||
const reportNoImportant = () => { | ||
const offenses: Offense[] = [] | ||
|
||
if (results.length > 0) { | ||
results.forEach((result) => { | ||
offenses.push({ | ||
file: result.filePath, | ||
rule: `<text_info>rdd ~ no !important</text_info>`, | ||
description: `👉 <text_warn>Avoid !important as it complicates CSS management and disrupts natural cascading.</text_warn>`, | ||
message: `${result.message} 🚨`, | ||
}) | ||
}) | ||
} | ||
|
||
resetResults() | ||
|
||
return offenses | ||
} | ||
|
||
export { checkNoImportant, reportNoImportant } |
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