From b65d3f0553975e467a0a1528694ccaae62af2177 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 8 Mar 2022 12:04:04 -0500 Subject: [PATCH 1/3] Refactor --- src/lib/generateRules.js | 98 +++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index 1ff2800cf562..86607ef5bce5 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -456,60 +456,64 @@ function* resolveMatches(candidate, context) { } } - // Only keep the result of the very first plugin if we are dealing with - // arbitrary values, to protect against ambiguity. - if (isArbitraryValue(modifier) && matches.length > 1) { - let typesPerPlugin = matches.map((match) => new Set([...(typesByMatches.get(match) ?? [])])) - - // Remove duplicates, so that we can detect proper unique types for each plugin. - for (let pluginTypes of typesPerPlugin) { - for (let type of pluginTypes) { - let removeFromOwnGroup = false - - for (let otherGroup of typesPerPlugin) { - if (pluginTypes === otherGroup) continue - - if (otherGroup.has(type)) { - otherGroup.delete(type) - removeFromOwnGroup = true + if (isArbitraryValue(modifier)) { + // When generated arbitrary values are ambiguous, we can't know + // which to pick so don't generate any utilities for them + if (matches.length > 1) { + let typesPerPlugin = matches.map((match) => new Set([...(typesByMatches.get(match) ?? [])])) + + // Remove duplicates, so that we can detect proper unique types for each plugin. + for (let pluginTypes of typesPerPlugin) { + for (let type of pluginTypes) { + let removeFromOwnGroup = false + + for (let otherGroup of typesPerPlugin) { + if (pluginTypes === otherGroup) continue + + if (otherGroup.has(type)) { + otherGroup.delete(type) + removeFromOwnGroup = true + } } - } - if (removeFromOwnGroup) pluginTypes.delete(type) + if (removeFromOwnGroup) pluginTypes.delete(type) + } } - } - let messages = [] - - for (let [idx, group] of typesPerPlugin.entries()) { - for (let type of group) { - let rules = matches[idx] - .map(([, rule]) => rule) - .flat() - .map((rule) => - rule - .toString() - .split('\n') - .slice(1, -1) // Remove selector and closing '}' - .map((line) => line.trim()) - .map((x) => ` ${x}`) // Re-indent - .join('\n') + let messages = [] + + for (let [idx, group] of typesPerPlugin.entries()) { + for (let type of group) { + let rules = matches[idx] + .map(([, rule]) => rule) + .flat() + .map((rule) => + rule + .toString() + .split('\n') + .slice(1, -1) // Remove selector and closing '}' + .map((line) => line.trim()) + .map((x) => ` ${x}`) // Re-indent + .join('\n') + ) + .join('\n\n') + + messages.push( + ` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\`` ) - .join('\n\n') - - messages.push(` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\``) - break + break + } } - } - log.warn([ - `The class \`${candidate}\` is ambiguous and matches multiple utilities.`, - ...messages, - `If this is content and not a class, replace it with \`${candidate - .replace('[', '[') - .replace(']', ']')}\` to silence this warning.`, - ]) - continue + log.warn([ + `The class \`${candidate}\` is ambiguous and matches multiple utilities.`, + ...messages, + `If this is content and not a class, replace it with \`${candidate + .replace('[', '[') + .replace(']', ']')}\` to silence this warning.`, + ]) + continue + } } matches = matches.flat() From b56b629b2f96be6ce036051eecb6ebd54466233d Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 8 Mar 2022 12:04:30 -0500 Subject: [PATCH 2/3] =?UTF-8?q?Don=E2=80=99t=20output=20unparsable=20arbit?= =?UTF-8?q?rary=20values?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/generateRules.js | 15 +++++++++++++++ tests/arbitrary-values.test.js | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index 86607ef5bce5..fc9a6bbd6ec1 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -303,6 +303,19 @@ function looksLikeUri(declaration) { } } +function isParsableNode(node) { + let isParsable = true + + node.walkDecls((decl) => { + if (!isParsableCssValue(decl.name, decl.value)) { + isParsable = false + return false + } + }) + + return isParsable +} + function isParsableCssValue(property, value) { // We don't want to to treat [https://example.com] as a custom property // Even though, according to the CSS grammar, it's a totally valid CSS declaration @@ -514,6 +527,8 @@ function* resolveMatches(candidate, context) { ]) continue } + + matches = matches.map((list) => list.filter((match) => isParsableNode(match[1]))) } matches = matches.flat() diff --git a/tests/arbitrary-values.test.js b/tests/arbitrary-values.test.js index c8fbf352c58e..55d78b49ebfc 100644 --- a/tests/arbitrary-values.test.js +++ b/tests/arbitrary-values.test.js @@ -370,3 +370,17 @@ it('should be possible to read theme values in arbitrary values (with quotes) wh `) }) }) + +it('should not output unparsable arbitrary CSS values', () => { + let config = { + content: [ + { + raw: 'let classes = `w-[${sizes.width}]`', + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(``) + }) +}) From 2c03d2d8593b7e8c18cce15e99c8a83f428f8642 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 8 Mar 2022 12:17:52 -0500 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e26226f7a4dc..5a5e1141ff60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Only add `!` to selector class matching template candidate when using important modifier with mutli-class selectors ([#7664](https://github.com/tailwindlabs/tailwindcss/pull/7664)) - Correctly parse and prefix animation names with dots ([#7163](https://github.com/tailwindlabs/tailwindcss/pull/7163)) - Fix extraction from template literal/function with array ([#7481](https://github.com/tailwindlabs/tailwindcss/pull/7481)) +- Don't output unparsable arbitrary values ([#7789](https://github.com/tailwindlabs/tailwindcss/pull/7789)) ### Changed