Skip to content

Commit 43dec96

Browse files
nzakasmdjermanovic
andauthored
feat: no-unknown-properties rule (#5)
* feat: no-unknown-properties rule * Fix rule description * Update docs/rules/no-unknown-properties.md Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com> --------- Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
1 parent 61ec7ae commit 43dec96

File tree

5 files changed

+191
-4
lines changed

5 files changed

+191
-4
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ export default [
5656

5757
<!-- Rule Table Start -->
5858

59-
| **Rule Name** | **Description** | **Recommended** |
60-
| :------------------------------------------------------------- | :-------------------------------- | :-------------: |
61-
| [`no-duplicate-imports`](./docs/rules/no-duplicate-imports.md) | Disallow duplicate @import rules. | yes |
62-
| [`no-empty-blocks`](./docs/rules/no-empty-blocks.md) | Disallow empty blocks. | yes |
59+
| **Rule Name** | **Description** | **Recommended** |
60+
| :--------------------------------------------------------------- | :-------------------------------- | :-------------: |
61+
| [`no-duplicate-imports`](./docs/rules/no-duplicate-imports.md) | Disallow duplicate @import rules. | yes |
62+
| [`no-empty-blocks`](./docs/rules/no-empty-blocks.md) | Disallow empty blocks. | yes |
63+
| [`no-unknown-properties`](./docs/rules/no-unknown-properties.md) | Disallow unknown properties. | yes |
6364

6465
<!-- Rule Table End -->
6566

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# no-unknown-properties
2+
3+
Disallow unknown properties.
4+
5+
## Background
6+
7+
CSS rules may contain any number of properties consisting of a name and a value. As long as the property name is valid CSS, it will parse correctly, even if the property won't be recognized by a web browser. For example:
8+
9+
```css
10+
a {
11+
ccolor: black;
12+
}
13+
```
14+
15+
Here, `ccolor` is a syntactically valid identifier even though it will be ignored by browsers. Such errors are often caused by typos.
16+
17+
## Rule Details
18+
19+
This rule warns when it finds a CSS property that isn't part of the CSS specification and aren't custom properties (beginning with `--` as in `--my-color`). The property data is provided via the [CSSTree](https://github.com/csstree/csstree) project.
20+
21+
Examples of incorrect code:
22+
23+
```css
24+
a {
25+
ccolor: black;
26+
}
27+
28+
body {
29+
bg: red;
30+
}
31+
```
32+
33+
## When Not to Use It
34+
35+
If you aren't concerned with unknown properties, you can safely disable this rule.
36+
37+
## Prior Art
38+
39+
- [`known-properties`](https://github.com/CSSLint/csslint/wiki/Require-use-of-known-properties)
40+
- [`property-no-unknown`](https://stylelint.io/user-guide/rules/property-no-unknown)

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { CSSLanguage } from "./languages/css-language.js";
1111
import { CSSSourceCode } from "./languages/css-source-code.js";
1212
import noEmptyBlocks from "./rules/no-empty-blocks.js";
1313
import noDuplicateImports from "./rules/no-duplicate-imports.js";
14+
import noUnknownProperties from "./rules/no-unknown-properties.js";
1415

1516
//-----------------------------------------------------------------------------
1617
// Plugin
@@ -27,6 +28,7 @@ const plugin = {
2728
rules: {
2829
"no-empty-blocks": noEmptyBlocks,
2930
"no-duplicate-imports": noDuplicateImports,
31+
"no-unknown-properties": noUnknownProperties,
3032
},
3133
configs: {},
3234
};
@@ -37,6 +39,7 @@ Object.assign(plugin.configs, {
3739
rules: {
3840
"css/no-empty-blocks": "error",
3941
"css/no-duplicate-imports": "error",
42+
"css/no-unknown-properties": "error",
4043
},
4144
},
4245
});

src/rules/no-unknown-properties.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* @fileoverview Rule to prevent the use of unknown properties in CSS.
3+
* @author Nicholas C. Zakas
4+
*/
5+
6+
//-----------------------------------------------------------------------------
7+
// Imports
8+
//-----------------------------------------------------------------------------
9+
10+
import data from "css-tree/definition-syntax-data";
11+
12+
//-----------------------------------------------------------------------------
13+
// Helpers
14+
//-----------------------------------------------------------------------------
15+
16+
const knownProperties = new Set(Object.keys(data.properties));
17+
18+
//-----------------------------------------------------------------------------
19+
// Rule Definition
20+
//-----------------------------------------------------------------------------
21+
22+
export default {
23+
meta: {
24+
type: "problem",
25+
26+
docs: {
27+
description: "Disallow unknown properties.",
28+
recommended: true,
29+
},
30+
31+
messages: {
32+
unknownProperty: "Unknown property '{{property}}' found.",
33+
},
34+
},
35+
36+
create(context) {
37+
return {
38+
Declaration(node) {
39+
if (
40+
!node.property.startsWith("--") &&
41+
!knownProperties.has(node.property)
42+
) {
43+
const loc = node.loc;
44+
45+
context.report({
46+
loc: {
47+
start: loc.start,
48+
end: {
49+
line: loc.start.line,
50+
column: loc.start.column + node.property.length,
51+
},
52+
},
53+
messageId: "unknownProperty",
54+
data: {
55+
property: node.property,
56+
},
57+
});
58+
}
59+
},
60+
};
61+
},
62+
};
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* @fileoverview Tests for no-unknown-properties rule.
3+
* @author Nicholas C. Zakas
4+
*/
5+
6+
//------------------------------------------------------------------------------
7+
// Imports
8+
//------------------------------------------------------------------------------
9+
10+
import rule from "../../src/rules/no-unknown-properties.js";
11+
import css from "../../src/index.js";
12+
import { RuleTester } from "eslint";
13+
14+
//------------------------------------------------------------------------------
15+
// Tests
16+
//------------------------------------------------------------------------------
17+
18+
const ruleTester = new RuleTester({
19+
plugins: {
20+
css,
21+
},
22+
language: "css/css",
23+
});
24+
25+
ruleTester.run("no-unknown-properties", rule, {
26+
valid: [
27+
"a { color: red; }",
28+
"a { color: red; background-color: blue; }",
29+
"a { color: red; transition: none; }",
30+
"body { --custom-property: red; }",
31+
],
32+
invalid: [
33+
{
34+
code: "a { foo: bar }",
35+
errors: [
36+
{
37+
messageId: "unknownProperty",
38+
data: { property: "foo" },
39+
line: 1,
40+
column: 5,
41+
endLine: 1,
42+
endColumn: 8,
43+
},
44+
],
45+
},
46+
{
47+
code: "a { color: red; -moz-transition: bar }",
48+
errors: [
49+
{
50+
messageId: "unknownProperty",
51+
data: { property: "-moz-transition" },
52+
line: 1,
53+
column: 17,
54+
endLine: 1,
55+
endColumn: 32,
56+
},
57+
],
58+
},
59+
{
60+
code: "a { my-color: red; -webkit-transition: bar }",
61+
errors: [
62+
{
63+
messageId: "unknownProperty",
64+
data: { property: "my-color" },
65+
line: 1,
66+
column: 5,
67+
endLine: 1,
68+
endColumn: 13,
69+
},
70+
{
71+
messageId: "unknownProperty",
72+
data: { property: "-webkit-transition" },
73+
line: 1,
74+
column: 20,
75+
endLine: 1,
76+
endColumn: 38,
77+
},
78+
],
79+
},
80+
],
81+
});

0 commit comments

Comments
 (0)