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 0e91912d_5423_6991_60b0_8afbca30e459["migrateTheme()"] dc1d7e71_14d1_dd51_5d14_8265f9e59cce["migrateJsConfig()"] dc1d7e71_14d1_dd51_5d14_8265f9e59cce -->|calls| 0e91912d_5423_6991_60b0_8afbca30e459 678b66f4_0a04_0d6e_1925_b3716614324d["resolveConfig()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| 678b66f4_0a04_0d6e_1925_b3716614324d c8623640_b79b_0216_79ed_a099482fb629["removeUnnecessarySpacingKeys()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| c8623640_b79b_0216_79ed_a099482fb629 d4865106_45da_0461_2954_69ab7533f3ba["keyframesToCss()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| d4865106_45da_0461_2954_69ab7533f3ba f9776eb1_2e39_1c04_0c09_5a1f1eec4204["buildCustomContainerUtilityRules()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| f9776eb1_2e39_1c04_0c09_5a1f1eec4204 a9af385a_fd12_f1d8_7cf0_ccb9b281ca18["atRule()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| a9af385a_fd12_f1d8_7cf0_ccb9b281ca18 0638028e_f2f7_8e77_2f19_1bd2ce4b2d6a["parse()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| 0638028e_f2f7_8e77_2f19_1bd2ce4b2d6a 303b7e7d_33cb_6a63_7591_f61feb3c4e3d["themeableValues()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| 303b7e7d_33cb_6a63_7591_f61feb3c4e3d 93c615c1_689e_1732_75cf_439dd95740f6["isValidOpacityValue()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| 93c615c1_689e_1732_75cf_439dd95740f6 36a174f5_8af8_ad9e_a3e2_7f8dd1ed3d11["createSectionKey()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| 36a174f5_8af8_ad9e_a3e2_7f8dd1ed3d11 971f7bc7_6ac2_a554_ba52_47038ff41b13["keyPathToCssProperty()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| 971f7bc7_6ac2_a554_ba52_47038ff41b13 22e232f7_919c_8490_d3d0_2af2fca034d5["escape()"] 0e91912d_5423_6991_60b0_8afbca30e459 -->|calls| 22e232f7_919c_8490_d3d0_2af2fca034d5 style 0e91912d_5423_6991_60b0_8afbca30e459 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 11 function(s): atRule, buildCustomContainerUtilityRules, createSectionKey, escape, isValidOpacityValue, keyPathToCssProperty, keyframesToCss, parse, and 3 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