Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add custom-property-no-missing-var-function rule (#5317)
- Loading branch information
Showing
5 changed files
with
264 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
45 changes: 45 additions & 0 deletions
45
lib/rules/custom-property-no-missing-var-function/README.md
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,45 @@ | ||
# custom-property-no-missing-var-function | ||
|
||
Disallow missing `var` function for custom properties. | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
:root { --foo: red; } | ||
a { color: --foo; } | ||
/** ↑ | ||
* This custom property */ | ||
``` | ||
|
||
This rule only reports custom properties that are defined within the same source. | ||
|
||
## Options | ||
|
||
### `true` | ||
|
||
The following patterns are considered violations: | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
:root { --foo: red; } | ||
a { color: --foo; } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
@property --foo {} | ||
a { color: --foo; } | ||
``` | ||
|
||
The following patterns are _not_ considered violations: | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
:root { --foo: red; } | ||
a { color: var(--foo); } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
@property --foo {} | ||
a { color: var(--foo); } | ||
``` |
136 changes: 136 additions & 0 deletions
136
lib/rules/custom-property-no-missing-var-function/__tests__/index.js
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,136 @@ | ||
'use strict'; | ||
|
||
const stripIndent = require('common-tags').stripIndent; | ||
|
||
const { messages, ruleName } = require('..'); | ||
|
||
testRule({ | ||
ruleName, | ||
config: true, | ||
|
||
accept: [ | ||
{ | ||
code: 'a { color: --foo; }', | ||
description: 'undeclared dashed-ident', | ||
}, | ||
{ | ||
code: 'a { color: var(--foo); }', | ||
description: 'undeclared dashed-ident in var', | ||
}, | ||
{ | ||
code: 'a { color: env(--foo); }', | ||
description: 'undeclared dashed-ident in env', | ||
}, | ||
{ | ||
code: 'a { color: color(--foo 0% 0% 0% 0%); }', | ||
description: 'undeclared dashed-ident in color', | ||
}, | ||
{ | ||
code: 'a { color: calc(var(--foo) + var(--bar)); }', | ||
description: 'undeclared dashed-idents in vars in calc', | ||
}, | ||
{ | ||
code: 'a { color: var(--foo, red); }', | ||
description: 'undeclared dashed-idents in var with fallback', | ||
}, | ||
{ | ||
code: 'a { --foo: var(--bar); }', | ||
description: 'undeclared dashed-idents in vars assigned to custom property', | ||
}, | ||
{ | ||
code: ':root { --foo: red; } a { color: var(--foo); }', | ||
description: 'declared custom property in var', | ||
}, | ||
{ | ||
code: '@property --foo {} a { color: var(--foo); }', | ||
description: 'declared via at-property custom property in var', | ||
}, | ||
{ | ||
code: ':--foo {}', | ||
description: 'custom selector', | ||
}, | ||
{ | ||
code: '@media(--foo) {}', | ||
description: 'custom media query', | ||
}, | ||
], | ||
|
||
reject: [ | ||
{ | ||
code: 'a { --foo: red; color: --foo; }', | ||
message: messages.rejected('--foo'), | ||
line: 1, | ||
column: 24, | ||
description: 'declared custom property', | ||
}, | ||
{ | ||
code: '@property --foo {} a { color: --foo; }', | ||
message: messages.rejected('--foo'), | ||
line: 1, | ||
column: 31, | ||
description: 'declared via at-property custom property', | ||
}, | ||
{ | ||
code: ':root { --bar: 0; } a { --foo: --bar; }', | ||
message: messages.rejected('--bar'), | ||
line: 1, | ||
column: 32, | ||
description: 'declared in :root custom property', | ||
}, | ||
{ | ||
code: ':root { --bar: 0px; } a { color: calc(var(--foo) + --bar)); }', | ||
message: messages.rejected('--bar'), | ||
line: 1, | ||
column: 52, | ||
description: 'declared custom property and used inside calc', | ||
}, | ||
{ | ||
code: ':root { --foo: pink; } a { color: --foo, red; }', | ||
message: messages.rejected('--foo'), | ||
line: 1, | ||
column: 36, | ||
description: 'declared custom property and used with fall back', | ||
}, | ||
{ | ||
code: ':root { --bar: 0; } a { color: --foo(--bar); }', | ||
message: messages.rejected('--bar'), | ||
line: 1, | ||
column: 38, | ||
description: 'declared custom property used inside custom function', | ||
}, | ||
{ | ||
code: stripIndent` | ||
:root { | ||
--bar: 0; | ||
--baz: 0; | ||
} | ||
a { | ||
--foo: --bar; | ||
color: --baz; | ||
} | ||
`, | ||
warnings: [ | ||
{ message: messages.rejected('--bar'), line: 7, column: 9 }, | ||
{ message: messages.rejected('--baz'), line: 8, column: 9 }, | ||
], | ||
description: 'two declared custom properties', | ||
}, | ||
{ | ||
code: stripIndent` | ||
@property --bar {} | ||
@property --baz {} | ||
a { | ||
--foo: --bar; | ||
color: --baz; | ||
} | ||
`, | ||
warnings: [ | ||
{ message: messages.rejected('--bar'), line: 5, column: 9 }, | ||
{ message: messages.rejected('--baz'), line: 6, column: 9 }, | ||
], | ||
description: 'two declared via at-property custom properties', | ||
}, | ||
], | ||
}); |
76 changes: 76 additions & 0 deletions
76
lib/rules/custom-property-no-missing-var-function/index.js
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,76 @@ | ||
// @ts-nocheck | ||
|
||
'use strict'; | ||
|
||
const valueParser = require('postcss-value-parser'); | ||
|
||
const declarationValueIndex = require('../../utils/declarationValueIndex'); | ||
const isCustomProperty = require('../../utils/isCustomProperty'); | ||
const report = require('../../utils/report'); | ||
const ruleMessages = require('../../utils/ruleMessages'); | ||
const validateOptions = require('../../utils/validateOptions'); | ||
|
||
const ruleName = 'custom-property-no-missing-var-function'; | ||
|
||
const messages = ruleMessages(ruleName, { | ||
rejected: (customProperty) => `Unexpected missing var function for "${customProperty}"`, | ||
}); | ||
|
||
function rule(actual) { | ||
return (root, result) => { | ||
const validOptions = validateOptions(result, ruleName, { | ||
actual, | ||
}); | ||
|
||
if (!validOptions) return; | ||
|
||
const customProperties = new Set(); | ||
|
||
root.walkAtRules(/^property$/i, (atRule) => { | ||
customProperties.add(atRule.params); | ||
}); | ||
|
||
root.walkDecls(({ prop }) => { | ||
if (isCustomProperty(prop)) customProperties.add(prop); | ||
}); | ||
|
||
root.walkDecls((decl) => { | ||
const { value } = decl; | ||
const parsedValue = valueParser(value); | ||
|
||
parsedValue.walk((node) => { | ||
if (isVarFunction(node)) return false; | ||
|
||
if (!isDashedIdent(node)) return; | ||
|
||
if (!isKnownCustomProperty(node)) return; | ||
|
||
report({ | ||
message: messages.rejected(node.value), | ||
node: decl, | ||
index: declarationValueIndex(decl) + node.sourceIndex, | ||
result, | ||
ruleName, | ||
}); | ||
|
||
return false; | ||
}); | ||
}); | ||
|
||
function isKnownCustomProperty({ value }) { | ||
return customProperties.has(value); | ||
} | ||
}; | ||
} | ||
|
||
function isDashedIdent({ type, value }) { | ||
return type === 'word' && value.startsWith('--'); | ||
} | ||
|
||
function isVarFunction({ type, value }) { | ||
return type === 'function' && value === 'var'; | ||
} | ||
|
||
rule.ruleName = ruleName; | ||
rule.messages = messages; | ||
module.exports = 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