diff --git a/lib/rules/function-no-unknown/README.md b/lib/rules/function-no-unknown/README.md index bd6af56175..2b3200f2c0 100644 --- a/lib/rules/function-no-unknown/README.md +++ b/lib/rules/function-no-unknown/README.md @@ -35,3 +35,29 @@ a { transform: scale(1); } ```css a { transform: --custom-function(1); } ``` + +## Optional secondary options + +### `ignoreFunctions: ["/regex/", /regex/, "non-regex"]` + +Ignore the specified functions. + +For example, with `true`. + +Given: + +```json +["theme", "/^foo-/"] +``` + +The following patterns are _not_ considered problems: + + +```css +a { transform: theme(1); } +``` + + +```css +a { transform: foo-func(1); } +``` diff --git a/lib/rules/function-no-unknown/__tests__/index.js b/lib/rules/function-no-unknown/__tests__/index.js index a3991768b2..97ca4f9c8e 100644 --- a/lib/rules/function-no-unknown/__tests__/index.js +++ b/lib/rules/function-no-unknown/__tests__/index.js @@ -56,3 +56,42 @@ testRule({ }, ], }); + +testRule({ + ruleName, + config: [true, { ignoreFunctions: ['theme', '/^foo-/', /^bar$/i] }], + skipBasicChecks: true, + + accept: [ + { + code: 'a { transform: translate(1px); }', + }, + { + code: 'a { transform: theme(1px); }', + }, + { + code: 'a { transform: foo-func(1px); }', + }, + { + code: 'a { transform: bar(1px); }', + }, + { + code: 'a { transform: BAR(1px); }', + }, + ], + + reject: [ + { + code: 'a { transform: unknown(1px); }', + message: messages.rejected('unknown'), + line: 1, + column: 16, + }, + { + code: 'a { transform: theme-custom(1px); }', + message: messages.rejected('theme-custom'), + line: 1, + column: 16, + }, + ], +}); diff --git a/lib/rules/function-no-unknown/index.js b/lib/rules/function-no-unknown/index.js index 3d861d589a..03d21fd2fd 100644 --- a/lib/rules/function-no-unknown/index.js +++ b/lib/rules/function-no-unknown/index.js @@ -6,11 +6,13 @@ const valueParser = require('postcss-value-parser'); const functionsListPath = require('css-functions-list'); const declarationValueIndex = require('../../utils/declarationValueIndex'); +const optionsMatches = require('../../utils/optionsMatches'); const report = require('../../utils/report'); const ruleMessages = require('../../utils/ruleMessages'); const validateOptions = require('../../utils/validateOptions'); const isStandardSyntaxFunction = require('../../utils/isStandardSyntaxFunction'); const isCustomFunction = require('../../utils/isCustomFunction'); +const { isRegExp, isString } = require('../../utils/validateTypes'); const ruleName = 'function-no-unknown'; @@ -23,9 +25,20 @@ const meta = { }; /** @type {import('stylelint').Rule} */ -const rule = (primary) => { +const rule = (primary, secondaryOptions) => { return (root, result) => { - const validOptions = validateOptions(result, ruleName, { actual: primary }); + const validOptions = validateOptions( + result, + ruleName, + { actual: primary }, + { + actual: secondaryOptions, + possible: { + ignoreFunctions: [isString, isRegExp], + }, + optional: true, + }, + ); if (!validOptions) { return; @@ -50,6 +63,10 @@ const rule = (primary) => { return; } + if (optionsMatches(secondaryOptions, 'ignoreFunctions', node.value)) { + return; + } + if (functionsList.includes(node.value.toLowerCase())) { return; }