Skip to content

Commit

Permalink
add pure ignore comment for css modules
Browse files Browse the repository at this point in the history
  • Loading branch information
jantimon committed Nov 2, 2024
1 parent fde62d7 commit 90c16fe
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 3 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ Declarations (mode `local`, by default):
```
<!-- prettier-ignore-end -->

## Pure Mode

In pure mode, all selectors must contain at least one local class or id
selector

To ignore this rule for a specific selector, add the following comment in front
of the selector:

```css
/* cssmodules-pure-ignore */
:global(#modal-backdrop) {
...;
}
```

## Building

```bash
Expand Down
28 changes: 25 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,26 @@ 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 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;
}

function normalizeNodeArray(nodes) {
const array = [];

Expand Down Expand Up @@ -524,7 +542,7 @@ module.exports = (options = {}) => {
let globalKeyframes = globalMode;

if (globalMatch) {
if (pureMode) {
if (pureMode && !hasIgnoreComment(atRule)) {
throw atRule.error(
"@keyframes :global(...) is not allowed in pure mode"
);
Expand Down Expand Up @@ -564,7 +582,11 @@ module.exports = (options = {}) => {
context.options = options;
context.localAliasMap = localAliasMap;

if (pureMode && context.hasPureGlobals) {
if (
pureMode &&
context.hasPureGlobals &&
!hasIgnoreComment(atRule)
) {
throw atRule.error(
'Selector in at-rule"' +
selector +
Expand Down Expand Up @@ -615,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 +
Expand Down
141 changes: 141 additions & 0 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,147 @@ const tests = [
options: { mode: "pure" },
error: /is not pure/,
},
{
name: "should suppress errors for global selectors after ignore comment",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore */
:global(.foo) { color: blue; }`,
expected: `/* cssmodules-pure-ignore */
.foo { color: blue; }`,
},
{
name: "should allow additional text in ignore comment",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore - needed for third party integration */
:global(#foo) { color: blue; }`,
expected: `/* cssmodules-pure-ignore - needed for third party integration */
#foo { color: blue; }`,
},
{
name: "should not affect rules after the ignored block",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore */
:global(.foo) { color: blue; }
:global(.bar) { color: red; }`,
error: /is not pure/,
},
{
name: "should work with nested global selectors in ignored block",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore */
:global(.foo) {
:global(.bar) { color: blue; }
}`,
error: /is not pure/,
},
{
name: "should work with ignored nested global selectors in ignored block",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore */
:global(.foo) {
/* cssmodules-pure-ignore */
:global(.bar) { color: blue; }
}`,
expected: `/* cssmodules-pure-ignore */
.foo {
/* cssmodules-pure-ignore */
.bar { color: blue; }
}`,
},
{
name: "should work with view transitions in ignored block",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore */
::view-transition-group(modal) {
animation-duration: 300ms;
}`,
expected: `/* cssmodules-pure-ignore */
::view-transition-group(modal) {
animation-duration: 300ms;
}`,
},
{
name: "should work with keyframes in ignored block",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore */
@keyframes :global(fadeOut) {
from { opacity: 1; }
to { opacity: 0; }
}`,
expected: `/* cssmodules-pure-ignore */
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}`,
},
{
name: "should work in media queries",
options: { mode: "pure" },
input: `@media (min-width: 768px) {
/* cssmodules-pure-ignore */
:global(.foo) { color: blue; }
}`,
expected: `@media (min-width: 768px) {
/* cssmodules-pure-ignore */
.foo { color: blue; }
}`,
},
{
name: "should handle multiple ignore comments",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore */
:global(.foo) { color: blue; }
.local { color: green; }
/* cssmodules-pure-ignore */
:global(.bar) { color: red; }`,
expected: `/* cssmodules-pure-ignore */
.foo { color: blue; }
:local(.local) { color: green; }
/* cssmodules-pure-ignore */
.bar { color: red; }`,
},
{
name: "should work with complex selectors in ignored block",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore */
:global(.foo):hover > :global(.bar) + :global(.baz) {
color: blue;
}`,
expected: `/* cssmodules-pure-ignore */
.foo:hover > .bar + .baz {
color: blue;
}`,
},
{
name: "should work with multiple selectors in ignored block",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore */
:global(.foo),
:global(.bar),
:global(.baz) {
color: blue;
}`,
expected: `/* cssmodules-pure-ignore */
.foo,
.bar,
.baz {
color: blue;
}`,
},
{
name: "should work with pseudo-elements in ignored block",
options: { mode: "pure" },
input: `/* cssmodules-pure-ignore */
:global(.foo)::before,
:global(.foo)::after {
content: '';
}`,
expected: `/* cssmodules-pure-ignore */
.foo::before,
.foo::after {
content: '';
}`,
},
{
name: "css nesting",
input: `
Expand Down

0 comments on commit 90c16fe

Please sign in to comment.