tailwindcss/packages/@tailwindcss-upgrade/src/codemods
Robin Malfait 4f8ca556cf
CSS codemod: inject @import in a more expected location (#14536)
This PR inserts the `@import` in a more sensible location when running
codemods.

The idea is that we replace `@tailwind base; @tailwind components;
@tailwind utilities;` with the much simple `@import "tailwindcss";`. We
did this by adding the `@import` to the top of the file.

While this is correct, this means that the diff might not be as clear.
For example, if you have a situation where you have a license comment:
```css
/**! My license comment */
@tailwind base;
@tailwind components;
@tailwind utilities;
```

This resulted in:
```css
@import "tailwindcss";
/**! My license comment */
```

While it is not wrong, it feels weird that this behaves like this. In
this commit we make sure that it is injected in-place (the first
`@tailwind` at-rule we find) and fixup the position if we can't inject
it in-place.

The above example results in this:
```css
/**! My license comment */
@import "tailwindcss";
```

However, there are scenario's where you can't replace the `@tailwind`
directives directly. E.g.:
```css
/**! My license comment */
html {
  color: red;
}
@tailwind base;
@tailwind components;
@tailwind utilities;
```

If we replace the `@tailwind` directives in-place, it would look like
this:
```css
/**! My license comment */
html {
  color: red;
}
@import "tailwindcss";
```

But this is invalid CSS, because you can't have CSS above an `@import`
at-rule. There are some exceptions like:
- `@charset`
- `@import`
- `@layer foo, bar;` (just the order, without a body)
- comments

In this scenario, we inject the import in the nearest place where it is
allowed to. In this case:

```css
/**! My license comment */
@import "tailwindcss";
@layer base {
  html {
     color: red;
  }
}
```

Additionally, we will wrap the existing CSS in an `@layer` of the first
Tailwind directive we saw. In this case an `@layer base`. This ensures
that utilities still win from the default styles.

Also note that the (license) comment is allowed to exist before the
`@import`, therefore we do not put the `@import` above it. This also
means that the diff doesn't touch the license header at all, which makes
the diffs cleaner and easier to reason about.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2024-09-30 13:32:30 +00:00
..
format-nodes.test.ts Add CSS codemod for missing @layer (#14504) 2024-09-24 16:32:50 +00:00
format-nodes.ts Add CSS codemod for missing @layer (#14504) 2024-09-24 16:32:50 +00:00
migrate-at-apply.test.ts Add initial codemod tooling (#14434) 2024-09-18 16:45:43 +02:00
migrate-at-apply.ts Add CSS codemod for missing @layer (#14504) 2024-09-24 16:32:50 +00:00
migrate-at-layer-utilities.test.ts CSS codemod: ensure we don't lose selectors (#14518) 2024-09-25 18:39:00 +02:00
migrate-at-layer-utilities.ts CSS codemod: ensure we don't lose selectors (#14518) 2024-09-25 18:39:00 +02:00
migrate-missing-layers.test.ts CSS codemod: inject @import in a more expected location (#14536) 2024-09-30 13:32:30 +00:00
migrate-missing-layers.ts CSS codemod: inject @import in a more expected location (#14536) 2024-09-30 13:32:30 +00:00
migrate-tailwind-directives.test.ts CSS codemod: inject @import in a more expected location (#14536) 2024-09-30 13:32:30 +00:00
migrate-tailwind-directives.ts CSS codemod: inject @import in a more expected location (#14536) 2024-09-30 13:32:30 +00:00