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

196 lines
5.1 KiB
TypeScript
Raw Normal View History

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
#!/usr/bin/env node
import { globby } from 'globby'
import fs from 'node:fs/promises'
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 path from 'node:path'
import postcss from 'postcss'
import { formatNodes } from './codemods/format-nodes'
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 { help } from './commands/help'
import {
analyze as analyzeStylesheets,
migrate as migrateStylesheet,
split as splitStylesheets,
} from './migrate'
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
import { migrateJsConfig } from './migrate-js-config'
import { migratePostCSSConfig } from './migrate-postcss'
import { Stylesheet } from './stylesheet'
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
import { migrate as migrateTemplate } from './template/migrate'
import { prepareConfig } from './template/prepare-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
import { args, type Arg } from './utils/args'
import { isRepoDirty } from './utils/git'
import { pkg } from './utils/packages'
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 { eprintln, error, header, highlight, info, success } from './utils/renderer'
const options = {
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
'--config': { type: 'string', description: 'Path to the configuration file', alias: '-c' },
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
'--help': { type: 'boolean', description: 'Display usage information', alias: '-h' },
'--force': { type: 'boolean', description: 'Force the migration', alias: '-f' },
'--version': { type: 'boolean', description: 'Display the version number', alias: '-v' },
} satisfies Arg
const flags = args(options)
if (flags['--help']) {
help({
usage: ['npx @tailwindcss/upgrade'],
options,
})
process.exit(0)
}
async function run() {
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
let base = process.cwd()
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
eprintln(header())
eprintln()
if (!flags['--force']) {
if (isRepoDirty()) {
error('Git directory is not clean. Please stash or commit your changes before migrating.')
info(
`You may use the ${highlight('--force')} flag to silence this warning and perform the migration.`,
)
process.exit(1)
}
}
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
let config = await prepareConfig(flags['--config'], { base })
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
{
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
// Template migrations
info('Migrating templates using the provided configuration file.')
let set = new Set<string>()
for (let { pattern, base } of config.globs) {
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
let files = await globby([pattern], {
absolute: true,
gitignore: true,
cwd: base,
})
for (let file of files) {
set.add(file)
}
}
let files = Array.from(set)
files.sort()
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
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
// Migrate each file
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
await Promise.allSettled(
files.map((file) => migrateTemplate(config.designSystem, config.userConfig, file)),
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
)
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
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
success('Template migration complete.')
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
}
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
// Migrate JS config
info('Migrating JavaScript configuration files using the provided configuration file.')
let jsConfigMigration = await migrateJsConfig(config.designSystem, config.configFilePath, base)
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
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
{
// Stylesheet migrations
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
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
// Use provided files
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
let files = flags._.map((file) => path.resolve(base, file))
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
// Discover CSS files in case no files were provided
if (files.length === 0) {
info(
'No input stylesheets provided. Searching for CSS files in the current directory and its subdirectories…',
)
files = await globby(['**/*.css'], {
absolute: true,
gitignore: true,
})
}
// Ensure we are only dealing with CSS files
files = files.filter((file) => file.endsWith('.css'))
// Analyze the stylesheets
let loadResults = await Promise.allSettled(files.map((filepath) => Stylesheet.load(filepath)))
// Load and parse all stylesheets
for (let result of loadResults) {
if (result.status === 'rejected') {
error(`${result.reason}`)
}
}
let stylesheets = loadResults
.filter((result) => result.status === 'fulfilled')
.map((result) => result.value)
// Analyze the stylesheets
try {
await analyzeStylesheets(stylesheets)
} catch (e: unknown) {
error(`${e}`)
}
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
// Migrate each file
let migrateResults = await Promise.allSettled(
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
stylesheets.map((sheet) => migrateStylesheet(sheet, { ...config, jsConfigMigration })),
)
for (let result of migrateResults) {
if (result.status === 'rejected') {
error(`${result.reason}`)
}
}
// Split up stylesheets (as needed)
try {
await splitStylesheets(stylesheets)
} catch (e: unknown) {
error(`${e}`)
}
// Format nodes
for (let sheet of stylesheets) {
await postcss([formatNodes()]).process(sheet.root!, { from: sheet.file! })
}
// Write all files to disk
for (let sheet of stylesheets) {
if (!sheet.file) continue
await fs.writeFile(sheet.file, sheet.root.toString())
}
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
success('Stylesheet migration complete.')
}
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
{
// PostCSS config migration
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
await migratePostCSSConfig(base)
}
try {
// Upgrade Tailwind CSS
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
await pkg('add tailwindcss@next', base)
} catch {}
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
// Remove the JS config if it was fully migrated
if (jsConfigMigration !== null) {
await fs.rm(config.configFilePath)
}
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
// Figure out if we made any changes
if (isRepoDirty()) {
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
success('Verify the changes and commit them to your repository.')
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
} else {
Add setup for template migrations (#14502) This PR adds the initial setup and a first codemod for the template migrations. These are a new set of migrations that operate on files defined in the Tailwind v3 config as part of the `content` option (so your HTML, JavaScript, TSX files etc.). The migration for this is integrated in the new `@tailwindcss/upgrade` package and will require pointing the migration to an input JavaScript config file, like this: ``` npx @tailwindcss/upgrade --config tailwind.config.js ``` The idea of template migrations is to apply breaking changes from the v3 to v4 migration within your template files. ## Migrating !important syntax The first migration that I’m adding with this PR is to ensure we use the v4 important syntax that has the exclamation mark at the end of the utility. For example, this: ```html <div class="!flex sm:!block"></div> ``` Will now turn into: ```html <div class="flex! sm:block!"></div> ``` ## Architecture considerations Implementation wise, we make use of Oxide to scan the content files fast and efficiently. By relying on the same scanner als Tailwind v4, we guarantee that all candidates that are part of the v4 output will have gone through a migration. Migrations itself operate on the abstract `Candidate` type, similar to the type we use in the v4 codebase. It will parse the candidate into its parts so they can easily be introspected/modified. Migrations are typed as: ```ts type TemplateMigration = (candidate: Candidate) => Candidate | null ``` `null` should be returned if the `Candidate` does not need a migration. We currently use the v4 `parseCandidate` function to get an abstract definition of the candidate rule that we can operate on. _This will likely need to change in the future as we need to fork `parseCandidate` for v3 specific syntax_. Additionally, we're inlining a `printCandidate` function that can stringify the abstract `Candidate` type. It is not guaranteed that this is an identity function since some information can be lost during the parse step. This is not a problem though, because migrations will only run selectively and if none of the selectors trigger, the candidates are not updated. h/t to @RobinMalfait for providing the printer. So the overall flow of a migration looks like this: - Scan the config file for `content` files - Use Oxide to extract a list of candidate and their positions from these `content` files - Run a few migrations that operate on the `Candidate` abstract type. - Print the updated `Candidate` back into the original `content` file. --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-25 16:20:14 +02:00
success('No changes were made to your repository.')
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
}
}
run()
.then(() => process.exit(0))
.catch((err) => {
console.error(err)
process.exit(1)
})