Skip to content

Commit

Permalink
feat: no-unknown-properties rule (#5)
Browse files Browse the repository at this point in the history
* feat: no-unknown-properties rule

* Fix rule description

* Update docs/rules/no-unknown-properties.md

Co-authored-by: Milos Djermanovic <[email protected]>

---------

Co-authored-by: Milos Djermanovic <[email protected]>
  • Loading branch information
nzakas and mdjermanovic authored Nov 13, 2024
1 parent 61ec7ae commit 43dec96
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 4 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ export default [

<!-- Rule Table Start -->

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

<!-- Rule Table End -->

Expand Down
40 changes: 40 additions & 0 deletions docs/rules/no-unknown-properties.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# no-unknown-properties

Disallow unknown properties.

## Background

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:

```css
a {
ccolor: black;
}
```

Here, `ccolor` is a syntactically valid identifier even though it will be ignored by browsers. Such errors are often caused by typos.

## Rule Details

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.

Examples of incorrect code:

```css
a {
ccolor: black;
}

body {
bg: red;
}
```

## When Not to Use It

If you aren't concerned with unknown properties, you can safely disable this rule.

## Prior Art

- [`known-properties`](https://github.com/CSSLint/csslint/wiki/Require-use-of-known-properties)
- [`property-no-unknown`](https://stylelint.io/user-guide/rules/property-no-unknown)
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { CSSLanguage } from "./languages/css-language.js";
import { CSSSourceCode } from "./languages/css-source-code.js";
import noEmptyBlocks from "./rules/no-empty-blocks.js";
import noDuplicateImports from "./rules/no-duplicate-imports.js";
import noUnknownProperties from "./rules/no-unknown-properties.js";

//-----------------------------------------------------------------------------
// Plugin
Expand All @@ -27,6 +28,7 @@ const plugin = {
rules: {
"no-empty-blocks": noEmptyBlocks,
"no-duplicate-imports": noDuplicateImports,
"no-unknown-properties": noUnknownProperties,
},
configs: {},
};
Expand All @@ -37,6 +39,7 @@ Object.assign(plugin.configs, {
rules: {
"css/no-empty-blocks": "error",
"css/no-duplicate-imports": "error",
"css/no-unknown-properties": "error",
},
},
});
Expand Down
62 changes: 62 additions & 0 deletions src/rules/no-unknown-properties.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @fileoverview Rule to prevent the use of unknown properties in CSS.
* @author Nicholas C. Zakas
*/

//-----------------------------------------------------------------------------
// Imports
//-----------------------------------------------------------------------------

import data from "css-tree/definition-syntax-data";

//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------

const knownProperties = new Set(Object.keys(data.properties));

//-----------------------------------------------------------------------------
// Rule Definition
//-----------------------------------------------------------------------------

export default {
meta: {
type: "problem",

docs: {
description: "Disallow unknown properties.",
recommended: true,
},

messages: {
unknownProperty: "Unknown property '{{property}}' found.",
},
},

create(context) {
return {
Declaration(node) {
if (
!node.property.startsWith("--") &&
!knownProperties.has(node.property)
) {
const loc = node.loc;

context.report({
loc: {
start: loc.start,
end: {
line: loc.start.line,
column: loc.start.column + node.property.length,
},
},
messageId: "unknownProperty",
data: {
property: node.property,
},
});
}
},
};
},
};
81 changes: 81 additions & 0 deletions tests/rules/no-unknown-properties.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* @fileoverview Tests for no-unknown-properties rule.
* @author Nicholas C. Zakas
*/

//------------------------------------------------------------------------------
// Imports
//------------------------------------------------------------------------------

import rule from "../../src/rules/no-unknown-properties.js";
import css from "../../src/index.js";
import { RuleTester } from "eslint";

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

const ruleTester = new RuleTester({
plugins: {
css,
},
language: "css/css",
});

ruleTester.run("no-unknown-properties", rule, {
valid: [
"a { color: red; }",
"a { color: red; background-color: blue; }",
"a { color: red; transition: none; }",
"body { --custom-property: red; }",
],
invalid: [
{
code: "a { foo: bar }",
errors: [
{
messageId: "unknownProperty",
data: { property: "foo" },
line: 1,
column: 5,
endLine: 1,
endColumn: 8,
},
],
},
{
code: "a { color: red; -moz-transition: bar }",
errors: [
{
messageId: "unknownProperty",
data: { property: "-moz-transition" },
line: 1,
column: 17,
endLine: 1,
endColumn: 32,
},
],
},
{
code: "a { my-color: red; -webkit-transition: bar }",
errors: [
{
messageId: "unknownProperty",
data: { property: "my-color" },
line: 1,
column: 5,
endLine: 1,
endColumn: 13,
},
{
messageId: "unknownProperty",
data: { property: "-webkit-transition" },
line: 1,
column: 20,
endLine: 1,
endColumn: 38,
},
],
},
],
});

0 comments on commit 43dec96

Please sign in to comment.