From c1adceee1579a4b9ce5e26817740e489bddb19e2 Mon Sep 17 00:00:00 2001 From: Aleks Hudochenkov Date: Tue, 10 Jan 2023 01:02:06 +0100 Subject: [PATCH] Fix `isStandardSyntaxFunction` false positives for interpolation and backticks in CSS-in-JS (#6565) --- .changeset/quiet-adults-leave.md | 5 +++ .../isStandardSyntaxFunction.test.js | 41 +++++++++++-------- lib/utils/isStandardSyntaxFunction.js | 10 +++++ 3 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 .changeset/quiet-adults-leave.md diff --git a/.changeset/quiet-adults-leave.md b/.changeset/quiet-adults-leave.md new file mode 100644 index 0000000000..879d308801 --- /dev/null +++ b/.changeset/quiet-adults-leave.md @@ -0,0 +1,5 @@ +--- +"stylelint": patch +--- + +Fixed: `function-no-unknown` false positives for interpolation and backticks in CSS-in-JS diff --git a/lib/utils/__tests__/isStandardSyntaxFunction.test.js b/lib/utils/__tests__/isStandardSyntaxFunction.test.js index 9f9c72c7e9..2ba1f9c084 100644 --- a/lib/utils/__tests__/isStandardSyntaxFunction.test.js +++ b/lib/utils/__tests__/isStandardSyntaxFunction.test.js @@ -1,42 +1,51 @@ 'use strict'; const isStandardSyntaxFunction = require('../isStandardSyntaxFunction'); -const postcss = require('postcss'); const valueParser = require('postcss-value-parser'); describe('isStandardSyntaxFunction', () => { it('calc', () => { - expect(isStandardSyntaxFunction(func('a { prop: calc(a + b) }'))).toBe(true); + expect(isStandardSyntaxFunction(getFunction('calc(a + b)'))).toBe(true); }); it('url', () => { - expect(isStandardSyntaxFunction(func("a { prop: url('x.css') }"))).toBe(true); + expect(isStandardSyntaxFunction(getFunction("url('x.css')"))).toBe(true); }); it('scss list', () => { - expect(isStandardSyntaxFunction(func('a { $list: (list) }'))).toBe(false); + // as in $list: (list) + expect(isStandardSyntaxFunction(getFunction('(list)'))).toBe(false); }); it('scss map', () => { - expect(isStandardSyntaxFunction(func('a { $map: (key: value) }'))).toBe(false); + // as in $map: (key: value) + expect(isStandardSyntaxFunction(getFunction('(key: value)'))).toBe(false); }); - it('scss function in custom prop', () => { - expect(isStandardSyntaxFunction(func('a { --primary-color: #{darken(#fff, 0.2)} }'))).toBe( - false, - ); + it('scss function in scss interpolation', () => { + expect(isStandardSyntaxFunction(getFunction('#{darken(#fff, 0.2)}'))).toBe(false); + }); + + it('CSS-in-JS interpolation', () => { + expect( + isStandardSyntaxFunction( + getFunction('${({ size }) => (size === "small") ? "0.8em" : "1em"}'), + ), + ).toBe(false); + }); + + it('CSS-in-JS syntax', () => { + expect(isStandardSyntaxFunction(getFunction('`calc(${token.radiusBase} + 2px)`'))).toBe(false); }); }); -function func(css) { +function getFunction(declValue) { const functions = []; - postcss.parse(css).walkDecls((decl) => { - valueParser(decl.value).walk((valueNode) => { - if (valueNode.type === 'function') { - functions.push(valueNode); - } - }); + valueParser(declValue).walk((valueNode) => { + if (valueNode.type === 'function') { + functions.push(valueNode); + } }); return functions[0]; diff --git a/lib/utils/isStandardSyntaxFunction.js b/lib/utils/isStandardSyntaxFunction.js index d2f465fae1..5c1e29adf3 100644 --- a/lib/utils/isStandardSyntaxFunction.js +++ b/lib/utils/isStandardSyntaxFunction.js @@ -16,5 +16,15 @@ module.exports = function isStandardSyntaxFunction(node) { return false; } + // CSS-in-JS interpolation + if (node.value.startsWith('${')) { + return false; + } + + // CSS-in-JS syntax + if (node.value.startsWith('`')) { + return false; + } + return true; };