Skip to content
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

86 changes: 86 additions & 0 deletions lib/rules/function-name-arguments-allowed-list/README.md
@@ -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:
Copy link
Member

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.

Copy link
Author

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


<!-- 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%);}
```
57 changes: 57 additions & 0 deletions lib/rules/function-name-arguments-allowed-list/__tests__/index.js
@@ -0,0 +1,57 @@
'use strict';

const { messages, ruleName } = require('..');

testRule({
ruleName,

config: [
{
'/^background/': ['/^data:/', '/^images/', '/^http/', '/^vendor/'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure here, but are you saying that background is the function? I believe that url is the actual function that you should be specifying, while background is a CSS property. This indicates either an issue with the tests, or with the implementation of the rule. Not entirely sure about this though, feel free to elabourate if needed.

Copy link
Author

Choose a reason for hiding this comment

The 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,
},
],
});
71 changes: 71 additions & 0 deletions lib/rules/function-name-arguments-allowed-list/index.js
@@ -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;
3 changes: 3 additions & 0 deletions lib/rules/index.js
Expand Up @@ -185,6 +185,9 @@ const rules = {
'function-whitespace-after': importLazy(() => require('./function-whitespace-after'))(),
// Renamed to function-allowed-list
'function-whitelist': importLazy(() => require('./function-allowed-list'))(),
'function-name-arguments-allowed-list': importLazy(() =>
require('./function-name-arguments-allowed-list'),
)(),
'hue-degree-notation': importLazy(() => require('./hue-degree-notation'))(),
'keyframe-declaration-no-important': importLazy(() =>
require('./keyframe-declaration-no-important'),
Expand Down