Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Allow compiling utilities without considering the design systen’s imp…
…ortant flag
  • Loading branch information
thecrypticace committed Jun 27, 2025
commit 2756659b2e012c43cd86e2eda70623861ca48bc2
28 changes: 23 additions & 5 deletions packages/tailwindcss/src/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
type StyleRule,
} from './ast'
import { type Candidate, type Variant } from './candidate'
import { type DesignSystem } from './design-system'
import { CompileAstFlags, type DesignSystem } from './design-system'
import GLOBAL_PROPERTY_ORDER from './property-order'
import { asColor, type Utility } from './utilities'
import { compare } from './utils/compare'
Expand All @@ -19,7 +19,10 @@ import type { Variants } from './variants'
export function compileCandidates(
rawCandidates: Iterable<string>,
designSystem: DesignSystem,
{ onInvalidCandidate }: { onInvalidCandidate?: (candidate: string) => void } = {},
{
onInvalidCandidate,
respectImportant,
}: { onInvalidCandidate?: (candidate: string) => void; respectImportant?: boolean } = {},
) {
let nodeSorting = new Map<
AstNode,
Expand All @@ -44,14 +47,20 @@ export function compileCandidates(
matches.set(rawCandidate, candidates)
}

let flags = CompileAstFlags.None

if (respectImportant || respectImportant === undefined) {
flags |= CompileAstFlags.RespectImportant
}

let variantOrderMap = designSystem.getVariantOrder()

// Create the AST
for (let [rawCandidate, candidates] of matches) {
let found = false

for (let candidate of candidates) {
let rules = designSystem.compileAstNodes(candidate)
let rules = designSystem.compileAstNodes(candidate, flags)
if (rules.length === 0) continue

found = true
Expand Down Expand Up @@ -119,10 +128,16 @@ export function compileCandidates(
}
}

export function compileAstNodes(candidate: Candidate, designSystem: DesignSystem) {
export function compileAstNodes(
candidate: Candidate,
designSystem: DesignSystem,
flags: CompileAstFlags,
) {
let asts = compileBaseUtility(candidate, designSystem)
if (asts.length === 0) return []

let respectImportant = Boolean(flags & CompileAstFlags.RespectImportant)

let rules: {
node: AstNode
propertySort: {
Expand All @@ -136,7 +151,10 @@ export function compileAstNodes(candidate: Candidate, designSystem: DesignSystem
for (let nodes of asts) {
let propertySort = getPropertySort(nodes)

if (candidate.important || designSystem.important) {
// If the candidate itself is important then we want to always mark
// the utility as important. However, at a design system level we want
// to be able to opt-out when using things like `@apply`
if (candidate.important || (designSystem.important && respectImportant)) {
applyImportant(nodes)
}

Expand Down
53 changes: 31 additions & 22 deletions packages/tailwindcss/src/design-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import { DefaultMap } from './utils/default-map'
import { extractUsedVariables } from './utils/variables'
import { Variants, createVariants } from './variants'

export const enum CompileAstFlags {
None = 0,
RespectImportant = 1 << 0,
}

export type DesignSystem = {
theme: Theme
utilities: Utilities
Expand All @@ -34,7 +39,7 @@ export type DesignSystem = {

parseCandidate(candidate: string): Readonly<Candidate>[]
parseVariant(variant: string): Readonly<Variant> | null
compileAstNodes(candidate: Candidate): ReturnType<typeof compileAstNodes>
compileAstNodes(candidate: Candidate, flags?: CompileAstFlags): ReturnType<typeof compileAstNodes>

printCandidate(candidate: Candidate): string
printVariant(variant: Variant): string
Expand All @@ -57,26 +62,28 @@ export function buildDesignSystem(theme: Theme): DesignSystem {
Array.from(parseCandidate(candidate, designSystem)),
)

let compiledAstNodes = new DefaultMap<Candidate>((candidate) => {
let ast = compileAstNodes(candidate, designSystem)

// Arbitrary values (`text-[theme(--color-red-500)]`) and arbitrary
// properties (`[--my-var:theme(--color-red-500)]`) can contain function
// calls so we need evaluate any functions we find there that weren't in
// the source CSS.
try {
substituteFunctions(
ast.map(({ node }) => node),
designSystem,
)
} catch (err) {
// If substitution fails then the candidate likely contains a call to
// `theme()` that is invalid which may be because of incorrect usage,
// invalid arguments, or a theme key that does not exist.
return []
}
let compiledAstNodes = new DefaultMap<number>((flags) => {
return new DefaultMap<Candidate>((candidate) => {
let ast = compileAstNodes(candidate, designSystem, flags)

// Arbitrary values (`text-[theme(--color-red-500)]`) and arbitrary
// properties (`[--my-var:theme(--color-red-500)]`) can contain function
// calls so we need evaluate any functions we find there that weren't in
// the source CSS.
try {
substituteFunctions(
ast.map(({ node }) => node),
designSystem,
)
} catch (err) {
// If substitution fails then the candidate likely contains a call to
// `theme()` that is invalid which may be because of incorrect usage,
// invalid arguments, or a theme key that does not exist.
return []
}

return ast
return ast
})
})

let trackUsedVariables = new DefaultMap((raw) => {
Expand Down Expand Up @@ -134,8 +141,10 @@ export function buildDesignSystem(theme: Theme): DesignSystem {
parseVariant(variant: string) {
return parsedVariants.get(variant)
},
compileAstNodes(candidate: Candidate) {
return compiledAstNodes.get(candidate)
compileAstNodes(candidate: Candidate, flags?: CompileAstFlags) {
flags ??= CompileAstFlags.RespectImportant

return compiledAstNodes.get(flags).get(candidate)
},

printCandidate(candidate: Candidate) {
Expand Down