CSS codemod: ensure we don't lose selectors (#14518)

This PR fixes an issue where a CSS rule with a selector that contains
multiple selectors lost everything but the last selector.

While testing the `npx @tailwindcss/upgrade` codemods on real world
projects, I noticed that we lost one of the selectors in the
`docker/docs` repository.

```diff
diff --git a/assets/css/toc.css b/assets/css/toc.css
index 91ff92d7cd..3b2432e913 100644
--- a/assets/css/toc.css
+++ b/assets/css/toc.css
@@ -2,7 +2,7 @@
   #TableOfContents {
     .toc a {
       @apply block max-w-full truncate py-1 pl-2 hover:font-medium hover:no-underline;
-      &[aria-current="true"],
+      
       &:hover {
         @apply border-l-2 border-l-gray-light bg-gradient-to-r from-gray-light-100 font-medium text-black dark:border-l-gray-dark dark:from-gray-dark-200 dark:text-white;
       }
```

This PR fixes the issue by not overriding the `node.selector` internally
with the last selector we handled. Instead, we let the selector parser
handle it entirely.
This commit is contained in:
Robin Malfait 2024-09-25 18:39:00 +02:00 committed by GitHub
parent 732147a761
commit 8bbdb57457
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 40 additions and 6 deletions

View File

@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- _Experimental_: Fix incorrect empty `layer()` at the end of `@import` at-rules when running codemods ([#14513](https://github.com/tailwindlabs/tailwindcss/pull/14513))
- _Experimental_: Migrate `@import "tailwindcss/tailwind.css"` to `@import "tailwindcss"` ([#14514](https://github.com/tailwindlabs/tailwindcss/pull/14514))
- _Experimental_: Do not wrap comment nodes in `@layer` when running codemods ([#14517](https://github.com/tailwindlabs/tailwindcss/pull/14517))
- _Experimental_: Ensure we don't lose selectors when running codemods ([#14518](https://github.com/tailwindlabs/tailwindcss/pull/14518))
## [4.0.0-alpha.25] - 2024-09-24

View File

@ -783,3 +783,40 @@ describe('comments', () => {
`)
})
})
// Saw this when testing codemods on https://github.com/docker/docs
it('should not lose attribute selectors', async () => {
expect(
await migrate(css`
@layer components {
#TableOfContents {
.toc a {
@apply block max-w-full truncate py-1 pl-2 hover:font-medium hover:no-underline;
&[aria-current='true'],
&:hover {
@apply border-l-2 border-l-gray-light bg-gradient-to-r from-gray-light-100 font-medium text-black dark:border-l-gray-dark dark:from-gray-dark-200 dark:text-white;
}
&:not([aria-current='true']) {
@apply text-gray-light-600 hover:text-black dark:text-gray-dark-700 dark:hover:text-white;
}
}
}
}
`),
).toMatchInlineSnapshot(`
"@layer components {
#TableOfContents {
.toc a {
@apply block max-w-full truncate py-1 pl-2 hover:font-medium hover:no-underline;
&[aria-current='true'],
&:hover {
@apply border-l-2 border-l-gray-light bg-gradient-to-r from-gray-light-100 font-medium text-black dark:border-l-gray-dark dark:from-gray-dark-200 dark:text-white;
}
&:not([aria-current='true']) {
@apply text-gray-light-600 hover:text-black dark:text-gray-dark-700 dark:hover:text-white;
}
}
}
}"
`)
})

View File

@ -75,9 +75,8 @@ export function migrateAtLayerUtilities(): Plugin {
return WalkAction.Stop
}
})
node.selector = selector.toString()
})
}).processSync(node.selector, { updateSelector: false })
}).processSync(node, { updateSelector: true })
})
// Upgrade every Rule in `@layer utilities` to an `@utility` at-rule.
@ -157,10 +156,7 @@ export function migrateAtLayerUtilities(): Plugin {
}
})
})
// Update the selector
node.selector = selectors.toString()
}).processSync(node.selector)
}).processSync(node, { updateSelector: true })
// Cleanup all the nodes that should not be part of the `@utility` rule.
if (!containsClass) {