From 66c4d50adc7775e9170ef99a0f4ba58c2e5adfc3 Mon Sep 17 00:00:00 2001 From: Romain Menke <11521496+romainmenke@users.noreply.github.com> Date: Fri, 30 Jun 2023 17:39:28 +0200 Subject: [PATCH] Fix `unit-disallowed-list` false negatives with percentages (#7018) * Fix `unit-disallowed-list` false negatives with percentages * cleanup * Create angry-mails-give.md * cleanup --- .changeset/angry-mails-give.md | 5 +++++ .../unit-disallowed-list/__tests__/index.js | 8 ++++++++ lib/rules/unit-disallowed-list/index.js | 19 ++++++++++++------- 3 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 .changeset/angry-mails-give.md diff --git a/.changeset/angry-mails-give.md b/.changeset/angry-mails-give.md new file mode 100644 index 0000000000..a44e6a2151 --- /dev/null +++ b/.changeset/angry-mails-give.md @@ -0,0 +1,5 @@ +--- +"stylelint": patch +--- + +Fixed: `unit-disallowed-list` false negatives with percentages diff --git a/lib/rules/unit-disallowed-list/__tests__/index.js b/lib/rules/unit-disallowed-list/__tests__/index.js index 49293e43c4..ad135ca3cb 100644 --- a/lib/rules/unit-disallowed-list/__tests__/index.js +++ b/lib/rules/unit-disallowed-list/__tests__/index.js @@ -641,6 +641,14 @@ testRule({ endLine: 1, endColumn: 80, }, + { + code: 'a { color: rgb(10% 127 127) }', + message: messages.rejected('%'), + line: 1, + column: 18, + endLine: 1, + endColumn: 19, + }, ], }); diff --git a/lib/rules/unit-disallowed-list/index.js b/lib/rules/unit-disallowed-list/index.js index 57b80823ae..602eb7d4c6 100644 --- a/lib/rules/unit-disallowed-list/index.js +++ b/lib/rules/unit-disallowed-list/index.js @@ -119,7 +119,7 @@ const rule = (primary, secondaryOptions) => { if (!hasDimension(params)) return; - parseFromTokens(tokenizeWithoutPercentageTokens(params)).forEach((mediaQuery) => { + parseFromTokens(tokenizeWithoutPercentages(params)).forEach((mediaQuery) => { /** @type {{ mediaFeatureName: string | undefined }} */ const initialState = { mediaFeatureName: undefined, @@ -154,7 +154,7 @@ const rule = (primary, secondaryOptions) => { if (!hasDimension(value)) return; - parseListOfComponentValues(tokenize({ css: value })).forEach((componentValue) => { + parseListOfComponentValues(tokenizeWithoutPercentages(value)).forEach((componentValue) => { if (isTokenNode(componentValue)) { check( decl, @@ -194,15 +194,20 @@ const rule = (primary, secondaryOptions) => { }; /** - * @param {string} value + * In the CSS syntax percentages are a different token type than dimensions. + * For CSS authors however this distinction doesn't make sense, so we convert + * percentage tokens to dimension tokens with a unit of "%". + * + * Percentage tokens also aren't valid in media queries. + * Converting percentage tokens to dimension tokens simplifies any code checking for units. + * + * @param {string} css * @returns {Array} */ -function tokenizeWithoutPercentageTokens(value) { - return tokenize({ css: value }).map((x) => { +function tokenizeWithoutPercentages(css) { + return tokenize({ css }).map((x) => { if (x[0] !== TokenType.Percentage) return x; - // Percentage values are not valid in media queries, so we can't parse them and get something valid back. - // Dimension tokens with a unit of "%" work just fine. return [ TokenType.Dimension, x[1],