Repository: postcss/postcss-import
Pull request #511 (2022-12-01 05:13:30)

preserve `layer` in ignored `@imports` statements
fix : #510

- preserves `layer` when writing `@import` rules
- correctly "concats" layers for `@import` rules

@argyleink Can you also take a look at this?


Patch:
diff --git a/index.js b/index.js
index 8c88170..d14873d 100755
--- a/index.js
+++ b/index.js
@@ -9,6 +9,7 @@ const resolveId = require("./lib/resolve-id")
 const loadContent = require("./lib/load-content")
 const processContent = require("./lib/process-content")
 const parseStatements = require("./lib/parse-statements")
+const assignLayerNames = require("./lib/assign-layer-names")
 
 function AtImport(options) {
   options = {
@@ -86,13 +87,36 @@ function AtImport(options) {
             return
           }
 
+          if (stmt.layer.length > 1) {
+            assignLayerNames(stmt.layer, stmt.node, state, options)
+          }
+
           if (stmt.type === "import") {
-            stmt.node.params = `${stmt.fullUri} ${stmt.media.join(", ")}`
+            const parts = [stmt.fullUri]
+
+            const media = stmt.media.join(", ")
+
+            if (stmt.layer.length) {
+              const layerName = stmt.layer.join(".")
+
+              let layerParams = "layer"
+              if (layerName) {
+                layerParams = `layer(${layerName})`
+              }
+
+              parts.push(layerParams)
+            }
+
+            if (media) {
+              parts.push(media)
+            }
+
+            stmt.node.params = parts.join(" ")
           } else if (stmt.type === "media") {
             if (stmt.layer.length) {
               const layerNode = atRule({
                 name: "layer",
-                params: stmt.layer.filter(layer => layer !== "").join("."),
+                params: stmt.layer.join("."),
                 source: stmt.node.source,
               })
 
@@ -128,7 +152,7 @@ function AtImport(options) {
 
               const layerNode = atRule({
                 name: "layer",
-                params: stmt.layer.filter(layer => layer !== "").join("."),
+                params: stmt.layer.join("."),
                 source: parent.source,
               })
 
@@ -147,7 +171,7 @@ function AtImport(options) {
             } else if (stmt.layer.length) {
               const layerNode = atRule({
                 name: "layer",
-                params: stmt.layer.filter(layer => layer !== "").join("."),
+                params: stmt.layer.join("."),
                 source: parent.source,
               })
 
@@ -315,19 +339,8 @@ function AtImport(options) {
       function loadImportContent(result, stmt, filename, options, state) {
         const atRule = stmt.node
         const { media, layer } = stmt
-        layer.forEach((layerPart, i) => {
-          if (layerPart === "") {
-            if (options.nameLayer) {
-              layer[i] = options
-                .nameLayer(state.anonymousLayerCounter++, state.rootFilename)
-                .toString()
-            } else {
-              throw atRule.error(
-                `When using anonymous layers in @import you must also set the "nameLayer" plugin option`
-              )
-            }
-          }
-        })
+
+        assignLayerNames(layer, atRule, state, options)
 
         if (options.skipDuplicates) {
           // skip files already imported at the same scope
diff --git a/lib/assign-layer-names.js b/lib/assign-layer-names.js
new file mode 100644
index 0000000..18cfcc7
--- /dev/null
+++ b/lib/assign-layer-names.js
@@ -0,0 +1,17 @@
+"use strict"
+
+module.exports = function (layer, node, state, options) {
+  layer.forEach((layerPart, i) => {
+    if (layerPart.trim() === "") {
+      if (options.nameLayer) {
+        layer[i] = options
+          .nameLayer(state.anonymousLayerCounter++, state.rootFilename)
+          .toString()
+      } else {
+        throw node.error(
+          `When using anonymous layers in @import you must also set the "nameLayer" plugin option`
+        )
+      }
+    }
+  })
+}


Test patch:
diff --git a/test/fixtures/ignore.css b/test/fixtures/ignore.css
index 71a7951..5f66c64 100644
--- a/test/fixtures/ignore.css
+++ b/test/fixtures/ignore.css
@@ -12,5 +12,9 @@
 @import url("//css");
 @import url('//css');
 @import url(//css);
+@import "http://css" layer;
+@import "http://css" layer(bar);
+@import "http://css" layer screen and (min-width: 25em), print;
+@import "http://css" layer(bar) screen and (min-width: 25em), print;
 
 content{}
diff --git a/test/fixtures/ignore.expected.css b/test/fixtures/ignore.expected.css
index 527c13e..0f1fcc7 100644
--- a/test/fixtures/ignore.expected.css
+++ b/test/fixtures/ignore.expected.css
@@ -13,6 +13,10 @@
 @import url("//css");
 @import url('//css');
 @import url(//css);
+@import "http://css" layer;
+@import "http://css" layer(bar);
+@import "http://css" layer screen and (min-width: 25em), print;
+@import "http://css" layer(bar) screen and (min-width: 25em), print;
 @media (min-width: 25em){
 ignore{}
 }
diff --git a/test/fixtures/imports/layer-level-2-anonymous.css b/test/fixtures/imports/layer-level-2-anonymous.css
index 36d69c2..6846c75 100644
--- a/test/fixtures/imports/layer-level-2-anonymous.css
+++ b/test/fixtures/imports/layer-level-2-anonymous.css
@@ -1,3 +1,5 @@
+@import "http://css" layer;
+@import "http://css-bar" layer(bar);
 @import url("layer-level-3.css") layer (min-width: 320px);
 
 @layer Y {
diff --git a/test/fixtures/layer-import-atrules-anonymous.css b/test/fixtures/layer-import-atrules-anonymous.css
index f2d9356..dc0eb16 100644
--- a/test/fixtures/layer-import-atrules-anonymous.css
+++ b/test/fixtures/layer-import-atrules-anonymous.css
@@ -1,3 +1,7 @@
 @import url("layer-anonymous.css") layer screen;
 
 @import url("layer-anonymous.css") layer;
+
+@import url("layer-anonymous.css") layer(named-layer-1);
+
+@import "http://css-top-level" layer;
diff --git a/test/fixtures/layer-import-atrules-anonymous.expected.css b/test/fixtures/layer-import-atrules-anonymous.expected.css
index be1df27..83111e9 100644
--- a/test/fixtures/layer-import-atrules-anonymous.expected.css
+++ b/test/fixtures/layer-import-atrules-anonymous.expected.css
@@ -1,5 +1,12 @@
-@media screen and (min-width: 320px) {
-@layer import-anon-layer-0.import-anon-layer-1.import-anon-layer-2 {
+@import "http://css" layer(import-anon-layer-0.import-anon-layer-1.import-anon-layer-8) screen;
+@import "http://css-bar" layer(import-anon-layer-0.import-anon-layer-1.bar) screen;
+@import "http://css" layer(import-anon-layer-3.import-anon-layer-4.import-anon-layer-9);
+@import "http://css-bar" layer(import-anon-layer-3.import-anon-layer-4.bar);
+@import "http://css" layer(named-layer-1.import-anon-layer-6.import-anon-layer-10);
+@import "http://css-bar" layer(named-layer-1.import-anon-layer-6.bar);
+@import "http://css-top-level" layer;
+@media screen and (min-width: 320px){
+@layer import-anon-layer-0.import-anon-layer-1.import-anon-layer-2{
 @layer Z {
   body {
     color: cyan;
@@ -7,9 +14,8 @@
 }
 }
 }
-
-@media screen {
-@layer import-anon-layer-0.import-anon-layer-1 {
+@media screen{
+@layer import-anon-layer-0.import-anon-layer-1{
 
 @layer Y {
   body {
@@ -18,18 +24,16 @@
 }
 }
 }
-
-@media screen {
-@layer import-anon-layer-0 {
+@media screen{
+@layer import-anon-layer-0{
 
 body {
   order: 1;
 }
 }
 }
-
-@media screen {
-@layer import-anon-layer-0 {
+@media screen{
+@layer import-anon-layer-0{
 
 @media (min-width: 50rem) {
   body {
@@ -38,9 +42,8 @@ body {
 }
 }
 }
-
-@media screen {
-@layer import-anon-layer-0 {
+@media screen{
+@layer import-anon-layer-0{
 
 @keyframes RED_TO_BLUE {
   0% {
@@ -65,9 +68,8 @@ body {
 }
 }
 }
-
-@media (min-width: 320px) {
-@layer import-anon-layer-3.import-anon-layer-4.import-anon-layer-5 {
+@media (min-width: 320px){
+@layer import-anon-layer-3.import-anon-layer-4.import-anon-layer-5{
 @layer Z {
   body {
     color: cyan;
@@ -75,8 +77,7 @@ body {
 }
 }
 }
-
-@layer import-anon-layer-3.import-anon-layer-4 {
+@layer import-anon-layer-3.import-anon-layer-4{
 
 @layer Y {
   body {
@@ -84,15 +85,13 @@ body {
   }
 }
 }
-
-@layer import-anon-layer-3 {
+@layer import-anon-layer-3{
 
 body {
   order: 1;
 }
 }
-
-@layer import-anon-layer-3 {
+@layer import-anon-layer-3{
 
 @media (min-width: 50rem) {
   body {
@@ -100,8 +99,62 @@ body {
   }
 }
 }
+@layer import-anon-layer-3{
+
+@keyframes RED_TO_BLUE {
+  0% {
+    background-color: red;
+  }
+  100% {
+    background-color: blue;
+  }
+}
+
+@supports (display: grid) {
+  body {
+    display: grid;
+    order: 3;
+  }
+}
+
+@layer A {
+  body {
+    order: 4;
+  }
+}
+}
+@media (min-width: 320px){
+@layer named-layer-1.import-anon-layer-6.import-anon-layer-7{
+@layer Z {
+  body {
+    color: cyan;
+  }
+}
+}
+}
+@layer named-layer-1.import-anon-layer-6{
+
+@layer Y {
+  body {
+    color: purple;
+  }
+}
+}
+@layer named-layer-1{
+
+body {
+  order: 1;
+}
+}
+@layer named-layer-1{
 
-@layer import-anon-layer-3 {
+@media (min-width: 50rem) {
+  body {
+    order: 2;
+  }
+}
+}
+@layer named-layer-1{
 
 @keyframes RED_TO_BLUE {
   0% {