migrateTheme() — tailwindcss Function Reference
Architecture documentation for the migrateTheme() function in migrate-js-config.ts from the tailwindcss codebase.
Entity Profile
Dependency Diagram
graph TD 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19["migrateTheme()"] 8d0812d4_61e4_e939_916d_a33e94faf43f["migrateJsConfig()"] 8d0812d4_61e4_e939_916d_a33e94faf43f -->|calls| 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 6b5865d6_780d_1bbb_5df1_7ecca0e9b1a1["resolveConfig()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| 6b5865d6_780d_1bbb_5df1_7ecca0e9b1a1 abaa1198_ca17_6d7e_fe6d_a70c79ad1e3f["removeUnnecessarySpacingKeys()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| abaa1198_ca17_6d7e_fe6d_a70c79ad1e3f f7274245_f1a4_d8b1_30d8_a1497768c1d4["keyframesToCss()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| f7274245_f1a4_d8b1_30d8_a1497768c1d4 6e906b7f_b503_9163_425a_c68220491669["buildCustomContainerUtilityRules()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| 6e906b7f_b503_9163_425a_c68220491669 c35acfc6_964d_737e_6ecc_275e6f10293a["atRule()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| c35acfc6_964d_737e_6ecc_275e6f10293a e5eb2faf_45a2_ac47_3404_8bd4e7eb6817["parse()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| e5eb2faf_45a2_ac47_3404_8bd4e7eb6817 3e33c90a_e618_0b36_8589_88cf333c1482["themeableValues()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| 3e33c90a_e618_0b36_8589_88cf333c1482 3962ad41_d147_715e_98ef_72bf2be093d9["isValidOpacityValue()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| 3962ad41_d147_715e_98ef_72bf2be093d9 585e2570_70ea_9c34_2ea1_950e5cc89977["createSectionKey()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| 585e2570_70ea_9c34_2ea1_950e5cc89977 f8dcf272_aab9_d786_7975_56fd563c0739["keyPathToCssProperty()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| f8dcf272_aab9_d786_7975_56fd563c0739 7cf1fe2b_69a4_05dc_ae13_d3eebe4e10fc["escape()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| 7cf1fe2b_69a4_05dc_ae13_d3eebe4e10fc e7a34553_0273_6202_4792_07409e33d8f0["toCss()"] 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 -->|calls| e7a34553_0273_6202_4792_07409e33d8f0 style 77d1d37f_6021_dc8c_6d04_0c3b07e3ad19 fill:#6366f1,stroke:#818cf8,color:#fff
Relationship Graph
Source Code
packages/@tailwindcss-upgrade/src/codemods/config/migrate-js-config.ts lines 97–290
async function migrateTheme(
designSystem: DesignSystem,
unresolvedConfig: Config,
base: string,
): Promise<string> {
// Resolve the config file without applying plugins and presets, as these are
// migrated to CSS separately.
let configToResolve: ConfigFile = {
base,
config: { ...unresolvedConfig, plugins: [], presets: undefined },
reference: false,
src: undefined,
}
let { resolvedConfig, replacedThemeKeys } = resolveConfig(designSystem, [configToResolve])
let resetNamespaces = new Map<string, boolean>(
Array.from(replacedThemeKeys.entries()).map(([key]) => [key, false]),
)
removeUnnecessarySpacingKeys(designSystem, resolvedConfig, replacedThemeKeys)
let css = ''
let prevSectionKey = ''
let themeSection: string[] = []
let keyframesCss = ''
let variants = new Map<string, string>()
// Special handling of specific theme keys:
{
if ('keyframes' in resolvedConfig.theme) {
keyframesCss += keyframesToCss(resolvedConfig.theme.keyframes)
delete resolvedConfig.theme.keyframes
}
if ('container' in resolvedConfig.theme) {
let rules = buildCustomContainerUtilityRules(resolvedConfig.theme.container, designSystem)
if (rules.length > 0) {
// Using `theme` instead of `utility` so it sits before the `@layer
// base` with compatibility CSS. While this is technically a utility, it
// makes a bit more sense to emit this closer to the `@theme` values
// since it is needed for backwards compatibility.
css += `\n@tw-bucket theme {\n`
css += toCss([atRule('@utility', 'container', rules)])
css += '}\n' // @tw-bucket
}
delete resolvedConfig.theme.container
}
if ('aria' in resolvedConfig.theme) {
for (let [key, value] of Object.entries(resolvedConfig.theme.aria ?? {})) {
// Will be handled by bare values if the names match.
// E.g.: `aria-foo:flex` should produce `[aria-foo="true"]`
if (new RegExp(`^${key}=(['"]?)true\\1$`).test(`${value}`)) continue
// Create custom variant
variants.set(`aria-${key}`, `&[aria-${value}]`)
}
delete resolvedConfig.theme.aria
}
if ('data' in resolvedConfig.theme) {
for (let [key, value] of Object.entries(resolvedConfig.theme.data ?? {})) {
// Will be handled by bare values if the names match.
// E.g.: `data-foo:flex` should produce `[data-foo]`
if (key === value) continue
// Create custom variant
variants.set(`data-${key}`, `&[data-${value}]`)
}
delete resolvedConfig.theme.data
}
if ('supports' in resolvedConfig.theme) {
for (let [key, value] of Object.entries(resolvedConfig.theme.supports ?? {})) {
// Will be handled by bare values if the value of the declaration is a
// CSS variable.
let parsed = ValueParser.parse(`${value}`)
// Unwrap the parens, e.g.: `(foo: var(--bar))` → `foo: var(--bar)`
if (parsed.length === 1 && parsed[0].kind === 'function' && parsed[0].value === '') {
parsed = parsed[0].nodes
}
// Verify structure: `foo: var(--bar)`
// ^^^ ← must match the `key`
if (
parsed.length === 3 &&
parsed[0].kind === 'word' &&
parsed[0].value === key &&
parsed[2].kind === 'function' &&
parsed[2].value === 'var'
) {
continue
}
// Create custom variant
variants.set(`supports-${key}`, `{@supports(${value}){@slot;}}`)
}
delete resolvedConfig.theme.supports
}
}
// Convert theme values to CSS custom properties
for (let [key, value] of themeableValues(resolvedConfig.theme)) {
if (typeof value !== 'string' && typeof value !== 'number') {
continue
}
if (typeof value === 'string') {
// This is more advanced than the version in core as ideally something
// like `rgba(0 0 0 / <alpha-value>)` becomes `rgba(0 0 0)`. Since we know
// from the `/` that it's used in an alpha channel and we can remove it.
//
// In other cases we may not know exactly how its used, so we'll just
// replace it with `1` like core does.
value = value.replace(/\s*\/\s*<alpha-value>/, '').replace(/<alpha-value>/, '1')
}
// Convert `opacity` namespace from decimal to percentage values.
// Additionally we can drop values that resolve to the same value as the
// named modifier with the same name.
if (key[0] === 'opacity' && (typeof value === 'number' || typeof value === 'string')) {
let numValue = typeof value === 'string' ? parseFloat(value) : value
if (numValue >= 0 && numValue <= 1) {
value = numValue * 100 + '%'
}
if (
typeof value === 'string' &&
key[1] === value.replace(/%$/, '') &&
isValidOpacityValue(key[1])
) {
continue
}
}
let sectionKey = createSectionKey(key)
if (sectionKey !== prevSectionKey) {
themeSection.push('')
prevSectionKey = sectionKey
}
let property = keyPathToCssProperty(key)
if (property !== null) {
if (
!property.startsWith('default-') &&
resetNamespaces.has(key[0]) &&
resetNamespaces.get(key[0]) === false
) {
resetNamespaces.set(key[0], true)
let ns = keyPathToCssProperty([key[0]])
if (ns !== null) {
themeSection.push(` ${escape(`--${ns}`)}-*: initial;`)
}
}
themeSection.push(` ${escape(`--${property}`)}: ${value};`)
}
}
if (keyframesCss) {
themeSection.push('', keyframesCss)
}
if (themeSection.length > 0) {
css += `\n@tw-bucket theme {\n`
css += `\n@theme {\n`
css += themeSection.join('\n') + '\n'
css += '}\n' // @theme
css += '}\n' // @tw-bucket
}
if (variants.size > 0) {
css += '\n@tw-bucket custom-variant {\n'
let previousRoot = ''
for (let [name, selector] of variants) {
let root = name.split('-')[0]
if (previousRoot !== root) css += '\n'
previousRoot = root
if (selector.startsWith('{')) {
css += `@custom-variant ${name} ${selector}\n`
} else {
css += `@custom-variant ${name} (${selector});\n`
}
}
css += '}\n'
}
return css
}
Domain
Subdomains
Calls
Called By
Source
Frequently Asked Questions
What does migrateTheme() do?
migrateTheme() is a function in the tailwindcss codebase.
What does migrateTheme() call?
migrateTheme() calls 12 function(s): atRule, buildCustomContainerUtilityRules, createSectionKey, escape, isValidOpacityValue, keyPathToCssProperty, keyframesToCss, parse, and 4 more.
What calls migrateTheme()?
migrateTheme() is called by 1 function(s): migrateJsConfig.
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free