Skip to content

Commit 1b0cd07

Browse files
authored
Merge pull request #21 from elisecodedestrucs/no-css-animation
add rule no-css-animations
2 parents 72dfdf4 + 2879047 commit 1b0cd07

File tree

5 files changed

+178
-0
lines changed

5 files changed

+178
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
13+
- [#21](https://github.com/green-code-initiative/ecoCode-javascript/pull/21) Add rule `@ecocode/avoid-css-animations`
1214
- [#19](https://github.com/green-code-initiative/ecoCode-javascript/pull/19) add rule `@ecocode/no-empty-image-src-attribute`
1315
- [#18](https://github.com/green-code-initiative/ecoCode-javascript/pull/18) add rule `@ecocode/limit-db-query-results`
1416
- [#14](https://github.com/green-code-initiative/ecoCode-javascript/pull/14) Create SonarQube plugin

eslint-plugin/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Add `@ecocode` to the `plugins` section of your `.eslintrc`, followed by rules c
5858

5959
| Name | Description | ⚠️ |
6060
| :------------------------------------------------------------------------------------- | :--------------------------------------------------------- | :- |
61+
| [avoid-css-animations](docs/rules/avoid-css-animations.md) | Avoid usage of CSS animations ||
6162
| [avoid-high-accuracy-geolocation](docs/rules/avoid-high-accuracy-geolocation.md) | Avoid using high accuracy geolocation in web applications. ||
6263
| [limit-db-query-results](docs/rules/limit-db-query-results.md) | Should limit the number of returns for a SQL query ||
6364
| [no-empty-image-src-attribute](docs/rules/no-empty-image-src-attribute.md) | Disallow usage of image with empty source attribute ||
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Avoid usage of CSS animations (`@ecocode/avoid-css-animations`)
2+
3+
⚠️ This rule _warns_ in the ✅ `recommended` config.
4+
5+
<!-- end auto-generated rule header -->
6+
7+
## Rule Details
8+
9+
This rule aims to limit the usage of all types of CSS animations which can be very costly in terms of CPU and memory.
10+
They must only be used when they are indispensable and should be limited to the CSS properties `opacity` and `transform`
11+
with it's associated functions : `translate`, `rotate` and `scale`. You can also inform the navigator of upcoming
12+
changes with the `will-change` instruction for more optimization.
13+
14+
## Examples
15+
16+
Examples of **non compliant** code for this rule:
17+
18+
```js
19+
<div style={{ border: "1px solid black", transition: "border 2s ease" }}/>
20+
```
21+
22+
Examples of **compliant** code for this rule:
23+
24+
```js
25+
<div style={{ border: "1px solid black" }}/>
26+
```
27+
28+
## Further details
29+
30+
This recommendation is made by the
31+
CNUMR: [Avoid JavaScript / CSS animations](https://github.com/cnumr/best-practices/blob/main/chapters/BP_039_en.md)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* Copyright (C) 2023 Green Code Initiative
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
"use strict";
18+
19+
/** @type {import('eslint').Rule.RuleModule} */
20+
module.exports = {
21+
meta: {
22+
type: "suggestion",
23+
docs: {
24+
description: "Avoid usage of CSS animations",
25+
category: "eco-design",
26+
recommended: "warn",
27+
},
28+
messages: {
29+
AvoidCSSAnimations: "Avoid using {{attribute}} in CSS.",
30+
},
31+
schema: [],
32+
},
33+
create(context) {
34+
const forbiddenProperties = ["transition", "animation"];
35+
return {
36+
JSXOpeningElement(node) {
37+
const styleAttribute = node.attributes.find(
38+
(attribute) => attribute.name.name === "style",
39+
);
40+
41+
if (styleAttribute && styleAttribute.value.expression) {
42+
// To prevent (for example) <div style={{ animate: 'width 2s' }}>
43+
const property = styleAttribute.value.expression.properties.find(
44+
(prop) =>
45+
forbiddenProperties.some((forbidProp) =>
46+
prop.key.name.includes(forbidProp),
47+
),
48+
);
49+
if (property != null) {
50+
context.report({
51+
node: property,
52+
messageId: "AvoidCSSAnimations",
53+
data: {
54+
attribute: property.key.name,
55+
},
56+
});
57+
}
58+
}
59+
},
60+
};
61+
},
62+
};
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* Copyright (C) 2023 Green Code Initiative
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
"use strict";
18+
19+
//------------------------------------------------------------------------------
20+
// Requirements
21+
//------------------------------------------------------------------------------
22+
23+
const rule = require("../../../lib/rules/avoid-css-animations");
24+
const RuleTester = require("eslint").RuleTester;
25+
26+
//------------------------------------------------------------------------------
27+
// Tests
28+
//------------------------------------------------------------------------------
29+
30+
const ruleTester = new RuleTester({
31+
parserOptions: {
32+
ecmaVersion: 2021,
33+
sourceType: "module",
34+
ecmaFeatures: {
35+
jsx: true,
36+
},
37+
},
38+
});
39+
40+
ruleTester.run("avoid-css-animations", rule, {
41+
valid: [
42+
`
43+
import React from 'react';
44+
import './styles.css'; // External CSS file
45+
46+
const MyComponent = () => {
47+
return <div className="my-class">This content is styled using an external CSS file.</div>;
48+
};
49+
50+
export default MyComponent;
51+
`,
52+
`<div style={{ width: '100px', height: '100px' }}>Hello world</div>`,
53+
`<div style="border: 2px solid red">My red element</div>`,
54+
],
55+
56+
invalid: [
57+
{
58+
code: "<div style={{ transition: 'width 2s' }} />",
59+
errors: [
60+
{
61+
messageId: "AvoidCSSAnimations",
62+
data: {
63+
attribute: "transition",
64+
},
65+
type: "Property",
66+
},
67+
],
68+
},
69+
{
70+
code: "<div style={{ animationName: 'example', animationDuration: '4s' }} />",
71+
errors: [
72+
{
73+
messageId: "AvoidCSSAnimations",
74+
data: {
75+
attribute: "animationName",
76+
},
77+
type: "Property",
78+
},
79+
],
80+
},
81+
],
82+
});

0 commit comments

Comments
 (0)