From bd8f9685891b849ce09899e03be25465f4b72c29 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Thu, 31 Oct 2024 08:47:19 +0100 Subject: [PATCH] add pure ignore comment for css modules --- src/index.js | 36 +++++++++++++++++++++++++-- test/index.test.js | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index eeaef93..ae003a2 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,8 @@ const selectorParser = require("postcss-selector-parser"); const valueParser = require("postcss-value-parser"); const { extractICSS } = require("icss-utils"); +const IGNORE_MARKER = "cssmodules-pure-ignore"; + const isSpacing = (node) => node.type === "combinator" && node.value === " "; function normalizeNodeArray(nodes) { @@ -26,6 +28,8 @@ function normalizeNodeArray(nodes) { } function localizeNode(rule, mode, localAliasMap) { + const isIgnored = hasIgnoreComment(rule); + const transform = (node, context) => { if (context.ignoreNextSpacing && !isSpacing(node)) { throw new Error("Missing whitespace after " + context.ignoreNextSpacing); @@ -212,6 +216,10 @@ function localizeNode(rule, mode, localAliasMap) { break; } + if (isIgnored) { + break; + } + const isImportedValue = localAliasMap.has(node.value); const isImportedWithExplicitScope = isImportedValue && context.explicit; @@ -348,6 +356,10 @@ function localizeDeclarationValues(localize, declaration, context) { } function localizeDeclaration(declaration, context) { + if (hasIgnoreComment(declaration)) { + return; + } + const isAnimation = /animation$/i.test(declaration.prop); if (isAnimation) { @@ -471,6 +483,22 @@ function localizeDeclaration(declaration, context) { } } +function hasIgnoreComment(node) { + if (!node.parent) { + return false; + } + const indexInParent = node.parent.index(node); + for (let i = indexInParent - 1; i >= 0; i--) { + const prevNode = node.parent.nodes[i]; + if (prevNode.type === "comment") { + return prevNode.text.trimStart().startsWith(IGNORE_MARKER) + } else { + break; + } + } + return false; +} + module.exports = (options = {}) => { if ( options && @@ -554,7 +582,11 @@ module.exports = (options = {}) => { context.options = options; context.localAliasMap = localAliasMap; - if (pureMode && context.hasPureGlobals) { + if ( + pureMode && + context.hasPureGlobals && + !hasIgnoreComment(selector) + ) { throw atRule.error( 'Selector in at-rule"' + selector + @@ -605,7 +637,7 @@ module.exports = (options = {}) => { context.options = options; context.localAliasMap = localAliasMap; - if (pureMode && context.hasPureGlobals) { + if (pureMode && context.hasPureGlobals && !hasIgnoreComment(rule)) { throw rule.error( 'Selector "' + rule.selector + diff --git a/test/index.test.js b/test/index.test.js index c1bab02..9f78ea4 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1015,6 +1015,68 @@ const tests = [ options: { mode: "pure" }, expected: ":export { foo: __foo; }", }, + { + name: "global selectors after an ignore comments should be pure", + options: { mode: "pure" }, + input: `/* cssmodules-pure-ignore */ + .global { a_value: some-value; }`, + expected: `/* cssmodules-pure-ignore */ + .global { a_value: some-value; }`, + }, + { + name: "global selectors after an ignore comments with postfix stays pure", + options: { mode: "pure" }, + input: `/* cssmodules-pure-ignore With additional explanation */ + .global { a_value: some-value; }`, + expected: `/* cssmodules-pure-ignore With additional explanation */ + .global { a_value: some-value; }`, + }, + { + name: "global selector after an ignore comments should still localize its properties", + options: { mode: "pure" }, + input: `/* cssmodules-pure-ignore */ + .global { + animation: fadeOut; + }`, + expected: `/* cssmodules-pure-ignore */ + .global { + animation: :local(fadeOut); + }`, + }, + { + name: "global selector after an ignore comments should still localize its child selectors", + options: { mode: "pure" }, + input: `/* cssmodules-pure-ignore */ + .outer { + .inner { a_value: some-value; } + }`, + expected: `/* cssmodules-pure-ignore */ + .outer { + :local(.inner) { a_value: some-value; } + }`, + }, + { + name: "global animation after an ignore comments should be pure", + options: { mode: "pure" }, + input: `.foo { /* cssmodules-pure-ignore */ + animation: fadeOut; }`, + expected: `:local(.foo) { /* cssmodules-pure-ignore */ + animation: fadeOut; }`, + }, + { + name: "global follow up properties after an ignore comments should be localized", + options: { mode: "pure" }, + input: `.foo { + /* cssmodules-pure-ignore */ + animation: fadeOut; + &:disabled { animation-name: localAnimation; } + }`, + expected: `:local(.foo) { + /* cssmodules-pure-ignore */ + animation: fadeOut; + &:disabled { animation-name: :local(localAnimation); } + }`, + }, { name: "handle negative animation-delay in animation shorthand", input: ".foo { animation: 1s -500ms; }",