test: postcss plugins (#20100)

This commit is contained in:
Alexander Akait 2025-11-07 03:22:57 +03:00 committed by GitHub
parent 13cdb57909
commit 3ba1e98c07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 6066 additions and 189 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
.a {
color: red;
}
.b {
color: red;
}
.c {
color: red;
}
.d {
color: red;
}

View File

@ -0,0 +1,2 @@
@value exportName12: blue;
@value exportNameRed: blue;

View File

@ -0,0 +1,9 @@
@value exportNameRed: blue;
@value exportNameBlue: yellow;
@value otherBlue: red;
@value otherRed: blue;
@value wrongOrder: blue;
@value --red: blue;
@value namedBlue: red;
@value namedRed: blue;

View File

@ -1,3 +1,15 @@
.abc {
color: red;
}
.__foo {
color: red;
}
.some-value {
color: red;
}
.otherClass {
color: red;
}

View File

@ -1,4 +1,9 @@
import * as classes from "./style.modules.css";
import * as composes from "./postcss-modules-extract-imports.modules.css";
import * as local from "./postcss-modules-local-by-default.local.modules.css";
import * as global from "./postcss-modules-local-by-default.global.modules.css";
import * as pure from "./postcss-modules-local-by-default.pure.modules.css";
import * as scope from "./postcss-modules-scope.modules.css";
import * as values from "./postcss-modules-values.modules.css";
it("should work", () => {
const links = document.getElementsByTagName("link");
@ -9,6 +14,11 @@ it("should work", () => {
css.push(link.sheet.css);
}
expect(classes).toMatchSnapshot();
expect(composes).toMatchSnapshot();
expect(local).toMatchSnapshot();
expect(global).toMatchSnapshot();
expect(pure).toMatchSnapshot();
expect(scope).toMatchSnapshot();
expect(values).toMatchSnapshot();
expect(css).toMatchSnapshot();
});

View File

@ -0,0 +1,59 @@
/* postcss-modules-local-by-default */
/* localize and not localize animation-name in mixed case #2 */
.foo { animation-name: fadeInOut, global(moveLeft300px), local(bounce); }
/* localize and not localize a certain animation in mixed case #2 */
.foo { animation: rotate 1s, global(spin) 3s, local(fly) 6s; }
/* default to global when mode provided */
.foo { a_value: some-value; }
/* TODO bug */
/* use correct spacing */
.a :local .b {}
.a:local.b {}
.a:local(.b) {}
.a:local( .b ) {}
.a :local(.b) {}
.a :local( .b ) {}
:local(.a).b {}
:local( .a ).b {}
:local(.a) .b {}
:local( .a ) .b {}
/* localize keyframes in global default mode */
@keyframes foo { a_value: some-value; }
/* css nesting #1 */
:local(.foo) {
&:local(.class) {
a_value: some-value;
}
@media screen and (min-width: 900px) {
b_value: some-value;
:local(.bar) {
c_value: some-value;
}
&:local(.baz) {
c_value: some-value;
}
}
}
/* @scope at-rule #3 */
@scope (:local(.article-header)) to (:global(.class)) {
.article-footer {
border: 5px solid black;
}
:local(.class-1) {
color: red;
}
:global(.class-2) {
color: blue;
}
}

View File

@ -0,0 +1,579 @@
/* postcss-modules-local-by-default */
/* scope selectors */
.foobar { a_value: some-value; }
/* scope escaped selectors */
.\3A \) {}
/* scope ids */
#foobar { a_value: some-value; }
/* scope escaped ids */
#\#test {}
/* scope escaped ids (2) */
#u-m\00002b {}
/* scope multiple selectors */
.foo, .baz { a_value: some-value; }
/* scope sibling selectors */
.foo ~ .baz { a_value: some-value; }
/* scope pseudo elements */
.foo:after { a_value: some-value; }
/* scope media queries */
@media only screen { .foo { a_value: some-value; } }
/* allow narrow global selectors */
:global(.foo .bar) { a_value: some-value; }
/* allow narrow local selectors */
:local(.foo .bar) { a_value: some-value; }
/* allow broad global selectors */
:global .foo .bar { a_value: some-value; }
/* allow broad local selectors */
:local .foo .bar { a_value: some-value; }
/* allow multiple narrow global selectors */
:global(.foo), :global(.bar) { a_value: some-value; }
/* allow multiple broad global selectors */
:global .foo, :global .bar { a_value: some-value; }
/* allow multiple broad local selectors */
:local .foo, :local .bar { a_value: some-value; }
/* allow narrow global selectors nested inside local styles */
.foo :global(.foo .bar) { a_value: some-value; }
/* allow broad global selectors nested inside local styles */
.foo :global .foo .bar { a_value: some-value; }
/* allow parentheses inside narrow global selectors */
.foo :global(.foo:not(.bar)) { a_value: some-value; }
/* allow parentheses inside narrow local selectors */
.foo :local(.foo:not(.bar)) { a_value: some-value; }
/* allow narrow global selectors appended to local styles */
.foo:global(.foo.bar) { a_value: some-value; }
/* ignore selectors that are already local */
:local(.foobar) { a_value: some-value; }
/* ignore nested selectors that are already local */
:local(.foo) :local(.bar) { a_value: some-value; }
/* ignore multiple selectors that are already local */
:local(.foo), :local(.bar) { a_value: some-value; }
/* ignore sibling selectors that are already local */
:local(.foo) ~ :local(.bar) { a_value: some-value; }
/* ignore psuedo elements that are already local */
:local(.foo):after { a_value: some-value; }
/* trim whitespace after empty broad selector */
.bar :global :global { a_value: some-value; }
/* broad global should be limited to selector */
:global .foo, .bar :global, .foobar :global { a_value: some-value; }
/* TODO bug */
/* broad global should be limited to nested selector */
.foo:not(:global .bar).foobar { a_value: some-value; }
/* broad global and local should allow switching */
.foo :global .bar :local .foobar :local .barfoo { a_value: some-value; }
/* localize a single animation-name */
.foo { animation-name: bar; }
/* TODO bug */
/* localize a single animation-name #2 */
.foo { animation-name: local(bar); }
/* passed because `--bar` not found */
/* not localize animation-name in a var function */
.foo { animation-name: var(--bar); }
/* passed because `--bar` not found */
/* not localize animation-name in a var function #2 */
.foo { animation-name: vAr(--bar); }
/* not localize animation-name in an env function */
.foo { animation-name: env(bar); }
/* TODO bug */
/* not localize animation-name in an global function */
.foo { animation-name: global(bar); }
/* TODO bug */
/* localize and not localize animation-name in mixed case */
.foo { animation-name: fadeInOut, global(moveLeft300px), local(bounce); }
/* TODO bug */
/* not localize animation in an global function */
.foo { animation: global(bar); }
/* TODO bug */
/* not localize a certain animation in an global function */
.foo { animation: global(bar), foo; }
/* TODO bug */
/* localize and not localize a certain animation in mixed case */
.foo { animation: rotate 1s, global(spin) 3s, local(fly) 6s; }
/* not localize animation-name in an env function #2 */
.foo { animation-name: eNv(bar); }
/* not localize a single animation-delay */
.foo { animation-delay: 1s; }
/* localize multiple animation-names */
.foo { animation-name: bar, foobar; }
/* TODO bug */
/* not localize revert */
.foo { animation: revert; }
/* TODO bug */
/* not localize revert #2 */
.foo { animation-name: revert; }
/* TODO bug */
/* not localize revert #3 */
.foo { animation-name: revert, foo, none; }
/* TODO bug */
/* not localize revert-layer */
.foo { animation: revert-layer; }
/* TODO bug */
/* not localize revert */
.foo { animation-name: revert-layer; }
/* localize animation using special characters */
.foo { animation: \@bounce; }
/* localize animation using special characters */
.foo { animation: bou\@nce; }
/* localize animation using special characters */
.foo { animation: \ as; }
/* localize animation using special characters */
.foo { animation: t\ t; }
/* localize animation using special characters */
.foo { animation: -\a; }
/* localize animation using special characters */
.foo { animation: --\a; }
/* localize animation using special characters */
.foo { animation: \a; }
/* localize animation using special characters */
.foo { animation: -\a; }
/* localize animation using special characters */
.foo { animation: --; }
/* TODO test me in real browser */
/* localize animation using special characters */
.foo { animation: 😃bounce😃; }
/* TODO test me in real browser */
/* not localize custom property */
.foo { animation: --foo; }
/* not localize name in nested function */
.foo { animation: fade .2s var(--easeOutQuart) .1s forwards }
/* TODO bug */
/* not localize name in nested function #2 */
.foo { animation: fade .2s env(FOO_BAR) .1s forwards, name }
/* not localize name in nested function #3 */
.foo { animation: var(--foo-bar) .1s forwards, name }
/* not localize name in nested function #4 */
.foo { animation: var(--foo-bar) .1s forwards name, name }
/* localize animation */
.foo { animation: a; }
/* localize animation #2 */
.foo { animation: bar 5s, foobar; }
/* localize animation #3 */
.foo { animation: ease ease; }
/* TODO bug */
/* localize animation #4 */
.foo { animation: 0s ease 0s 1 normal none test running; }
/* localize animation with vendor prefix */
.foo { -webkit-animation: bar; animation: bar; }
/* not localize other rules */
.foo { content: "animation: bar;" }
/* not localize global rules */
:global .foo { animation: foo; animation-name: bar; }
/* handle nested global */
:global .a:not(:global .b) { a_value: some-value; }
/* handle nested global #1 */
:global .a:not(:global .b:not(:global .c)) { a_value: some-value; }
/* handle nested global #2 */
:local .a:not(:not(:not(:global .c))) { a_value: some-value; }
/* handle nested global #3 */
:global .a:not(:global .b, :global .c) { a_value: some-value; }
/* handle nested global #4 */
:local .a:not(:global .b, :local .c) { a_value: some-value; }
/* handle nested global #5 */
:global .a:not(:local .b, :global .c) { a_value: some-value; }
/* TODO bug */
/* handle nested global #6 */
:global .a:not(.b, .c) { a_value: some-value; }
/* handle nested global #7 */
:local .a:not(.b, .c) { a_value: some-value; }
/* handle nested global #8 */
:global .a:not(:local .b, .c) { a_value: some-value; }
/* TODO bug */
/* handle a complex animation rule */
.foo { animation: foo, bar 5s linear 2s infinite alternate, barfoo 1s; }
/* handle animations where the first value is not the animation name */
.foo { animation: 1s foo; }
/* handle animations where the first value is not the animation name whilst also using keywords */
.foo { animation: 1s normal ease-out infinite foo; }
/* TODO bug */
/* not treat animation curve as identifier of animation name even if it separated by comma */
.foo { animation: slide-right 300ms forwards ease-out, fade-in 300ms forwards ease-out; }
/* TODO bug */
/* not treat "start" and "end" keywords in steps() function as identifiers */
.foo { animation: spin 1s steps(12, end) infinite; }
.foo { animation: spin 1s STEPS(12, start) infinite; }
.foo { animation: spin 1s steps(12, END) infinite; }
.foo { animation: spin 1s steps(12, START) infinite; }
/* handle animations with custom timing functions */
.foo { animation: 1s normal cubic-bezier(0.25, 0.5, 0.5. 0.75) foo; }
/* handle animations whose names are keywords */
.foo { animation: 1s infinite infinite; }
/* TODO bug */
/* handle not localize an animation shorthand value of "inherit" */
.foo { animation: inherit; }
/* TODO test me in browser */
/* handle "constructor" as animation name */
.foo { animation: constructor constructor; }
/* default to local when mode provided */
.foo { a_value: some-value; }
/* localize keyframes */
@keyframes foo { from { a_value: some-value; } to { a_value: some-value; } }
/* localize keyframes starting with special characters */
@keyframes \@foo { from { color: red; } to { color: blue; } }
/* localize keyframes containing special characters */
@keyframes f\@oo { from { color: red; } to { color: blue; } }
/* TODO bug */
/* localize explicit keyframes */
@keyframes :local(foo) { 0% { color: red; } 33.3% { color: yellow; } 100% { color: blue; } } @-webkit-keyframes :global(bar) { from { color: red; } to { color: blue; } }
/* ignore :export statements */
:export { foo: __foo; }
/* ignore :import statements */
:import("./import.modules.css") { foo: __foo; }
/* TODO bug */
/* incorrectly handle nested selectors */
.bar:not(:global .foo, .baz) { a_value: some-value; }
/* compile explict global element */
:global(input) { a_value: some-value; }
/* compile explict global attribute */
:global([type="radio"]), :not(:global [type="radio"]) { a_value: some-value; }
/* TODO bug? */
/* throw on inconsistent selector result */
:global .foo, .bar { a_value: some-value; }
/* TODO bug? */
/* throw on nested :locals */
:local(:local(.foo)) { a_value: some-value; }
/* TODO bug? */
/* throw on nested :globals */
:global(:global(.foo)) { a_value: some-value; }
/* TODO bug? */
/* throw on nested mixed */
:local(:global(.foo)) { a_value: some-value; }
/* TODO bug? */
/* throw on nested broad :local */
:global(:local .foo) { a_value: some-value; }
/* TODO bug? */
/* throw on incorrect spacing with broad :global */
.foo :global.bar { a_value: some-value; }
/* TODO bug? */
/* throw on incorrect spacing with broad :local */
.foo:local .bar { a_value: some-value; }
/* pass through global element */
input { a_value: some-value; }
/* localise class and pass through element */
.foo input { a_value: some-value; }
/* pass through attribute selector */
[type="radio"] { a_value: some-value; }
/* Not related to us */
/* not modify urls without option */
/*.a { background: url(./image.png); }*/
/*:global .b { background: url(image.png); }*/
/*.c { background: url("./image.png"); }*/
/* Not related to us */
/* rewrite url in local block */
/*.a { background: url(./image.png); }*/
/*:global .b { background: url(image.png); }*/
/*.c { background: url("./image.png"); }*/
/*.c { background: url('./image.png'); }*/
/*.d { background: -webkit-image-set(url("./image.png") 1x, url("./image2x.png") 2x); }*/
/*@font-face { src: url("./font.woff"); }*/
/*@-webkit-font-face { src: url("./font.woff"); }*/
/*@media screen { .a { src: url("./image.png"); } }*/
/*@keyframes :global(ani1) { 0% { src: url("image.png"); } }*/
/*@keyframes ani2 { 0% { src: url("./image.png"); } }*/
/*foo { background: end-with-url(something); }*/
/* Not related to us */
/* not crash on atrule without nodes */
/*@charset "utf-8";*/
/* not break unicode characters */
.a { content: "\2193" }
/* not break unicode characters */
.a { content: "\2193\2193" }
/* not break unicode characters */
.a { content: "\2193 \2193" }
/* not break unicode characters */
.a { content: "\2193\2193\2193" }
/* not break unicode characters */
.a { content: "\2193 \2193 \2193" }
/* not ignore custom property set */
:root { --title-align: center; --sr-only: { position: absolute; } }
/* TODO bug? */
/* not localize imported alias */
:import("./import.modules.css") { a_value1: some-value; }
.foo > .a_value { a_value1: some-value; }
/* TODO bug? */
/* not localize nested imported alias */
:import("./import.modules.css") { a_value2: some-value; }
.foo > .a_value > .bar { a_value2: some-value; }
/* TODO bug? */
/* ignore imported in explicit local */
:import("./import.modules.css") { a_value3: some-value; }
:local(.a_value) { a_value3: some-value; }
/* TODO bug? */
/* escape local context with explict global */
:import("./import.modules.css") { a_value4: some-value; }
:local .foo :global(.a_value) .bar { a_value4: some-value; }
/* TODO bug? */
/* respect explicit local */
:import("./import.modules.css") { a_value5: some-value; }
.a_value :local .a_value .foo :global .a_value { a_value5: some-value; }
/* TODO bug? */
/* not localize imported animation-name */
:import("./import.modules.css") { a_value6: some-value; }
.foo { animation-name: a_value; }
/* Not related to us */
/* throw on invalid syntax id usage */
. { a_value: some-value; }
/* Not related to us */
/* throw on invalid syntax class usage */
# { a_value: some-value; }
/* TODO bug */
/* throw on invalid syntax local class usage */
:local(.) { a_value: some-value; }
/* TODO bug */
/* throw on invalid syntax local id usage */
:local(#) { a_value: some-value; }
/* TODO bug */
/* throw on invalid global class usage */
:global(.) { a_value: some-value; }
/* TODO bug */
/* throw on invalid global class usage */
:global(#) { a_value: some-value; }
/* TODO bug? */
/* throw on invalid global class usage */
:global(.a:not(:global .b, :global .c)) { a_value: some-value; }
/* css nesting */
.foo {
&.class {
a_value: some-value;
}
@media screen and (min-width: 900px) {
b_value: some-value;
.bar {
c_value: some-value;
}
&.baz {
c_value: some-value;
}
}
}
/* handle negative animation-delay in animation shorthand */
.foo { animation: 1s -500ms; }
/* handle negative animation-delay in animation shorthand #1 */
.foo { animation: 1s -500.0ms; }
/* handle negative animation-delay in animation shorthand #2 */
.foo { animation: 1s -500.0ms -a_value; }
/* @scope at-rule */
.article-header {
color: red;
}
.article-body {
color: blue;
}
@scope (.article-body) to (.article-header) {
.article-body {
border: 5px solid black;
background-color: goldenrod;
}
}
@scope(.article-body)to(.article-header){
.article-footer {
border: 5px solid black;
}
}
@scope ( .article-body ) {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
@scope {
:scope {
color: red;
}
}
/* @scope at-rule #1 */
@scope (.article-body) to (figure) {
.article-footer {
border: 5px solid black;
}
}
/* TODO bug */
/* @scope at-rule #2 */
@scope (:local(.article-body)) to (:global(.class)) {
.article-footer {
border: 5px solid black;
}
:local(.class-1) {
color: red;
}
:global(.class-2) {
color: blue;
}
}
/* @scope at-rule #5 */
@scope (.article-header) to (.class) {
.article-footer {
color: red;
}
}
/* @scope at-rule #6 */
.foo {
@scope (.article-header) to (.class) {
:scope {
background: blue;
}
.bar {
color: red;
}
}
}
/* duplicate-name */
#duplicate-name { color: red; }
.duplicate-name { color: red; }
/* in-media */
@media screen and (min-width: 900px) { html .foo { a_value: some-value } }

View File

@ -0,0 +1,452 @@
/* postcss-modules-local-by-default */
/* TODO not implemented yet */
/* localize and not localize animation-name in mixed case #3 */
.foo { animation-name: fadeInOut, global(moveLeft300px), local(bounce); }
/* localize and not localize a certain animation in mixed case #2 */
.foo { animation: rotate 1s, global(spin) 3s, local(fly) 6s; }
/* compile in pure mode */
:global(.foo).bar, [type="radio"] ~ .label, :not(.foo), #bar { a_value: some-value; }
/* throw on not pure selector (global class) */
:global(.foo) { a_value: some-value; }
/* throw on not pure selector (with multiple 1) */
.foo, :global(.bar) { a_value: some-value; }
/* throw on not pure selector (with multiple 2) */
:global(.bar), .foo { a_value: some-value; }
/* throw on not pure selector (element) */
input { a_value: some-value; }
/* throw on not pure selector (attribute) */
[type="radio"] { a_value: some-value; }
/* throw on not pure keyframes */
@keyframes :global(foo) { a_value: some-value; }
/* consider & statements as pure */
.foo { &:hover { a_value: some-value; } }
/* consider & statements as pure #2 */
.foo { @media screen and (min-width: 900px) { &:hover { a_value: some-value; } } }
/* consider global inside local as pure */
.foo button { a_value: some-value; }
/* consider selector & statements as pure */
.foo { html &:hover { a_value: some-value; } }
/* consider selector & statements as pure */
.foo { &:global(.bar) { a_value: some-value; } }
/* throw on nested & selectors without a local selector */
:global(.foo) { &:hover { a_value: some-value; } }
/* should suppress errors for global selectors after ignore comment */
/* cssmodules-pure-ignore */
:global(.foo) { color: blue; }
/* should suppress errors for global selectors after ignore comment #2 */
/* cssmodules-pure-ignore */
/* another comment */
:global(.foo) { color: blue; }
/* should suppress errors for global selectors after ignore comment #3 */
/* another comment */
/* cssmodules-pure-ignore */
:global(.foo) { color: blue; }
/* should suppress errors for global selectors after ignore comment #4 */
/* cssmodules-pure-ignore */ /* another comment */
:global(.foo) { color: blue; }
/* should suppress errors for global selectors after ignore comment #5 */
/* another comment */ /* cssmodules-pure-ignore */
:global(.foo) { color: blue; }
/* should suppress errors for global selectors after ignore comment #6 */
.foo { /* cssmodules-pure-ignore */ :global(.bar) { color: blue }; }
/* should suppress errors for global selectors after ignore comment #7 */
/* cssmodules-pure-ignore */ :global(.foo) { /* cssmodules-pure-ignore */ :global(.bar) { color: blue } }
/* should suppress errors for global selectors after ignore comment #8 */
/* cssmodules-pure-ignore */ :global(.foo) { color: blue; }
/* should suppress errors for global selectors after ignore comment #9 */
/*
cssmodules-pure-ignore
*/ :global(.foo) { color: blue; }
/* should allow additional text in ignore comment */
/* cssmodules-pure-ignore - needed for third party integration */
:global(#foo) { color: blue; }
/* should not affect rules after the ignored block */
/* cssmodules-pure-ignore */
:global(.foo) { color: blue; }
:global(.bar) { color: red; }
/* should work with nested global selectors in ignored block */
/* cssmodules-pure-ignore */
:global(.foo) {
:global(.bar) { color: blue; }
}
/* should work with ignored nested global selectors in ignored block */
/* cssmodules-pure-ignore */
:global(.foo) {
/* cssmodules-pure-ignore */
:global(.bar) { color: blue; }
}
/* should work with view transitions in ignored block */
/* cssmodules-pure-ignore */
::view-transition-group(modal) {
animation-duration: 300ms;
}
/* should work with keyframes in ignored block */
/* cssmodules-pure-ignore */
@keyframes :global(fadeOut) {
from { opacity: 1; }
to { opacity: 0; }
}
/* should work with scope in ignored block */
/* cssmodules-pure-ignore */
@scope (:global(.foo)) to (:global(.bar)) {
.article-footer {
border: 5px solid black;
}
}
/* should work with scope in ignored block #2 */
/* cssmodules-pure-ignore */
@scope (:global(.foo))
to (:global(.bar)) {
.article-footer {
border: 5px solid black;
}
}
/* should work in media queries */
@media (min-width: 768px) {
/* cssmodules-pure-ignore */
:global(.foo) { color: blue; }
}
/* should handle multiple ignore comments */
/* cssmodules-pure-ignore */
:global(.foo) { color: blue; }
.local { color: green; }
/* cssmodules-pure-ignore */
:global(.bar) { color: red; }
/* should work with complex selectors in ignored block */
/* cssmodules-pure-ignore */
:global(.foo):hover > :global(.bar) + :global(.baz) {
color: blue;
}
/* should work with multiple selectors in ignored block */
/* cssmodules-pure-ignore */
:global(.foo),
:global(.bar),
:global(.baz) {
color: blue;
}
/* should work with pseudo-elements in ignored block */
/* cssmodules-pure-ignore */
:global(.foo)::before,
:global(.foo)::after {
content: '';
}
/* should disable pure mode checks for entire file with no-check comment */
/* cssmodules-pure-no-check */
:global(.foo) { border: 1px solid #e2e8f0 }
:global(.bar) { box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1) }
:global(.baz) { background: #4299e1 }
/* should disable pure mode checks for nested selectors */
/* cssmodules-pure-no-check */
:global(.foo) {
&:hover { border-color: #cbd5e0 }
& :global(.bar) { color: blue }
}
/* should ignore no-check comment if not at root level */
:global(.bar) { color: blue }
/* cssmodules-pure-no-check */
/* should ignore no-check comment if not at root level #2 */
/* Some file description */
.class { color: red; }
/* cssmodules-pure-no-check */
:global(.foo) { color: blue }
/* should allow other comments before no-check comment */
/* Some file description */
/* cssmodules-pure-no-check */
:global(.foo) { color: blue }
/* should disable pure mode checks for deep nested selectors */
/* cssmodules-pure-no-check */
:global(.foo) { max-width: 600px }
:global(.bar) { background: #fafafa }
:global(.baz) {
:global(.foobar) {
&::-webkit-scrollbar { width: 8px }
}
}
/* should work with keyframes when no-check is enabled */
/* cssmodules-pure-no-check */
@keyframes :global(fadeIn) {
from { opacity: 0 }
to { opacity: 1 }
}
:global(.animate) { animation: global(fadeIn) 0.3s }
/* should allow multiline no-check comment */
/*
cssmodules-pure-no-check
*/
:global(.foo) { color: blue }
/* should allow additional text in no-check comment */
/* cssmodules-pure-no-check - needed for styling third-party components */
:global(.foo) { color: blue }
/* should work with media queries when no-check is enabled */
/* cssmodules-pure-no-check */
@media (max-width: 768px) {
:global(.foo) { position: fixed }
}
/* css nesting #2 */
.foo {
&.class {
a_value: some-value;
}
@media screen and (min-width: 900px) {
b_value: some-value;
.bar {
c_value: some-value;
}
&.baz {
c_value: some-value;
}
}
}
/* css nesting #3 */
.foo { span { a_value: some-value; } }
/* css nesting (unfolded) #3 */
.foo span { a_value: some-value }
/* css nesting #4 */
.foo { span { a { a_value: some-value; } } }
/* css nesting (unfolded) #4 */
.foo span a { a_value: some-value }
/* css nesting #5 */
html { .foo { a_value: some-value; } }
/* css nesting (unfolded) #5 */
html .foo { a_value: some-value }
/* css nesting #6 */
html { @media screen and (min-width: 900px) { .foo { a_value: some-value; } } }
/* css nesting (unfolded) #6 */
@media screen and (min-width: 900px) { html .foo { a_value: some-value } }
/* css nesting #7 */
html { .foo { a_value: some-value; } .bar { a_value: some-value; } }
/* css nesting (unfolded) #7 */
html .foo, html .bar { a_value: some-value }
/* css nesting #8 */
.class { @media screen and (min-width: 900px) { & > span { a_value: some-value; } } }
/* css nesting (unfolded) #8 */
@media screen and (min-width: 900px) { .class > span { a_value: some-value } }
/* css nesting #9 */
html { @media screen and (min-width: 900px) { & > .class { a_value: some-value; } } }
/* css nesting (unfolded) #9 */
@media screen and (min-width: 900px) { html > .class { a_value: some-value } }
/* css nesting #10 */
.class { @media screen and (min-width: 900px) { & { a_value: some-value; } } }
/* css nesting (unfolded) #10 */
@media screen and (min-width: 900px) { .class { a_value: some-value } }
/* css nesting #11 */
html { .foo { span { a_value: some-value; } } }
/* css nesting (unfolded) #11 */
html .foo span { a_value: some-value }
/* css nesting #12 */
html { button { .foo { div { span { a_value: some-value; } } } } }
/* css nesting #13 */
.foo { button { div { div { span { a_value: some-value; } } } } }
/* css nesting #14 */
html { button { div { div { .foo { a_value: some-value; } } } } }
/* css nesting #15 */
html { button { @media screen and (min-width: 900px) { .foo { div { span { a_value: some-value; } } } } } }
/* css nesting #16 */
html { .foo { a_value: some-value; } }
/* css nesting #17 */
.foo { div { a_value: some-value; } }
/* css nesting #18 */
@media screen and (min-width: 900px) { html { .foo { a_value: some-value; } } }
/* css nesting #19 */
html { @media screen and (min-width: 900px) { .foo { a_value: some-value; } } }
/* css nesting #20 */
html { .foo { @media screen and (min-width: 900px) { a_value: some-value; } } }
/* css nesting #21 */
@media screen and (min-width: 900px) { .foo { div { a_value: some-value; } } }
/* css nesting #22 */
.foo { @media screen and (min-width: 900px) { div { a_value: some-value; } } }
/* css nesting #23 */
.foo { div { @media screen and (min-width: 900px) { a_value: some-value; } } }
/* css nesting - throw on mixed parents */
.foo, html { span { a_value: some-value; } }
/* css nesting - throw on & */
html { & > span { a_value: some-value; } }
/* css nesting - throw on & #2 */
html { button { & > span { a_value: some-value; } } }
/* css nesting - throw on & #3 */
html { @media screen and (min-width: 900px) { & > span { a_value: some-value; } } }
/* css nesting - throw on & #4 */
html { button { div { div { & { a_value: some-value; } } } } }
/* css nesting - throw */
html { button { div { div { div { a_value: some-value; } } } } }
/* css nesting - throw #2 */
html { button { div { div { div { } } } } }
/* css nesting - throw #3 */
html { button { @media screen and (min-width: 900px) { div { div { div { } } } } } }
/* css nesting - throw #4 */
@media screen and (min-width: 900px) { html { button { div { div { div { } } } } } }
/* css nesting - throw #5 */
html { div { @media screen and (min-width: 900px) { color: red } } }
/* css nesting - throw #6 */
html { div { @media screen and (min-width: 900px) { @media screen and (min-width: 900px) { color: red } } } }
/* css nesting - throw #7 */
html { div { @media screen and (min-width: 900px) { .a { } @media screen and (min-width: 900px) { color: red } } } }
/* css nesting - throw #7 */
html { div { @media screen and (min-width: 900px) { .a { a_value: some-value; } @media screen and (min-width: 900px) { color: red } } } }
/* css nesting - throw #8 */
@media screen and (min-width: 900px) {
.a { a_value: some-value; }
@media screen and (min-width: 900px) {
div {
color: red
}
}
}
/* css nesting - throw on global styles with a local selector */
html { a_value: some-value; .foo { a_value: some-value; } }
/* css nesting - throw on global styles with a local selector #2 */
html { .foo { a_value: some-value; } a_value: some-value; }
/* css nesting - throw on global styles with a local selector #3 */
html {
.foo { a_value: some-value; }
button {
color: red;
.bar { a_value: some-value; }
}
}
/* css nesting - throw on global styles with a local selector #4 */
html {
@media screen and (min-width: 900px) {
button {
color: red;
.bar { a_value: some-value; }
}
}
}
/* consider :import statements pure */
:import("./import.modules.css") { foo: __foo; }
/* consider :export statements pure */
:export { foo: __foo; }
/* @scope at-rule #4 */
@scope (.article-header) to (.class) {
.article-footer {
border: 5px solid black;
}
.class-1 {
color: red;
}
.class-2 {
color: blue;
}
}
/* @scope at-rule #7 */
@scope (:global(.article-header).foo) to (:global(.class).bar) {
.bar {
color: red;
}
}

View File

@ -0,0 +1,513 @@
/* postcss-modules-scope */
/* at-rule-scope */
:local(.exportName4) {
color: red;
}
@scope (:local(.exportName1)) to (:local(.exportName2)) {
:local(.exportName3) {
border: 5px solid black;
background-color: goldenrod;
}
}
@scope (:local(.exportName1)) {
:local(.exportName5) {
border: 5px solid black;
}
}
@scope (:local(.exportName1)) to (img) {
:local(.exportName3) {
background-color: goldenrod;
}
}
@scope (:local(.exportName6)) {
img {
backdrop-filter: blur(2px);
}
}
@scope {
:scope {
color: red;
}
}
/* at-rule */
:local(.exportName7) {
background: red;
}
@media screen {
:local(.exportName8) {
color: green;
:local(.exportName9) {
color: blue;
}
}
}
/* TODO bug */
/* composes-only-allowed */
:local(.exportName10) {
/*composes: global(a);*/
/*compose-with: global(b);*/
a-composes: global(c);
composes-b: global(d);
a-composes-b: global(e);
a-compose-with-b: global(b);
}
/* css-nesting-composes */
:local(.exportName11) {
color: red;
}
:local(.exportName12) {
display: grid;
composes: exportName11;
@media (orientation: landscape) {
grid-auto-flow: column;
}
}
/* css-nesting */
:local(.exportName12) {
background: red;
}
:local(.exportName13) {
color: green;
@media (max-width: 520px) {
:local(.exportName14) {
color: darkgreen;
}
&:local(.exportName15) {
color: blue;
}
}
}
:local(.exportName16) {
color: red;
&:local(.exportName17) {
color: green;
}
:local(.exportName18) {
color: blue;
}
}
/* TODO bug */
/* error-comma-in-local */
/*.className { color: red; }*/
/*:local(.exportName19, .exportName20) {*/
/* composes: className;*/
/*}*/
/* error-composes-css-nesting-at-rule */
:local(.exportName21) {
}
@media (min-width: 1024px) {
:local(.exportName22) {
:local(.exportName23) {
compose-with: exportName21;
}
}
}
/* error-composes-css-nesting-with-media */
:local(.exportName24) {
}
:local(.exportName25) {
@media (min-width: 1024px) {
:local(.exportName26) {
compose-with: exportName24;
}
}
}
/* error-composes-css-nesting */
:local(.exportName27) {
}
:local(.exportName28) {
:local(.exportName29) {
compose-with: exportName27;
}
}
/* TODO bug no report */
/* error-composes-keyframes */
:local(.exportName30) {
}
@keyframes slidein {
from {
transform: translateX(0%);
}
to {
composes: exportName30;
}
}
/* TODO bug no report */
/* error-composes-not-allowed-in-local-id */
.exportName31 {}
:local(#idName) {
composes: exportName31;
}
/* error-composes-not-allowed-in-multiple */
.exportName32 {}
:local(.exportName33) :local(.exportName34) {
composes: exportName32;
}
/* TODO bug no report */
/* error-composes-not-allowed-in-simple */
.exportName35 {}
body {
composes: exportName35;
}
/* error-composes-not-allowed-in-wrong-local */
.exportName36 {}
:local(.exportName37.exportName38) {
composes: exportName36;
}
/* error-composes-not-defined-class */
:local(.exportName39) {
compose-with: exportName40;
}
/* TODO bug no report */
/* error-multiple-nested-media */
:local(.exportName41) {
color: blue;
}
:local(.exportName42) {
display: grid;
@media (orientation: landscape) {
grid-auto-flow: column;
@media (min-width: 1024px) {
composes: exportName41;
}
}
}
/* TODO bug no report */
/* error-not-allowed-in-local */
:local(body) {
color: red;
}
/* TODO bug no report */
/* error-when-attribute-is-href */
:local(.exportName42[href^="https"]) {
color: blue;
}
/* TODO bug no report */
/* error-when-attribute-is-target */
:local(.exportName43[target="_blank"]) {
color: blue;
}
/* TODO bug no report */
/* error-when-attribute-is-title */
:local(.exportName44[title="flower"]) {
color: blue;
}
/* TODO bug no report */
/* error-when-attribute-is-title */
:local(.exportName45[type="text"]) {
color: blue;
}
/* escape-sequence */
:local(.smile) {
color: red;
}
:local(.smile) :local(.smile) {
color: red;
}
:local(.smile) :local(.smile) :local(.smile) {
color: red;
}
:local(.smile_with_A) {
color: red;
}
.\1F600 :local(.smile) {
color: red;
}
:local(.smile) .\1F600 {
color: red;
}
.\1F600 :local(.smile) .\1F600 {
color: red;
}
.\1F600 :local(.smile_with_A) .\1F600 {
color: red;
}
#\1F600 :local(#smile) #\1F600 {
color: red;
}
#\1F600 :local(#smile_with_A) #\1F600 {
color: red;
}
.a :local(.smile) b {
color: red;
}
:local(.smile) > :local(.smile) > :local(.smile) {
color: red;
}
.\1F600 :local(.smile) {
color: red;
}
.\1F600:local(.smile) {
color: red;
}
.\1F600 :local(.smile) {
color: red;
}
:local(.smile) .a {
color: red;
}
:local(.smile).a {
color: red;
}
.a :local(.smile) {
color: red;
}
.a:local(.smile) {
color: red;
}
/* export-child-class */
:local(.exportName46) {
color: red;
}
:local(.exportName46) h1 {
color: blue;
}
/* TODO bug */
/* export-class-attribute */
:local(.exportName47) {
color: red;
}
:local(.exportName48) {
color: green;
}
:local(.exportName49[class="exportName47"]) {
color: blue;
}
/* TODO bug */
/* export-difficult */
@keyframes :local(fade-in) {
from {
opacity: 0;
}
}
@-webkit-keyframes :local(fade-out) {
to {
opacity: 0;
}
}
:local(.fadeIn) {
animation: :local(fade-in) 5s,/* some, :local(comment) */
:local(fade-out) 1s :local(wrong);
content: :local(fade-in), wrong, "difficult, :local(wrong)" :local(wrong);
}
/* export-global-class */
.exportName50 {
color: green;
}
.exportName50:hover {
color: red;
}
@media screen {
body {
background: red;
}
}
:local(.exportName51) {
color: blue;
}
/* export-keyframes */
@keyframes :local(fade-in-export) {
from {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fade-export {
from {
opacity: 0.5;
}
}
:local(.fadeIn-export) {
animation-name: :local(fade-in-export);
}
:local(.fadeIn-export) {
animation: 2s :local(fade-in-export);
}
:local(.fadeIn-export) {
animation: :local(fade-in-export) 2s;
}
/* export-keywords-selector */
:local(.constructor) {
color: green;
}
:local(.toString) {
color: red;
}
/* export-multiple-classes */
:local(.exportName52) :local(.exportName53) {
color: green;
}
:local(.exportName52):local(.exportName53) {
color: red;
}
/* export-nested-class */
:local(.exportName54):not(:local(.exportName55).global) {
color: green;
}
:local(.exportName54):has(:local(.exportName55), :local(.exportName56)) {
color: red;
}
/* TODO bug */
/* export-with-composes-imported-class */
/*:import("./import.modules.css") {*/
/* imported_otherClass: otherClass;*/
/*}*/
/*:local(.exportName) {*/
/* composes: imported_otherClass;*/
/* color: green;*/
/*}*/
/* TODO bug */
/* export-with-composes */
:local(.exportName57) { background: red; }
:local(.exportName58) { compose-with: exportName57; color: green; }
:local(.exportName59) { compose-with: exportName58; color: green; }
/* TODO bug */
/* export-with-global-composes */
.exportName60 { background: red; }
.exportName61 { font-size: 2em; }
.exportName62 { color: red; }
/*:local(.exportName63) { compose-with: global(otherClass) global(andAgain); compose-with: global(aThirdClass); color: green; }*/
/* export-with-multiple-composes */
:local(.exportName63) { background: red; }
:local(.exportName64) { font-size: 2em; }
:local(.exportName65) { color: red; }
:local(.exportName66) { compose-with: exportName63 exportName64; compose-with: exportName65; color: green; }
/* TODO bug */
/* export-with-transitive-composes */
:local(.exportName67) {
font-size: 2em;
}
:local(.exportName68) {
composes: exportName67;
background: red;
}
:local(.exportName69) {
composes: exportName68;
color: green;
}
/* Not related to us */
/* ignore-custom-property-set */
:root {
--title-align: center;
--sr-only: {
position: absolute;
}
}
/* TODO bug */
/* multiple-composes */
/*:import("abcd.modules.css") {*/
/* i__i_a_0: a;*/
/* i__i_b_0: b;*/
/* i__i_c_0: c;*/
/* i__i_d_0: d;*/
/*}*/
/*:local(.class) {*/
/* composes: i__i_a_0 i__i_b_0, i__i_c_0, global(d) global(e), global(f), i__i_d_0;*/
/* color: red;*/
/*}*/
/* TODO bug */
/* nested-rule */
:root {
--test: {
--test: foo;
--bar: 1;
}
}

View File

@ -0,0 +1,150 @@
/* postcss-modules-values */
/* should export a constant */
@value exportName blue;
/* Should pass for us, not a warning */
/* gives a warnings when there is no semicolon between lines */
@value exportName1 blue @value exportName2 yellow;
/* Should pass for us, not a warning */
/* gives a warnings on empty value */
@value v-comment:;
/* Should pass for us, not a warning */
/* gives a warnings on empty value with comment */
@value v-comment-other:/* comment */;
/* should export a more complex constant */
@value exportName2: (max-width: 599px);
/* should replace constants within the file */
@value exportName3: red;
.foo-replace { color: exportName3; }
/* should replace constants within the file #1 */
@value exportName4: red;
.foo-replace-1 { &.bar { color: exportName4; } }
/* should replace constants within the file #2 */
@value exportName5: red;
.foo-replace-2 { @media (min-width: 1024px) { &.bar { color: exportName5; } } }
/* should replace constants within the file #3 */
@value exportName6: red;
.foo-replace-3 { @media (min-width: 1024px) { &.bar { @media (min-width: 1024px) { color: exportName6; } } } }
/* should replace constants within the file #4 */
@value exportName7: 40px;
@value exportName8: 36px;
.foo-replace-4 { height: exportName7; height: exportName8; }
/* TODO bug */
/* should replace selectors within the file */
@value exportName9: red;
.exportName9 { color: exportName9; }
/* TODO bug */
/* should replace selectors within the file #1 */
@value exportName10: red;
#exportName10 { color: exportName10; }
/* TODO bug */
/* should replace selectors within the file #2 */
@value exportName11: red;
.exportName11 > .exportName11 { color: exportName11; }
/* TODO bug - should reexport and inherit module type and output warning if not found */
/* should import and re-export a simple constant */
@value exportName12 from "./colors.css";
/* should import a simple constant and replace usages */
@value exportNameRed from "./colors.modules.css";
.exportName13 { color: exportNameRed; }
/* should import and alias a constant and replace usages */
@value exportNameBlue as red from "./colors.modules.css";
.exportName14 { color: red; }
/* should import multiple from a single file */
@value otherBlue, otherRed from "./colors.modules.css";
.exportName15 { color: otherRed; }
.exportName16 { color: otherBlue }
/* should import from a definition */
@value colors: "./colors.modules.css";
@value otherBlue from colors;
.exportName17 { color: otherBlue; }
/* should only allow values for paths if defined in the right order */
@value wrongOrder from colors;
@value colors: "./colors.css";
/* should allow transitive values */
@value exportName18: #FFF;
@value exportName19: exportName18;
.exportName20 { color: exportName19; }
/* TODO bug */
/* should allow transitive values within calc */
@value exportName22: 10px;
@value exportName23: calc(exportName22 * 2);
.exportName24 { margin: exportName23; }
/* should preserve import order */
@value a from "./a.modules.css";
@value b from "./b.modules.css";
/* should allow custom-property-style names */
@value --red from "./colors.modules.css";
.exportName25 { color: --red; }
/* should allow all colour types */
@value named: aqua;
@value char3 #0f0;
@value char6 #00ff00;
@value rgba rgba(34, 12, 64, 0.3);
@value hsla hsla(220, 13.0%, 18.0%, 1);
.exportName26 {
color: named;
background-color: char3;
border-top-color: char6;
border-bottom-color: rgba;
outline-color: hsla;
}
/* TODO bug */
/* should import multiple from a single file on multiple lines */
@value (
namedBlue,
namedRed
) from "./colors.modules.css";
.exportName27 { color: namedBlue; }
.exportName28 { color: namedRed }
/* should allow definitions with commas in them */
@value coolShadow: 0 11px 15px -7px rgba(0,0,0,.2),0 24px 38px 3px rgba(0,0,0,.14) ;
.exportName29 { box-shadow: coolShadow; }
/* should allow values with nested parentheses */
@value parentheses: color(red lightness(50%));
.exportName30 {
color: parentheses
}
/* should work with custom properties */
@value v-color: my-custom-value;
:root { --my-own-color: v-color; }
/* should work with empty custom properties */
@value v-empty-1: ;
:root { --color:v-empty-1; }
/* should work with empty custom properties #2 */
@value v-empty-2: ;
:root { --color:v-empty-2; }
/* TODO bug no extra space before */
/* should work with empty custom properties #3 */
@value v-empty: /* comment */;
:root { --color:v-empty; }

View File

@ -5,5 +5,14 @@ module.exports = [
/Incorrect composition, expected global keyword or string value/,
/Incorrect composition, expected class named/,
/Referenced class name "className" in composes not found/,
/Self-referencing class name "abc-from-def" in composes not found/
/Self-referencing class name "abc-from-def" in composes not found/,
/Composition is only allowed when selector is single local class name not in "exportName22", "exportName23"/,
/Composition is only allowed when selector is single local class name not in "exportName25", "exportName26"/,
/Composition is only allowed when selector is single local class name not in "exportName28", "exportName29"/,
/Composition is only allowed when selector is single local class name not in "exportName33", "exportName34"/,
/Composition is only allowed when selector is single local class name not in "exportName37", "exportName38"/,
/Self-referencing class name "exportName40" in composes not found/,
/Missing whitespace after ':local' in ':local.b \{'/,
/Missing whitespace after ':global' in ':global, .foobar :global \{'/,
/Missing whitespace after ':global' in ':global.bar \{'/
];

View File

@ -6,5 +6,22 @@ module.exports = {
mode: "development",
experiments: {
css: true
},
module: {
rules: [
{
test: /postcss-modules-local-by-default\.global\.modules\.css$/,
type: "css/global"
},
{
test: /postcss-modules-local-by-default\.local\.modules\.css$/,
type: "css/module"
},
{
test: /postcss-modules-local-by-default\.pure\.modules\.css$/,
// Pure is like a local but more strict
type: "css/module"
}
]
}
};