import type { FactIndex, TailwindClassFact, TailwindTokenResolvedFact } from "../facts/index.js"; export const TAILWIND_COLOR_UTILITIES = new Set([ "accent", "bg", "border", "border-b", "border-e", "border-l", "border-r", "border-s", "border-t", "border-x", "border-y", "caret", "decoration", "divide", "fill", "from", "outline", "placeholder", "ring", "ring-offset", "shadow", "stroke", "text", "to", "via", ]); /** * Tailwind color *keywords* that are not palette families and carry no * satisfiable "use a named family" remedy. `bg-white`, `text-black`, * `border-transparent`, `ring-current`, `divide-inherit` are stock utilities a * project ships with regardless of its configured palette, so the palette * allow/deny policy must never flag them (doing so produces an unfixable * warning and double-reports against `raw-color-via-token`). */ export const UNIVERSAL_TAILWIND_COLOR_TOKENS = new Set([ "white", "black", "transparent", "current", "inherit", "none", ]); export const TAILWIND_SPACING_UTILITY_TO_PROPERTY: ReadonlyMap = new Map([ ["m", "margin"], ["mt", "margin"], ["mr", "margin"], ["mb", "margin"], ["ml", "margin"], ["ms", "margin"], ["me", "margin"], ["mx", "margin"], ["my", "margin"], ["p", "padding"], ["pt", "padding"], ["pr", "padding"], ["pb", "padding"], ["pl", "padding"], ["ps", "padding"], ["pe", "padding"], ["px", "padding"], ["py", "padding"], ["gap", "gap"], ["gap-x", "gap"], ["gap-y", "gap"], ["space-x", "gap"], ["space-y", "gap"], ] as const); export function indexResolvedTailwindTokens( ix: FactIndex ): Map { const out = new Map(); for (const fact of ix.byKind("tailwind_token_resolved")) { out.set(resolvedKey(fact.utility, fact.token), fact); } return out; } export function resolvedForClass( resolvedByKey: ReadonlyMap, klass: TailwindClassFact ): TailwindTokenResolvedFact | undefined { if (klass.value.kind !== "token") return undefined; return resolvedByKey.get(resolvedKey(klass.utility, klass.value.token)); } export function resolvedKey(utility: string, token: string): string { return `${utility}\0${token}`; } export function matchPattern(value: string, patterns: readonly string[]): string | null { for (const pattern of patterns) { if (matchesTokenGlob(value, pattern)) return pattern; } return null; } function matchesTokenGlob(value: string, pattern: string): boolean { const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*"); return new RegExp(`^${escaped}$`).test(value); }