From 9b15a5c62e441f3c3edd7d30f32862b525367cc6 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Wed, 16 Oct 2024 18:08:27 +0200 Subject: [PATCH] Don't generate invalid CSS when migrating a complex `screens` config (#14691) Co-authored-by: Robin Malfait --- CHANGELOG.md | 1 + integrations/upgrade/js-config.test.ts | 59 +++++++++++++++++++ .../src/migrate-js-config.ts | 14 ++++- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06c698893..4e47a5bee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure `theme` values defined outside of `extend` in JS configuration files overwrite all existing values for that namespace ([#14672](https://github.com/tailwindlabs/tailwindcss/pull/14672)) - _Upgrade (experimental)_: Speed up template migrations ([#14679](https://github.com/tailwindlabs/tailwindcss/pull/14679)) +- _Upgrade (experimental)_: Don't generate invalid CSS when migrating a complex `screens` config ([#14691](https://github.com/tailwindlabs/tailwindcss/pull/14691)) ## [4.0.0-alpha.27] - 2024-10-15 diff --git a/integrations/upgrade/js-config.test.ts b/integrations/upgrade/js-config.test.ts index 9225da5f8..06904b2a4 100644 --- a/integrations/upgrade/js-config.test.ts +++ b/integrations/upgrade/js-config.test.ts @@ -369,3 +369,62 @@ test( `) }, ) + +test( + `does not upgrade JS config files with non-simple screens object`, + { + fs: { + 'package.json': json` + { + "dependencies": { + "@tailwindcss/upgrade": "workspace:^" + } + } + `, + 'tailwind.config.ts': ts` + import { type Config } from 'tailwindcss' + + export default { + theme: { + screens: { + xl: { min: '1024px', max: '1279px' }, + tall: { raw: '(min-height: 800px)' }, + }, + }, + } satisfies Config + `, + 'src/input.css': css` + @tailwind base; + @tailwind components; + @tailwind utilities; + `, + }, + }, + async ({ exec, fs }) => { + await exec('npx @tailwindcss/upgrade') + + expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` + " + --- src/input.css --- + @import 'tailwindcss'; + @config '../tailwind.config.ts'; + " + `) + + expect(await fs.dumpFiles('tailwind.config.ts')).toMatchInlineSnapshot(` + " + --- tailwind.config.ts --- + import { type Config } from 'tailwindcss' + + export default { + theme: { + screens: { + xl: { min: '1024px', max: '1279px' }, + tall: { raw: '(min-height: 800px)' }, + }, + }, + } satisfies Config + " + `) + }, +) diff --git a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts index 5b4874341..8d6f1baaa 100644 --- a/packages/@tailwindcss-upgrade/src/migrate-js-config.ts +++ b/packages/@tailwindcss-upgrade/src/migrate-js-config.ts @@ -226,9 +226,9 @@ function canMigrateConfig(unresolvedConfig: Config, source: string): boolean { // migrated let theme = unresolvedConfig.theme if (theme && typeof theme === 'object') { - if (theme.extend && !onlyUsesAllowedTopLevelKeys(theme.extend)) return false + if (theme.extend && !onlyAllowedThemeValues(theme.extend)) return false let { extend: _extend, ...themeCopy } = theme - if (!onlyUsesAllowedTopLevelKeys(themeCopy)) return false + if (!onlyAllowedThemeValues(themeCopy)) return false } return true @@ -239,12 +239,20 @@ const DEFAULT_THEME_KEYS = [ // Used by @tailwindcss/container-queries 'containers', ] -function onlyUsesAllowedTopLevelKeys(theme: ThemeConfig): boolean { +function onlyAllowedThemeValues(theme: ThemeConfig): boolean { for (let key of Object.keys(theme)) { if (!DEFAULT_THEME_KEYS.includes(key)) { return false } } + + if ('screens' in theme && typeof theme.screens === 'object' && theme.screens !== null) { + for (let screen of Object.values(theme.screens)) { + if (typeof screen === 'object' && screen !== null && ('max' in screen || 'raw' in screen)) { + return false + } + } + } return true }