Improve missing layer codemod (#14512)

This PR improves the missing layers codemod where everything after the
last Tailwind directive can stay as-is without wrapping it in a `@layer`
directive.

The `@layer` at-rules are only important for CSS that exists between
Tailwind directives.

E.g.:
```css
@tailwind base;

html {}

@tailwind components;

.btn {}

@tailwind utilities;

.foo {}

.bar {}
```

Was transformed into:
```css
@import "tailwindcss";

@layer base {
  html {}
}

@layer components {
  .btn {}
}

@layer utilities {
  .foo {}
  
  .bar {}
}
```

But the last `@layer utilities` is already in the correct spot, so we
can simplify this to just this instead:
```css
@import "tailwindcss";

@layer base {
  html {}
}

@layer components {
  .btn {}
}

.foo {}

.bar {}
```
This commit is contained in:
Robin Malfait 2024-09-25 10:42:19 +02:00 • committed by GitHub
parent c094fadbbc
commit 951f6448fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 20 additions and 16 deletions

View file

@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Nothing yet!
### Fixed
- _Experimental_: Improve codemod output, keep CSS after last Tailwind directive unlayered ([#14512](https://github.com/tailwindlabs/tailwindcss/pull/14512))
## [4.0.0-alpha.25] - 2024-09-24

View file

@ -55,11 +55,9 @@ it('should migrate rules between tailwind directives', async () => {
@tailwind utilities;
@layer utilities {
.utility-a {
}
.utility-b {
}
.utility-a {
}
.utility-b {
}"
`)
})

View file

@ -78,28 +78,32 @@ export function migrateMissingLayers(): Plugin {
// Track the node
if (lastLayer !== '') {
if (bucket.push(node) !== 1) {
node.remove()
}
bucket.push(node)
}
})
// Add the last bucket if it's not empty
if (bucket.length > 0) {
buckets.push([lastLayer, bucket.splice(0)])
}
// Wrap each bucket in an `@layer` at-rule
for (let [layerName, nodes] of buckets) {
let target = nodes[0]
let layerNode = new AtRule({
name: 'layer',
params: layerName,
nodes,
nodes: nodes.map((node) => {
// Keep the target node as-is, because we will be replacing that one
// with the new layer node.
if (node === target) {
return node
}
// Every other node should be removed from its original position. They
// will be added to the new layer node.
return node.remove()
}),
raws: {
tailwind_pretty: true,
},
})
nodes[0].replaceWith(layerNode)
target.replaceWith(layerNode)
}
}