New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add function-name-arguments-allowed-list #4816
Changes from all commits
3c97e71
a64ee6d
27c276e
8d63a48
3b3de22
a118c99
28b4213
907513a
45afff9
2f06e7a
e74c8c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# function-name-arguments-allowed-list | ||
|
||
Specify an list of allowed property and value pairs within declarations. | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background: url('http://www.example.com/file.jpg'); } | ||
/** ↑ ↑ | ||
* These properties and these values */ | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background-image: url('http://www.example.com/file.jpg'); } | ||
/** ↑ ↑ | ||
* These properties and these values */ | ||
``` | ||
|
||
## Options | ||
|
||
`object`: `{"unprefixed-function-name": ["/regex/", /regex/] }` | ||
|
||
Given: | ||
|
||
``` | ||
['/^data:/', '/^images/', '/^http/', '/^vendor/'] | ||
``` | ||
|
||
The following patterns are considered violations: | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background-image: url(data/x.jpg); } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background: url(#fff) } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background-image: url('//example.com/file.jpg'); } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background-image: url('./path/to/file.jpg'); } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background-image: url('vendor/file.jpg'); } | ||
``` | ||
|
||
The following patterns are _not_ considered violations: | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background: url(images/x.jpg); } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background-image: url(vendor/x.jpg); } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background: url(https://image/1.png); } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=); } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a { background-image: #fff url(images/select2.png) no-repeat 100% -22px } | ||
``` | ||
|
||
<!-- prettier-ignore --> | ||
```css | ||
a {background-image: url(images/select2.png) no-repeat 100% -22px, -moz-linear-gradient(bottom, #fff 85%, #eee 99%);} | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
'use strict'; | ||
|
||
const { messages, ruleName } = require('..'); | ||
|
||
testRule({ | ||
ruleName, | ||
|
||
config: [ | ||
{ | ||
'/^background/': ['/^data:/', '/^images/', '/^http/', '/^vendor/'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not entirely sure here, but are you saying that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If background or background-image CSS property has the value called URL function means have to check to start of the folder name. |
||
}, | ||
], | ||
|
||
accept: [ | ||
{ | ||
code: 'a { background: url(images/x.jpg); }', | ||
}, | ||
{ | ||
code: 'a { background-image: url(vendor/x.jpg); }', | ||
}, | ||
{ | ||
code: 'a { background: url(https://image/1.png); }', | ||
}, | ||
{ | ||
code: | ||
'a { background-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=); }', | ||
}, | ||
{ | ||
code: 'a { background-image: #fff url(images/select2.png) no-repeat 100% -22px }', | ||
}, | ||
{ | ||
code: | ||
'a {background-image: url(images/select2.png) no-repeat 100% -22px, -moz-linear-gradient(bottom, #fff 85%, #eee 99%);}', | ||
}, | ||
], | ||
|
||
reject: [ | ||
{ | ||
code: 'a { background-image: url(data/x.jpg); }', | ||
message: messages.rejected('background-image', 'data/x.jpg'), | ||
line: 1, | ||
column: 27, | ||
}, | ||
{ | ||
code: 'a { background-image: #fff url(magic/select2.png) no-repeat 100% -22px }', | ||
message: messages.rejected('background-image', 'magic/select2.png'), | ||
line: 1, | ||
column: 32, | ||
}, | ||
{ | ||
code: 'a { background: url(#fff) }', | ||
message: messages.rejected('background', '#fff'), | ||
line: 1, | ||
column: 21, | ||
}, | ||
], | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// @ts-nocheck | ||
|
||
'use strict'; | ||
|
||
const _ = require('lodash'); | ||
const declarationValueIndex = require('../../utils/declarationValueIndex'); | ||
const matchesStringOrRegExp = require('../../utils/matchesStringOrRegExp'); | ||
const postcss = require('postcss'); | ||
const report = require('../../utils/report'); | ||
const ruleMessages = require('../../utils/ruleMessages'); | ||
const validateOptions = require('../../utils/validateOptions'); | ||
const valueParser = require('postcss-value-parser'); | ||
const ruleName = 'function-name-arguments-allowed-list'; | ||
|
||
const messages = ruleMessages(ruleName, { | ||
rejected: (property, value) => `Unexpected value "${value}" for property "${property}"`, | ||
}); | ||
|
||
function rule(whitelist) { | ||
return (root, result) => { | ||
const validOptions = validateOptions(result, ruleName, { | ||
actual: whitelist, | ||
possible: [_.isObject], | ||
}); | ||
|
||
if (!validOptions) { | ||
return; | ||
} | ||
|
||
root.walkDecls((decl) => { | ||
const prop = decl.prop; | ||
const value = decl.value; | ||
|
||
const unprefixedProp = postcss.vendor.unprefixed(prop); | ||
|
||
const propWhitelist = _.find(whitelist, (list, propIdentifier) => | ||
matchesStringOrRegExp(unprefixedProp, propIdentifier), | ||
); | ||
|
||
if (_.isEmpty(propWhitelist)) { | ||
return; | ||
} | ||
|
||
valueParser(value).walk((node) => { | ||
if (node.value !== 'url') { | ||
return; | ||
} | ||
|
||
const nodes = node.nodes.length && node.nodes[0]; | ||
|
||
const { value, sourceIndex } = nodes; | ||
|
||
if (matchesStringOrRegExp(value, propWhitelist)) { | ||
return; | ||
} | ||
|
||
report({ | ||
message: messages.rejected(prop, value), | ||
node: decl, | ||
index: declarationValueIndex(decl) + sourceIndex, | ||
result, | ||
ruleName, | ||
}); | ||
}); | ||
}); | ||
}; | ||
} | ||
|
||
rule.ruleName = ruleName; | ||
rule.messages = messages; | ||
module.exports = rule; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would also be good if you explained the behaviour of how this rule interacts with random, unspecified functions (e.g.
calc
) - and maybe in the tests as well.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can u give me an example for my use case