tailwindcss/packages/@tailwindcss-upgrade/src/index.test.ts

312 lines
7 KiB
TypeScript
Raw Normal View History

import { __unstable__loadDesignSystem } from '@tailwindcss/node'
Add initial codemod tooling (#14434) This PR adds some initial tooling for codemods. We are currently only interested in migrating CSS files, so we will be using PostCSS under the hood to do this. This PR also implements the "migrate `@apply`" codemod from #14412. The usage will look like this: ```sh npx @tailwindcss/upgrade ``` You can pass in CSS files to transform as arguments: ```sh npx @tailwindcss/upgrade src/**/*.css ``` But, if none are provided, it will search for CSS files in the current directory and its subdirectories. ``` ≈ tailwindcss v4.0.0-alpha.24 │ No files provided. Searching for CSS files in the current │ directory and its subdirectories… │ Migration complete. Verify the changes and commit them to │ your repository. ``` The tooling also requires the Git repository to be in a clean state. This is a common convention to ensure that everything is undo-able. If we detect that the git repository is dirty, we will abort the migration. ``` ≈ tailwindcss v4.0.0-alpha.24 │ Git directory is not clean. Please stash or commit your │ changes before migrating. │ You may use the `--force` flag to override this safety │ check. ``` --- This PR alsoo adds CSS codemods for migrating existing `@apply` directives to the new version. This PR has the ability to migrate the following cases: --- In v4, the convention is to put the important modifier `!` at the end of the utility class instead of right before it. This makes it easier to reason about, especially when you are variants. Input: ```css .foo { @apply !flex flex-col! hover:!items-start items-center; } ``` Output: ```css .foo { @apply flex! flex-col! hover:items-start! items-center; } ``` --- In v4 we don't support `!important` as a marker at the end of `@apply` directives. Instead, you can append the `!` to each utility class to make it `!important`. Input: ```css .foo { @apply flex flex-col !important; } ``` Output: ```css .foo { @apply flex! flex-col!; } ```
2024-09-18 16:45:43 +02:00
import dedent from 'dedent'
import path from 'node:path'
import postcss from 'postcss'
Add initial codemod tooling (#14434) This PR adds some initial tooling for codemods. We are currently only interested in migrating CSS files, so we will be using PostCSS under the hood to do this. This PR also implements the "migrate `@apply`" codemod from #14412. The usage will look like this: ```sh npx @tailwindcss/upgrade ``` You can pass in CSS files to transform as arguments: ```sh npx @tailwindcss/upgrade src/**/*.css ``` But, if none are provided, it will search for CSS files in the current directory and its subdirectories. ``` ≈ tailwindcss v4.0.0-alpha.24 │ No files provided. Searching for CSS files in the current │ directory and its subdirectories… │ Migration complete. Verify the changes and commit them to │ your repository. ``` The tooling also requires the Git repository to be in a clean state. This is a common convention to ensure that everything is undo-able. If we detect that the git repository is dirty, we will abort the migration. ``` ≈ tailwindcss v4.0.0-alpha.24 │ Git directory is not clean. Please stash or commit your │ changes before migrating. │ You may use the `--force` flag to override this safety │ check. ``` --- This PR alsoo adds CSS codemods for migrating existing `@apply` directives to the new version. This PR has the ability to migrate the following cases: --- In v4, the convention is to put the important modifier `!` at the end of the utility class instead of right before it. This makes it easier to reason about, especially when you are variants. Input: ```css .foo { @apply !flex flex-col! hover:!items-start items-center; } ``` Output: ```css .foo { @apply flex! flex-col! hover:items-start! items-center; } ``` --- In v4 we don't support `!important` as a marker at the end of `@apply` directives. Instead, you can append the `!` to each utility class to make it `!important`. Input: ```css .foo { @apply flex flex-col !important; } ``` Output: ```css .foo { @apply flex! flex-col!; } ```
2024-09-18 16:45:43 +02:00
import { expect, it } from 'vitest'
import { formatNodes } from './codemods/format-nodes'
import { sortBuckets } from './codemods/sort-buckets'
Add initial codemod tooling (#14434) This PR adds some initial tooling for codemods. We are currently only interested in migrating CSS files, so we will be using PostCSS under the hood to do this. This PR also implements the "migrate `@apply`" codemod from #14412. The usage will look like this: ```sh npx @tailwindcss/upgrade ``` You can pass in CSS files to transform as arguments: ```sh npx @tailwindcss/upgrade src/**/*.css ``` But, if none are provided, it will search for CSS files in the current directory and its subdirectories. ``` ≈ tailwindcss v4.0.0-alpha.24 │ No files provided. Searching for CSS files in the current │ directory and its subdirectories… │ Migration complete. Verify the changes and commit them to │ your repository. ``` The tooling also requires the Git repository to be in a clean state. This is a common convention to ensure that everything is undo-able. If we detect that the git repository is dirty, we will abort the migration. ``` ≈ tailwindcss v4.0.0-alpha.24 │ Git directory is not clean. Please stash or commit your │ changes before migrating. │ You may use the `--force` flag to override this safety │ check. ``` --- This PR alsoo adds CSS codemods for migrating existing `@apply` directives to the new version. This PR has the ability to migrate the following cases: --- In v4, the convention is to put the important modifier `!` at the end of the utility class instead of right before it. This makes it easier to reason about, especially when you are variants. Input: ```css .foo { @apply !flex flex-col! hover:!items-start items-center; } ``` Output: ```css .foo { @apply flex! flex-col! hover:items-start! items-center; } ``` --- In v4 we don't support `!important` as a marker at the end of `@apply` directives. Instead, you can append the `!` to each utility class to make it `!important`. Input: ```css .foo { @apply flex flex-col !important; } ``` Output: ```css .foo { @apply flex! flex-col!; } ```
2024-09-18 16:45:43 +02:00
import { migrateContents } from './migrate'
const css = dedent
let designSystem = await __unstable__loadDesignSystem(
css`
@import 'tailwindcss';
`,
{ base: __dirname },
)
let config = {
designSystem,
userConfig: {},
newPrefix: null,
configFilePath: path.resolve(__dirname, './tailwind.config.js'),
Add simple JS config migration (#14639) This PR implements the first version of JS config file migration to CSS. It is based on the most simple config setups we are using in the Tailwind UI templates Commit, Primer, Radiant, and Studio. The example we use in the integration test is a config that looks like this: ```js import { type Config } from 'tailwindcss' import defaultTheme from 'tailwindcss/defaultTheme' module.exports = { darkMode: 'selector', content: ['./src/**/*.{html,js}'], theme: { boxShadow: { sm: '0 2px 6px rgb(15 23 42 / 0.08)', }, colors: { red: { 500: '#ef4444', }, }, fontSize: { xs: ['0.75rem', { lineHeight: '1rem' }], sm: ['0.875rem', { lineHeight: '1.5rem' }], base: ['1rem', { lineHeight: '2rem' }], }, extend: { colors: { red: { 600: '#dc2626', }, }, fontFamily: { sans: 'Inter, system-ui, sans-serif', display: ['Cabinet Grotesk', ...defaultTheme.fontFamily.sans], }, borderRadius: { '4xl': '2rem', }, }, }, plugins: [], } satisfies Config ``` As you can see, this file only has a `darkMode` selector, custom `content` globs, a `theme` (with some theme keys being overwriting the default theme and some others extending the defaults). Note that it does not support `plugins` and/or `presets` yet. In the case above, we will find the CSS file containing the existing `@tailwind` directives and are migrating it to the following: ```css @import 'tailwindcss'; @source './**/*.{html,js}'; @variant dark (&:where(.dark, .dark *)); @theme { --box-shadow-*: initial; --box-shadow-sm: 0 2px 6px rgb(15 23 42 / 0.08); --color-*: initial; --color-red-500: #ef4444; --font-size-*: initial; --font-size-xs: 0.75rem; --font-size-xs--line-height: 1rem; --font-size-sm: 0.875rem; --font-size-sm--line-height: 1.5rem; --font-size-base: 1rem; --font-size-base--line-height: 2rem; --color-red-600: #dc2626; --font-family-sans: Inter, system-ui, sans-serif; --font-family-display: Cabinet Grotesk, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; --border-radius-4xl: 2rem; } ``` This replicates all features of the JS config so we can even delete the existing JS config in this case. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-10-11 15:27:53 +02:00
jsConfigMigration: null,
}
function migrate(input: string, config: any) {
return migrateContents(input, config, expect.getState().testPath)
.then((result) => postcss([sortBuckets(), formatNodes()]).process(result.root, result.opts))
.then((result) => result.css)
}
Add initial codemod tooling (#14434) This PR adds some initial tooling for codemods. We are currently only interested in migrating CSS files, so we will be using PostCSS under the hood to do this. This PR also implements the "migrate `@apply`" codemod from #14412. The usage will look like this: ```sh npx @tailwindcss/upgrade ``` You can pass in CSS files to transform as arguments: ```sh npx @tailwindcss/upgrade src/**/*.css ``` But, if none are provided, it will search for CSS files in the current directory and its subdirectories. ``` ≈ tailwindcss v4.0.0-alpha.24 │ No files provided. Searching for CSS files in the current │ directory and its subdirectories… │ Migration complete. Verify the changes and commit them to │ your repository. ``` The tooling also requires the Git repository to be in a clean state. This is a common convention to ensure that everything is undo-able. If we detect that the git repository is dirty, we will abort the migration. ``` ≈ tailwindcss v4.0.0-alpha.24 │ Git directory is not clean. Please stash or commit your │ changes before migrating. │ You may use the `--force` flag to override this safety │ check. ``` --- This PR alsoo adds CSS codemods for migrating existing `@apply` directives to the new version. This PR has the ability to migrate the following cases: --- In v4, the convention is to put the important modifier `!` at the end of the utility class instead of right before it. This makes it easier to reason about, especially when you are variants. Input: ```css .foo { @apply !flex flex-col! hover:!items-start items-center; } ``` Output: ```css .foo { @apply flex! flex-col! hover:items-start! items-center; } ``` --- In v4 we don't support `!important` as a marker at the end of `@apply` directives. Instead, you can append the `!` to each utility class to make it `!important`. Input: ```css .foo { @apply flex flex-col !important; } ``` Output: ```css .foo { @apply flex! flex-col!; } ```
2024-09-18 16:45:43 +02:00
it('should print the input as-is', async () => {
expect(
await migrate(
Add initial codemod tooling (#14434) This PR adds some initial tooling for codemods. We are currently only interested in migrating CSS files, so we will be using PostCSS under the hood to do this. This PR also implements the "migrate `@apply`" codemod from #14412. The usage will look like this: ```sh npx @tailwindcss/upgrade ``` You can pass in CSS files to transform as arguments: ```sh npx @tailwindcss/upgrade src/**/*.css ``` But, if none are provided, it will search for CSS files in the current directory and its subdirectories. ``` ≈ tailwindcss v4.0.0-alpha.24 │ No files provided. Searching for CSS files in the current │ directory and its subdirectories… │ Migration complete. Verify the changes and commit them to │ your repository. ``` The tooling also requires the Git repository to be in a clean state. This is a common convention to ensure that everything is undo-able. If we detect that the git repository is dirty, we will abort the migration. ``` ≈ tailwindcss v4.0.0-alpha.24 │ Git directory is not clean. Please stash or commit your │ changes before migrating. │ You may use the `--force` flag to override this safety │ check. ``` --- This PR alsoo adds CSS codemods for migrating existing `@apply` directives to the new version. This PR has the ability to migrate the following cases: --- In v4, the convention is to put the important modifier `!` at the end of the utility class instead of right before it. This makes it easier to reason about, especially when you are variants. Input: ```css .foo { @apply !flex flex-col! hover:!items-start items-center; } ``` Output: ```css .foo { @apply flex! flex-col! hover:items-start! items-center; } ``` --- In v4 we don't support `!important` as a marker at the end of `@apply` directives. Instead, you can append the `!` to each utility class to make it `!important`. Input: ```css .foo { @apply flex flex-col !important; } ``` Output: ```css .foo { @apply flex! flex-col!; } ```
2024-09-18 16:45:43 +02:00
css`
/* above */
.foo/* after */ {
/* above */
color: /* before */ red /* after */;
/* below */
}
`,
config,
Add initial codemod tooling (#14434) This PR adds some initial tooling for codemods. We are currently only interested in migrating CSS files, so we will be using PostCSS under the hood to do this. This PR also implements the "migrate `@apply`" codemod from #14412. The usage will look like this: ```sh npx @tailwindcss/upgrade ``` You can pass in CSS files to transform as arguments: ```sh npx @tailwindcss/upgrade src/**/*.css ``` But, if none are provided, it will search for CSS files in the current directory and its subdirectories. ``` ≈ tailwindcss v4.0.0-alpha.24 │ No files provided. Searching for CSS files in the current │ directory and its subdirectories… │ Migration complete. Verify the changes and commit them to │ your repository. ``` The tooling also requires the Git repository to be in a clean state. This is a common convention to ensure that everything is undo-able. If we detect that the git repository is dirty, we will abort the migration. ``` ≈ tailwindcss v4.0.0-alpha.24 │ Git directory is not clean. Please stash or commit your │ changes before migrating. │ You may use the `--force` flag to override this safety │ check. ``` --- This PR alsoo adds CSS codemods for migrating existing `@apply` directives to the new version. This PR has the ability to migrate the following cases: --- In v4, the convention is to put the important modifier `!` at the end of the utility class instead of right before it. This makes it easier to reason about, especially when you are variants. Input: ```css .foo { @apply !flex flex-col! hover:!items-start items-center; } ``` Output: ```css .foo { @apply flex! flex-col! hover:items-start! items-center; } ``` --- In v4 we don't support `!important` as a marker at the end of `@apply` directives. Instead, you can append the `!` to each utility class to make it `!important`. Input: ```css .foo { @apply flex flex-col !important; } ``` Output: ```css .foo { @apply flex! flex-col!; } ```
2024-09-18 16:45:43 +02:00
),
).toMatchInlineSnapshot(`
"/* above */
.foo/* after */ {
/* above */
color: /* before */ red /* after */;
/* below */
}"
`)
})
it('should migrate a stylesheet', async () => {
expect(
await migrate(
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
css`
@tailwind base;
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
html {
overflow: hidden;
}
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
@tailwind components;
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
.a {
z-index: 1;
}
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
@layer components {
.b {
z-index: 2;
}
}
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
.c {
z-index: 3;
}
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
@tailwind utilities;
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
.d {
z-index: 4;
}
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
@layer utilities {
.e {
z-index: 5;
}
}
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
`,
config,
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
),
).toMatchInlineSnapshot(`
"@import 'tailwindcss';
/*
The default border color has changed to \`currentColor\` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
/*
Form elements have a 1px border by default in Tailwind CSS v4, so we've
added these compatibility styles to make sure everything still looks the
same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add \`border-0\` to
any form elements that shouldn't have a border.
*/
@layer base {
input:where(:not([type='button'], [type='reset'], [type='submit'])),
select,
textarea {
border-width: 0;
}
}
@utility b {
z-index: 2;
}
@utility e {
z-index: 5;
}
@layer base {
html {
overflow: hidden;
}
}
@layer components {
.a {
z-index: 1;
}
}
@layer components {
.c {
z-index: 3;
}
}
@layer utilities {
.d {
z-index: 4;
}
}"
`)
})
it('should migrate a stylesheet (with imports)', async () => {
expect(
await migrate(
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
css`
@import 'tailwindcss/base';
@import './my-base.css';
@import 'tailwindcss/components';
@import './my-components.css';
@import 'tailwindcss/utilities';
@import './my-utilities.css';
`,
config,
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
),
).toMatchInlineSnapshot(`
"@import 'tailwindcss';
@import './my-base.css' layer(base);
@import './my-components.css' layer(components);
@import './my-utilities.css' layer(utilities);
/*
The default border color has changed to \`currentColor\` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
/*
Form elements have a 1px border by default in Tailwind CSS v4, so we've
added these compatibility styles to make sure everything still looks the
same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add \`border-0\` to
any form elements that shouldn't have a border.
*/
@layer base {
input:where(:not([type='button'], [type='reset'], [type='submit'])),
select,
textarea {
border-width: 0;
}
}"
`)
})
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 15:32:30 +02:00
it('should migrate a stylesheet (with preceding rules that should be wrapped in an `@layer`)', async () => {
expect(
await migrate(
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
css`
@charset "UTF-8";
@layer foo, bar, baz;
/**! My license comment */
html {
color: red;
}
@tailwind base;
@tailwind components;
@tailwind utilities;
`,
config,
Template migrations: Migrate v3 prefixes to v4 (#14557) This PR adds a new migration that can migrate Tailwind CSS v3 style prefixes into Tailwind CSS v4. The migration is split into three separate pieces of work: 1. Firstly, we need to read the full JavaScript config to get the _old_ prefix option. This is necessary because in v4, we will not allow things like custom-separators for the prefix. From this option we will then try and compute a new prefix (in 90% of the cases this is going to just remove the trailing `-` but it can also work in more complex cases). 2. Then we migrate all Candidates. The important thing here is that we need to operate on the raw candidate string because by relying on `parseCandidate` (which we do for all other migrations) would not work, as the candidates are not valid in v4 syntax. More on that in a bit. 3. Lastly we also make sure to update the CSS config to include the new prefix. This is done by prepending the prefix option like so: ```css @import "tailwindcss" prefix(tw); ``` ### Migrating candidates The main difference between v3 prefixes and v4 prefixes is that in v3, the prefix was _part of the utility_ where as in v4 it is _always in front of the CSS class. So, for example, this candidate in v3: ``` hover:-tw-mr-4 ``` Would be converted to the following in v4: ``` tw:hover:-mr-4 ``` Since the first example _won't parse as a valid Candidate in v4, as the `tw-mr` utility does not exist, we have to operate on the raw candidate string first. To do this I created a fork of the `parseCandidate` function _without any validation of utilities or variants_. This is used to identify part of the candidate that is the `base` and then ensuring the `base` starts with the old prefix. We then remove this to create an "unprefixed" candidate that we validate against a version of the DesignSystem _with no prefixes configured_. If the variant is valid this way, we can then print it again with the `DesignSystem` that has the new prefix to get the migrated version. Since we set up the `DesignSystem` to include the new prefix, we can also be certain that migrations that happen afterwards would still disqualify candidates that aren't valid according to the new prefix policy. This does mean we need to have the prefix fixup be the first step in our pipeline. One interesting bit is that in v3, arbitrary properties did not require prefixes where as in v4 they do. So the following candidate: ``` [color:red] ``` Will be converted to: ``` tw:[color:red] ```
2024-10-01 18:04:08 +02:00
),
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 15:32:30 +02:00
).toMatchInlineSnapshot(`
"@charset "UTF-8";
@layer foo, bar, baz;
/**! My license comment */
@import 'tailwindcss';
/*
The default border color has changed to \`currentColor\` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
/*
Form elements have a 1px border by default in Tailwind CSS v4, so we've
added these compatibility styles to make sure everything still looks the
same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add \`border-0\` to
any form elements that shouldn't have a border.
*/
@layer base {
input:where(:not([type='button'], [type='reset'], [type='submit'])),
select,
textarea {
border-width: 0;
}
}
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 15:32:30 +02:00
@layer base {
html {
color: red;
}
}"
`)
})
it('should keep CSS as-is before existing `@layer` at-rules', async () => {
expect(
await migrate(
css`
.foo {
color: blue;
}
@layer components {
.bar {
color: red;
}
}
`,
config,
),
).toMatchInlineSnapshot(`
"@utility bar {
color: red;
}
.foo {
color: blue;
}"
`)
})