diff --git a/.changeset/tidy-engine-package.md b/.changeset/tidy-engine-package.md new file mode 100644 index 00000000..53fd4db7 --- /dev/null +++ b/.changeset/tidy-engine-package.md @@ -0,0 +1,8 @@ +--- +"@tailwindcss-mangle/engine": minor +"tailwindcss-patch": minor +--- + +新增独立的 Tailwind CSS 引擎包,承载候选类名提取、Tailwind v3/v4 样式生成、v4 source 扫描与 bare arbitrary value 解析能力。 + +`tailwindcss-patch` 现在通过 `@tailwindcss-mangle/engine` 复用这些能力,并保留原有公共导出兼容性;同时将 Node.js 版本要求提升到 `>=22.13.0`。 diff --git a/package.json b/package.json index 4ed5f85e..cd55d7b6 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "build:docs": "turbo run build --filter=./website", "lint": "eslint \"packages/**/*.ts\" packages/tailwindcss-patch/tsdown.config.mts \"e2e/**/*.ts\" scripts/check-package-boundaries.mjs --ignore-pattern \"packages/**/bench/**\" --ignore-pattern \"packages/**/test-d/**\" --fix", "preinstall": "npx only-allow pnpm", - "sync": "cnpm sync @tailwindcss-mangle/shared @tailwindcss-mangle/config tailwindcss-patch unplugin-tailwindcss-mangle @tailwindcss-mangle/core", + "sync": "cnpm sync @tailwindcss-mangle/shared @tailwindcss-mangle/config @tailwindcss-mangle/engine tailwindcss-patch unplugin-tailwindcss-mangle @tailwindcss-mangle/core", "publish-packages": "pnpm run build && pnpm run test && changeset version && changeset publish", "-------": "-----------", "release": "changeset", diff --git a/packages/engine/package.json b/packages/engine/package.json new file mode 100644 index 00000000..ca8754bc --- /dev/null +++ b/packages/engine/package.json @@ -0,0 +1,248 @@ +{ + "name": "@tailwindcss-mangle/engine", + "type": "module", + "version": "0.0.0", + "description": "Tailwind CSS candidate extraction and style generation engine for tailwindcss-mangle", + "author": "ice breaker <1324318532@qq.com>", + "license": "MIT", + "engines": { + "node": ">=22.13.0" + }, + "homepage": "https://mangle.icebreaker.top/", + "repository": { + "type": "git", + "url": "git+https://github.com/sonofmagic/tailwindcss-mangle.git", + "directory": "packages/engine" + }, + "bugs": { + "url": "https://github.com/sonofmagic/tailwindcss-mangle/issues" + }, + "keywords": [ + "tailwindcss", + "engine", + "extract", + "class", + "mangle" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./src/index.ts", + "require": "./dist/index.cjs" + }, + "./style-candidates": { + "types": "./dist/style-candidates.d.ts", + "import": "./src/style-candidates.ts", + "require": "./dist/style-candidates.cjs" + }, + "./style-generator": { + "types": "./dist/style-generator.d.ts", + "import": "./src/style-generator.ts", + "require": "./dist/style-generator.cjs" + }, + "./types": { + "types": "./dist/types.d.ts", + "import": "./src/types.ts", + "require": "./dist/types.cjs" + }, + "./extraction/candidate-extractor": { + "types": "./dist/extraction/candidate-extractor.d.ts", + "import": "./src/extraction/candidate-extractor.ts", + "require": "./dist/extraction/candidate-extractor.cjs" + }, + "./extraction/split-candidate-tokens": { + "types": "./dist/extraction/split-candidate-tokens.d.ts", + "import": "./src/extraction/split-candidate-tokens.ts", + "require": "./dist/extraction/split-candidate-tokens.cjs" + }, + "./v3": { + "types": "./dist/v3/index.d.ts", + "import": "./src/v3/index.ts", + "require": "./dist/v3/index.cjs" + }, + "./v3/style-generator": { + "types": "./dist/v3/style-generator.d.ts", + "import": "./src/v3/style-generator.ts", + "require": "./dist/v3/style-generator.cjs" + }, + "./v4": { + "types": "./dist/v4/index.d.ts", + "import": "./src/v4/index.ts", + "require": "./dist/v4/index.cjs" + }, + "./v4/bare-arbitrary-values": { + "types": "./dist/v4/bare-arbitrary-values.d.ts", + "import": "./src/v4/bare-arbitrary-values.ts", + "require": "./dist/v4/bare-arbitrary-values.cjs" + }, + "./v4/candidates": { + "types": "./dist/v4/candidates.d.ts", + "import": "./src/v4/candidates.ts", + "require": "./dist/v4/candidates.cjs" + }, + "./v4/engine": { + "types": "./dist/v4/engine.d.ts", + "import": "./src/v4/engine.ts", + "require": "./dist/v4/engine.cjs" + }, + "./v4/node-adapter": { + "types": "./dist/v4/node-adapter.d.ts", + "import": "./src/v4/node-adapter.ts", + "require": "./dist/v4/node-adapter.cjs" + }, + "./v4/source": { + "types": "./dist/v4/source.d.ts", + "import": "./src/v4/source.ts", + "require": "./dist/v4/source.cjs" + }, + "./v4/source-scan": { + "types": "./dist/v4/source-scan.d.ts", + "import": "./src/v4/source-scan.ts", + "require": "./dist/v4/source-scan.cjs" + }, + "./v4/style-generator": { + "types": "./dist/v4/style-generator.d.ts", + "import": "./src/v4/style-generator.ts", + "require": "./dist/v4/style-generator.cjs" + }, + "./v4/types": { + "types": "./dist/v4/types.d.ts", + "import": "./src/v4/types.ts", + "require": "./dist/v4/types.cjs" + } + }, + "main": "./dist/index.cjs", + "module": "./src/index.ts", + "types": "./dist/index.d.ts", + "typesVersions": { + "*": { + "*": [ + "./dist/*", + "./dist/index.d.ts" + ] + } + }, + "files": [ + "dist" + ], + "scripts": { + "dev": "tsdown --watch --sourcemap", + "build": "tsdown", + "test": "vitest run --coverage.enabled", + "test:dev": "vitest", + "test:types": "pnpm build && tsd --typings dist/index.d.ts --files test-d/**/*.test-d.ts" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "./style-candidates": { + "types": "./dist/style-candidates.d.ts", + "import": "./dist/style-candidates.js", + "require": "./dist/style-candidates.cjs" + }, + "./style-generator": { + "types": "./dist/style-generator.d.ts", + "import": "./dist/style-generator.js", + "require": "./dist/style-generator.cjs" + }, + "./types": { + "types": "./dist/types.d.ts", + "import": "./dist/types.js", + "require": "./dist/types.cjs" + }, + "./extraction/candidate-extractor": { + "types": "./dist/extraction/candidate-extractor.d.ts", + "import": "./dist/extraction/candidate-extractor.js", + "require": "./dist/extraction/candidate-extractor.cjs" + }, + "./extraction/split-candidate-tokens": { + "types": "./dist/extraction/split-candidate-tokens.d.ts", + "import": "./dist/extraction/split-candidate-tokens.js", + "require": "./dist/extraction/split-candidate-tokens.cjs" + }, + "./v3": { + "types": "./dist/v3/index.d.ts", + "import": "./dist/v3/index.js", + "require": "./dist/v3/index.cjs" + }, + "./v3/style-generator": { + "types": "./dist/v3/style-generator.d.ts", + "import": "./dist/v3/style-generator.js", + "require": "./dist/v3/style-generator.cjs" + }, + "./v4": { + "types": "./dist/v4/index.d.ts", + "import": "./dist/v4/index.js", + "require": "./dist/v4/index.cjs" + }, + "./v4/bare-arbitrary-values": { + "types": "./dist/v4/bare-arbitrary-values.d.ts", + "import": "./dist/v4/bare-arbitrary-values.js", + "require": "./dist/v4/bare-arbitrary-values.cjs" + }, + "./v4/candidates": { + "types": "./dist/v4/candidates.d.ts", + "import": "./dist/v4/candidates.js", + "require": "./dist/v4/candidates.cjs" + }, + "./v4/engine": { + "types": "./dist/v4/engine.d.ts", + "import": "./dist/v4/engine.js", + "require": "./dist/v4/engine.cjs" + }, + "./v4/node-adapter": { + "types": "./dist/v4/node-adapter.d.ts", + "import": "./dist/v4/node-adapter.js", + "require": "./dist/v4/node-adapter.cjs" + }, + "./v4/source": { + "types": "./dist/v4/source.d.ts", + "import": "./dist/v4/source.js", + "require": "./dist/v4/source.cjs" + }, + "./v4/source-scan": { + "types": "./dist/v4/source-scan.d.ts", + "import": "./dist/v4/source-scan.js", + "require": "./dist/v4/source-scan.cjs" + }, + "./v4/style-generator": { + "types": "./dist/v4/style-generator.d.ts", + "import": "./dist/v4/style-generator.js", + "require": "./dist/v4/style-generator.cjs" + }, + "./v4/types": { + "types": "./dist/v4/types.d.ts", + "import": "./dist/v4/types.js", + "require": "./dist/v4/types.cjs" + } + }, + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts" + }, + "peerDependencies": { + "tailwindcss": ">=2.0.0" + }, + "peerDependenciesMeta": { + "tailwindcss": { + "optional": true + } + }, + "dependencies": { + "@tailwindcss/node": "^4.3.1", + "@tailwindcss/oxide": "^4.3.1", + "micromatch": "^4.0.8", + "pathe": "^2.0.3", + "postcss": "^8.5.15" + }, + "devDependencies": { + "tailwindcss": "^4.3.1", + "tailwindcss-3": "catalog:tailwindcss3" + } +} diff --git a/packages/engine/src/extraction/candidate-extractor.ts b/packages/engine/src/extraction/candidate-extractor.ts new file mode 100644 index 00000000..faa9c361 --- /dev/null +++ b/packages/engine/src/extraction/candidate-extractor.ts @@ -0,0 +1,704 @@ +import type { SourceEntry } from '@tailwindcss/oxide' +import type { + TailwindTokenByFileMap, + TailwindTokenFileKey, + TailwindTokenLocation, + TailwindTokenReport, +} from '../types.ts' +import type { BareArbitraryValueOptions } from '../v4/bare-arbitrary-values.ts' +import { promises as fs } from 'node:fs' +import process from 'node:process' +import path from 'pathe' +import { + extractBareArbitraryValueSourceCandidatesWithPositions, + resolveBareArbitraryValueCandidate, +} from '../v4/bare-arbitrary-values.ts' +import { extractTailwindV4InlineSourceCandidates, resolveValidTailwindV4Candidates } from '../v4/candidates.ts' +import { compileTailwindV4Source, getTailwindV4DesignSystemCacheKey, loadTailwindV4DesignSystem } from '../v4/node-adapter.ts' +import { + createTailwindV4CompiledSourceEntries, + normalizeTailwindV4ScannerSources, +} from '../v4/source-scan.ts' + +let oxideImportPromise: ReturnType | undefined +const designSystemCandidateCache = new Map>() + +function createOxideRuntimeDependencyError(cause: unknown) { + return new Error( + [ + '@tailwindcss-mangle/engine could not load @tailwindcss/oxide, which is required for source candidate scanning.', + 'This dependency should be installed automatically by @tailwindcss-mangle/engine.', + 'Reinstall dependencies without disabling optional dependencies, or install @tailwindcss/oxide@^4.2.4 manually if your package manager omitted it.', + ].join(' '), + { cause }, + ) +} + +async function importOxide() { + try { + return await import('@tailwindcss/oxide') + } + catch (error) { + throw createOxideRuntimeDependencyError(error) + } +} + +function getOxideModule() { + oxideImportPromise ??= importOxide() + oxideImportPromise.catch(() => { + oxideImportPromise = undefined + }) + return oxideImportPromise +} + +export interface ExtractValidCandidatesOption { + sources?: SourceEntry[] + base?: string + baseFallbacks?: string[] + css?: string + cwd?: string + bareArbitraryValues?: boolean | BareArbitraryValueOptions +} + +export interface ExtractCandidateOptions { + bareArbitraryValues?: boolean | BareArbitraryValueOptions +} + +export interface ExtractSourceCandidate { + rawCandidate: string + start: number + end: number +} + +interface ExtractSourceCandidateWithContext extends ExtractSourceCandidate { + content: string + extension: string + localStart: number +} + +const HTML_ATTRIBUTE_NAME_CANDIDATE_RE = /^(?:class|className|hover-class|hoverClass)$/ +const CSS_DIRECTIVE_CANDIDATE_RE = /^@(?:apply|tailwind|source|config|plugin|theme|utility|custom-variant|variant)$/ +const CSS_APPLY_IMPORTANT = '!important' +const CSS_APPLY_RE = /@apply\s+([^;{}]+)/g +const JS_LIKE_SOURCE_EXTENSION_RE = /^[cm]?[jt]sx?$/ +const MIXED_TEMPLATE_SOURCE_EXTENSION_RE = /^(?:vue|uvue|nvue|svelte|mpx)$/ +const CSS_LIKE_SOURCE_EXTENSION_RE = /^(?:css|wxss|acss|jxss|ttss|qss|tyss|scss|sass|less|styl|stylus)$/ +const SFC_SCRIPT_BLOCK_RE = /]*>([\s\S]*?)<\/script>/gi + +function isWhitespace(value: string | undefined) { + return value === ' ' || value === '\n' || value === '\r' || value === '\t' || value === '\f' +} + +function isHtmlAttributeNameCandidate(content: string, candidate: ExtractSourceCandidate) { + if (!HTML_ATTRIBUTE_NAME_CANDIDATE_RE.test(candidate.rawCandidate)) { + return false + } + let index = candidate.end + while (isWhitespace(content[index])) { + index++ + } + return content[index] === '=' +} + +function isInsideHtmlTagText(content: string, candidate: ExtractSourceCandidate) { + const open = content.lastIndexOf('<', candidate.start) + const close = content.lastIndexOf('>', candidate.start) + if (open > close) { + return false + } + const nextOpen = content.indexOf('<', candidate.end) + return nextOpen !== -1 && (nextOpen < content.indexOf('>', candidate.end) || !content.includes('>', candidate.end)) +} + +function isCssDirectiveCandidate(candidate: string) { + return candidate === CSS_APPLY_IMPORTANT || CSS_DIRECTIVE_CANDIDATE_RE.test(candidate) +} + +function isCandidateInCssApplyParams(content: string, candidate: ExtractSourceCandidate) { + const apply = content.lastIndexOf('@apply', candidate.start) + if (apply === -1) { + return false + } + const boundary = content.slice(apply + '@apply'.length, candidate.start) + return !/[;{}]/.test(boundary) +} + +function isCandidateInsideJsStringStaticContent(content: string, start: number) { + let quote: '"' | '\'' | '`' | undefined + let templateExpressionDepth = 0 + for (let index = 0; index < start; index++) { + const char = content[index] + const next = content[index + 1] + + if (quote && char === '\\') { + index++ + continue + } + + if (quote === '`' && templateExpressionDepth > 0) { + if (char === '"' || char === '\'') { + const nestedQuote = char + index++ + while (index < start) { + const nestedChar = content[index] + if (nestedChar === '\\') { + index += 2 + continue + } + if (nestedChar === nestedQuote) { + break + } + index++ + } + continue + } + if (char === '`') { + index++ + while (index < start) { + const nestedChar = content[index] + if (nestedChar === '\\') { + index += 2 + continue + } + if (nestedChar === '`') { + break + } + index++ + } + continue + } + if (char === '{') { + templateExpressionDepth++ + continue + } + if (char === '}') { + templateExpressionDepth-- + continue + } + continue + } + + if (quote) { + if (quote === '`' && char === '$' && next === '{') { + templateExpressionDepth = 1 + index++ + continue + } + if (char === quote) { + quote = undefined + } + continue + } + + if (char === '"' || char === '\'' || char === '`') { + quote = char + } + } + + return quote !== undefined && templateExpressionDepth === 0 +} + +function shouldKeepSourceCandidate(content: string, extension: string, candidate: ExtractSourceCandidate) { + if (!candidate.rawCandidate || isCssDirectiveCandidate(candidate.rawCandidate)) { + return false + } + if (CSS_LIKE_SOURCE_EXTENSION_RE.test(extension) && !isCandidateInCssApplyParams(content, candidate)) { + return false + } + if (isHtmlAttributeNameCandidate(content, candidate)) { + return false + } + if (isInsideHtmlTagText(content, candidate)) { + return false + } + if ( + JS_LIKE_SOURCE_EXTENSION_RE.test(extension) + && !isCandidateInsideJsStringStaticContent(content, candidate.start) + ) { + return false + } + return true +} + +function createLocalCandidate(candidate: ExtractSourceCandidateWithContext): ExtractSourceCandidate { + return { + rawCandidate: candidate.rawCandidate, + start: candidate.localStart, + end: candidate.localStart + candidate.rawCandidate.length, + } +} + +function dedupeCandidatesWithPositions(candidates: ExtractSourceCandidate[]) { + const seen = new Set() + return candidates.filter((candidate) => { + const key = `${candidate.start}:${candidate.end}:${candidate.rawCandidate}` + if (seen.has(key)) { + return false + } + seen.add(key) + return true + }) +} + +function createBareArbitraryValueCandidateContexts( + content: string, + extension: string, + offset: number, + options?: ExtractCandidateOptions, +): ExtractSourceCandidateWithContext[] { + return extractBareArbitraryValueSourceCandidatesWithPositions(content, options?.bareArbitraryValues) + .map(candidate => ({ + content, + extension, + localStart: candidate.start, + rawCandidate: candidate.rawCandidate, + start: candidate.start + offset, + end: candidate.end + offset, + })) +} + +async function extractCssApplyCandidates(content: string, extension: string, options?: ExtractCandidateOptions) { + const candidates: ExtractSourceCandidateWithContext[] = [] + CSS_APPLY_RE.lastIndex = 0 + let match = CSS_APPLY_RE.exec(content) + while (match !== null) { + const applyParams = match[1] ?? '' + const applyParamsStart = match.index + match[0].indexOf(applyParams) + // eslint-disable-next-line ts/no-use-before-define + const applyCandidates = await extractRawCandidatesWithPositions(applyParams, extension) + candidates.push(...applyCandidates.map(candidate => ({ + content: applyParams, + extension: 'html', + localStart: candidate.start, + rawCandidate: candidate.rawCandidate, + start: candidate.start + applyParamsStart, + end: candidate.end + applyParamsStart, + }))) + candidates.push(...createBareArbitraryValueCandidateContexts(applyParams, 'html', applyParamsStart, options)) + match = CSS_APPLY_RE.exec(content) + } + return candidates +} + +async function extractMixedSourceScriptCandidates(content: string, options?: ExtractCandidateOptions) { + const candidates: ExtractSourceCandidateWithContext[] = [] + SFC_SCRIPT_BLOCK_RE.lastIndex = 0 + let match = SFC_SCRIPT_BLOCK_RE.exec(content) + while (match !== null) { + const scriptContent = match[1] ?? '' + const scriptStart = match.index + match[0].indexOf(scriptContent) + // eslint-disable-next-line ts/no-use-before-define + const scriptCandidates = await extractRawCandidatesWithPositions(scriptContent, 'js') + candidates.push(...scriptCandidates.map(candidate => ({ + content: scriptContent, + extension: 'js', + localStart: candidate.start, + rawCandidate: candidate.rawCandidate, + start: candidate.start + scriptStart, + end: candidate.end + scriptStart, + }))) + candidates.push(...createBareArbitraryValueCandidateContexts(scriptContent, 'js', scriptStart, options)) + match = SFC_SCRIPT_BLOCK_RE.exec(content) + } + return candidates +} + +function createCandidateCacheKey( + designSystemKey: string, + options: Pick, +) { + if (options.bareArbitraryValues == null || options.bareArbitraryValues === false) { + return designSystemKey + } + return `${designSystemKey}:bare-arbitrary:${JSON.stringify(options.bareArbitraryValues)}` +} + +export async function extractRawCandidatesWithPositions( + content: string, + extension: string = 'html', + options?: ExtractCandidateOptions, +): Promise { + const { Scanner } = await getOxideModule() + const scanner = new Scanner({}) + const result = scanner.getCandidatesWithPositions({ content, extension }) + + const candidates = result.map(({ candidate, position }) => ({ + rawCandidate: candidate, + start: position, + end: position + candidate.length, + })) + candidates.push(...extractBareArbitraryValueSourceCandidatesWithPositions(content, options?.bareArbitraryValues)) + return dedupeCandidatesWithPositions(candidates) +} + +export async function extractSourceCandidatesWithPositions( + content: string, + extension: string = 'html', + options?: ExtractCandidateOptions, +): Promise { + const normalizedExtension = extension.replace(/^\./, '') + const candidates: ExtractSourceCandidateWithContext[] = CSS_LIKE_SOURCE_EXTENSION_RE.test(normalizedExtension) + ? await extractCssApplyCandidates(content, normalizedExtension, options) + : (await extractRawCandidatesWithPositions(content, normalizedExtension, options)) + .map(candidate => ({ + ...candidate, + content, + extension: normalizedExtension, + localStart: candidate.start, + })) + if (MIXED_TEMPLATE_SOURCE_EXTENSION_RE.test(normalizedExtension)) { + candidates.push(...await extractMixedSourceScriptCandidates(content, options)) + } + const seen = new Set() + return candidates.filter((candidate) => { + if (!shouldKeepSourceCandidate(candidate.content, candidate.extension, createLocalCandidate(candidate))) { + return false + } + const key = `${candidate.start}:${candidate.end}:${candidate.rawCandidate}` + if (seen.has(key)) { + return false + } + seen.add(key) + return true + }).map(({ rawCandidate, start, end }) => ({ rawCandidate, start, end })) +} + +export async function extractSourceCandidates( + content: string, + extension: string = 'html', + options?: ExtractCandidateOptions, +): Promise { + const candidates = await extractSourceCandidatesWithPositions(content, extension, options) + return [...new Set(candidates.map(candidate => candidate.rawCandidate))] +} + +export async function extractRawCandidates( + sources?: SourceEntry[], + options?: ExtractCandidateOptions, +): Promise { + const { Scanner } = await getOxideModule() + const scanner = new Scanner(sources === undefined ? {} : { sources }) + + const candidates = new Set(scanner.scan()) + if (options?.bareArbitraryValues !== undefined && options.bareArbitraryValues !== false) { + await Promise.all((scanner.files ?? []).map(async (file) => { + try { + const content = await fs.readFile(file, 'utf8') + // eslint-disable-next-line ts/no-use-before-define + const extension = toExtension(file) + for (const candidate of extractBareArbitraryValueSourceCandidatesWithPositions(content, options.bareArbitraryValues)) { + if (shouldKeepSourceCandidate(content, extension, candidate)) { + candidates.add(candidate.rawCandidate) + } + } + } + catch { + // 文件可能在扫描和读取之间被移除,保持与 Tailwind 原扫描结果一致。 + } + })) + } + return [...candidates] +} + +export async function extractValidCandidates(options?: ExtractValidCandidatesOption) { + const providedOptions = options ?? {} + const defaultCwd = providedOptions.cwd ?? process.cwd() + + const base = providedOptions.base ?? defaultCwd + const baseFallbacks = providedOptions.baseFallbacks ?? [] + const css = providedOptions.css ?? '@import "tailwindcss";' + const sources = (providedOptions.sources ?? [ + { + base: defaultCwd, + pattern: '**/*', + negated: false, + }, + ]).map(source => ({ + base: source.base ?? defaultCwd, + pattern: source.pattern, + negated: source.negated, + })) + + const source = { + projectRoot: defaultCwd, + base, + baseFallbacks, + css, + dependencies: [], + } + const designSystemKey = getTailwindV4DesignSystemCacheKey(source) + const designSystem = await loadTailwindV4DesignSystem(source) + const candidateCacheKey = createCandidateCacheKey(designSystemKey, providedOptions) + const candidateCache = designSystemCandidateCache.get(candidateCacheKey) ?? new Map() + designSystemCandidateCache.set(candidateCacheKey, candidateCache) + + const candidates = await extractRawCandidates( + sources, + providedOptions.bareArbitraryValues === undefined + ? undefined + : { bareArbitraryValues: providedOptions.bareArbitraryValues }, + ) + const inlineSources = extractTailwindV4InlineSourceCandidates(css) + for (const candidate of inlineSources.included) { + candidates.push(candidate) + } + for (const candidate of inlineSources.excluded) { + let index = candidates.indexOf(candidate) + while (index !== -1) { + candidates.splice(index, 1) + index = candidates.indexOf(candidate) + } + } + const validCandidates: string[] = [] + const uncachedCandidates: string[] = [] + + for (const rawCandidate of candidates) { + const cached = candidateCache.get(rawCandidate) + if (cached === true) { + validCandidates.push(rawCandidate) + continue + } + + if (cached === false) { + continue + } + + const bareArbitrary = resolveBareArbitraryValueCandidate(rawCandidate, providedOptions.bareArbitraryValues) + if ( + designSystem.parseCandidate(rawCandidate).length > 0 + || (bareArbitrary && designSystem.parseCandidate(bareArbitrary.canonicalCandidate).length > 0) + ) { + uncachedCandidates.push(rawCandidate) + continue + } + + candidateCache.set(rawCandidate, false) + } + + if (uncachedCandidates.length === 0) { + return validCandidates + } + + const validUncachedCandidates = resolveValidTailwindV4Candidates( + designSystem, + uncachedCandidates, + providedOptions.bareArbitraryValues === undefined + ? undefined + : { bareArbitraryValues: providedOptions.bareArbitraryValues }, + ) + + for (const candidate of uncachedCandidates) { + const isValid = validUncachedCandidates.has(candidate) + candidateCache.set(candidate, isValid) + if (!isValid) { + continue + } + validCandidates.push(candidate) + } + + return validCandidates +} + +function buildLineOffsets(content: string) { + const offsets: number[] = [0] + for (let i = 0; i < content.length; i++) { + if (content[i] === '\n') { + offsets.push(i + 1) + } + } + // Push a sentinel to simplify bounds checks during binary search. + if (offsets[offsets.length - 1] !== content.length) { + offsets.push(content.length) + } + return offsets +} + +function resolveLineMeta(content: string, offsets: number[], index: number) { + let low = 0 + let high = offsets.length - 1 + while (low <= high) { + const mid = Math.floor((low + high) / 2) + const start = offsets[mid] + if (start === undefined) { + break + } + const nextStart = offsets[mid + 1] ?? content.length + + if (index < start) { + high = mid - 1 + continue + } + + if (index >= nextStart) { + low = mid + 1 + continue + } + + const line = mid + 1 + const column = index - start + 1 + const lineEnd = content.indexOf('\n', start) + const lineText = content.slice(start, lineEnd === -1 ? content.length : lineEnd) + + return { line, column, lineText } + } + + const lastStart = offsets[offsets.length - 2] ?? 0 + return { + line: offsets.length - 1, + column: index - lastStart + 1, + lineText: content.slice(lastStart), + } +} + +function toExtension(filename: string) { + const ext = path.extname(filename).replace(/^\./, '') + return ext || 'txt' +} + +function toRelativeFile(cwd: string, filename: string) { + const relative = path.relative(cwd, filename) + return relative === '' ? path.basename(filename) : relative +} + +export interface ExtractProjectCandidatesOptions { + cwd?: string + sources?: SourceEntry[] + base?: string + baseFallbacks?: string[] + css?: string +} + +export interface ResolveProjectSourceFilesOptions { + cwd?: string + sources?: SourceEntry[] + ignoredSources?: SourceEntry[] + base?: string + baseFallbacks?: string[] + css?: string + filter?: (file: string) => boolean +} + +async function resolveScannerSources(options?: ResolveProjectSourceFilesOptions) { + const cwd = options?.cwd ? path.resolve(options.cwd) : process.cwd() + if (options?.sources?.length || options?.css === undefined) { + return { + cwd, + sources: normalizeTailwindV4ScannerSources(options?.sources, cwd, options?.ignoredSources), + } + } + + const base = options.base ? path.resolve(options.base) : cwd + const { compiled } = await compileTailwindV4Source({ + projectRoot: cwd, + base, + baseFallbacks: options.baseFallbacks?.map(baseFallback => path.resolve(baseFallback)) ?? [], + css: options.css, + dependencies: [], + }) + return { + cwd, + sources: normalizeTailwindV4ScannerSources( + createTailwindV4CompiledSourceEntries(compiled.root, compiled.sources, base), + cwd, + options.ignoredSources, + ), + } +} + +export async function resolveProjectSourceFiles(options?: ResolveProjectSourceFilesOptions): Promise { + const { sources } = await resolveScannerSources(options) + const { Scanner } = await getOxideModule() + const scanner = new Scanner({ + sources, + }) + const files = scanner.files ?? [] + return options?.filter + ? files.filter(options.filter) + : files +} + +export async function extractProjectCandidatesWithPositions( + options?: ExtractProjectCandidatesOptions, +): Promise { + const { cwd, sources } = await resolveScannerSources(options) + const { Scanner } = await getOxideModule() + const scanner = new Scanner({ + sources, + }) + + const files = scanner.files ?? [] + const entries: TailwindTokenLocation[] = [] + const skipped: TailwindTokenReport['skippedFiles'] = [] + + for (const file of files) { + let content: string + try { + content = await fs.readFile(file, 'utf8') + } + catch (error) { + skipped.push({ + file, + reason: error instanceof Error ? error.message : 'Unknown error', + }) + continue + } + + const extension = toExtension(file) + const matches = scanner.getCandidatesWithPositions({ + file, + content, + extension, + }) + + if (!matches.length) { + continue + } + + const offsets = buildLineOffsets(content) + const relativeFile = toRelativeFile(cwd, file) + + for (const match of matches) { + const info = resolveLineMeta(content, offsets, match.position) + entries.push({ + rawCandidate: match.candidate, + file, + relativeFile, + extension, + start: match.position, + end: match.position + match.candidate.length, + length: match.candidate.length, + line: info.line, + column: info.column, + lineText: info.lineText, + }) + } + } + + return { + entries, + filesScanned: files.length, + skippedFiles: skipped, + sources, + } +} + +export function groupTokensByFile( + report: TailwindTokenReport, + options?: { key?: TailwindTokenFileKey, stripAbsolutePaths?: boolean }, +): TailwindTokenByFileMap { + const key = options?.key ?? 'relative' + const stripAbsolute = options?.stripAbsolutePaths ?? key !== 'absolute' + + return report.entries.reduce((acc, entry) => { + const bucketKey = key === 'absolute' ? entry.file : entry.relativeFile + const bucket = acc[bucketKey] ?? (acc[bucketKey] = []) + const value = stripAbsolute + ? { + ...entry, + file: entry.relativeFile, + } + : entry + bucket.push(value) + return acc + }, {}) +} diff --git a/packages/engine/src/extraction/split-candidate-tokens.ts b/packages/engine/src/extraction/split-candidate-tokens.ts new file mode 100644 index 00000000..be97761c --- /dev/null +++ b/packages/engine/src/extraction/split-candidate-tokens.ts @@ -0,0 +1,101 @@ +// 参考链接:https://github.com/tailwindlabs/tailwindcss/blob/master/src/lib/regex.js +// eslint-disable-next-line regexp/no-obscure-range +export const validateCandidateTokenRE = /[\w\u00A0-\uFFFF%-?]/ + +export function isValidCandidateToken(token = ''): token is string { + return validateCandidateTokenRE.test(token) +} + +const SPLIT_CACHE_LIMIT = 8192 +const ESCAPED_WHITESPACE_RE = /\\[nrt]/g +const splitCache = new Map() + +function isSplitter(char: string, bracketDepth: number) { + return bracketDepth === 0 && (char === '"' || /\s/.test(char)) +} + +function hasClosingQuotedArbitraryValue(code: string, start: number, quote: string) { + for (let index = start; index < code.length; index++) { + if (code[index] === '\\') { + index++ + continue + } + if (code[index] === quote) { + return code.includes(']', index + 1) + } + } + + return false +} + +function splitBracketAware(code: string) { + const result: string[] = [] + let bracketDepth = 0 + let bracketQuote: string | undefined + let start = 0 + + for (let index = 0; index < code.length; index++) { + const char = code[index] + if (char === undefined) { + continue + } + if (bracketDepth > 0 && char === '\\') { + index++ + continue + } + + if (bracketDepth > 0 && (char === '"' || char === '\'')) { + if (bracketQuote === char) { + bracketQuote = undefined + } + else if (bracketQuote === undefined && hasClosingQuotedArbitraryValue(code, index + 1, char)) { + bracketQuote = char + } + } + + if (bracketQuote === undefined) { + if (char === '[' && code.includes(']', index + 1)) { + bracketDepth++ + } + else if (char === ']' && bracketDepth > 0) { + bracketDepth-- + } + } + + if (!isSplitter(char, bracketDepth)) { + continue + } + + const candidate = code.slice(start, index) + if (isValidCandidateToken(candidate)) { + result.push(candidate) + } + start = index + 1 + } + + const candidate = code.slice(start) + if (isValidCandidateToken(candidate)) { + result.push(candidate) + } + + return result +} + +export function splitCandidateTokens(code: string) { + const cached = splitCache.get(code) + if (cached) { + return cached + } + + // 把压缩产物中的转义空白字符(\n \r \t)先还原成空格,避免被粘连到类名上。 + const normalized = code.includes('\\') ? code.replace(ESCAPED_WHITESPACE_RE, ' ') : code + const result = splitBracketAware(normalized) + + // 防止缓存无限增长。 + if (splitCache.size >= SPLIT_CACHE_LIMIT) { + splitCache.clear() + } + splitCache.set(code, result) + + return result +} diff --git a/packages/engine/src/index.ts b/packages/engine/src/index.ts new file mode 100644 index 00000000..117e3ba5 --- /dev/null +++ b/packages/engine/src/index.ts @@ -0,0 +1,7 @@ +export * from './extraction/candidate-extractor.ts' +export * from './extraction/split-candidate-tokens.ts' +export * from './style-candidates.ts' +export * from './style-generator.ts' +export * from './types.ts' +export * from './v3/index.ts' +export * from './v4/index.ts' diff --git a/packages/engine/src/style-candidates.ts b/packages/engine/src/style-candidates.ts new file mode 100644 index 00000000..a26630aa --- /dev/null +++ b/packages/engine/src/style-candidates.ts @@ -0,0 +1,35 @@ +import type { BareArbitraryValueOptions } from './v4/bare-arbitrary-values.ts' +import { extractSourceCandidates } from './extraction/candidate-extractor.ts' + +export interface TailwindStyleSource { + content: string + extension?: string + file?: string +} + +export interface TailwindStyleCandidateOptions { + candidates?: Iterable + sources?: TailwindStyleSource[] + /** + * Enables UnoCSS-style bare arbitrary values such as `p-10%` and `p-2.5px`. + */ + bareArbitraryValues?: boolean | BareArbitraryValueOptions +} + +export async function collectTailwindStyleCandidates( + options: TailwindStyleCandidateOptions = {}, +): Promise> { + const candidates = new Set() + for (const candidate of options.candidates ?? []) { + candidates.add(candidate) + } + for (const source of options.sources ?? []) { + const sourceCandidates = await extractSourceCandidates(source.content, source.extension, { + bareArbitraryValues: options.bareArbitraryValues, + }) + for (const candidate of sourceCandidates) { + candidates.add(candidate) + } + } + return candidates +} diff --git a/packages/engine/src/style-generator.ts b/packages/engine/src/style-generator.ts new file mode 100644 index 00000000..496a8654 --- /dev/null +++ b/packages/engine/src/style-generator.ts @@ -0,0 +1,80 @@ +import type { + TailwindStyleCandidateOptions, + TailwindStyleSource, +} from './style-candidates.ts' +import type { + TailwindV3StyleGenerateOptions, + TailwindV3StyleGenerateResult, +} from './v3/index.ts' +import type { + TailwindV4StyleGenerateOptions, + TailwindV4StyleGenerateResult, +} from './v4/index.ts' +import { collectTailwindStyleCandidates } from './style-candidates.ts' +import { generateTailwindV3Style } from './v3/index.ts' +import { generateTailwindV4Style } from './v4/index.ts' + +export interface CustomTailwindStyleGenerateContext { + tokens: Set + classSet: Set + sources: TailwindStyleSource[] +} + +export interface CustomTailwindStyleGenerateOptions extends TailwindStyleCandidateOptions { + generate: (context: CustomTailwindStyleGenerateContext) => string | Promise +} + +export interface CustomTailwindStyleGenerateResult { + version: 'custom' + css: string + tokens: Set + classSet: Set + sources: TailwindStyleSource[] +} + +export type TailwindStyleGenerateOptions + = | ({ version: 3 } & TailwindV3StyleGenerateOptions) + | ({ version: 4 } & TailwindV4StyleGenerateOptions) + | ({ version: 'custom' } & CustomTailwindStyleGenerateOptions) + +export type TailwindStyleGenerateResult + = | TailwindV3StyleGenerateResult + | (TailwindV4StyleGenerateResult & { version: 4 }) + | CustomTailwindStyleGenerateResult + +export async function generateCustomStyle( + options: CustomTailwindStyleGenerateOptions, +): Promise { + const tokens = await collectTailwindStyleCandidates(options) + const classSet = new Set(tokens) + const sources = options.sources ?? [] + const css = await options.generate({ + tokens, + classSet, + sources, + }) + + return { + version: 'custom', + css, + tokens, + classSet, + sources, + } +} + +export async function generateTailwindStyle( + options: TailwindStyleGenerateOptions, +): Promise { + if (options.version === 3) { + return generateTailwindV3Style(options) + } + if (options.version === 4) { + const result = await generateTailwindV4Style(options) + return { + ...result, + version: 4, + } + } + return generateCustomStyle(options) +} diff --git a/packages/engine/src/types.ts b/packages/engine/src/types.ts new file mode 100644 index 00000000..079f0432 --- /dev/null +++ b/packages/engine/src/types.ts @@ -0,0 +1,88 @@ +import type { SourceEntry } from '@tailwindcss/oxide' +import type { Node, Rule } from 'postcss' +import type { Config } from 'tailwindcss' + +type TailwindcssClassCacheEntry = Rule | { + layer: string + options: Record + sort: Record +} + +export type TailwindcssClassCache = Map + +export interface TailwindcssRuntimeContext { + applyClassCache: Map + candidateRuleCache: Map< + string, + Set< + [ + { + arbitrary: any + index: any + layer: string + options: any[] + parallelIndex: any + parentLayer: string + variants: any + }, + Node, + ] + > + > + candidateRuleMap: Map + changedContent: any[] + classCache: TailwindcssClassCache + disposables: any[] + getClassList: (...args: any[]) => any + getClassOrder: (...args: any[]) => any + getVariants: (...args: any[]) => any + markInvalidUtilityCandidate: (...args: any[]) => any + markInvalidUtilityNode: (...args: any[]) => any + notClassCache: Set + offsets: { + layerPositions: object + offsets: object + reservedVariantBits: any + variantOffsets: Map + } + postCssNodeCache: Map + ruleCache: Set<[object, Node]> + stylesheetCache: Record> + tailwindConfig: Config + userConfigPath: string | null + variantMap: Map unknown]]> + variantOptions: Map +} + +export interface ExtractResult { + classList: string[] + classSet: Set + filename?: string +} + +export interface TailwindTokenLocation { + rawCandidate: string + file: string + relativeFile: string + extension: string + start: number + end: number + length: number + line: number + column: number + lineText: string +} + +export type TailwindTokenFileKey = 'relative' | 'absolute' + +export interface TailwindTokenReport { + entries: TailwindTokenLocation[] + filesScanned: number + sources: SourceEntry[] + skippedFiles: { + file: string + reason: string + }[] +} + +export type TailwindTokenByFileMap = Record diff --git a/packages/engine/src/v3/index.ts b/packages/engine/src/v3/index.ts new file mode 100644 index 00000000..b3e02727 --- /dev/null +++ b/packages/engine/src/v3/index.ts @@ -0,0 +1,11 @@ +export { + generateTailwindV3RawStyle, + generateTailwindV3Style, +} from './style-generator.ts' +export type { + TailwindV3RawStyleGenerateOptions, + TailwindV3RawStyleGenerateResult, + TailwindV3StyleGenerateOptions, + TailwindV3StyleGenerateResult, + TailwindV3StyleLayer, +} from './style-generator.ts' diff --git a/packages/engine/src/v3/style-generator.ts b/packages/engine/src/v3/style-generator.ts new file mode 100644 index 00000000..adff659e --- /dev/null +++ b/packages/engine/src/v3/style-generator.ts @@ -0,0 +1,388 @@ +import type { Node } from 'postcss' +import type { Config } from 'tailwindcss' +import type { TailwindStyleCandidateOptions, TailwindStyleSource } from '../style-candidates.ts' +import type { TailwindcssRuntimeContext } from '../types.ts' +import { createRequire } from 'node:module' +import process from 'node:process' +import path from 'pathe' +import postcss from 'postcss' +import { collectTailwindStyleCandidates } from '../style-candidates.ts' + +type NodeRequire = ReturnType + +interface TailwindV3CreateContextModule { + createContext: ( + tailwindConfig: Config, + changedContent?: Array<{ content?: string, extension?: string }>, + root?: ReturnType, + ) => TailwindcssRuntimeContext +} + +interface TailwindV3GenerateRulesModule { + generateRules: ( + candidates: Set, + context: TailwindcssRuntimeContext, + ) => Array<[unknown, Node]> +} + +interface TailwindV3ProcessResult { + css: string + messages: Array> +} + +interface TailwindV3CollapseRulesModule { + default?: (context: TailwindcssRuntimeContext) => (root: postcss.Root, result: TailwindV3ProcessResult) => void +} + +interface TailwindV3ProcessTailwindFeaturesModule { + default?: ( + setupContext: () => (root: postcss.Root) => TailwindcssRuntimeContext, + ) => (root: postcss.Root, result: TailwindV3ProcessResult) => Promise +} + +interface TailwindV3ResolveDefaultsAtRulesModule { + default?: (context: TailwindcssRuntimeContext) => (root: postcss.Root, result: TailwindV3ProcessResult) => void +} + +interface TailwindV3ValidateConfigModule { + validateConfig: (config: unknown) => Config +} + +interface TailwindV3SharedStateModule { + NOT_ON_DEMAND?: string +} + +type ResolveConfig = (config: Config) => Config + +interface TailwindV3Offsets { + sort: (rules: Array<[unknown, T]>) => Array<[{ + layer: 'base' | 'components' | 'defaults' | 'utilities' | 'variants' + }, T]> +} + +export interface TailwindV3StyleGenerateOptions extends TailwindStyleCandidateOptions { + /** + * Tailwind v3 package name or alias. Defaults to `tailwindcss`. + */ + packageName?: string + /** + * `createRequire` base used to resolve the Tailwind v3 package. + */ + cwd?: string + /** + * Inline Tailwind v3 config. `content` is injected from collected candidates. + */ + config?: Partial + /** + * Generate all layers by default. Pass a subset to emit only selected layers. + */ + layers?: TailwindV3StyleLayer[] +} + +export type TailwindV3StyleLayer = 'base' | 'components' | 'utilities' | 'variants' + +export interface TailwindV3RawStyleGenerateOptions extends TailwindStyleCandidateOptions { + /** + * Tailwind v3 package name or alias. Defaults to `tailwindcss`. + */ + packageName?: string + /** + * `createRequire` base used to resolve the Tailwind v3 package. + */ + cwd?: string + /** + * Tailwind v3 entry CSS. Defaults to `@tailwind utilities;`. + */ + css?: string + /** + * Inline Tailwind v3 config. Candidate content is injected automatically. + */ + config?: Partial + /** + * Directly append generated utility rules when the CSS is exactly `@tailwind utilities;`. + * This mirrors Tailwind v3's internal fast path and keeps output order aligned. + */ + directUtilitiesOnly?: boolean | 'auto' +} + +export interface TailwindV3RawStyleGenerateResult { + version: 3 + css: string + tokens: Set + classSet: Set + context: TailwindcssRuntimeContext + dependencies: string[] + sources: TailwindStyleSource[] + config: Config +} + +export interface TailwindV3StyleGenerateResult { + version: 3 + css: string + tokens: Set + classSet: Set + sources: TailwindStyleSource[] + config: Config +} + +function createPackageRequire(cwd?: string): NodeRequire { + return createRequire(path.join(path.resolve(cwd ?? process.cwd()), 'package.json')) +} + +function createDefaultTailwindV3Config(tokens: Set): Config { + return { + content: [ + { + raw: [...tokens].join(' '), + extension: 'html', + }, + ], + theme: { + extend: {}, + }, + plugins: [], + } +} + +function getDefaultExport(module: { default?: T } | T): T { + if (module && typeof module === 'object' && 'default' in module) { + return module.default as T + } + return module as T +} + +function loadTailwindV3Modules(options: Pick) { + const packageName = options.packageName ?? 'tailwindcss' + const moduleRequire = createPackageRequire(options.cwd) + const resolveConfig = getDefaultExport( + moduleRequire(`${packageName}/lib/public/resolve-config`) as { default?: ResolveConfig } | ResolveConfig, + ) + const contextModule = moduleRequire(`${packageName}/lib/lib/setupContextUtils`) as TailwindV3CreateContextModule + const generateRulesModule = moduleRequire(`${packageName}/lib/lib/generateRules`) as TailwindV3GenerateRulesModule + const collapseAdjacentRulesModule = moduleRequire(`${packageName}/lib/lib/collapseAdjacentRules`) as TailwindV3CollapseRulesModule + const collapseDuplicateDeclarationsModule = moduleRequire(`${packageName}/lib/lib/collapseDuplicateDeclarations`) as TailwindV3CollapseRulesModule + const processTailwindFeaturesModule = moduleRequire(`${packageName}/lib/processTailwindFeatures`) as TailwindV3ProcessTailwindFeaturesModule + const resolveDefaultsAtRulesModule = moduleRequire(`${packageName}/lib/lib/resolveDefaultsAtRules`) as TailwindV3ResolveDefaultsAtRulesModule + const sharedStateModule = moduleRequire(`${packageName}/lib/lib/sharedState`) as TailwindV3SharedStateModule + const validateConfigModule = moduleRequire(`${packageName}/lib/util/validateConfig.js`) as TailwindV3ValidateConfigModule + return { + collapseAdjacentRules: getDefaultExport(collapseAdjacentRulesModule), + collapseDuplicateDeclarations: getDefaultExport(collapseDuplicateDeclarationsModule), + createContext: contextModule.createContext, + generateRules: generateRulesModule.generateRules, + notOnDemandCandidate: sharedStateModule.NOT_ON_DEMAND ?? '*', + processTailwindFeatures: getDefaultExport(processTailwindFeaturesModule), + resolveDefaultsAtRules: getDefaultExport(resolveDefaultsAtRulesModule), + resolveConfig, + validateConfig: validateConfigModule.validateConfig, + } +} + +function createRawContentEntries(candidates: Iterable, sources: TailwindStyleSource[]) { + const entries: Array<{ raw: string, extension: string }> = [] + const candidateContent = [...candidates].join(' ') + if (candidateContent.length > 0) { + entries.push({ + raw: candidateContent, + extension: 'html', + }) + } + for (const source of sources) { + entries.push({ + raw: source.content, + extension: source.extension ?? 'html', + }) + } + return entries +} + +function createChangedContentEntries(candidates: Iterable, sources: TailwindStyleSource[]) { + return createRawContentEntries(candidates, sources).map(entry => ({ + content: entry.raw, + extension: entry.extension, + })) +} + +function createTailwindConfigWithContent( + config: Partial | undefined, + tokens: Set, + sources: TailwindStyleSource[], +) { + const userContent = config?.content + return { + ...createDefaultTailwindV3Config(tokens), + ...(config ?? {}), + content: [ + ...(Array.isArray(userContent) ? userContent : []), + ...createRawContentEntries(tokens, sources), + ], + } as Config +} + +function isDirectUtilitiesOnlyCss(css: string) { + return css.replace(/\s+/g, '') === '@tailwindutilities;' +} + +function sortCandidates(candidates: Iterable) { + return [...candidates].sort((a, z) => { + if (a === z) { + return 0 + } + return a < z ? -1 : 1 + }) +} + +function appendUtilityRules( + root: postcss.Root, + context: TailwindcssRuntimeContext, + rules: Array<[unknown, Node]>, +) { + const sortedRules = (context.offsets as unknown as TailwindV3Offsets).sort(rules) + for (const [sort, rule] of sortedRules) { + const tailwindRaw = rule.raws.tailwind as { parentLayer?: string } | undefined + if (sort.layer === 'utilities' || (sort.layer === 'variants' && tailwindRaw?.parentLayer === 'utilities')) { + root.append(rule.clone()) + } + } +} + +function collectClassSet(context: TailwindcssRuntimeContext, notOnDemandCandidate: string) { + const classSet = new Set() + for (const candidate of context.classCache.keys()) { + if (String(candidate) !== String(notOnDemandCandidate)) { + classSet.add(candidate) + } + } + return classSet +} + +function collectDependencyMessages(result: TailwindV3ProcessResult) { + const dependencies = new Set() + for (const message of result.messages) { + const file = message.file + if (message.type === 'dependency' && typeof file === 'string') { + dependencies.add(file) + } + } + return [...dependencies] +} + +function buildStylesheetNodes( + rules: Array<[unknown, Node]>, + context: TailwindcssRuntimeContext, + layers: TailwindV3StyleLayer[], +) { + const sortedRules = (context.offsets as unknown as TailwindV3Offsets).sort(rules) + const nodes: Node[] = [] + const layerSet = new Set(layers) + + for (const [sort, rule] of sortedRules) { + const layer = sort.layer === 'defaults' ? 'base' : sort.layer + if (layerSet.has(layer)) { + nodes.push(rule.clone()) + } + } + return nodes +} + +function createRootFromNodes(nodes: Node[]) { + const root = postcss.root() + for (const node of nodes) { + root.append(node) + } + return root +} + +export async function generateTailwindV3Style( + options: TailwindV3StyleGenerateOptions = {}, +): Promise { + const tokens = await collectTailwindStyleCandidates(options) + const { createContext, generateRules, resolveConfig } = loadTailwindV3Modules(options) + const userContent = options.config?.content + const config = resolveConfig({ + ...createDefaultTailwindV3Config(tokens), + ...(options.config ?? {}), + content: [ + ...(Array.isArray(userContent) ? userContent : []), + { + raw: [...tokens].join(' '), + extension: 'html', + }, + ], + } as Config) + const root = postcss.root() + const context = createContext(config, [], root) + const rules = generateRules(tokens, context) + const nodes = buildStylesheetNodes(rules, context, options.layers ?? ['base', 'components', 'utilities', 'variants']) + const css = createRootFromNodes(nodes).toString() + + return { + version: 3, + css, + tokens, + classSet: new Set(context.classCache.keys()), + sources: options.sources ?? [], + config, + } +} + +export async function generateTailwindV3RawStyle( + options: TailwindV3RawStyleGenerateOptions = {}, +): Promise { + const tokens = await collectTailwindStyleCandidates(options) + const { + collapseAdjacentRules, + collapseDuplicateDeclarations, + createContext, + generateRules, + notOnDemandCandidate, + processTailwindFeatures, + resolveConfig, + resolveDefaultsAtRules, + validateConfig, + } = loadTailwindV3Modules(options) + const css = options.css ?? '@tailwind utilities;' + const config = validateConfig(resolveConfig(createTailwindConfigWithContent(options.config, tokens, options.sources ?? []))) + const root = postcss.parse(css, { + from: undefined, + }) + const result: TailwindV3ProcessResult = { + css: '', + messages: [], + } + const changedContent = createChangedContentEntries(tokens, options.sources ?? []) + const shouldUseDirectUtilities = options.directUtilitiesOnly === true + || (options.directUtilitiesOnly !== false && isDirectUtilitiesOnlyCss(css)) + let context: TailwindcssRuntimeContext + + if (shouldUseDirectUtilities) { + context = createContext(config, changedContent, root) + generateRules(new Set(sortCandidates([notOnDemandCandidate, ...tokens])), context) + root.removeAll() + appendUtilityRules(root, context, [...context.ruleCache]) + resolveDefaultsAtRules(context)(root, result) + collapseAdjacentRules(context)(root, result) + collapseDuplicateDeclarations(context)(root, result) + } + else { + let createdContext: TailwindcssRuntimeContext | undefined + const setupContext = () => { + return (currentRoot: postcss.Root) => { + createdContext = createContext(config, changedContent, currentRoot) + return createdContext + } + } + context = await processTailwindFeatures(setupContext)(root, result) ?? createdContext! + } + + return { + version: 3, + css: root.toString(), + tokens, + classSet: collectClassSet(context, notOnDemandCandidate), + context, + dependencies: collectDependencyMessages(result), + sources: options.sources ?? [], + config, + } +} diff --git a/packages/engine/src/v4/bare-arbitrary-values.ts b/packages/engine/src/v4/bare-arbitrary-values.ts new file mode 100644 index 00000000..71720414 --- /dev/null +++ b/packages/engine/src/v4/bare-arbitrary-values.ts @@ -0,0 +1,545 @@ +export interface BareArbitraryValueOptions { + /** + * 允许作为无方括号任意值的单位列表。 + */ + units?: string[] +} + +export interface BareArbitraryValueResolveResult { + candidate: string + canonicalCandidate: string +} + +export interface BareArbitraryValueSourceCandidate { + rawCandidate: string + start: number + end: number +} + +const DEFAULT_BARE_ARBITRARY_VALUE_UNITS = [ + '%', + 'px', + 'rpx', + 'rem', + 'em', + 'vw', + 'vh', + 'vmin', + 'vmax', + 'dvw', + 'dvh', + 'svw', + 'svh', + 'lvw', + 'lvh', + 'ch', + 'ex', + 'lh', + 'rlh', + 'fr', + 'deg', + 'rad', + 'turn', + 's', + 'ms', +] + +const NUMBER_RE = /^-?(?:\d+|\d*\.\d+)$/ +const FUNCTION_VALUE_RE = /^[a-z_-][\w-]*\(/i +const HEX_ESCAPE_RE = /^[\da-f]$/i +const ASPECT_RATIO_RE = /^\d+\/\d+$/ +const ESCAPED_WHITESPACE_RE = /\\[nrt]/g + +function splitVariantPrefix(candidate: string) { + let depth = 0 + let quote: string | undefined + let lastSeparator = -1 + + for (let index = 0; index < candidate.length; index++) { + const character = candidate[index] + if (character === '\\') { + index++ + continue + } + + if (quote) { + if (character === quote) { + quote = undefined + } + continue + } + + if (character === '"' || character === '\'') { + quote = character + continue + } + + if (character === '[' || character === '(' || character === '{') { + depth++ + continue + } + + if (character === ']' || character === ')' || character === '}') { + depth = Math.max(0, depth - 1) + continue + } + + if (depth === 0 && character === ':') { + lastSeparator = index + } + } + + if (lastSeparator === -1) { + return { + prefix: '', + body: candidate, + } + } + + return { + prefix: candidate.slice(0, lastSeparator + 1), + body: candidate.slice(lastSeparator + 1), + } +} + +function isBalancedFunctionValue(value: string) { + let depth = 0 + let quote: string | undefined + + for (let index = 0; index < value.length; index++) { + const character = value[index] + + if (character === '\\') { + index++ + continue + } + + if (quote) { + if (character === quote) { + quote = undefined + } + continue + } + + if (character === '"' || character === '\'') { + quote = character + continue + } + + if (character === '(') { + depth++ + continue + } + + if (character === ')') { + depth-- + if (depth < 0) { + return false + } + } + } + + return depth === 0 && quote === undefined +} + +function isEscapedAt(value: string, index: number) { + let slashCount = 0 + for (let slashIndex = index - 1; slashIndex >= 0 && value[slashIndex] === '\\'; slashIndex--) { + slashCount++ + } + return slashCount % 2 === 1 +} + +function isBalancedBareArbitraryBody(value: string) { + let depth = 0 + let quote: string | undefined + + for (let index = 0; index < value.length; index++) { + const character = value[index] + + if (isEscapedAt(value, index)) { + continue + } + + if (quote) { + if (character === quote) { + quote = undefined + } + continue + } + + if (character === '"' || character === '\'') { + quote = character + continue + } + + if (character === '(' || character === '{') { + depth++ + continue + } + + if (character === ')' || character === '}') { + depth-- + if (depth < 0) { + return false + } + } + } + + return depth === 0 && quote === undefined +} + +function isHexColorValue(value: string) { + return /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6,8})$/i.test(value) +} + +function isQuotedValue(value: string) { + const quote = value[0] + if ((quote !== '"' && quote !== '\'') || value[value.length - 1] !== quote) { + return false + } + + let escaped = false + for (let index = 1; index < value.length - 1; index++) { + const character = value[index] + if (escaped) { + escaped = false + continue + } + if (character === '\\') { + escaped = true + } + } + + return !escaped +} + +function normalizeBareArbitraryValueOptions(options: boolean | BareArbitraryValueOptions | undefined) { + if (options === false || options === undefined || options === null) { + return + } + + const units = options === true ? DEFAULT_BARE_ARBITRARY_VALUE_UNITS : options.units ?? DEFAULT_BARE_ARBITRARY_VALUE_UNITS + const normalizedUnits = [...new Set(units.filter(unit => typeof unit === 'string' && unit.length > 0))] + if (normalizedUnits.length === 0) { + return + } + return { + units: normalizedUnits.sort((a, b) => b.length - a.length), + } +} + +export function isBareArbitraryValuesEnabled(options: boolean | BareArbitraryValueOptions | undefined) { + return normalizeBareArbitraryValueOptions(options) !== undefined +} + +function normalizeEscapedValue(value: string) { + let result = '' + for (let index = 0; index < value.length; index++) { + const character = value[index] + if (character !== '\\') { + result += character + continue + } + + const nextCharacter = value[index + 1] + if (nextCharacter === undefined) { + result += character + continue + } + + if (HEX_ESCAPE_RE.test(nextCharacter)) { + let hex = '' + let nextIndex = index + 1 + while (nextIndex < value.length && hex.length < 6) { + const hexCharacter = value[nextIndex] + if (hexCharacter === undefined || !HEX_ESCAPE_RE.test(hexCharacter)) { + break + } + hex += hexCharacter + nextIndex++ + } + if (/[\t\n\f\r ]/.test(value[nextIndex] ?? '')) { + nextIndex++ + } + + const decoded = String.fromCodePoint(Number.parseInt(hex, 16)) + result += decoded === '_' ? '\\_' : decoded + index = nextIndex - 1 + continue + } + + result += nextCharacter === '_' ? '\\_' : nextCharacter + index++ + } + return result +} + +function resolveValueWithUnit(body: string, units: string[]) { + const value = normalizeEscapedValue(body) + for (const unit of units) { + if (!value.endsWith(unit)) { + continue + } + const numberPart = value.slice(0, -unit.length) + if (NUMBER_RE.test(numberPart)) { + return `${numberPart}${unit}` + } + } +} + +function resolveArbitraryValue(utility: string, body: string, units: string[]) { + const value = normalizeEscapedValue(body) + const withUnit = resolveValueWithUnit(value, units) + if (withUnit) { + return withUnit + } + + if (utility === 'aspect' && ASPECT_RATIO_RE.test(value)) { + return value + } + + if (isHexColorValue(value)) { + return value + } + + if (isQuotedValue(value)) { + return value + } + + if (FUNCTION_VALUE_RE.test(value) && value.endsWith(')') && isBalancedFunctionValue(value)) { + if (utility === 'text' && /^var\(/i.test(value)) { + return `color:${value}` + } + return value + } +} + +function resolveUtilityAndValue(body: string, units: string[]) { + let depth = 0 + let quote: string | undefined + + for (let index = body.length - 1; index > 0; index--) { + const character = body[index] + + if (isEscapedAt(body, index)) { + continue + } + + if (quote) { + if (character === quote) { + quote = undefined + } + continue + } + + if (character === '"' || character === '\'') { + quote = character + continue + } + + if (character === ')' || character === '}') { + depth++ + continue + } + + if (character === '(' || character === '{') { + depth = Math.max(0, depth - 1) + continue + } + + if (depth > 0 || character !== '-') { + continue + } + + const utility = body.slice(0, index) + const rawValue = body.slice(index + 1) + if (!utility || !rawValue) { + continue + } + + const value = resolveArbitraryValue(utility, rawValue, units) + if (value) { + return { + utility, + value, + } + } + } +} + +export function resolveBareArbitraryValueCandidate( + candidate: string, + options?: boolean | BareArbitraryValueOptions, +): BareArbitraryValueResolveResult | undefined { + const normalizedOptions = normalizeBareArbitraryValueOptions(options) + if (!normalizedOptions || !candidate || candidate.includes('[') || candidate.includes(']')) { + return + } + + const { prefix, body } = splitVariantPrefix(candidate) + const important = body.startsWith('!') ? '!' : '' + let normalizedBody = important ? body.slice(1) : body + const negative = normalizedBody.startsWith('-') ? '-' : '' + if (negative) { + normalizedBody = normalizedBody.slice(1) + } + if (!isBalancedBareArbitraryBody(normalizedBody)) { + return + } + + const resolved = resolveUtilityAndValue(normalizedBody, normalizedOptions.units) + if (!resolved) { + return + } + + return { + candidate, + canonicalCandidate: `${prefix}${important}${negative}${resolved.utility}-[${resolved.value}]`, + } +} + +function isBareArbitrarySourceSplitter(char: string) { + return /\s/.test(char) +} + +function isQuoteBoundary(content: string, start: number, index: number) { + const tokenPrefix = content.slice(start, index) + return tokenPrefix.length === 0 || !tokenPrefix.endsWith('-') +} + +function trimBareArbitrarySourceToken(token: string, start: number) { + let nextToken = token + let nextStart = start + while (nextToken.length > 0 && /^[<{([]$/.test(nextToken[0]!)) { + nextToken = nextToken.slice(1) + nextStart++ + } + while (nextToken.length > 0 && /^[>\],;]$/.test(nextToken[nextToken.length - 1]!)) { + nextToken = nextToken.slice(0, -1) + } + return { + token: nextToken, + start: nextStart, + } +} + +function pushBareArbitrarySourceCandidate( + result: BareArbitraryValueSourceCandidate[], + token: string, + start: number, + options: boolean | BareArbitraryValueOptions | undefined, +) { + const trimmed = trimBareArbitrarySourceToken(token, start) + if (!trimmed.token || trimmed.token.includes('=') || trimmed.token.includes('[') || trimmed.token.includes(']')) { + return + } + if (!resolveBareArbitraryValueCandidate(trimmed.token, options)) { + return + } + result.push({ + rawCandidate: trimmed.token, + start: trimmed.start, + end: trimmed.start + trimmed.token.length, + }) +} + +export function extractBareArbitraryValueSourceCandidatesWithPositions( + content: string, + options?: boolean | BareArbitraryValueOptions, +): BareArbitraryValueSourceCandidate[] { + if (!isBareArbitraryValuesEnabled(options)) { + return [] + } + + const normalized = content.includes('\\') ? content.replace(ESCAPED_WHITESPACE_RE, ' ') : content + const result: BareArbitraryValueSourceCandidate[] = [] + let depth = 0 + let quote: string | undefined + let start = 0 + + for (let index = 0; index < normalized.length; index++) { + const char = normalized[index] + if (char === undefined) { + continue + } + if (char === '\\') { + index++ + continue + } + + if (quote) { + if (char === quote) { + quote = undefined + } + } + else if ((char === '"' || char === '\'' || char === '`') && !isQuoteBoundary(normalized, start, index)) { + quote = char + } + else if (char === '(' || char === '{' || char === '[') { + depth++ + } + else if (char === ')' || char === '}' || char === ']') { + depth = Math.max(0, depth - 1) + } + + if (!isBareArbitrarySourceSplitter(char) && !((char === '"' || char === '\'' || char === '`') && depth === 0 && isQuoteBoundary(normalized, start, index))) { + continue + } + + pushBareArbitrarySourceCandidate(result, normalized.slice(start, index), start, options) + start = index + 1 + } + + pushBareArbitrarySourceCandidate(result, normalized.slice(start), start, options) + return result +} + +export function extractBareArbitraryValueSourceCandidates( + content: string, + options?: boolean | BareArbitraryValueOptions, +) { + return [...new Set( + extractBareArbitraryValueSourceCandidatesWithPositions(content, options) + .map(candidate => candidate.rawCandidate), + )] +} + +// Based on the CSS.escape algorithm, scoped to class selector escaping. +export function escapeCssClassName(value: string) { + let result = '' + for (let index = 0; index < value.length; index++) { + const codeUnit = value.charCodeAt(index) + const character = value.charAt(index) + + if (codeUnit === 0x0000) { + result += '\uFFFD' + continue + } + + if ( + (codeUnit >= 0x0001 && codeUnit <= 0x001F) + || codeUnit === 0x007F + || (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) + || (index === 1 && codeUnit >= 0x0030 && codeUnit <= 0x0039 && value.charCodeAt(0) === 0x002D) + ) { + result += `\\${codeUnit.toString(16)} ` + continue + } + + if ( + codeUnit >= 0x0080 + || codeUnit === 0x002D + || codeUnit === 0x005F + || (codeUnit >= 0x0030 && codeUnit <= 0x0039) + || (codeUnit >= 0x0041 && codeUnit <= 0x005A) + || (codeUnit >= 0x0061 && codeUnit <= 0x007A) + ) { + result += character + continue + } + + result += `\\${character}` + } + return result +} diff --git a/packages/engine/src/v4/candidates.ts b/packages/engine/src/v4/candidates.ts new file mode 100644 index 00000000..eeaa42f0 --- /dev/null +++ b/packages/engine/src/v4/candidates.ts @@ -0,0 +1,316 @@ +import type { BareArbitraryValueOptions } from './bare-arbitrary-values.ts' +import type { TailwindV4DesignSystem } from './types.ts' +import postcss from 'postcss' +import { escapeCssClassName, resolveBareArbitraryValueCandidate } from './bare-arbitrary-values.ts' + +export function resolveValidTailwindV4Candidates( + designSystem: TailwindV4DesignSystem, + candidates: Iterable, + options?: { + bareArbitraryValues?: boolean | BareArbitraryValueOptions + }, +): Set { + const validCandidates = new Set() + const parsedCandidates: string[] = [] + const originalCandidatesByCanonical = new Map>() + + for (const candidate of candidates) { + if (!candidate) { + continue + } + + const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options?.bareArbitraryValues) + const candidateToCheck = bareArbitrary?.canonicalCandidate ?? candidate + + if (bareArbitrary) { + const originalCandidates = originalCandidatesByCanonical.get(candidateToCheck) ?? new Set() + originalCandidates.add(candidate) + originalCandidatesByCanonical.set(candidateToCheck, originalCandidates) + } + + const alreadyParsed = parsedCandidates.includes(candidateToCheck) + if (alreadyParsed) { + continue + } + + if (designSystem.parseCandidate(candidateToCheck).length > 0) { + parsedCandidates.push(candidateToCheck) + } + } + + if (parsedCandidates.length === 0) { + return validCandidates + } + + const cssByCandidate = designSystem.candidatesToCss(parsedCandidates) + for (let index = 0; index < parsedCandidates.length; index++) { + const candidate = parsedCandidates[index] + const candidateCss = cssByCandidate[index] + if (candidate && typeof candidateCss === 'string' && candidateCss.trim().length > 0) { + const originalCandidates = originalCandidatesByCanonical.get(candidate) + if (originalCandidates) { + for (const originalCandidate of originalCandidates) { + validCandidates.add(originalCandidate) + } + continue + } + validCandidates.add(candidate) + } + } + + return validCandidates +} + +function createSelectorAliasMap( + candidates: Iterable, + options?: boolean | BareArbitraryValueOptions, +) { + const aliases = new Map>() + for (const candidate of candidates) { + const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options) + if (!bareArbitrary) { + continue + } + const canonicalSelector = escapeCssClassName(bareArbitrary.canonicalCandidate) + const bareSelectors = aliases.get(canonicalSelector) ?? new Set() + bareSelectors.add(escapeCssClassName(bareArbitrary.candidate)) + aliases.set(canonicalSelector, bareSelectors) + } + return aliases +} + +export function replaceBareArbitraryValueSelectors( + css: string, + candidates: Iterable, + options?: boolean | BareArbitraryValueOptions, +) { + const aliases = createSelectorAliasMap(candidates, options) + if (aliases.size === 0) { + return css + } + + if (Array.from(aliases.values()).every(bareSelectors => bareSelectors.size === 1)) { + let result = css + for (const [canonicalSelector, bareSelectors] of aliases) { + const bareSelector = Array.from(bareSelectors)[0] + if (bareSelector !== undefined) { + result = result.replaceAll(canonicalSelector, bareSelector) + } + } + return result + } + + const root = postcss.parse(css) + root.walkRules((rule) => { + let selectors = rule.selectors + for (const [canonicalSelector, bareSelectors] of aliases) { + selectors = selectors.flatMap((selector) => { + if (!selector.includes(canonicalSelector)) { + return selector + } + return Array.from(bareSelectors, bareSelector => selector.replaceAll(canonicalSelector, bareSelector)) + }) + } + rule.selectors = selectors + }) + return root.toString() +} + +export function canonicalizeBareArbitraryValueCandidates( + candidates: Iterable, + options?: boolean | BareArbitraryValueOptions, +) { + return Array.from(candidates, (candidate) => { + const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options) + return bareArbitrary?.canonicalCandidate ?? candidate + }) +} + +function splitTopLevel(value: string, separator: string, options?: { keepEmpty?: boolean }) { + const result: string[] = [] + let start = 0 + let depth = 0 + let quote: string | undefined + + for (let index = 0; index < value.length; index++) { + const character = value[index] + if (character === '\\') { + index++ + continue + } + + if (quote) { + if (character === quote) { + quote = undefined + } + continue + } + + if (character === '"' || character === '\'') { + quote = character + continue + } + + if (character === '(' || character === '[' || character === '{') { + depth++ + continue + } + + if (character === ')' || character === ']' || character === '}') { + depth = Math.max(0, depth - 1) + continue + } + + if (depth === 0 && character === separator) { + const item = value.slice(start, index).trim() + if (item || options?.keepEmpty) { + result.push(item) + } + start = index + 1 + } + } + + const item = value.slice(start).trim() + if (item || options?.keepEmpty) { + result.push(item) + } + return result +} + +const sequencePattern = /^(-?\d+)\.\.(-?\d+)(?:\.\.(-?\d+))?$/ + +function expandSequence(value: string) { + const match = value.match(sequencePattern) + if (!match) { + return [value] + } + + const [, startValue, endValue, stepValue] = match + if (startValue === undefined || endValue === undefined) { + return [value] + } + + const start = Number.parseInt(startValue, 10) + const end = Number.parseInt(endValue, 10) + let step = stepValue === undefined ? (start <= end ? 1 : -1) : Number.parseInt(stepValue, 10) + if (step === 0) { + throw new Error('Step cannot be zero in Tailwind CSS v4 inline source sequence.') + } + + const ascending = start < end + if (ascending && step < 0) { + step = -step + } + if (!ascending && step > 0) { + step = -step + } + + const result: string[] = [] + for (let current = start; ascending ? current <= end : current >= end; current += step) { + result.push(current.toString()) + } + return result +} + +function expandInlinePattern(pattern: string): string[] { + const openIndex = pattern.indexOf('{') + if (openIndex === -1) { + return [pattern] + } + + const prefix = pattern.slice(0, openIndex) + const rest = pattern.slice(openIndex) + let depth = 0 + let closeIndex = -1 + for (let index = 0; index < rest.length; index++) { + const character = rest[index] + if (character === '{') { + depth++ + } + else if (character === '}') { + depth-- + if (depth === 0) { + closeIndex = index + break + } + } + } + + if (closeIndex === -1) { + throw new Error(`The Tailwind CSS v4 inline source pattern "${pattern}" is not balanced.`) + } + + const body = rest.slice(1, closeIndex) + const suffix = rest.slice(closeIndex + 1) + const parts = sequencePattern.test(body) + ? expandSequence(body) + : splitTopLevel(body, ',', { keepEmpty: true }).flatMap(part => expandInlinePattern(part)) + const suffixes = expandInlinePattern(suffix) + + const result: string[] = [] + for (const part of parts) { + for (const expandedSuffix of suffixes) { + result.push(`${prefix}${part}${expandedSuffix}`) + } + } + return result +} + +function unquoteCssString(value: string) { + const quote = value[0] + if ((quote !== '"' && quote !== '\'') || value[value.length - 1] !== quote) { + return undefined + } + + let result = '' + for (let index = 1; index < value.length - 1; index++) { + const character = value[index] + if (character === '\\') { + index++ + result += value[index] ?? '' + continue + } + result += character + } + return result +} + +export function extractTailwindV4InlineSourceCandidates(css: string) { + const included = new Set() + const excluded = new Set() + + const root = postcss.parse(css) + root.walkAtRules('source', (rule) => { + let params = rule.params.trim() + if (!params) { + return + } + + let negated = false + if (params.startsWith('not ')) { + negated = true + params = params.slice(4).trim() + } + + if (!params.startsWith('inline(') || !params.endsWith(')')) { + return + } + + const inlineValue = unquoteCssString(params.slice(7, -1).trim()) + if (inlineValue === undefined) { + return + } + + const target = negated ? excluded : included + for (const part of splitTopLevel(inlineValue, ' ')) { + for (const candidate of expandInlinePattern(part)) { + target.add(candidate) + } + } + }) + + return { + included, + excluded, + } +} diff --git a/packages/engine/src/v4/engine.ts b/packages/engine/src/v4/engine.ts new file mode 100644 index 00000000..8bb025c7 --- /dev/null +++ b/packages/engine/src/v4/engine.ts @@ -0,0 +1,112 @@ +import type { + TailwindV4Engine, + TailwindV4GenerateOptions, + TailwindV4GenerateResult, + TailwindV4ResolvedSource, + TailwindV4SourcePattern, +} from './types.ts' +import { extractRawCandidates, extractRawCandidatesWithPositions } from '../extraction/candidate-extractor.ts' +import { + canonicalizeBareArbitraryValueCandidates, + extractTailwindV4InlineSourceCandidates, + replaceBareArbitraryValueSelectors, + resolveValidTailwindV4Candidates, +} from './candidates.ts' +import { compileTailwindV4Source, loadTailwindV4DesignSystem } from './node-adapter.ts' +import { createTailwindV4CompiledSourceEntries } from './source-scan.ts' + +function resolveScanSources( + options: TailwindV4GenerateOptions | undefined, + source: TailwindV4ResolvedSource, + compiledRoot: TailwindV4GenerateResult['root'], + compiledSources: TailwindV4SourcePattern[], +) { + if (Array.isArray(options?.scanSources)) { + return options.scanSources + } + if (options?.scanSources === true) { + return createTailwindV4CompiledSourceEntries(compiledRoot, compiledSources, source.base) + } + return [] +} + +async function collectRawCandidates( + source: TailwindV4ResolvedSource, + options: TailwindV4GenerateOptions | undefined, + compiledRoot: TailwindV4GenerateResult['root'], + compiledSources: TailwindV4SourcePattern[] = [], +) { + const rawCandidates = new Set() + const extractOptions = options?.bareArbitraryValues === undefined + ? undefined + : { bareArbitraryValues: options.bareArbitraryValues } + + for (const candidate of options?.candidates ?? []) { + rawCandidates.add(candidate) + } + + for (const candidateSource of options?.sources ?? []) { + const candidates = await extractRawCandidatesWithPositions(candidateSource.content, candidateSource.extension, extractOptions) + for (const candidate of candidates) { + rawCandidates.add(candidate.rawCandidate) + } + } + + const filesystemSources = resolveScanSources(options, source, compiledRoot, compiledSources) + if (filesystemSources.length > 0) { + for (const candidate of await extractRawCandidates(filesystemSources, extractOptions)) { + rawCandidates.add(candidate) + } + } + + const inlineSources = extractTailwindV4InlineSourceCandidates(source.css) + for (const candidate of inlineSources.included) { + rawCandidates.add(candidate) + } + for (const candidate of inlineSources.excluded) { + rawCandidates.delete(candidate) + } + + return rawCandidates +} + +export function createTailwindV4Engine(source: TailwindV4ResolvedSource): TailwindV4Engine { + return { + source, + loadDesignSystem() { + return loadTailwindV4DesignSystem(source) + }, + async validateCandidates(candidates) { + const designSystem = await loadTailwindV4DesignSystem(source) + return resolveValidTailwindV4Candidates(designSystem, candidates) + }, + async generate(options): Promise { + const { compiled, dependencies } = await compileTailwindV4Source(source) + const rawCandidates = await collectRawCandidates(source, options, compiled.root, compiled.sources) + const designSystem = await loadTailwindV4DesignSystem(source) + const classSet = resolveValidTailwindV4Candidates(designSystem, rawCandidates, { + ...(options?.bareArbitraryValues === undefined ? {} : { bareArbitraryValues: options.bareArbitraryValues }), + }) + const inlineSources = extractTailwindV4InlineSourceCandidates(source.css) + for (const candidate of inlineSources.excluded) { + classSet.delete(candidate) + } + + const buildCandidates = canonicalizeBareArbitraryValueCandidates(classSet, options?.bareArbitraryValues) + const css = replaceBareArbitraryValueSelectors( + compiled.build(buildCandidates), + classSet, + options?.bareArbitraryValues, + ) + + return { + css, + classSet, + rawCandidates, + dependencies: Array.from(dependencies), + sources: compiled.sources, + root: compiled.root, + } + }, + } +} diff --git a/packages/engine/src/v4/index.ts b/packages/engine/src/v4/index.ts new file mode 100644 index 00000000..0c216d79 --- /dev/null +++ b/packages/engine/src/v4/index.ts @@ -0,0 +1,62 @@ +export { + escapeCssClassName, + extractBareArbitraryValueSourceCandidates, + extractBareArbitraryValueSourceCandidatesWithPositions, + isBareArbitraryValuesEnabled, + resolveBareArbitraryValueCandidate, +} from './bare-arbitrary-values.ts' +export { + canonicalizeBareArbitraryValueCandidates, + extractTailwindV4InlineSourceCandidates, + replaceBareArbitraryValueSelectors, + resolveValidTailwindV4Candidates, +} from './candidates.ts' +export { createTailwindV4Engine } from './engine.ts' +export { + compileTailwindV4Source, + loadTailwindV4DesignSystem, + loadTailwindV4NodeModule, +} from './node-adapter.ts' +export { + createTailwindV4CompiledSourceEntries, + createTailwindV4DefaultIgnoreSources, + createTailwindV4RootSources, + createTailwindV4SourceEntryMatcher, + createTailwindV4SourceExclusionMatcher, + expandTailwindV4SourceEntries, + expandTailwindV4SourceEntryBraces, + isFileExcludedByTailwindV4SourceEntries, + isFileMatchedByTailwindV4SourceEntries, + mergeTailwindV4SourceEntries, + normalizeTailwindV4ScannerSources, + normalizeTailwindV4SourceEntries, + resolveSourceScanPath, + resolveTailwindV4SourceBaseCandidates, + resolveTailwindV4SourceEntry, + TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN, + TAILWIND_V4_IGNORED_CONTENT_DIRS, + TAILWIND_V4_IGNORED_EXTENSIONS, + TAILWIND_V4_IGNORED_FILES, +} from './source-scan.ts' +export { + resolveTailwindV4Source, +} from './source.ts' +export { + collectTailwindV4StyleCandidates, + generateTailwindV4Style, +} from './style-generator.ts' +export type { + TailwindV4CandidateSource, + TailwindV4CompiledSourceRoot, + TailwindV4CssSource, + TailwindV4DesignSystem, + TailwindV4Engine, + TailwindV4GenerateOptions, + TailwindV4GenerateResult, + TailwindV4ResolvedSource, + TailwindV4SourceOptions, + TailwindV4SourcePattern, + TailwindV4StyleGenerateOptions, + TailwindV4StyleGenerateResult, + TailwindV4StyleSource, +} from './types.ts' diff --git a/packages/engine/src/v4/node-adapter.ts b/packages/engine/src/v4/node-adapter.ts new file mode 100644 index 00000000..5fbb9a52 --- /dev/null +++ b/packages/engine/src/v4/node-adapter.ts @@ -0,0 +1,207 @@ +import type { + TailwindV4CompiledSourceRoot, + TailwindV4DesignSystem, + TailwindV4ResolvedSource, + TailwindV4SourcePattern, +} from './types.ts' +import { createRequire } from 'node:module' +import { pathToFileURL } from 'node:url' +import path from 'pathe' + +interface TailwindV4CompiledSource { + sources: TailwindV4SourcePattern[] + root: TailwindV4CompiledSourceRoot + build: (candidates: string[]) => string +} + +interface TailwindV4NodeModule { + compile: (css: string, options: { + base: string + onDependency: (dependency: string) => void + customCssResolver?: (id: string, base: string) => Promise + }) => Promise + __unstable__loadDesignSystem: (css: string, options: { base: string }) => Promise +} + +const nodeModulePromiseCache = new Map>() +const designSystemPromiseCache = new Map>() + +function unique(values: Iterable) { + return Array.from(new Set(Array.from(values).filter(Boolean).map(value => path.resolve(value)))) +} + +function createRequireBase(base: string) { + return path.join(base, 'package.json') +} + +function isRelativeSpecifier(id: string) { + return id.startsWith('./') || id.startsWith('../') || id === '.' || id === '..' +} + +function isAbsoluteSpecifier(id: string) { + return path.isAbsolute(id) +} + +function isCssSpecifier(id: string) { + return path.extname(id) === '.css' +} + +function createCssResolutionCandidates(id: string) { + if (isCssSpecifier(id)) { + return [id] + } + return [`${id}/index.css`, id] +} + +function createFallbackCssResolver(baseCandidates: string[]) { + const bases = unique(baseCandidates) + return async (id: string) => { + if (isRelativeSpecifier(id) || isAbsoluteSpecifier(id)) { + return undefined + } + + for (const base of bases) { + const requireFromBase = createRequire(createRequireBase(base)) + for (const candidate of createCssResolutionCandidates(id)) { + try { + return requireFromBase.resolve(candidate) + } + catch {} + } + } + return undefined + } +} + +async function importResolvedModule(resolved: string): Promise { + return import(pathToFileURL(resolved).href) as unknown as Promise +} + +async function importTailwindNodeFromBase(base: string): Promise { + try { + const resolved = createRequire(createRequireBase(base)).resolve('@tailwindcss/node') + return await importResolvedModule(resolved) + } + catch { + return undefined + } +} + +async function importFallbackTailwindNode(): Promise { + return import('@tailwindcss/node') as unknown as Promise +} + +export async function loadTailwindV4NodeModule(baseCandidates: string[]): Promise { + const bases = unique(baseCandidates) + const cacheKey = JSON.stringify(bases) + const cached = nodeModulePromiseCache.get(cacheKey) + if (cached) { + return cached + } + + const promise = (async () => { + for (const base of bases) { + const loaded = await importTailwindNodeFromBase(base) + if (loaded) { + return loaded + } + } + + return importFallbackTailwindNode() + })() + + nodeModulePromiseCache.set(cacheKey, promise) + promise.catch(() => { + if (nodeModulePromiseCache.get(cacheKey) === promise) { + nodeModulePromiseCache.delete(cacheKey) + } + }) + return promise +} + +function createDesignSystemCacheKey(css: string, bases: string[]) { + return JSON.stringify({ + css, + bases: unique(bases), + }) +} + +export function getTailwindV4DesignSystemCacheKey(source: Pick) { + return createDesignSystemCacheKey(source.css, [source.base, ...source.baseFallbacks]) +} + +export async function loadTailwindV4DesignSystem(source: TailwindV4ResolvedSource): Promise { + const bases = unique([source.base, ...source.baseFallbacks]) + if (bases.length === 0) { + throw new Error('No base directories provided for Tailwind CSS v4 design system.') + } + + const cacheKey = createDesignSystemCacheKey(source.css, bases) + const cached = designSystemPromiseCache.get(cacheKey) + if (cached) { + return cached + } + + const promise = (async () => { + const node = await loadTailwindV4NodeModule([source.projectRoot, ...bases]) + let lastError: unknown + + for (const base of bases) { + try { + return await node.__unstable__loadDesignSystem(source.css, { base }) + } + catch (error) { + lastError = error + } + } + + if (lastError instanceof Error) { + throw lastError + } + throw new Error('Failed to load Tailwind CSS v4 design system.') + })() + + designSystemPromiseCache.set(cacheKey, promise) + promise.catch(() => { + if (designSystemPromiseCache.get(cacheKey) === promise) { + designSystemPromiseCache.delete(cacheKey) + } + }) + return promise +} + +export async function compileTailwindV4Source(source: TailwindV4ResolvedSource) { + const bases = unique([source.base, ...source.baseFallbacks]) + if (bases.length === 0) { + throw new Error('No base directories provided for Tailwind CSS v4 compiler.') + } + + const node = await loadTailwindV4NodeModule([source.projectRoot, ...bases]) + let lastError: unknown + + for (const base of bases) { + const dependencies = new Set(source.dependencies) + try { + const compiled = await node.compile(source.css, { + base, + customCssResolver: createFallbackCssResolver([source.projectRoot, ...bases]), + onDependency(dependency) { + dependencies.add(path.resolve(dependency)) + }, + }) + + return { + compiled, + dependencies, + } + } + catch (error) { + lastError = error + } + } + + if (lastError instanceof Error) { + throw lastError + } + throw new Error('Failed to compile Tailwind CSS v4 source.') +} diff --git a/packages/engine/src/v4/source-scan.ts b/packages/engine/src/v4/source-scan.ts new file mode 100644 index 00000000..7915c61d --- /dev/null +++ b/packages/engine/src/v4/source-scan.ts @@ -0,0 +1,432 @@ +import type { SourceEntry } from '@tailwindcss/oxide' +import type { TailwindV4CompiledSourceRoot, TailwindV4SourcePattern } from './types.ts' +import { realpathSync } from 'node:fs' +import { stat } from 'node:fs/promises' +import process from 'node:process' +import micromatch from 'micromatch' +import path from 'pathe' + +export const TAILWIND_V4_IGNORED_CONTENT_DIRS = [ + '.git', + '.hg', + '.jj', + '.next', + '.parcel-cache', + '.pnpm-store', + '.svelte-kit', + '.svn', + '.turbo', + '.venv', + '.vercel', + '.yarn', + '__pycache__', + 'node_modules', + 'venv', +] + +export const TAILWIND_V4_IGNORED_EXTENSIONS = [ + 'less', + 'lock', + 'sass', + 'scss', + 'styl', + 'log', +] + +export const TAILWIND_V4_IGNORED_FILES = [ + 'package-lock.json', + 'pnpm-lock.yaml', + 'bun.lockb', + '.gitignore', + '.env', + '.env.*', +] + +export const TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN = '**/*' + +function uniqueResolvedPaths(values: Iterable) { + const result: string[] = [] + for (const value of values) { + if (!value) { + continue + } + const resolved = path.resolve(value) + if (!result.includes(resolved)) { + result.push(resolved) + } + } + return result +} + +export function toPosixPath(value: string) { + return value.replaceAll(path.sep, '/') +} + +export function resolveSourceScanPath(value: string) { + const resolved = path.resolve(value) + try { + return realpathSync.native(resolved) + } + catch { + return resolved + } +} + +export function normalizeGlobPattern(pattern: string) { + return pattern.startsWith('./') ? pattern.slice(2) : pattern +} + +function hasGlobMagic(value: string) { + return /[*?[\]{}()!+@]/.test(value) +} + +function splitStaticGlobPrefix(pattern: string) { + const normalized = normalizeGlobPattern(pattern) + const segments = normalized.split(/[\\/]+/) + const prefix: string[] = [] + const rest: string[] = [] + let reachedGlob = false + + for (const segment of segments) { + if (!reachedGlob && segment && !hasGlobMagic(segment)) { + prefix.push(segment) + continue + } + reachedGlob = true + rest.push(segment) + } + + return { + prefix, + rest, + } +} + +async function pathExistsAsDirectory(file: string) { + try { + return (await stat(file)).isDirectory() + } + catch { + return false + } +} + +export function createTailwindV4DefaultIgnoreSources(base: string): TailwindV4SourcePattern[] { + return [ + ...TAILWIND_V4_IGNORED_CONTENT_DIRS.map(pattern => ({ + base, + pattern: `**/${pattern}/**`, + negated: true, + })), + ...TAILWIND_V4_IGNORED_EXTENSIONS.map(extension => ({ + base, + pattern: `**/*.${extension}`, + negated: true, + })), + ...TAILWIND_V4_IGNORED_FILES.map(pattern => ({ + base, + pattern: `**/${pattern}`, + negated: true, + })), + ] +} + +export function createTailwindV4RootSources( + root: TailwindV4CompiledSourceRoot, + fallbackBase: string, +): TailwindV4SourcePattern[] { + if (root === 'none') { + return [] + } + if (root === null) { + return [{ base: fallbackBase, pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN, negated: false }] + } + return [{ ...root, negated: false }] +} + +export function createTailwindV4CompiledSourceEntries( + root: TailwindV4CompiledSourceRoot, + sources: TailwindV4SourcePattern[], + fallbackBase: string, +) { + return [ + ...createTailwindV4RootSources(root, fallbackBase), + ...sources, + ] +} + +export async function resolveTailwindV4SourceEntry( + sourcePath: string, + base: string, + negated: boolean, + defaultPattern = TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN, +): Promise { + const absoluteSource = path.isAbsolute(sourcePath) ? path.resolve(sourcePath) : path.resolve(base, sourcePath) + + if (await pathExistsAsDirectory(absoluteSource)) { + return { + base: absoluteSource, + negated, + pattern: normalizeGlobPattern(defaultPattern), + } + } + + if (path.isAbsolute(sourcePath)) { + return { + base: path.dirname(absoluteSource), + negated, + pattern: normalizeGlobPattern(path.basename(absoluteSource)), + } + } + + const { prefix, rest } = splitStaticGlobPrefix(sourcePath) + if (prefix.length > 0 && rest.length > 0) { + return { + base: path.resolve(base, ...prefix), + negated, + pattern: normalizeGlobPattern(rest.join('/')), + } + } + + return { + base, + negated, + pattern: normalizeGlobPattern(sourcePath), + } +} + +export async function normalizeTailwindV4SourceEntries( + sources: TailwindV4SourcePattern[], + options: { + cwd?: string + defaultPattern?: string + } = {}, +) { + const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd() + return Promise.all(sources.map(source => + resolveTailwindV4SourceEntry( + source.pattern, + source.base ? path.resolve(source.base) : cwd, + source.negated, + options.defaultPattern, + ))) +} + +function expandBracePattern(pattern: string): string[] { + const index = pattern.indexOf('{') + if (index === -1) { + return [pattern] + } + + const rest = pattern.slice(index) + let depth = 0 + let endIndex = -1 + for (let i = 0; i < rest.length; i++) { + const char = rest[i] + if (char === '\\') { + i += 1 + continue + } + if (char === '{') { + depth += 1 + continue + } + if (char === '}') { + depth -= 1 + if (depth === 0) { + endIndex = i + break + } + } + } + if (endIndex === -1) { + return [pattern] + } + + const prefix = pattern.slice(0, index) + const inner = rest.slice(1, endIndex) + const suffix = rest.slice(endIndex + 1) + const parts: string[] = [] + const stack: string[] = [] + let lastPos = 0 + for (let i = 0; i < inner.length; i++) { + const char = inner[i] + if (char === '\\') { + i += 1 + continue + } + if (char === '{') { + stack.push('}') + continue + } + if (char === '}' && stack[stack.length - 1] === '}') { + stack.pop() + continue + } + if (char === ',' && stack.length === 0) { + parts.push(inner.slice(lastPos, i)) + lastPos = i + 1 + } + } + parts.push(inner.slice(lastPos)) + + return parts.flatMap(part => + expandBracePattern(`${prefix}${part}${suffix}`)) +} + +export function expandTailwindV4SourceEntryBraces(sources: TailwindV4SourcePattern[]): TailwindV4SourcePattern[] { + return sources.flatMap((source) => { + const base = path.resolve(source.base) + return expandBracePattern(source.pattern).map(pattern => ({ + base, + pattern, + negated: source.negated, + })) + }) +} + +export function normalizeTailwindV4ScannerSources( + sources: TailwindV4SourcePattern[] | undefined, + cwd: string, + ignoredSources: TailwindV4SourcePattern[] = [], +): SourceEntry[] { + const baseSources = sources?.length + ? sources + : [ + { + base: cwd, + pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN, + negated: false, + }, + ] + + return expandTailwindV4SourceEntryBraces([...baseSources, ...ignoredSources]) +} + +function normalizeEntryPattern(entry: TailwindV4SourcePattern) { + return path.isAbsolute(entry.pattern) + ? toPosixPath(path.relative(resolveSourceScanPath(entry.base), entry.pattern)) + : normalizeGlobPattern(entry.pattern) +} + +function isFileMatchedByTailwindV4SourceEntry(file: string, entry: TailwindV4SourcePattern) { + const relative = toPosixPath(path.relative(resolveSourceScanPath(entry.base), file)) + return Boolean(relative) + && !relative.startsWith('../') + && !path.isAbsolute(relative) + && micromatch.isMatch(relative, normalizeEntryPattern(entry)) +} + +export function isFileExcludedByTailwindV4SourceEntries( + file: string, + entries: TailwindV4SourcePattern[] | undefined, +) { + if (!entries?.length) { + return false + } + const resolvedFile = resolveSourceScanPath(file) + return entries.some(entry => entry.negated && isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry)) +} + +export function isFileMatchedByTailwindV4SourceEntries( + file: string, + entries: TailwindV4SourcePattern[] | undefined, +) { + if (!entries?.length) { + return true + } + + const positiveEntries = entries.filter(entry => !entry.negated) + const negativeEntries = entries.filter(entry => entry.negated) + if (positiveEntries.length === 0) { + return false + } + + const resolvedFile = resolveSourceScanPath(file) + const matchesPositive = positiveEntries.some(entry => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry)) + if (!matchesPositive) { + return false + } + + return !negativeEntries.some(entry => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry)) +} + +export function createTailwindV4SourceEntryMatcher(entries: TailwindV4SourcePattern[] | undefined) { + if (!entries?.length) { + return undefined + } + return (file: string) => isFileMatchedByTailwindV4SourceEntries(file, entries) +} + +export function createTailwindV4SourceExclusionMatcher(entries: TailwindV4SourcePattern[] | undefined) { + if (!entries?.length) { + return undefined + } + return (file: string) => isFileExcludedByTailwindV4SourceEntries(file, entries) +} + +export function groupTailwindV4SourceEntriesByBase(entries: TailwindV4SourcePattern[]) { + const entriesByBase = new Map() + for (const entry of entries) { + const base = path.resolve(entry.base) + const group = entriesByBase.get(base) ?? [] + group.push({ + ...entry, + base, + pattern: normalizeGlobPattern(entry.pattern), + }) + entriesByBase.set(base, group) + } + return entriesByBase +} + +export async function expandTailwindV4SourceEntries( + entries: TailwindV4SourcePattern[], + resolveFiles: (options: { cwd: string, sources: TailwindV4SourcePattern[] }) => Promise, +) { + if (entries.length === 0) { + return [] + } + + const files = new Set() + await Promise.all([...groupTailwindV4SourceEntriesByBase(entries).entries()].map(async ([base, group]) => { + const matched = await resolveFiles({ + cwd: base, + sources: group, + }) + for (const file of matched) { + files.add(path.resolve(file)) + } + })) + + return [...files].filter(file => !isFileExcludedByTailwindV4SourceEntries(file, entries)) +} + +export function mergeTailwindV4SourceEntries(...entries: Array) { + const result: TailwindV4SourcePattern[] = [] + const seen = new Set() + for (const group of entries) { + for (const entry of group ?? []) { + const normalized = { + base: path.resolve(entry.base), + pattern: normalizeGlobPattern(entry.pattern), + negated: entry.negated, + } + const key = JSON.stringify(normalized) + if (seen.has(key)) { + continue + } + seen.add(key) + result.push(normalized) + } + } + return result +} + +export function resolveTailwindV4SourceBaseCandidates( + projectRoot: string, + base: string, + baseFallbacks: string[], +) { + return uniqueResolvedPaths([base, projectRoot, ...baseFallbacks]) +} diff --git a/packages/engine/src/v4/source.ts b/packages/engine/src/v4/source.ts new file mode 100644 index 00000000..a56651cd --- /dev/null +++ b/packages/engine/src/v4/source.ts @@ -0,0 +1,191 @@ +import type { TailwindV4CssSource, TailwindV4ResolvedSource, TailwindV4SourceOptions } from './types.ts' +import { promises as fs } from 'node:fs' +import process from 'node:process' +import path from 'pathe' + +function resolveBase(value: string | undefined, fallback: string) { + return value === undefined + ? fallback + : path.isAbsolute(value) + ? path.resolve(value) + : path.resolve(fallback, value) +} + +function uniquePaths(values: Iterable) { + const result: string[] = [] + for (const value of values) { + if (!value) { + continue + } + const resolved = path.resolve(value) + if (!result.includes(resolved)) { + result.push(resolved) + } + } + return result +} + +function toCssImportPath(value: string) { + return value.replaceAll('\\', '/') +} + +function quoteCssImport(value: string) { + return value.replaceAll('\\', '\\\\').replaceAll('"', '\\"') +} + +function isPostcssPluginSpecifier(packageName: string) { + return packageName === '@tailwindcss/postcss' + || /(?:^|[/\\])@tailwindcss[/\\]postcss(?:[/\\]|$)/.test(packageName) + || /(?:^|[/\\])postcss(?:[/\\]|$)/i.test(packageName) + || /postcss\.config\.[cm]?[jt]s$/i.test(packageName) +} + +function createDefaultCss(packageName: string | undefined) { + const cssPackageName = packageName && !isPostcssPluginSpecifier(packageName) + ? packageName + : 'tailwindcss' + return `@import "${quoteCssImport(toCssImportPath(cssPackageName))}";` +} + +async function pathExists(filePath: string) { + try { + await fs.access(filePath) + return true + } + catch { + return false + } +} + +async function resolveCssEntries(entries: string[], projectRoot: string, base: string | undefined) { + const resolvedEntries = entries.map(entry => ({ + original: entry, + absolute: path.isAbsolute(entry) ? path.resolve(entry) : path.resolve(projectRoot, entry), + })) + const resolvedBase = base ?? path.dirname(resolvedEntries[0]?.absolute ?? projectRoot) + const dependencies = resolvedEntries.map(entry => entry.absolute) + const cssParts: string[] = [] + + for (const entry of resolvedEntries) { + if (await pathExists(entry.absolute)) { + cssParts.push(await fs.readFile(entry.absolute, 'utf8')) + continue + } + + const importPath = path.isAbsolute(entry.original) + ? entry.absolute + : path.relative(resolvedBase, entry.absolute) + cssParts.push(`@import "${quoteCssImport(toCssImportPath(importPath))}";`) + } + + return { + base: resolvedBase, + css: cssParts.join('\n'), + dependencies, + } +} + +function resolveCssSources(sources: TailwindV4CssSource[], projectRoot: string, base: string | undefined) { + const resolvedSources = sources.map(source => ({ + ...source, + base: source.base === undefined ? undefined : resolveBase(source.base, projectRoot), + file: source.file === undefined + ? undefined + : path.isAbsolute(source.file) + ? path.resolve(source.file) + : path.resolve(projectRoot, source.file), + dependencies: source.dependencies?.map(dependency => + path.isAbsolute(dependency) ? path.resolve(dependency) : path.resolve(projectRoot, dependency), + ) ?? [], + })) + const firstSource = resolvedSources[0] + const resolvedBase = base + ?? firstSource?.base + ?? (firstSource?.file ? path.dirname(firstSource.file) : projectRoot) + const dependencies = resolvedSources.flatMap(source => [ + source.file, + ...source.dependencies, + ]).filter((dependency): dependency is string => Boolean(dependency)) + + return { + base: resolvedBase, + css: resolvedSources.map(source => source.css).join('\n'), + dependencies, + } +} + +function normalizeResolvedSource( + source: { + projectRoot: string + cwd: string + base: string + baseFallbacks: string[] + css: string + dependencies: string[] + }, +): TailwindV4ResolvedSource { + const baseFallbacks = uniquePaths([ + ...source.baseFallbacks, + source.projectRoot, + source.cwd, + ]).filter(base => base !== source.base) + + return { + projectRoot: source.projectRoot, + base: source.base, + baseFallbacks, + css: source.css, + dependencies: Array.from(new Set(source.dependencies.map(dependency => path.resolve(dependency)))), + } +} + +export async function resolveTailwindV4Source(options: TailwindV4SourceOptions = {}): Promise { + const projectRoot = resolveBase(options.projectRoot, process.cwd()) + const cwd = resolveBase(options.cwd, projectRoot) + const configuredBase = options.base === undefined ? undefined : resolveBase(options.base, projectRoot) + const baseFallbacks = uniquePaths(options.baseFallbacks?.map(base => resolveBase(base, projectRoot)) ?? []) + + if (options.css !== undefined) { + return normalizeResolvedSource({ + projectRoot, + cwd, + base: configuredBase ?? cwd, + baseFallbacks, + css: options.css, + dependencies: [], + }) + } + + if (options.cssEntries?.length || options.cssSources?.length) { + const entries = options.cssEntries?.length + ? await resolveCssEntries(options.cssEntries, projectRoot, configuredBase) + : undefined + const sources = options.cssSources?.length + ? resolveCssSources(options.cssSources, projectRoot, configuredBase) + : undefined + const css = [ + entries?.css, + sources?.css, + ].filter(Boolean).join('\n') + return normalizeResolvedSource({ + projectRoot, + cwd, + base: configuredBase ?? entries?.base ?? sources?.base ?? cwd, + baseFallbacks, + css, + dependencies: [ + ...(entries?.dependencies ?? []), + ...(sources?.dependencies ?? []), + ], + }) + } + + return normalizeResolvedSource({ + projectRoot, + cwd, + base: configuredBase ?? cwd, + baseFallbacks, + css: createDefaultCss(options.packageName), + dependencies: [], + }) +} diff --git a/packages/engine/src/v4/style-generator.ts b/packages/engine/src/v4/style-generator.ts new file mode 100644 index 00000000..031c1864 --- /dev/null +++ b/packages/engine/src/v4/style-generator.ts @@ -0,0 +1,44 @@ +import type { + TailwindV4SourceOptions, + TailwindV4StyleGenerateOptions, + TailwindV4StyleGenerateResult, +} from './types.ts' +import { collectTailwindStyleCandidates } from '../style-candidates.ts' +import { createTailwindV4Engine } from './engine.ts' +import { resolveTailwindV4Source } from './source.ts' + +function createSourceOptions(options: TailwindV4StyleGenerateOptions): TailwindV4SourceOptions { + return { + ...(options.projectRoot === undefined ? {} : { projectRoot: options.projectRoot }), + ...(options.cwd === undefined ? {} : { cwd: options.cwd }), + ...(options.base === undefined ? {} : { base: options.base }), + ...(options.baseFallbacks === undefined ? {} : { baseFallbacks: options.baseFallbacks }), + ...(options.css === undefined ? {} : { css: options.css }), + ...(options.cssSources === undefined ? {} : { cssSources: options.cssSources }), + ...(options.cssEntries === undefined ? {} : { cssEntries: options.cssEntries }), + ...(options.packageName === undefined ? {} : { packageName: options.packageName }), + } +} + +export async function collectTailwindV4StyleCandidates( + options: Pick, +): Promise> { + return collectTailwindStyleCandidates(options) +} + +export async function generateTailwindV4Style( + options: TailwindV4StyleGenerateOptions = {}, +): Promise { + const source = options.source ?? await resolveTailwindV4Source(createSourceOptions(options)) + const candidates = await collectTailwindV4StyleCandidates(options) + const result = await createTailwindV4Engine(source).generate({ + candidates, + ...(options.bareArbitraryValues === undefined ? {} : { bareArbitraryValues: options.bareArbitraryValues }), + ...(options.scanSources === undefined ? {} : { scanSources: options.scanSources }), + }) + return { + ...result, + tokens: result.rawCandidates, + source, + } +} diff --git a/packages/engine/src/v4/types.ts b/packages/engine/src/v4/types.ts new file mode 100644 index 00000000..db32a98b --- /dev/null +++ b/packages/engine/src/v4/types.ts @@ -0,0 +1,103 @@ +import type { TailwindStyleSource } from '../style-candidates.ts' + +export interface TailwindV4SourceOptions { + projectRoot?: string + cwd?: string + base?: string + baseFallbacks?: string[] + css?: string + cssSources?: TailwindV4CssSource[] + cssEntries?: string[] + packageName?: string +} + +export interface TailwindV4CssSource { + css: string + base?: string + file?: string + dependencies?: string[] +} + +export interface TailwindV4ResolvedSource { + projectRoot: string + base: string + baseFallbacks: string[] + css: string + dependencies: string[] +} + +export interface TailwindV4CandidateSource { + content: string + extension?: string +} + +export interface TailwindV4StyleSource extends TailwindStyleSource {} + +export interface TailwindV4GenerateOptions { + candidates?: Iterable + sources?: TailwindV4CandidateSource[] + /** + * Enables UnoCSS-style bare arbitrary values such as `p-10%` and `p-2.5px`. + */ + bareArbitraryValues?: boolean | { + units?: string[] + } + /** + * 扫描文件系统 source entries 中的候选类名。 + * + * - `true`:使用 Tailwind v4 编译入口解析出的 `@source` 列表。 + * - `TailwindV4SourcePattern[]`:使用调用方显式传入的 source 列表。 + */ + scanSources?: boolean | TailwindV4SourcePattern[] +} + +export type TailwindV4CompiledSourceRoot = null | 'none' | { + base: string + pattern: string +} + +export interface TailwindV4SourcePattern { + base: string + pattern: string + negated: boolean +} + +export interface TailwindV4GenerateResult { + css: string + classSet: Set + rawCandidates: Set + dependencies: string[] + sources: TailwindV4SourcePattern[] + root: TailwindV4CompiledSourceRoot +} + +export interface TailwindV4StyleGenerateOptions extends TailwindV4SourceOptions { + source?: TailwindV4ResolvedSource + candidates?: Iterable + sources?: TailwindV4StyleSource[] + /** + * Enables UnoCSS-style bare arbitrary values such as `p-10%` and `p-2.5px`. + */ + bareArbitraryValues?: TailwindV4GenerateOptions['bareArbitraryValues'] + /** + * Scans the compiled Tailwind CSS v4 source entries in addition to in-memory sources. + */ + scanSources?: TailwindV4GenerateOptions['scanSources'] +} + +export interface TailwindV4StyleGenerateResult extends TailwindV4GenerateResult { + tokens: Set + source: TailwindV4ResolvedSource +} + +export interface TailwindV4DesignSystem { + parseCandidate: (candidate: string) => unknown[] + candidatesToCss: (candidates: string[]) => Array +} + +export interface TailwindV4Engine { + source: TailwindV4ResolvedSource + loadDesignSystem: () => Promise + validateCandidates: (candidates: Iterable) => Promise> + generate: (options?: TailwindV4GenerateOptions) => Promise +} diff --git a/packages/engine/test-d/public-api.test-d.ts b/packages/engine/test-d/public-api.test-d.ts new file mode 100644 index 00000000..f0cbc72f --- /dev/null +++ b/packages/engine/test-d/public-api.test-d.ts @@ -0,0 +1,46 @@ +import { expectAssignable, expectType } from 'tsd' +import { + collectTailwindStyleCandidates, + createTailwindV4Engine, + extractSourceCandidates, + extractSourceCandidatesWithPositions, + generateTailwindStyle, + generateTailwindV3RawStyle, + generateTailwindV4Style, + resolveTailwindV4Source, + splitCandidateTokens, + type TailwindStyleGenerateResult, + type TailwindV4GenerateResult, +} from '../dist/index' + +expectType(splitCandidateTokens('text-red-500')) +expectType>(extractSourceCandidates('
', 'html')) +expectType>>( + extractSourceCandidatesWithPositions('
', 'html'), +) +expectType>>(collectTailwindStyleCandidates({ + candidates: ['text-red-500'], +})) + +expectAssignable>(generateTailwindStyle({ + version: 4, + css: '@import "tailwindcss";', + candidates: ['text-red-500'], +})) + +expectType>(createTailwindV4Engine({ + projectRoot: process.cwd(), + base: process.cwd(), + baseFallbacks: [], + css: '@import "tailwindcss";', + dependencies: [], +}).generate({ + candidates: ['text-red-500'], +})) + +expectAssignable }>>(generateTailwindV3RawStyle({ + candidates: ['text-red-500'], +})) +expectAssignable> }>>(generateTailwindV4Style({ + css: '@import "tailwindcss";', +})) diff --git a/packages/engine/test/extraction.candidate-extractor.test.ts b/packages/engine/test/extraction.candidate-extractor.test.ts new file mode 100644 index 00000000..aa5d5483 --- /dev/null +++ b/packages/engine/test/extraction.candidate-extractor.test.ts @@ -0,0 +1,554 @@ +import { promises as fs } from 'node:fs' +import { createRequire } from 'node:module' +import os from 'node:os' +import path from 'pathe' +import { afterEach, describe, expect, it } from 'vitest' +import { + extractProjectCandidatesWithPositions, + extractRawCandidatesWithPositions, + extractSourceCandidates, + extractValidCandidates, + groupTokensByFile, + resolveProjectSourceFiles, +} from '@/extraction/candidate-extractor' + +const require = createRequire(import.meta.url) +const fixturesRoot = path.resolve(__dirname, 'fixtures') +const tokenFixturesRoot = path.resolve(fixturesRoot, 'token-scan') +const tailwindNodeBase = path.dirname(require.resolve('@tailwindcss/node')) +const v42FeaturePattern = 'v4/features-4.2.html' + +const v42UtilityCandidates = [ + 'text-shadow-md', + 'inset-ring-2', + 'field-sizing-content', + 'font-stretch-120%', + 'inline-4', + 'min-inline-8', + 'max-inline-12', + 'block-4', + 'min-block-8', + 'max-block-12', + 'pbs-4', + 'pbe-6', + 'inset-bs-2', + 'inset-be-3', + 'ms-4', + 'me-6', + 'border-s', + 'border-e', + 'rounded-s', + 'rounded-e', + 'start-4', + 'end-4', + 'scheme-dark', + 'text-wrap', + 'text-pretty', + 'text-balance', + 'mask-none', + 'mask-linear-45', + 'mask-radial-at-center', +] + +const v42VariantCandidates = [ + 'inert:opacity-50', + 'nth-3:bg-red-500', + 'nth-last-2:bg-blue-500', + 'nth-of-type-4:text-green-500', + 'nth-last-of-type-5:underline', +] +const tempDirs: string[] = [] + +async function createTempDir(prefix: string) { + const tempDir = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), prefix))) + tempDirs.push(tempDir) + return tempDir +} + +async function writeTempFile(file: string, content: string) { + await fs.mkdir(path.dirname(file), { recursive: true }) + await fs.writeFile(file, content, 'utf8') +} + +describe('candidate extractor', () => { + afterEach(async () => { + await Promise.all(tempDirs.splice(0).map(tempDir => fs.rm(tempDir, { recursive: true, force: true }))) + }) + + it('returns candidate positions for raw content', async () => { + const html = '
' + const result = await extractRawCandidatesWithPositions(html) + const classes = result.map(item => item.rawCandidate) + expect(classes).toContain('text-blue-500') + expect(result[0]).toHaveProperty('start') + }) + + it('extracts source candidates without html attribute names', async () => { + const result = await extractSourceCandidates( + '', + 'wxml', + ) + + expect(result).toEqual(expect.arrayContaining(['text-[23px]', 'bg-[#123456]', '!-mt-[1.5px]'])) + expect(result).not.toContain('class') + }) + + it('extracts UnoCSS-style bare arbitrary source candidates when enabled', async () => { + const source = '' + + await expect(extractSourceCandidates(source, 'wxml')).resolves.toEqual([ + 'hover:!p-2.5px', + 'sm:-top-1.5rem', + ]) + await expect(extractSourceCandidates(source, 'wxml', { bareArbitraryValues: true })).resolves.toEqual([ + 'hover:!p-2.5px', + 'sm:-top-1.5rem', + 'text-var(--brand)', + 'w-calc(100%-1rem)', + 'bg-#fff', + 'text-rgb(255,0,0)', + ]) + }) + + it('extracts source candidates from JavaScript string content only', async () => { + const result = await extractSourceCandidates( + [ + 'document.body.append(`
className
`)', + 'const className = "flex bg-yellow-300/30 w-[100px]"', + ].join('\n'), + 'js', + ) + + expect(result).toEqual(['flex', 'bg-yellow-300/30', 'w-[100px]']) + expect(result).not.toContain('className') + }) + + it('extracts CSS @apply params without directive tokens', async () => { + const result = await extractSourceCandidates( + '.x { @apply flex bg-[#123456] px-[12px] !mt-[1.5px] hover:text-[13px] !important; }', + 'css', + ) + + expect(result).toEqual(['flex', 'bg-[#123456]', 'px-[12px]', '!mt-[1.5px]', 'hover:text-[13px]']) + expect(result).not.toContain('x') + }) + + it('resolves project source files with Tailwind v4 scanner default ignores', async () => { + const root = await createTempDir('tw-engine-source-files-') + await writeTempFile(path.join(root, '.gitignore'), 'ignored-by-gitignore.html\n') + await writeTempFile(path.join(root, 'src/page.html'), '
') + await writeTempFile(path.join(root, 'node_modules/pkg/page.html'), '
') + await writeTempFile(path.join(root, '.next/server/page.html'), '
') + await writeTempFile(path.join(root, '.svelte-kit/page.html'), '
') + await writeTempFile(path.join(root, '.turbo/page.html'), '
') + await writeTempFile(path.join(root, 'ignored-by-gitignore.html'), '
') + await writeTempFile(path.join(root, 'src/ignored.scss'), '.x { @apply text-yellow-500; }') + await writeTempFile(path.join(root, 'src/debug.log'), 'text-zinc-500') + await writeTempFile(path.join(root, 'package-lock.json'), '{"class":"text-pink-500"}') + await writeTempFile(path.join(root, 'pnpm-lock.yaml'), 'text-indigo-500') + await writeTempFile(path.join(root, '.env.local'), 'text-rose-500') + + const files = await resolveProjectSourceFiles({ cwd: root }) + + expect(files.map(file => path.relative(root, file)).sort()).toEqual(['src/page.html']) + }) + + it('expands brace source patterns before passing them to the Tailwind v4 scanner', async () => { + const root = await createTempDir('tw-engine-source-files-brace-') + await writeTempFile(path.join(root, 'src/page.ts'), 'export const cls = "text-green-500"') + await writeTempFile(path.join(root, 'src/page.tsx'), 'export const cls = "text-blue-500"') + await writeTempFile(path.join(root, 'src/page.vue'), '') + + const files = await resolveProjectSourceFiles({ + cwd: root, + sources: [{ + base: root, + pattern: 'src/**/*.{ts,tsx}', + negated: false, + }], + }) + + expect(files.map(file => path.relative(root, file)).sort()).toEqual(['src/page.ts', 'src/page.tsx']) + }) + + it('lets explicit source patterns include extensions ignored by default', async () => { + const root = await createTempDir('tw-engine-source-files-explicit-') + const scssFile = path.join(root, 'src/explicit.scss') + await writeTempFile(scssFile, '.x { @apply text-yellow-500; }') + + const files = await resolveProjectSourceFiles({ + cwd: root, + sources: [{ + base: path.join(root, 'src'), + pattern: 'explicit.scss', + negated: false, + }], + }) + + expect(files.map(file => path.normalize(file))).toEqual([path.normalize(scssFile)]) + }) + + it('resolves Tailwind v4 @source paths and @source not paths from css like official integrations', async () => { + const root = await createTempDir('tw-engine-source-files-css-') + await writeTempFile(path.join(root, 'src/page.html'), '
') + await writeTempFile(path.join(root, 'src/legacy/page.html'), '
') + await writeTempFile(path.join(root, 'vendor/ui/button.html'), '') + await writeTempFile(path.join(root, 'outside/page.html'), '
') + + const files = await resolveProjectSourceFiles({ + cwd: root, + base: root, + baseFallbacks: [tailwindNodeBase], + css: [ + '@import "tailwindcss" source("./src");', + '@source not "./src/legacy";', + '@source "./vendor/ui";', + ].join('\n'), + }) + + expect(files.map(file => path.relative(root, file)).sort()).toEqual([ + 'src/page.html', + 'vendor/ui/button.html', + ]) + }) + + it('respects @import "tailwindcss" source(none) when resolving css sources', async () => { + const root = await createTempDir('tw-engine-source-files-none-') + await writeTempFile(path.join(root, 'src/page.html'), '
') + await writeTempFile(path.join(root, 'admin/page.html'), '
') + await writeTempFile(path.join(root, 'shared/page.html'), '
') + + const files = await resolveProjectSourceFiles({ + cwd: root, + base: root, + baseFallbacks: [tailwindNodeBase], + css: [ + '@import "tailwindcss" source(none);', + '@source "./admin";', + '@source "./shared";', + ].join('\n'), + }) + + expect(files.map(file => path.relative(root, file)).sort()).toEqual([ + 'admin/page.html', + 'shared/page.html', + ]) + }) + + it('uses the Tailwind v4 default source root when css has no source override', async () => { + const root = await createTempDir('tw-engine-source-files-default-root-') + await writeTempFile(path.join(root, 'src/page.html'), '
') + await writeTempFile(path.join(root, 'node_modules/pkg/page.html'), '
') + + const files = await resolveProjectSourceFiles({ + cwd: root, + base: root, + baseFallbacks: [tailwindNodeBase], + css: '@import "tailwindcss";', + }) + + expect(files.map(file => path.relative(root, file)).sort()).toEqual(['src/page.html']) + }) + + it.each(['vue', 'uvue', 'nvue'])('extracts source candidates from mixed %s template and script content', async (extension) => { + const result = await extractSourceCandidates( + [ + '', + '', + ].join('\n'), + extension, + ) + + expect(result).toEqual(expect.arrayContaining([ + 'bg-[#000020]', + 'text-[23.000020px]', + 'flex', + 'w-[100px]', + ])) + expect(result).not.toContain('class') + expect(result).not.toContain('className') + }) + + it('filters valid Tailwind candidates using design system', async () => { + const result = await extractValidCandidates({ + base: fixturesRoot, + sources: [ + { + base: fixturesRoot, + pattern: 'hello-world.html', + negated: false, + }, + ], + }) + + expect(result).toContain('text-3xl') + expect(result).toContain('font-bold') + expect(result).toContain('underline') + }) + + it('keeps bare arbitrary values disabled by default', async () => { + const result = await extractValidCandidates({ + base: tailwindNodeBase, + sources: [ + { + base: fixturesRoot, + pattern: 'hello-world.html', + negated: false, + }, + ], + }) + + expect(result).not.toContain('p-10%') + }) + + it('can include UnoCSS-style bare arbitrary values when enabled', async () => { + const result = await extractValidCandidates({ + base: tailwindNodeBase, + bareArbitraryValues: true, + sources: [ + { + base: fixturesRoot, + pattern: '**/*.html', + negated: false, + }, + ], + }) + + expect(result).toEqual(expect.arrayContaining([ + 'p-10%', + 'p-2.5px', + 'm-4rem', + 'bg-#fff', + 'text-rgb(255,0,0)', + 'text-var(--brand)', + 'w-calc(100%-1rem)', + ])) + }) + + it('ignores HTTP header literals when filtering candidates', async () => { + const result = await extractValidCandidates({ + base: fixturesRoot, + sources: [ + { + base: fixturesRoot, + pattern: 'http-headers.ts', + negated: false, + }, + ], + }) + + expect(result).toContain('text-red-500') + expect(result).not.toContain('text/event-stream') + expect(result).not.toContain('text/plain') + expect(result).not.toContain('text/html') + }) + + it('supports Tailwind v4.2 utility families via @tailwindcss/node', async () => { + const result = await extractValidCandidates({ + base: tailwindNodeBase, + sources: [ + { + base: fixturesRoot, + pattern: v42FeaturePattern, + negated: false, + }, + ], + }) + + expect(result).toEqual(expect.arrayContaining(v42UtilityCandidates)) + expect(result).not.toContain('definitely-not-a-tailwind-class') + }) + + it('supports Tailwind v4.2 structural variants via @tailwindcss/node', async () => { + const result = await extractValidCandidates({ + base: tailwindNodeBase, + sources: [ + { + base: fixturesRoot, + pattern: v42FeaturePattern, + negated: false, + }, + ], + }) + + expect(result).toEqual(expect.arrayContaining(v42VariantCandidates)) + }) + + it('falls back to secondary base directories when loading v4.2 design system', async () => { + const result = await extractValidCandidates({ + base: path.join(fixturesRoot, '__missing-tailwind-base__'), + baseFallbacks: [tailwindNodeBase], + sources: [ + { + base: fixturesRoot, + pattern: v42FeaturePattern, + negated: false, + }, + ], + }) + + expect(result).toEqual(expect.arrayContaining(['text-shadow-md', 'inert:opacity-50'])) + }) + + it('accepts @source inline() syntax with extra whitespace in css option', async () => { + const result = await extractValidCandidates({ + base: tailwindNodeBase, + css: [ + '@import "tailwindcss";', + '@source inline( "text-shadow-md" );', + '@source not inline( "text-shadow-2xs" );', + ].join('\n'), + sources: [ + { + base: fixturesRoot, + pattern: v42FeaturePattern, + negated: false, + }, + ], + }) + + expect(result).toContain('text-shadow-md') + expect(result).toContain('text-pretty') + }) + + it('expands Tailwind v4 @source inline variants, ranges, and not inline exclusions', async () => { + const result = await extractValidCandidates({ + base: tailwindNodeBase, + css: [ + '@import "tailwindcss";', + '@source inline("{hover:,focus:,}underline");', + '@source inline("p-{2..6..2}");', + '@source inline("bg-red-{50,{100..300..100},950}");', + '@source not inline("bg-red-{200..300..100}");', + ].join('\n'), + sources: [], + }) + + expect(result).toEqual(expect.arrayContaining([ + 'underline', + 'hover:underline', + 'focus:underline', + 'p-2', + 'p-4', + 'p-6', + 'bg-red-50', + 'bg-red-100', + 'bg-red-950', + ])) + expect(result).not.toContain('bg-red-200') + expect(result).not.toContain('bg-red-300') + }) + + it('supports official @source inline whitespace, brace, range, and not inline syntax in css option', async () => { + const result = await extractValidCandidates({ + base: tailwindNodeBase, + css: [ + '@import "tailwindcss" source(none);', + '@source inline( "underline" );', + '@source inline(', + ' "{hover:,focus:,}block"', + ');', + '@source inline("p-{2..6..2}");', + '@source inline("bg-red-{50,{100..300..100},950}");', + '@source not inline("bg-red-{200..300..100}");', + ].join('\n'), + sources: [], + }) + + expect(result).toEqual(expect.arrayContaining([ + 'underline', + 'block', + 'hover:block', + 'focus:block', + 'p-2', + 'p-4', + 'p-6', + 'bg-red-50', + 'bg-red-100', + 'bg-red-950', + ])) + expect(result).not.toContain('bg-red-200') + expect(result).not.toContain('bg-red-300') + }) + + it('scans project files for token metadata', async () => { + const result = await extractProjectCandidatesWithPositions({ + cwd: tokenFixturesRoot, + sources: [ + { + base: tokenFixturesRoot, + pattern: '**/*.{html,tsx}', + negated: false, + }, + ], + }) + + expect(result.filesScanned).toBe(2) + expect(result.entries.length).toBeGreaterThan(0) + + const htmlMatch = result.entries.find( + entry => entry.relativeFile.endsWith('page.html') && entry.rawCandidate === 'bg-blue-500', + ) + const tsxMatch = result.entries.find( + entry => entry.relativeFile.endsWith('button.tsx') && entry.rawCandidate === 'text-red-500', + ) + + expect(htmlMatch).toBeTruthy() + expect(htmlMatch?.line).toBeGreaterThan(0) + expect(htmlMatch?.column).toBeGreaterThan(0) + expect(tsxMatch?.lineText).toContain('className') + }) + + it('groups token metadata by relative file path', async () => { + const report = await extractProjectCandidatesWithPositions({ + cwd: tokenFixturesRoot, + sources: [ + { + base: tokenFixturesRoot, + pattern: '**/*.{html,tsx}', + negated: false, + }, + ], + }) + + const grouped = groupTokensByFile(report) + expect(Object.keys(grouped)).toEqual(expect.arrayContaining(['page.html', 'button.tsx'])) + expect(grouped['page.html'].length).toBeGreaterThan(0) + expect(grouped['button.tsx'][0].relativeFile).toBe('button.tsx') + expect(grouped['button.tsx'][0].file).toBe('button.tsx') + + const absoluteGrouped = groupTokensByFile(report, { key: 'absolute', stripAbsolutePaths: false }) + const absoluteKey = Object.keys(absoluteGrouped).find(key => key.endsWith('button.tsx')) + expect(absoluteKey).toBeTruthy() + if (absoluteKey) { + expect(absoluteGrouped[absoluteKey][0].file).toBe(absoluteKey) + } + }) + + it('generates the CLI token command output', async () => { + const report = await extractProjectCandidatesWithPositions({ + cwd: tokenFixturesRoot, + sources: [ + { + base: tokenFixturesRoot, + pattern: '**/*.{html,tsx}', + negated: false, + }, + ], + }) + + const lines = report.entries.map( + entry => `${entry.relativeFile}:${entry.line}:${entry.column} ${entry.rawCandidate} (${entry.start}-${entry.end})`, + ) + + expect(lines.length).toBeGreaterThan(0) + + const cliCommand = 'pnpm dlx tw-patch tokens --format lines --no-write' + const preview = `${cliCommand}\n${lines.join('\n')}` + + expect(preview.startsWith(cliCommand)).toBe(true) + expect(preview.split('\n').length).toBe(lines.length + 1) + }) +}) diff --git a/packages/engine/test/extraction.split-candidate-tokens.test.ts b/packages/engine/test/extraction.split-candidate-tokens.test.ts new file mode 100644 index 00000000..40e228c4 --- /dev/null +++ b/packages/engine/test/extraction.split-candidate-tokens.test.ts @@ -0,0 +1,71 @@ +import { describe, expect, it } from 'vitest' +import { + isValidCandidateToken, + splitCandidateTokens, +} from '@/extraction/split-candidate-tokens' +import { splitCandidateTokens as splitCandidateTokensFromIndex } from '@/index' + +describe('split candidate tokens', () => { + it('splits plain source snippets without emitting empty tokens', () => { + expect(splitCandidateTokens(' foo bar ')).toEqual(['foo', 'bar']) + expect(splitCandidateTokens('" "')).toEqual([]) + }) + + it('splits quoted html-like attributes while preserving candidate values', () => { + const snippet = 'class="foo bar" data-test="baz"' + + expect(splitCandidateTokens(snippet)).toEqual(['class=', 'foo', 'bar', 'data-test=', 'baz']) + }) + + it('preserves single and double quoted arbitrary values', () => { + expect(splitCandidateTokens('before:content-["11111"] before:content-[\'222\']')).toEqual([ + 'before:content-["11111"]', + 'before:content-[\'222\']', + ]) + expect(splitCandidateTokens('')).toEqual([ + '', + ]) + expect(splitCandidateTokens('before:content-["]"] before:content-[\']\']')).toEqual([ + 'before:content-["]"]', + 'before:content-[\']\']', + ]) + }) + + it('does not swallow later tokens when arbitrary values are malformed', () => { + expect(splitCandidateTokens('before:content-["11111" text-red-500 class="foo bar"')).toEqual([ + 'before:content-[', + '11111', + 'text-red-500', + 'class=', + 'foo', + 'bar', + ]) + expect(splitCandidateTokens('before:content-["] text-red-500 class="foo bar"')).toEqual([ + 'before:content-["]', + 'text-red-500', + 'class=', + 'foo', + 'bar', + ]) + }) + + it('normalizes escaped whitespace from minified output', () => { + expect(splitCandidateTokens('foo\\nbar\\tbaz\\rqux')).toEqual(['foo', 'bar', 'baz', 'qux']) + }) + + it('exports the splitter from package entry', () => { + expect(splitCandidateTokensFromIndex('foo before:content-["bar"]')).toEqual([ + 'foo', + 'before:content-["bar"]', + ]) + }) + + it('validates non-empty candidate-like tokens', () => { + expect(isValidCandidateToken('text-red-500')).toBe(true) + expect(isValidCandidateToken('"')).toBe(false) + }) +}) diff --git a/packages/engine/test/fixtures/apps/0.common/.tw-patch/tw-class-list.json b/packages/engine/test/fixtures/apps/0.common/.tw-patch/tw-class-list.json new file mode 100644 index 00000000..3645fa5d --- /dev/null +++ b/packages/engine/test/fixtures/apps/0.common/.tw-patch/tw-class-list.json @@ -0,0 +1,5 @@ +[ + "font-bold", + "text-3xl", + "underline" +] \ No newline at end of file diff --git a/packages/engine/test/fixtures/apps/0.common/package.json b/packages/engine/test/fixtures/apps/0.common/package.json new file mode 100644 index 00000000..ab5b759a --- /dev/null +++ b/packages/engine/test/fixtures/apps/0.common/package.json @@ -0,0 +1,13 @@ +{ + "name": "0.common", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "tw-init": "npx tw-patch init", + "tw-extract": "npx tw-patch extract" + }, + "keywords": [], + "author": "", + "license": "ISC" +} \ No newline at end of file diff --git a/packages/engine/test/fixtures/apps/0.common/postcss.config.js b/packages/engine/test/fixtures/apps/0.common/postcss.config.js new file mode 100644 index 00000000..c0d6c627 --- /dev/null +++ b/packages/engine/test/fixtures/apps/0.common/postcss.config.js @@ -0,0 +1,10 @@ +const path = require('path') + +module.exports = { + plugins: { + tailwindcss: { + config: path.resolve(__dirname, './tailwind.config.js') + }, + autoprefixer: {}, + } +} \ No newline at end of file diff --git a/packages/engine/test/fixtures/apps/0.common/src/index.html b/packages/engine/test/fixtures/apps/0.common/src/index.html new file mode 100644 index 00000000..a794de5b --- /dev/null +++ b/packages/engine/test/fixtures/apps/0.common/src/index.html @@ -0,0 +1,16 @@ + + + + + + + + + + +

+ Hello world! +

+ + + \ No newline at end of file diff --git a/packages/engine/test/fixtures/apps/0.common/tailwind.config.js b/packages/engine/test/fixtures/apps/0.common/tailwind.config.js new file mode 100644 index 00000000..c9f0d3ab --- /dev/null +++ b/packages/engine/test/fixtures/apps/0.common/tailwind.config.js @@ -0,0 +1,9 @@ +const path = require('path') +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [path.resolve(__dirname, "./src/**/*.{html,js}")], + theme: { + extend: {}, + }, + plugins: [], +} \ No newline at end of file diff --git a/packages/engine/test/fixtures/apps/0.common/tailwindcss-mangle.config.ts b/packages/engine/test/fixtures/apps/0.common/tailwindcss-mangle.config.ts new file mode 100644 index 00000000..6ac0a806 --- /dev/null +++ b/packages/engine/test/fixtures/apps/0.common/tailwindcss-mangle.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from 'tailwindcss-patch' + +export default defineConfig({}) diff --git a/packages/engine/test/fixtures/apps/0.common/tailwindcss-patch.config.ts b/packages/engine/test/fixtures/apps/0.common/tailwindcss-patch.config.ts new file mode 100644 index 00000000..6ac0a806 --- /dev/null +++ b/packages/engine/test/fixtures/apps/0.common/tailwindcss-patch.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from 'tailwindcss-patch' + +export default defineConfig({}) diff --git a/packages/engine/test/fixtures/apps/1.default/.tw-patch/tw-class-list.json b/packages/engine/test/fixtures/apps/1.default/.tw-patch/tw-class-list.json new file mode 100644 index 00000000..3645fa5d --- /dev/null +++ b/packages/engine/test/fixtures/apps/1.default/.tw-patch/tw-class-list.json @@ -0,0 +1,5 @@ +[ + "font-bold", + "text-3xl", + "underline" +] \ No newline at end of file diff --git a/packages/engine/test/fixtures/apps/1.default/package.json b/packages/engine/test/fixtures/apps/1.default/package.json new file mode 100644 index 00000000..b5ad4187 --- /dev/null +++ b/packages/engine/test/fixtures/apps/1.default/package.json @@ -0,0 +1,13 @@ +{ + "name": "1.default", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "tw-init": "npx tw-patch init", + "tw-extract": "npx tw-patch extract" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/packages/engine/test/fixtures/apps/1.default/postcss.config.js b/packages/engine/test/fixtures/apps/1.default/postcss.config.js new file mode 100644 index 00000000..88ae48b5 --- /dev/null +++ b/packages/engine/test/fixtures/apps/1.default/postcss.config.js @@ -0,0 +1,7 @@ +// const path = require('path') + +module.exports = { + plugins: { + tailwindcss: {} + } +} \ No newline at end of file diff --git a/packages/engine/test/fixtures/apps/1.default/src/index.html b/packages/engine/test/fixtures/apps/1.default/src/index.html new file mode 100644 index 00000000..a794de5b --- /dev/null +++ b/packages/engine/test/fixtures/apps/1.default/src/index.html @@ -0,0 +1,16 @@ + + + + + + + + + + +

+ Hello world! +

+ + + \ No newline at end of file diff --git a/packages/engine/test/fixtures/apps/1.default/tailwind.config.js b/packages/engine/test/fixtures/apps/1.default/tailwind.config.js new file mode 100644 index 00000000..2c1c94f9 --- /dev/null +++ b/packages/engine/test/fixtures/apps/1.default/tailwind.config.js @@ -0,0 +1,9 @@ +const path = require('path') +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ["./src/**/*.{html,js}"],//[path.resolve(__dirname, "./src/**/*.{html,js}")], + theme: { + extend: {}, + }, + plugins: [], +} \ No newline at end of file diff --git a/packages/engine/test/fixtures/apps/1.default/tailwindcss-mangle.config.ts b/packages/engine/test/fixtures/apps/1.default/tailwindcss-mangle.config.ts new file mode 100644 index 00000000..6ac0a806 --- /dev/null +++ b/packages/engine/test/fixtures/apps/1.default/tailwindcss-mangle.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from 'tailwindcss-patch' + +export default defineConfig({}) diff --git a/packages/engine/test/fixtures/apps/1.default/tailwindcss-patch.config.ts b/packages/engine/test/fixtures/apps/1.default/tailwindcss-patch.config.ts new file mode 100644 index 00000000..6ac0a806 --- /dev/null +++ b/packages/engine/test/fixtures/apps/1.default/tailwindcss-patch.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from 'tailwindcss-patch' + +export default defineConfig({}) diff --git a/packages/engine/test/fixtures/cache/index.json b/packages/engine/test/fixtures/cache/index.json new file mode 100644 index 00000000..75171ff2 --- /dev/null +++ b/packages/engine/test/fixtures/cache/index.json @@ -0,0 +1 @@ +["*","bg-[#123456]","font-bold","text-3xl","underline"] diff --git a/packages/engine/test/fixtures/cache/merge-multiple-context.json b/packages/engine/test/fixtures/cache/merge-multiple-context.json new file mode 100644 index 00000000..1eaec923 --- /dev/null +++ b/packages/engine/test/fixtures/cache/merge-multiple-context.json @@ -0,0 +1 @@ +["*","text-[99px]","text-[100px]"] diff --git a/packages/engine/test/fixtures/cache/raw-method.json b/packages/engine/test/fixtures/cache/raw-method.json new file mode 100644 index 00000000..9d804e48 --- /dev/null +++ b/packages/engine/test/fixtures/cache/raw-method.json @@ -0,0 +1 @@ +["a","b","c"] diff --git a/packages/engine/test/fixtures/cli/index.css b/packages/engine/test/fixtures/cli/index.css new file mode 100644 index 00000000..bd6213e1 --- /dev/null +++ b/packages/engine/test/fixtures/cli/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/packages/engine/test/fixtures/config/0.default/tailwindcss-mangle.config.ts b/packages/engine/test/fixtures/config/0.default/tailwindcss-mangle.config.ts new file mode 100644 index 00000000..6ac0a806 --- /dev/null +++ b/packages/engine/test/fixtures/config/0.default/tailwindcss-mangle.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from 'tailwindcss-patch' + +export default defineConfig({}) diff --git a/packages/engine/test/fixtures/config/1.change-options/tailwindcss-mangle.config.ts b/packages/engine/test/fixtures/config/1.change-options/tailwindcss-mangle.config.ts new file mode 100644 index 00000000..9126834e --- /dev/null +++ b/packages/engine/test/fixtures/config/1.change-options/tailwindcss-mangle.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'tailwindcss-patch' + +export default defineConfig({ + registry: { + output: { + file: 'xxx/yyy/zzz.json', + pretty: false, + stripUniversalSelector: false, + }, + tailwind: { + classic: { + cwd: 'aaa/bbb/cc', + }, + }, + }, +}) diff --git a/packages/engine/test/fixtures/config/1.change-options/tailwindcss-patch.config.ts b/packages/engine/test/fixtures/config/1.change-options/tailwindcss-patch.config.ts new file mode 100644 index 00000000..9126834e --- /dev/null +++ b/packages/engine/test/fixtures/config/1.change-options/tailwindcss-patch.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'tailwindcss-patch' + +export default defineConfig({ + registry: { + output: { + file: 'xxx/yyy/zzz.json', + pretty: false, + stripUniversalSelector: false, + }, + tailwind: { + classic: { + cwd: 'aaa/bbb/cc', + }, + }, + }, +}) diff --git a/packages/engine/test/fixtures/hello-world.css b/packages/engine/test/fixtures/hello-world.css new file mode 100644 index 00000000..f6745ef0 --- /dev/null +++ b/packages/engine/test/fixtures/hello-world.css @@ -0,0 +1,10 @@ +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} +.font-bold { + font-weight: 700; +} +.underline { + text-decoration-line: underline; +} diff --git a/packages/engine/test/fixtures/hello-world.html b/packages/engine/test/fixtures/hello-world.html new file mode 100644 index 00000000..0e3ea88e --- /dev/null +++ b/packages/engine/test/fixtures/hello-world.html @@ -0,0 +1,16 @@ + + + + + + + + + + +

+ Hello world! +

+ + + diff --git a/packages/engine/test/fixtures/hello-world.js b/packages/engine/test/fixtures/hello-world.js new file mode 100644 index 00000000..82fc3bb2 --- /dev/null +++ b/packages/engine/test/fixtures/hello-world.js @@ -0,0 +1,2 @@ +const el = document.getElementById('#app') +el && el.classList.add('bg-[#123456]') diff --git a/packages/engine/test/fixtures/hello-world.wxml b/packages/engine/test/fixtures/hello-world.wxml new file mode 100644 index 00000000..ff2ebc7e --- /dev/null +++ b/packages/engine/test/fixtures/hello-world.wxml @@ -0,0 +1 @@ +111 \ No newline at end of file diff --git a/packages/engine/test/fixtures/http-headers.ts b/packages/engine/test/fixtures/http-headers.ts new file mode 100644 index 00000000..86bb4b30 --- /dev/null +++ b/packages/engine/test/fixtures/http-headers.ts @@ -0,0 +1,11 @@ +const headers = { + Accept: 'text/event-stream', + 'Content-Type': 'text/plain', + 'X-HTML': 'text/html', +} + +export function useHeaders() { + return headers +} + +export const classes = `Hello` diff --git a/packages/engine/test/fixtures/img-url.jsx b/packages/engine/test/fixtures/img-url.jsx new file mode 100644 index 00000000..7ff941fc --- /dev/null +++ b/packages/engine/test/fixtures/img-url.jsx @@ -0,0 +1,3 @@ +export function Hello() { + return
+} diff --git a/packages/engine/test/fixtures/postcss7-compat/lib/jit/index.js b/packages/engine/test/fixtures/postcss7-compat/lib/jit/index.js new file mode 100644 index 00000000..8edcc0b6 --- /dev/null +++ b/packages/engine/test/fixtures/postcss7-compat/lib/jit/index.js @@ -0,0 +1,31 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = _default; + +var _setupTrackingContext = _interopRequireDefault(require("./lib/setupTrackingContext")); + +var _setupWatchingContext = _interopRequireDefault(require("./lib/setupWatchingContext")); + +var _sharedState = require("./lib/sharedState"); + +var _processTailwindFeatures = _interopRequireDefault(require("./processTailwindFeatures")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _default(configOrPath = {}) { + return [_sharedState.env.DEBUG && function (root) { + console.log('\n'); + console.time('JIT TOTAL'); + return root; + }, function (root, result) { + let setupContext = _sharedState.env.TAILWIND_MODE === 'watch' ? (0, _setupWatchingContext.default)(configOrPath) : (0, _setupTrackingContext.default)(configOrPath); + (0, _processTailwindFeatures.default)(setupContext)(root, result); + }, _sharedState.env.DEBUG && function (root) { + console.timeEnd('JIT TOTAL'); + console.log('\n'); + return root; + }].filter(Boolean); +} \ No newline at end of file diff --git a/packages/engine/test/fixtures/postcss7-compat/lib/jit/processTailwindFeatures.js b/packages/engine/test/fixtures/postcss7-compat/lib/jit/processTailwindFeatures.js new file mode 100644 index 00000000..271ffe9a --- /dev/null +++ b/packages/engine/test/fixtures/postcss7-compat/lib/jit/processTailwindFeatures.js @@ -0,0 +1,67 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = processTailwindFeatures; + +var _normalizeTailwindDirectives = _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); + +var _expandTailwindAtRules = _interopRequireDefault(require("./lib/expandTailwindAtRules")); + +var _expandApplyAtRules = _interopRequireDefault(require("./lib/expandApplyAtRules")); + +var _evaluateTailwindFunctions = _interopRequireDefault(require("../lib/evaluateTailwindFunctions")); + +var _substituteScreenAtRules = _interopRequireDefault(require("../lib/substituteScreenAtRules")); + +var _resolveDefaultsAtRules = _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); + +var _collapseAdjacentRules = _interopRequireDefault(require("./lib/collapseAdjacentRules")); + +var _setupContextUtils = require("./lib/setupContextUtils"); + +var _log = _interopRequireDefault(require("../util/log")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +let warned = false; + +function processTailwindFeatures(setupContext) { + return function (root, result) { + if (!warned) { + _log.default.warn([`You have enabled the JIT engine which is currently in preview.`, 'Preview features are not covered by semver, may introduce breaking changes, and can change at any time.']); + + warned = true; + } + + let tailwindDirectives = (0, _normalizeTailwindDirectives.default)(root); + let context = setupContext({ + tailwindDirectives, + + registerDependency(dependency) { + result.messages.push({ + plugin: 'tailwindcss', + parent: result.opts.from, + ...dependency + }); + }, + + createContext(tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, tailwindDirectives, root); + } + + })(root, result); + + if (context.tailwindConfig.separator === '-') { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + + (0, _expandTailwindAtRules.default)(context)(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + }; +} \ No newline at end of file diff --git a/packages/engine/test/fixtures/token-scan/button.tsx b/packages/engine/test/fixtures/token-scan/button.tsx new file mode 100644 index 00000000..b7c35c47 --- /dev/null +++ b/packages/engine/test/fixtures/token-scan/button.tsx @@ -0,0 +1,7 @@ +export function Button() { + return ( + + ) +} diff --git a/packages/engine/test/fixtures/token-scan/page.html b/packages/engine/test/fixtures/token-scan/page.html new file mode 100644 index 00000000..6c665dfa --- /dev/null +++ b/packages/engine/test/fixtures/token-scan/page.html @@ -0,0 +1,8 @@ + + + +
+

Token scan

+
+ + diff --git a/packages/engine/test/fixtures/trailing-slash.vue b/packages/engine/test/fixtures/trailing-slash.vue new file mode 100644 index 00000000..5f6b8b10 --- /dev/null +++ b/packages/engine/test/fixtures/trailing-slash.vue @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/packages/engine/test/fixtures/v4/.gitignore b/packages/engine/test/fixtures/v4/.gitignore new file mode 100644 index 00000000..a8f4870e --- /dev/null +++ b/packages/engine/test/fixtures/v4/.gitignore @@ -0,0 +1 @@ +!patch/dist \ No newline at end of file diff --git a/packages/engine/test/fixtures/v4/deep/index.html b/packages/engine/test/fixtures/v4/deep/index.html new file mode 100644 index 00000000..af352c7b --- /dev/null +++ b/packages/engine/test/fixtures/v4/deep/index.html @@ -0,0 +1,11 @@ + + + + + + Document + + +
+ + \ No newline at end of file diff --git a/packages/engine/test/fixtures/v4/features-4.2.html b/packages/engine/test/fixtures/v4/features-4.2.html new file mode 100644 index 00000000..5569e472 --- /dev/null +++ b/packages/engine/test/fixtures/v4/features-4.2.html @@ -0,0 +1,23 @@ + + + + + + Tailwind 4.2 Fixture + + +
+ + diff --git a/packages/engine/test/fixtures/v4/index.css b/packages/engine/test/fixtures/v4/index.css new file mode 100644 index 00000000..4f9a933c --- /dev/null +++ b/packages/engine/test/fixtures/v4/index.css @@ -0,0 +1 @@ +@import "tailwindcss" ; diff --git a/packages/engine/test/fixtures/v4/index.html b/packages/engine/test/fixtures/v4/index.html new file mode 100644 index 00000000..3d926b3f --- /dev/null +++ b/packages/engine/test/fixtures/v4/index.html @@ -0,0 +1,11 @@ + + + + + + Document + + +
+ + \ No newline at end of file diff --git a/packages/engine/test/fixtures/v4/patch/dist/a.mjs b/packages/engine/test/fixtures/v4/patch/dist/a.mjs new file mode 100644 index 00000000..365a485a --- /dev/null +++ b/packages/engine/test/fixtures/v4/patch/dist/a.mjs @@ -0,0 +1,2 @@ +var K = ["cm","mm","Q","in","pc","pt","px","em","ex","ch","rem","lh","rlh","vw","vh","vmin","vmax","vb","vi","svw","svh","lvw","lvh","dvw","dvh","cqw","cqh","cqi","cqb","cqmin","cqmax","rpx"], + Y = new RegExp(`^${g.source}(${K.join("|")})$`); \ No newline at end of file diff --git a/packages/engine/test/fixtures/v4/patch/dist/chunk-V2K3XTS4.mjs b/packages/engine/test/fixtures/v4/patch/dist/chunk-V2K3XTS4.mjs new file mode 100644 index 00000000..a838a133 --- /dev/null +++ b/packages/engine/test/fixtures/v4/patch/dist/chunk-V2K3XTS4.mjs @@ -0,0 +1,1474 @@ +import { a as v } from "./chunk-AZANAYY2.mjs"; +var U = new Set([ + "black", + "silver", + "gray", + "white", + "maroon", + "red", + "purple", + "fuchsia", + "green", + "lime", + "olive", + "yellow", + "navy", + "blue", + "teal", + "aqua", + "aliceblue", + "antiquewhite", + "aqua", + "aquamarine", + "azure", + "beige", + "bisque", + "black", + "blanchedalmond", + "blue", + "blueviolet", + "brown", + "burlywood", + "cadetblue", + "chartreuse", + "chocolate", + "coral", + "cornflowerblue", + "cornsilk", + "crimson", + "cyan", + "darkblue", + "darkcyan", + "darkgoldenrod", + "darkgray", + "darkgreen", + "darkgrey", + "darkkhaki", + "darkmagenta", + "darkolivegreen", + "darkorange", + "darkorchid", + "darkred", + "darksalmon", + "darkseagreen", + "darkslateblue", + "darkslategray", + "darkslategrey", + "darkturquoise", + "darkviolet", + "deeppink", + "deepskyblue", + "dimgray", + "dimgrey", + "dodgerblue", + "firebrick", + "floralwhite", + "forestgreen", + "fuchsia", + "gainsboro", + "ghostwhite", + "gold", + "goldenrod", + "gray", + "green", + "greenyellow", + "grey", + "honeydew", + "hotpink", + "indianred", + "indigo", + "ivory", + "khaki", + "lavender", + "lavenderblush", + "lawngreen", + "lemonchiffon", + "lightblue", + "lightcoral", + "lightcyan", + "lightgoldenrodyellow", + "lightgray", + "lightgreen", + "lightgrey", + "lightpink", + "lightsalmon", + "lightseagreen", + "lightskyblue", + "lightslategray", + "lightslategrey", + "lightsteelblue", + "lightyellow", + "lime", + "limegreen", + "linen", + "magenta", + "maroon", + "mediumaquamarine", + "mediumblue", + "mediumorchid", + "mediumpurple", + "mediumseagreen", + "mediumslateblue", + "mediumspringgreen", + "mediumturquoise", + "mediumvioletred", + "midnightblue", + "mintcream", + "mistyrose", + "moccasin", + "navajowhite", + "navy", + "oldlace", + "olive", + "olivedrab", + "orange", + "orangered", + "orchid", + "palegoldenrod", + "palegreen", + "paleturquoise", + "palevioletred", + "papayawhip", + "peachpuff", + "peru", + "pink", + "plum", + "powderblue", + "purple", + "rebeccapurple", + "red", + "rosybrown", + "royalblue", + "saddlebrown", + "salmon", + "sandybrown", + "seagreen", + "seashell", + "sienna", + "silver", + "skyblue", + "slateblue", + "slategray", + "slategrey", + "snow", + "springgreen", + "steelblue", + "tan", + "teal", + "thistle", + "tomato", + "turquoise", + "violet", + "wheat", + "white", + "whitesmoke", + "yellow", + "yellowgreen", + "transparent", + "currentcolor", + "canvas", + "canvastext", + "linktext", + "visitedtext", + "activetext", + "buttonface", + "buttontext", + "buttonborder", + "field", + "fieldtext", + "highlight", + "highlighttext", + "selecteditem", + "selecteditemtext", + "mark", + "marktext", + "graytext", + "accentcolor", + "accentcolortext", + ]), + O = /^(rgba?|hsla?|hwb|color|(ok)?(lab|lch)|light-dark|color-mix)\(/i; +function S(e) { + return e.charCodeAt(0) === 35 || O.test(e) || U.has(e.toLowerCase()); +} +var k = [ + "calc", + "min", + "max", + "clamp", + "mod", + "rem", + "sin", + "cos", + "tan", + "asin", + "acos", + "atan", + "atan2", + "pow", + "sqrt", + "hypot", + "log", + "exp", + "round", + ], + h = ["anchor-size"], + A = new RegExp(`(${h.join("|")})\\(`, "g"); +function b(e) { + return e.indexOf("(") !== -1 && k.some((r) => e.includes(`${r}(`)); +} +function ie(e) { + if (!k.some((n) => e.includes(n))) return e; + let r = !1; + h.some((n) => e.includes(n)) && + ((A.lastIndex = 0), + (e = e.replace(A, (n, o) => ((r = !0), `$${h.indexOf(o)}$(`)))); + let t = "", + i = []; + for (let n = 0; n < e.length; n++) { + let o = e[n]; + if (o === "(") { + t += o; + let m = n; + for (let c = n - 1; c >= 0; c--) { + let x = e.charCodeAt(c); + if (x >= 48 && x <= 57) m = c; + else if (x >= 97 && x <= 122) m = c; + else break; + } + let a = e.slice(m, n); + if (k.includes(a)) { + i.unshift(!0); + continue; + } else if (i[0] && a === "") { + i.unshift(!0); + continue; + } + i.unshift(!1); + continue; + } else if (o === ")") (t += o), i.shift(); + else if (o === "," && i[0]) { + t += ", "; + continue; + } else { + if (o === " " && i[0] && t[t.length - 1] === " ") continue; + if ((o === "+" || o === "*" || o === "/" || o === "-") && i[0]) { + let m = t.trimEnd(), + a = m[m.length - 1]; + if (a === "+" || a === "*" || a === "/" || a === "-") { + t += o; + continue; + } else if (a === "(" || a === ",") { + t += o; + continue; + } else e[n - 1] === " " ? (t += `${o} `) : (t += ` ${o} `); + } else if (i[0] && e.startsWith("to-zero", n)) { + let m = n; + (n += 7), (t += e.slice(m, n + 1)); + } else t += o; + } + } + return r ? t.replace(/\$(\d+)\$/g, (n, o) => h[o] ?? n) : t; +} +var y = new Uint8Array(256); +function u(e, r) { + let t = 0, + i = [], + n = 0, + o = e.length, + m = r.charCodeAt(0); + for (let a = 0; a < o; a++) { + let c = e.charCodeAt(a); + if (t === 0 && c === m) { + i.push(e.slice(n, a)), (n = a + 1); + continue; + } + switch (c) { + case 92: + a += 1; + break; + case 39: + case 34: + for (; ++a < o; ) { + let x = e.charCodeAt(a); + if (x === 92) { + a += 1; + continue; + } + if (x === c) break; + } + break; + case 40: + (y[t] = 41), t++; + break; + case 91: + (y[t] = 93), t++; + break; + case 123: + (y[t] = 125), t++; + break; + case 93: + case 125: + case 41: + t > 0 && c === y[t - 1] && t--; + break; + } + } + return i.push(e.slice(n)), i; +} +var R = { + color: S, + length: C, + percentage: E, + ratio: j, + number: M, + integer: p, + url: z, + position: Q, + "bg-size": X, + "line-width": D, + image: $, + "family-name": P, + "generic-name": H, + "absolute-size": q, + "relative-size": B, + angle: ee, + vector: re, +}; +function pe(e, r) { + if (e.startsWith("var(")) return null; + for (let t of r) if (R[t]?.(e)) return t; + return null; +} +var _ = /^url\(.*\)$/; +function z(e) { + return _.test(e); +} +function D(e) { + return e === "thin" || e === "medium" || e === "thick"; +} +var I = /^(?:element|image|cross-fade|image-set)\(/, + F = /^(repeating-)?(conic|linear|radial)-gradient\(/; +function $(e) { + let r = 0; + for (let t of u(e, ",")) + if (!t.startsWith("var(")) { + if (z(t)) { + r += 1; + continue; + } + if (F.test(t)) { + r += 1; + continue; + } + if (I.test(t)) { + r += 1; + continue; + } + return !1; + } + return r > 0; +} +function H(e) { + return ( + e === "serif" || + e === "sans-serif" || + e === "monospace" || + e === "cursive" || + e === "fantasy" || + e === "system-ui" || + e === "ui-serif" || + e === "ui-sans-serif" || + e === "ui-monospace" || + e === "ui-rounded" || + e === "math" || + e === "emoji" || + e === "fangsong" + ); +} +function P(e) { + let r = 0; + for (let t of u(e, ",")) { + let i = t.charCodeAt(0); + if (i >= 48 && i <= 57) return !1; + t.startsWith("var(") || (r += 1); + } + return r > 0; +} +function q(e) { + return ( + e === "xx-small" || + e === "x-small" || + e === "small" || + e === "medium" || + e === "large" || + e === "x-large" || + e === "xx-large" || + e === "xxx-large" + ); +} +function B(e) { + return e === "larger" || e === "smaller"; +} +var g = /[+-]?\d*\.?\d+(?:[eE][+-]?\d+)?/, + W = new RegExp(`^${g.source}$`); +function M(e) { + return W.test(e) || b(e); +} +var G = new RegExp(`^${g.source}%$`); +function E(e) { + return G.test(e) || b(e); +} +var V = new RegExp(`^${g.source}s*/s*${g.source}$`); +function j(e) { + return V.test(e) || b(e); +} +var K = ["cm","mm","Q","in","pc","pt","px","em","ex","ch","rem","lh","rlh","vw","vh","vmin","vmax","vb","vi","svw","svh","lvw","lvh","dvw","dvh","cqw","cqh","cqi","cqb","cqmin","cqmax","rpx"], + Y = new RegExp(`^${g.source}(${K.join("|")})$`); +function C(e) { + return Y.test(e) || b(e); +} +function Q(e) { + let r = 0; + for (let t of u(e, " ")) { + if ( + t === "center" || + t === "top" || + t === "right" || + t === "bottom" || + t === "left" + ) { + r += 1; + continue; + } + if (!t.startsWith("var(")) { + if (C(t) || E(t)) { + r += 1; + continue; + } + return !1; + } + } + return r > 0; +} +function X(e) { + let r = 0; + for (let t of u(e, ",")) { + if (t === "cover" || t === "contain") { + r += 1; + continue; + } + let i = u(t, " "); + if (i.length !== 1 && i.length !== 2) return !1; + if (i.every((n) => n === "auto" || C(n) || E(n))) { + r += 1; + continue; + } + } + return r > 0; +} +var J = ["deg", "rad", "grad", "turn"], + Z = new RegExp(`^${g.source}(${J.join("|")})$`); +function ee(e) { + return Z.test(e); +} +var te = new RegExp(`^${g.source} +${g.source} +${g.source}$`); +function re(e) { + return te.test(e); +} +function p(e) { + let r = Number(e); + return Number.isInteger(r) && r >= 0 && String(r) === String(e); +} +function ge(e) { + let r = Number(e); + return Number.isInteger(r) && r > 0 && String(r) === String(e); +} +function ue(e) { + return N(e, 0.25); +} +function de(e) { + return N(e, 0.25); +} +function N(e, r) { + let t = Number(e); + return t >= 0 && t % r === 0 && String(t) === String(e); +} +function f(e) { + return { __BARE_VALUE__: e }; +} +var l = f((e) => { + if (p(e.value)) return e.value; + }), + s = f((e) => { + if (p(e.value)) return `${e.value}%`; + }), + d = f((e) => { + if (p(e.value)) return `${e.value}px`; + }), + T = f((e) => { + if (p(e.value)) return `${e.value}ms`; + }), + w = f((e) => { + if (p(e.value)) return `${e.value}deg`; + }), + ne = f((e) => { + if (e.fraction === null) return; + let [r, t] = u(e.fraction, "/"); + if (!(!p(r) || !p(t))) return e.fraction; + }), + L = f((e) => { + if (p(Number(e.value))) return `repeat(${e.value}, minmax(0, 1fr))`; + }), + ye = { + accentColor: ({ theme: e }) => e("colors"), + animation: { + none: "none", + spin: "spin 1s linear infinite", + ping: "ping 1s cubic-bezier(0, 0, 0.2, 1) infinite", + pulse: "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite", + bounce: "bounce 1s infinite", + }, + aria: { + busy: 'busy="true"', + checked: 'checked="true"', + disabled: 'disabled="true"', + expanded: 'expanded="true"', + hidden: 'hidden="true"', + pressed: 'pressed="true"', + readonly: 'readonly="true"', + required: 'required="true"', + selected: 'selected="true"', + }, + aspectRatio: { auto: "auto", square: "1 / 1", video: "16 / 9", ...ne }, + backdropBlur: ({ theme: e }) => e("blur"), + backdropBrightness: ({ theme: e }) => ({ ...e("brightness"), ...s }), + backdropContrast: ({ theme: e }) => ({ ...e("contrast"), ...s }), + backdropGrayscale: ({ theme: e }) => ({ ...e("grayscale"), ...s }), + backdropHueRotate: ({ theme: e }) => ({ ...e("hueRotate"), ...w }), + backdropInvert: ({ theme: e }) => ({ ...e("invert"), ...s }), + backdropOpacity: ({ theme: e }) => ({ ...e("opacity"), ...s }), + backdropSaturate: ({ theme: e }) => ({ ...e("saturate"), ...s }), + backdropSepia: ({ theme: e }) => ({ ...e("sepia"), ...s }), + backgroundColor: ({ theme: e }) => e("colors"), + backgroundImage: { + none: "none", + "gradient-to-t": "linear-gradient(to top, var(--tw-gradient-stops))", + "gradient-to-tr": + "linear-gradient(to top right, var(--tw-gradient-stops))", + "gradient-to-r": "linear-gradient(to right, var(--tw-gradient-stops))", + "gradient-to-br": + "linear-gradient(to bottom right, var(--tw-gradient-stops))", + "gradient-to-b": "linear-gradient(to bottom, var(--tw-gradient-stops))", + "gradient-to-bl": + "linear-gradient(to bottom left, var(--tw-gradient-stops))", + "gradient-to-l": "linear-gradient(to left, var(--tw-gradient-stops))", + "gradient-to-tl": + "linear-gradient(to top left, var(--tw-gradient-stops))", + }, + backgroundOpacity: ({ theme: e }) => e("opacity"), + backgroundPosition: { + bottom: "bottom", + center: "center", + left: "left", + "left-bottom": "left bottom", + "left-top": "left top", + right: "right", + "right-bottom": "right bottom", + "right-top": "right top", + top: "top", + }, + backgroundSize: { auto: "auto", cover: "cover", contain: "contain" }, + blur: { + 0: "0", + none: "", + sm: "4px", + DEFAULT: "8px", + md: "12px", + lg: "16px", + xl: "24px", + "2xl": "40px", + "3xl": "64px", + }, + borderColor: ({ theme: e }) => ({ + DEFAULT: "currentColor", + ...e("colors"), + }), + borderOpacity: ({ theme: e }) => e("opacity"), + borderRadius: { + none: "0px", + sm: "0.125rem", + DEFAULT: "0.25rem", + md: "0.375rem", + lg: "0.5rem", + xl: "0.75rem", + "2xl": "1rem", + "3xl": "1.5rem", + full: "9999px", + }, + borderSpacing: ({ theme: e }) => e("spacing"), + borderWidth: { + DEFAULT: "1px", + 0: "0px", + 2: "2px", + 4: "4px", + 8: "8px", + ...d, + }, + boxShadow: { + sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)", + DEFAULT: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)", + md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)", + lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)", + xl: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)", + "2xl": "0 25px 50px -12px rgb(0 0 0 / 0.25)", + inner: "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)", + none: "none", + }, + boxShadowColor: ({ theme: e }) => e("colors"), + brightness: { + 0: "0", + 50: ".5", + 75: ".75", + 90: ".9", + 95: ".95", + 100: "1", + 105: "1.05", + 110: "1.1", + 125: "1.25", + 150: "1.5", + 200: "2", + ...s, + }, + caretColor: ({ theme: e }) => e("colors"), + colors: () => ({ ...v }), + columns: { + auto: "auto", + 1: "1", + 2: "2", + 3: "3", + 4: "4", + 5: "5", + 6: "6", + 7: "7", + 8: "8", + 9: "9", + 10: "10", + 11: "11", + 12: "12", + "3xs": "16rem", + "2xs": "18rem", + xs: "20rem", + sm: "24rem", + md: "28rem", + lg: "32rem", + xl: "36rem", + "2xl": "42rem", + "3xl": "48rem", + "4xl": "56rem", + "5xl": "64rem", + "6xl": "72rem", + "7xl": "80rem", + ...l, + }, + container: {}, + content: { none: "none" }, + contrast: { + 0: "0", + 50: ".5", + 75: ".75", + 100: "1", + 125: "1.25", + 150: "1.5", + 200: "2", + ...s, + }, + cursor: { + auto: "auto", + default: "default", + pointer: "pointer", + wait: "wait", + text: "text", + move: "move", + help: "help", + "not-allowed": "not-allowed", + none: "none", + "context-menu": "context-menu", + progress: "progress", + cell: "cell", + crosshair: "crosshair", + "vertical-text": "vertical-text", + alias: "alias", + copy: "copy", + "no-drop": "no-drop", + grab: "grab", + grabbing: "grabbing", + "all-scroll": "all-scroll", + "col-resize": "col-resize", + "row-resize": "row-resize", + "n-resize": "n-resize", + "e-resize": "e-resize", + "s-resize": "s-resize", + "w-resize": "w-resize", + "ne-resize": "ne-resize", + "nw-resize": "nw-resize", + "se-resize": "se-resize", + "sw-resize": "sw-resize", + "ew-resize": "ew-resize", + "ns-resize": "ns-resize", + "nesw-resize": "nesw-resize", + "nwse-resize": "nwse-resize", + "zoom-in": "zoom-in", + "zoom-out": "zoom-out", + }, + divideColor: ({ theme: e }) => e("borderColor"), + divideOpacity: ({ theme: e }) => e("borderOpacity"), + divideWidth: ({ theme: e }) => ({ ...e("borderWidth"), ...d }), + dropShadow: { + sm: "0 1px 1px rgb(0 0 0 / 0.05)", + DEFAULT: ["0 1px 2px rgb(0 0 0 / 0.1)", "0 1px 1px rgb(0 0 0 / 0.06)"], + md: ["0 4px 3px rgb(0 0 0 / 0.07)", "0 2px 2px rgb(0 0 0 / 0.06)"], + lg: ["0 10px 8px rgb(0 0 0 / 0.04)", "0 4px 3px rgb(0 0 0 / 0.1)"], + xl: ["0 20px 13px rgb(0 0 0 / 0.03)", "0 8px 5px rgb(0 0 0 / 0.08)"], + "2xl": "0 25px 25px rgb(0 0 0 / 0.15)", + none: "0 0 #0000", + }, + fill: ({ theme: e }) => e("colors"), + flex: { 1: "1 1 0%", auto: "1 1 auto", initial: "0 1 auto", none: "none" }, + flexBasis: ({ theme: e }) => ({ + auto: "auto", + "1/2": "50%", + "1/3": "33.333333%", + "2/3": "66.666667%", + "1/4": "25%", + "2/4": "50%", + "3/4": "75%", + "1/5": "20%", + "2/5": "40%", + "3/5": "60%", + "4/5": "80%", + "1/6": "16.666667%", + "2/6": "33.333333%", + "3/6": "50%", + "4/6": "66.666667%", + "5/6": "83.333333%", + "1/12": "8.333333%", + "2/12": "16.666667%", + "3/12": "25%", + "4/12": "33.333333%", + "5/12": "41.666667%", + "6/12": "50%", + "7/12": "58.333333%", + "8/12": "66.666667%", + "9/12": "75%", + "10/12": "83.333333%", + "11/12": "91.666667%", + full: "100%", + ...e("spacing"), + }), + flexGrow: { 0: "0", DEFAULT: "1", ...l }, + flexShrink: { 0: "0", DEFAULT: "1", ...l }, + fontFamily: { + sans: [ + "ui-sans-serif", + "system-ui", + "sans-serif", + '"Apple Color Emoji"', + '"Segoe UI Emoji"', + '"Segoe UI Symbol"', + '"Noto Color Emoji"', + ], + serif: [ + "ui-serif", + "Georgia", + "Cambria", + '"Times New Roman"', + "Times", + "serif", + ], + mono: [ + "ui-monospace", + "SFMono-Regular", + "Menlo", + "Monaco", + "Consolas", + '"Liberation Mono"', + '"Courier New"', + "monospace", + ], + }, + fontSize: { + xs: ["0.75rem", { lineHeight: "1rem" }], + sm: ["0.875rem", { lineHeight: "1.25rem" }], + base: ["1rem", { lineHeight: "1.5rem" }], + lg: ["1.125rem", { lineHeight: "1.75rem" }], + xl: ["1.25rem", { lineHeight: "1.75rem" }], + "2xl": ["1.5rem", { lineHeight: "2rem" }], + "3xl": ["1.875rem", { lineHeight: "2.25rem" }], + "4xl": ["2.25rem", { lineHeight: "2.5rem" }], + "5xl": ["3rem", { lineHeight: "1" }], + "6xl": ["3.75rem", { lineHeight: "1" }], + "7xl": ["4.5rem", { lineHeight: "1" }], + "8xl": ["6rem", { lineHeight: "1" }], + "9xl": ["8rem", { lineHeight: "1" }], + }, + fontWeight: { + thin: "100", + extralight: "200", + light: "300", + normal: "400", + medium: "500", + semibold: "600", + bold: "700", + extrabold: "800", + black: "900", + }, + gap: ({ theme: e }) => e("spacing"), + gradientColorStops: ({ theme: e }) => e("colors"), + gradientColorStopPositions: { + "0%": "0%", + "5%": "5%", + "10%": "10%", + "15%": "15%", + "20%": "20%", + "25%": "25%", + "30%": "30%", + "35%": "35%", + "40%": "40%", + "45%": "45%", + "50%": "50%", + "55%": "55%", + "60%": "60%", + "65%": "65%", + "70%": "70%", + "75%": "75%", + "80%": "80%", + "85%": "85%", + "90%": "90%", + "95%": "95%", + "100%": "100%", + ...s, + }, + grayscale: { 0: "0", DEFAULT: "100%", ...s }, + gridAutoColumns: { + auto: "auto", + min: "min-content", + max: "max-content", + fr: "minmax(0, 1fr)", + }, + gridAutoRows: { + auto: "auto", + min: "min-content", + max: "max-content", + fr: "minmax(0, 1fr)", + }, + gridColumn: { + auto: "auto", + "span-1": "span 1 / span 1", + "span-2": "span 2 / span 2", + "span-3": "span 3 / span 3", + "span-4": "span 4 / span 4", + "span-5": "span 5 / span 5", + "span-6": "span 6 / span 6", + "span-7": "span 7 / span 7", + "span-8": "span 8 / span 8", + "span-9": "span 9 / span 9", + "span-10": "span 10 / span 10", + "span-11": "span 11 / span 11", + "span-12": "span 12 / span 12", + "span-full": "1 / -1", + }, + gridColumnEnd: { + auto: "auto", + 1: "1", + 2: "2", + 3: "3", + 4: "4", + 5: "5", + 6: "6", + 7: "7", + 8: "8", + 9: "9", + 10: "10", + 11: "11", + 12: "12", + 13: "13", + ...l, + }, + gridColumnStart: { + auto: "auto", + 1: "1", + 2: "2", + 3: "3", + 4: "4", + 5: "5", + 6: "6", + 7: "7", + 8: "8", + 9: "9", + 10: "10", + 11: "11", + 12: "12", + 13: "13", + ...l, + }, + gridRow: { + auto: "auto", + "span-1": "span 1 / span 1", + "span-2": "span 2 / span 2", + "span-3": "span 3 / span 3", + "span-4": "span 4 / span 4", + "span-5": "span 5 / span 5", + "span-6": "span 6 / span 6", + "span-7": "span 7 / span 7", + "span-8": "span 8 / span 8", + "span-9": "span 9 / span 9", + "span-10": "span 10 / span 10", + "span-11": "span 11 / span 11", + "span-12": "span 12 / span 12", + "span-full": "1 / -1", + }, + gridRowEnd: { + auto: "auto", + 1: "1", + 2: "2", + 3: "3", + 4: "4", + 5: "5", + 6: "6", + 7: "7", + 8: "8", + 9: "9", + 10: "10", + 11: "11", + 12: "12", + 13: "13", + ...l, + }, + gridRowStart: { + auto: "auto", + 1: "1", + 2: "2", + 3: "3", + 4: "4", + 5: "5", + 6: "6", + 7: "7", + 8: "8", + 9: "9", + 10: "10", + 11: "11", + 12: "12", + 13: "13", + ...l, + }, + gridTemplateColumns: { + none: "none", + subgrid: "subgrid", + 1: "repeat(1, minmax(0, 1fr))", + 2: "repeat(2, minmax(0, 1fr))", + 3: "repeat(3, minmax(0, 1fr))", + 4: "repeat(4, minmax(0, 1fr))", + 5: "repeat(5, minmax(0, 1fr))", + 6: "repeat(6, minmax(0, 1fr))", + 7: "repeat(7, minmax(0, 1fr))", + 8: "repeat(8, minmax(0, 1fr))", + 9: "repeat(9, minmax(0, 1fr))", + 10: "repeat(10, minmax(0, 1fr))", + 11: "repeat(11, minmax(0, 1fr))", + 12: "repeat(12, minmax(0, 1fr))", + ...L, + }, + gridTemplateRows: { + none: "none", + subgrid: "subgrid", + 1: "repeat(1, minmax(0, 1fr))", + 2: "repeat(2, minmax(0, 1fr))", + 3: "repeat(3, minmax(0, 1fr))", + 4: "repeat(4, minmax(0, 1fr))", + 5: "repeat(5, minmax(0, 1fr))", + 6: "repeat(6, minmax(0, 1fr))", + 7: "repeat(7, minmax(0, 1fr))", + 8: "repeat(8, minmax(0, 1fr))", + 9: "repeat(9, minmax(0, 1fr))", + 10: "repeat(10, minmax(0, 1fr))", + 11: "repeat(11, minmax(0, 1fr))", + 12: "repeat(12, minmax(0, 1fr))", + ...L, + }, + height: ({ theme: e }) => ({ + auto: "auto", + "1/2": "50%", + "1/3": "33.333333%", + "2/3": "66.666667%", + "1/4": "25%", + "2/4": "50%", + "3/4": "75%", + "1/5": "20%", + "2/5": "40%", + "3/5": "60%", + "4/5": "80%", + "1/6": "16.666667%", + "2/6": "33.333333%", + "3/6": "50%", + "4/6": "66.666667%", + "5/6": "83.333333%", + full: "100%", + screen: "100vh", + svh: "100svh", + lvh: "100lvh", + dvh: "100dvh", + min: "min-content", + max: "max-content", + fit: "fit-content", + ...e("spacing"), + }), + hueRotate: { + 0: "0deg", + 15: "15deg", + 30: "30deg", + 60: "60deg", + 90: "90deg", + 180: "180deg", + ...w, + }, + inset: ({ theme: e }) => ({ + auto: "auto", + "1/2": "50%", + "1/3": "33.333333%", + "2/3": "66.666667%", + "1/4": "25%", + "2/4": "50%", + "3/4": "75%", + full: "100%", + ...e("spacing"), + }), + invert: { 0: "0", DEFAULT: "100%", ...s }, + keyframes: { + spin: { to: { transform: "rotate(360deg)" } }, + ping: { "75%, 100%": { transform: "scale(2)", opacity: "0" } }, + pulse: { "50%": { opacity: ".5" } }, + bounce: { + "0%, 100%": { + transform: "translateY(-25%)", + animationTimingFunction: "cubic-bezier(0.8,0,1,1)", + }, + "50%": { + transform: "none", + animationTimingFunction: "cubic-bezier(0,0,0.2,1)", + }, + }, + }, + letterSpacing: { + tighter: "-0.05em", + tight: "-0.025em", + normal: "0em", + wide: "0.025em", + wider: "0.05em", + widest: "0.1em", + }, + lineHeight: { + none: "1", + tight: "1.25", + snug: "1.375", + normal: "1.5", + relaxed: "1.625", + loose: "2", + 3: ".75rem", + 4: "1rem", + 5: "1.25rem", + 6: "1.5rem", + 7: "1.75rem", + 8: "2rem", + 9: "2.25rem", + 10: "2.5rem", + }, + listStyleType: { none: "none", disc: "disc", decimal: "decimal" }, + listStyleImage: { none: "none" }, + margin: ({ theme: e }) => ({ auto: "auto", ...e("spacing") }), + lineClamp: { 1: "1", 2: "2", 3: "3", 4: "4", 5: "5", 6: "6", ...l }, + maxHeight: ({ theme: e }) => ({ + none: "none", + full: "100%", + screen: "100vh", + svh: "100svh", + lvh: "100lvh", + dvh: "100dvh", + min: "min-content", + max: "max-content", + fit: "fit-content", + ...e("spacing"), + }), + maxWidth: ({ theme: e }) => ({ + none: "none", + xs: "20rem", + sm: "24rem", + md: "28rem", + lg: "32rem", + xl: "36rem", + "2xl": "42rem", + "3xl": "48rem", + "4xl": "56rem", + "5xl": "64rem", + "6xl": "72rem", + "7xl": "80rem", + full: "100%", + min: "min-content", + max: "max-content", + fit: "fit-content", + prose: "65ch", + ...e("spacing"), + }), + minHeight: ({ theme: e }) => ({ + full: "100%", + screen: "100vh", + svh: "100svh", + lvh: "100lvh", + dvh: "100dvh", + min: "min-content", + max: "max-content", + fit: "fit-content", + ...e("spacing"), + }), + minWidth: ({ theme: e }) => ({ + full: "100%", + min: "min-content", + max: "max-content", + fit: "fit-content", + ...e("spacing"), + }), + objectPosition: { + bottom: "bottom", + center: "center", + left: "left", + "left-bottom": "left bottom", + "left-top": "left top", + right: "right", + "right-bottom": "right bottom", + "right-top": "right top", + top: "top", + }, + opacity: { + 0: "0", + 5: "0.05", + 10: "0.1", + 15: "0.15", + 20: "0.2", + 25: "0.25", + 30: "0.3", + 35: "0.35", + 40: "0.4", + 45: "0.45", + 50: "0.5", + 55: "0.55", + 60: "0.6", + 65: "0.65", + 70: "0.7", + 75: "0.75", + 80: "0.8", + 85: "0.85", + 90: "0.9", + 95: "0.95", + 100: "1", + ...s, + }, + order: { + first: "-9999", + last: "9999", + none: "0", + 1: "1", + 2: "2", + 3: "3", + 4: "4", + 5: "5", + 6: "6", + 7: "7", + 8: "8", + 9: "9", + 10: "10", + 11: "11", + 12: "12", + ...l, + }, + outlineColor: ({ theme: e }) => e("colors"), + outlineOffset: { 0: "0px", 1: "1px", 2: "2px", 4: "4px", 8: "8px", ...d }, + outlineWidth: { 0: "0px", 1: "1px", 2: "2px", 4: "4px", 8: "8px", ...d }, + padding: ({ theme: e }) => e("spacing"), + placeholderColor: ({ theme: e }) => e("colors"), + placeholderOpacity: ({ theme: e }) => e("opacity"), + ringColor: ({ theme: e }) => ({ DEFAULT: "currentColor", ...e("colors") }), + ringOffsetColor: ({ theme: e }) => e("colors"), + ringOffsetWidth: { 0: "0px", 1: "1px", 2: "2px", 4: "4px", 8: "8px", ...d }, + ringOpacity: ({ theme: e }) => ({ DEFAULT: "0.5", ...e("opacity") }), + ringWidth: { + DEFAULT: "3px", + 0: "0px", + 1: "1px", + 2: "2px", + 4: "4px", + 8: "8px", + ...d, + }, + rotate: { + 0: "0deg", + 1: "1deg", + 2: "2deg", + 3: "3deg", + 6: "6deg", + 12: "12deg", + 45: "45deg", + 90: "90deg", + 180: "180deg", + ...w, + }, + saturate: { 0: "0", 50: ".5", 100: "1", 150: "1.5", 200: "2", ...s }, + scale: { + 0: "0", + 50: ".5", + 75: ".75", + 90: ".9", + 95: ".95", + 100: "1", + 105: "1.05", + 110: "1.1", + 125: "1.25", + 150: "1.5", + ...s, + }, + screens: { + sm: "40rem", + md: "48rem", + lg: "64rem", + xl: "80rem", + "2xl": "96rem", + }, + scrollMargin: ({ theme: e }) => e("spacing"), + scrollPadding: ({ theme: e }) => e("spacing"), + sepia: { 0: "0", DEFAULT: "100%", ...s }, + skew: { + 0: "0deg", + 1: "1deg", + 2: "2deg", + 3: "3deg", + 6: "6deg", + 12: "12deg", + ...w, + }, + space: ({ theme: e }) => e("spacing"), + spacing: { + px: "1px", + 0: "0px", + 0.5: "0.125rem", + 1: "0.25rem", + 1.5: "0.375rem", + 2: "0.5rem", + 2.5: "0.625rem", + 3: "0.75rem", + 3.5: "0.875rem", + 4: "1rem", + 5: "1.25rem", + 6: "1.5rem", + 7: "1.75rem", + 8: "2rem", + 9: "2.25rem", + 10: "2.5rem", + 11: "2.75rem", + 12: "3rem", + 14: "3.5rem", + 16: "4rem", + 20: "5rem", + 24: "6rem", + 28: "7rem", + 32: "8rem", + 36: "9rem", + 40: "10rem", + 44: "11rem", + 48: "12rem", + 52: "13rem", + 56: "14rem", + 60: "15rem", + 64: "16rem", + 72: "18rem", + 80: "20rem", + 96: "24rem", + }, + stroke: ({ theme: e }) => ({ none: "none", ...e("colors") }), + strokeWidth: { 0: "0", 1: "1", 2: "2", ...l }, + supports: {}, + data: {}, + textColor: ({ theme: e }) => e("colors"), + textDecorationColor: ({ theme: e }) => e("colors"), + textDecorationThickness: { + auto: "auto", + "from-font": "from-font", + 0: "0px", + 1: "1px", + 2: "2px", + 4: "4px", + 8: "8px", + ...d, + }, + textIndent: ({ theme: e }) => e("spacing"), + textOpacity: ({ theme: e }) => e("opacity"), + textUnderlineOffset: { + auto: "auto", + 0: "0px", + 1: "1px", + 2: "2px", + 4: "4px", + 8: "8px", + ...d, + }, + transformOrigin: { + center: "center", + top: "top", + "top-right": "top right", + right: "right", + "bottom-right": "bottom right", + bottom: "bottom", + "bottom-left": "bottom left", + left: "left", + "top-left": "top left", + }, + transitionDelay: { + 0: "0s", + 75: "75ms", + 100: "100ms", + 150: "150ms", + 200: "200ms", + 300: "300ms", + 500: "500ms", + 700: "700ms", + 1e3: "1000ms", + ...T, + }, + transitionDuration: { + DEFAULT: "150ms", + 0: "0s", + 75: "75ms", + 100: "100ms", + 150: "150ms", + 200: "200ms", + 300: "300ms", + 500: "500ms", + 700: "700ms", + 1e3: "1000ms", + ...T, + }, + transitionProperty: { + none: "none", + all: "all", + DEFAULT: + "color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter", + colors: + "color, background-color, border-color, outline-color, text-decoration-color, fill, stroke", + opacity: "opacity", + shadow: "box-shadow", + transform: "transform", + }, + transitionTimingFunction: { + DEFAULT: "cubic-bezier(0.4, 0, 0.2, 1)", + linear: "linear", + in: "cubic-bezier(0.4, 0, 1, 1)", + out: "cubic-bezier(0, 0, 0.2, 1)", + "in-out": "cubic-bezier(0.4, 0, 0.2, 1)", + }, + translate: ({ theme: e }) => ({ + "1/2": "50%", + "1/3": "33.333333%", + "2/3": "66.666667%", + "1/4": "25%", + "2/4": "50%", + "3/4": "75%", + full: "100%", + ...e("spacing"), + }), + size: ({ theme: e }) => ({ + auto: "auto", + "1/2": "50%", + "1/3": "33.333333%", + "2/3": "66.666667%", + "1/4": "25%", + "2/4": "50%", + "3/4": "75%", + "1/5": "20%", + "2/5": "40%", + "3/5": "60%", + "4/5": "80%", + "1/6": "16.666667%", + "2/6": "33.333333%", + "3/6": "50%", + "4/6": "66.666667%", + "5/6": "83.333333%", + "1/12": "8.333333%", + "2/12": "16.666667%", + "3/12": "25%", + "4/12": "33.333333%", + "5/12": "41.666667%", + "6/12": "50%", + "7/12": "58.333333%", + "8/12": "66.666667%", + "9/12": "75%", + "10/12": "83.333333%", + "11/12": "91.666667%", + full: "100%", + min: "min-content", + max: "max-content", + fit: "fit-content", + ...e("spacing"), + }), + width: ({ theme: e }) => ({ + auto: "auto", + "1/2": "50%", + "1/3": "33.333333%", + "2/3": "66.666667%", + "1/4": "25%", + "2/4": "50%", + "3/4": "75%", + "1/5": "20%", + "2/5": "40%", + "3/5": "60%", + "4/5": "80%", + "1/6": "16.666667%", + "2/6": "33.333333%", + "3/6": "50%", + "4/6": "66.666667%", + "5/6": "83.333333%", + "1/12": "8.333333%", + "2/12": "16.666667%", + "3/12": "25%", + "4/12": "33.333333%", + "5/12": "41.666667%", + "6/12": "50%", + "7/12": "58.333333%", + "8/12": "66.666667%", + "9/12": "75%", + "10/12": "83.333333%", + "11/12": "91.666667%", + full: "100%", + screen: "100vw", + svw: "100svw", + lvw: "100lvw", + dvw: "100dvw", + min: "min-content", + max: "max-content", + fit: "fit-content", + ...e("spacing"), + }), + willChange: { + auto: "auto", + scroll: "scroll-position", + contents: "contents", + transform: "transform", + }, + zIndex: { + auto: "auto", + 0: "0", + 10: "10", + 20: "20", + 30: "30", + 40: "40", + 50: "50", + ...l, + }, + }; +export { ie as a, u as b, pe as c, p as d, ge as e, ue as f, de as g, ye as h }; diff --git a/packages/engine/test/fixtures/v4/patch/dist/default-theme.js b/packages/engine/test/fixtures/v4/patch/dist/default-theme.js new file mode 100644 index 00000000..1afffad1 --- /dev/null +++ b/packages/engine/test/fixtures/v4/patch/dist/default-theme.js @@ -0,0 +1 @@ +"use strict";var C=["anchor-size"],N=new RegExp(`(${C.join("|")})\\(`,"g");var m=new Uint8Array(256);function k(e,c){let t=0,g=[],u=0,d=e.length,E=c.charCodeAt(0);for(let n=0;n0&&h===m[t-1]&&t--;break}}return g.push(e.slice(u)),g}var l=/[+-]?\d*\.?\d+(?:[eE][+-]?\d+)?/,I=new RegExp(`^${l.source}$`);var F=new RegExp(`^${l.source}%$`);var $=new RegExp(`^${l.source}s*/s*${l.source}$`);var v=["cm","mm","Q","in","pc","pt","px","em","ex","ch","rem","lh","rlh","vw","vh","vmin","vmax","vb","vi","svw","svh","lvw","lvh","dvw","dvh","cqw","cqh","cqi","cqb","cqmin","cqmax","rpx"],H=new RegExp(`^${l.source}(${v.join("|")})$`);var S=["deg","rad","grad","turn"],P=new RegExp(`^${l.source}(${S.join("|")})$`);var q=new RegExp(`^${l.source} +${l.source} +${l.source}$`);function i(e){let c=Number(e);return Number.isInteger(c)&&c>=0&&String(c)===String(e)}var f={inherit:"inherit",current:"currentColor",transparent:"transparent",black:"#000",white:"#fff",slate:{50:"oklch(0.984 0.003 247.858)",100:"oklch(0.968 0.007 247.896)",200:"oklch(0.929 0.013 255.508)",300:"oklch(0.869 0.022 252.894)",400:"oklch(0.704 0.04 256.788)",500:"oklch(0.554 0.046 257.417)",600:"oklch(0.446 0.043 257.281)",700:"oklch(0.372 0.044 257.287)",800:"oklch(0.279 0.041 260.031)",900:"oklch(0.208 0.042 265.755)",950:"oklch(0.129 0.042 264.695)"},gray:{50:"oklch(0.985 0.002 247.839)",100:"oklch(0.967 0.003 264.542)",200:"oklch(0.928 0.006 264.531)",300:"oklch(0.872 0.01 258.338)",400:"oklch(0.707 0.022 261.325)",500:"oklch(0.551 0.027 264.364)",600:"oklch(0.446 0.03 256.802)",700:"oklch(0.373 0.034 259.733)",800:"oklch(0.278 0.033 256.848)",900:"oklch(0.21 0.034 264.665)",950:"oklch(0.13 0.028 261.692)"},zinc:{50:"oklch(0.985 0 0)",100:"oklch(0.967 0.001 286.375)",200:"oklch(0.92 0.004 286.32)",300:"oklch(0.871 0.006 286.286)",400:"oklch(0.705 0.015 286.067)",500:"oklch(0.552 0.016 285.938)",600:"oklch(0.442 0.017 285.786)",700:"oklch(0.37 0.013 285.805)",800:"oklch(0.274 0.006 286.033)",900:"oklch(0.21 0.006 285.885)",950:"oklch(0.141 0.005 285.823)"},neutral:{50:"oklch(0.985 0 0)",100:"oklch(0.97 0 0)",200:"oklch(0.922 0 0)",300:"oklch(0.87 0 0)",400:"oklch(0.708 0 0)",500:"oklch(0.556 0 0)",600:"oklch(0.439 0 0)",700:"oklch(0.371 0 0)",800:"oklch(0.269 0 0)",900:"oklch(0.205 0 0)",950:"oklch(0.145 0 0)"},stone:{50:"oklch(0.985 0.001 106.423)",100:"oklch(0.97 0.001 106.424)",200:"oklch(0.923 0.003 48.717)",300:"oklch(0.869 0.005 56.366)",400:"oklch(0.709 0.01 56.259)",500:"oklch(0.553 0.013 58.071)",600:"oklch(0.444 0.011 73.639)",700:"oklch(0.374 0.01 67.558)",800:"oklch(0.268 0.007 34.298)",900:"oklch(0.216 0.006 56.043)",950:"oklch(0.147 0.004 49.25)"},red:{50:"oklch(0.971 0.013 17.38)",100:"oklch(0.936 0.032 17.717)",200:"oklch(0.885 0.062 18.334)",300:"oklch(0.808 0.114 19.571)",400:"oklch(0.704 0.191 22.216)",500:"oklch(0.637 0.237 25.331)",600:"oklch(0.577 0.245 27.325)",700:"oklch(0.505 0.213 27.518)",800:"oklch(0.444 0.177 26.899)",900:"oklch(0.396 0.141 25.723)",950:"oklch(0.258 0.092 26.042)"},orange:{50:"oklch(0.98 0.016 73.684)",100:"oklch(0.954 0.038 75.164)",200:"oklch(0.901 0.076 70.697)",300:"oklch(0.837 0.128 66.29)",400:"oklch(0.75 0.183 55.934)",500:"oklch(0.705 0.213 47.604)",600:"oklch(0.646 0.222 41.116)",700:"oklch(0.553 0.195 38.402)",800:"oklch(0.47 0.157 37.304)",900:"oklch(0.408 0.123 38.172)",950:"oklch(0.266 0.079 36.259)"},amber:{50:"oklch(0.987 0.022 95.277)",100:"oklch(0.962 0.059 95.617)",200:"oklch(0.924 0.12 95.746)",300:"oklch(0.879 0.169 91.605)",400:"oklch(0.828 0.189 84.429)",500:"oklch(0.769 0.188 70.08)",600:"oklch(0.666 0.179 58.318)",700:"oklch(0.555 0.163 48.998)",800:"oklch(0.473 0.137 46.201)",900:"oklch(0.414 0.112 45.904)",950:"oklch(0.279 0.077 45.635)"},yellow:{50:"oklch(0.987 0.026 102.212)",100:"oklch(0.973 0.071 103.193)",200:"oklch(0.945 0.129 101.54)",300:"oklch(0.905 0.182 98.111)",400:"oklch(0.852 0.199 91.936)",500:"oklch(0.795 0.184 86.047)",600:"oklch(0.681 0.162 75.834)",700:"oklch(0.554 0.135 66.442)",800:"oklch(0.476 0.114 61.907)",900:"oklch(0.421 0.095 57.708)",950:"oklch(0.286 0.066 53.813)"},lime:{50:"oklch(0.986 0.031 120.757)",100:"oklch(0.967 0.067 122.328)",200:"oklch(0.938 0.127 124.321)",300:"oklch(0.897 0.196 126.665)",400:"oklch(0.841 0.238 128.85)",500:"oklch(0.768 0.233 130.85)",600:"oklch(0.648 0.2 131.684)",700:"oklch(0.532 0.157 131.589)",800:"oklch(0.453 0.124 130.933)",900:"oklch(0.405 0.101 131.063)",950:"oklch(0.274 0.072 132.109)"},green:{50:"oklch(0.982 0.018 155.826)",100:"oklch(0.962 0.044 156.743)",200:"oklch(0.925 0.084 155.995)",300:"oklch(0.871 0.15 154.449)",400:"oklch(0.792 0.209 151.711)",500:"oklch(0.723 0.219 149.579)",600:"oklch(0.627 0.194 149.214)",700:"oklch(0.527 0.154 150.069)",800:"oklch(0.448 0.119 151.328)",900:"oklch(0.393 0.095 152.535)",950:"oklch(0.266 0.065 152.934)"},emerald:{50:"oklch(0.979 0.021 166.113)",100:"oklch(0.95 0.052 163.051)",200:"oklch(0.905 0.093 164.15)",300:"oklch(0.845 0.143 164.978)",400:"oklch(0.765 0.177 163.223)",500:"oklch(0.696 0.17 162.48)",600:"oklch(0.596 0.145 163.225)",700:"oklch(0.508 0.118 165.612)",800:"oklch(0.432 0.095 166.913)",900:"oklch(0.378 0.077 168.94)",950:"oklch(0.262 0.051 172.552)"},teal:{50:"oklch(0.984 0.014 180.72)",100:"oklch(0.953 0.051 180.801)",200:"oklch(0.91 0.096 180.426)",300:"oklch(0.855 0.138 181.071)",400:"oklch(0.777 0.152 181.912)",500:"oklch(0.704 0.14 182.503)",600:"oklch(0.6 0.118 184.704)",700:"oklch(0.511 0.096 186.391)",800:"oklch(0.437 0.078 188.216)",900:"oklch(0.386 0.063 188.416)",950:"oklch(0.277 0.046 192.524)"},cyan:{50:"oklch(0.984 0.019 200.873)",100:"oklch(0.956 0.045 203.388)",200:"oklch(0.917 0.08 205.041)",300:"oklch(0.865 0.127 207.078)",400:"oklch(0.789 0.154 211.53)",500:"oklch(0.715 0.143 215.221)",600:"oklch(0.609 0.126 221.723)",700:"oklch(0.52 0.105 223.128)",800:"oklch(0.45 0.085 224.283)",900:"oklch(0.398 0.07 227.392)",950:"oklch(0.302 0.056 229.695)"},sky:{50:"oklch(0.977 0.013 236.62)",100:"oklch(0.951 0.026 236.824)",200:"oklch(0.901 0.058 230.902)",300:"oklch(0.828 0.111 230.318)",400:"oklch(0.746 0.16 232.661)",500:"oklch(0.685 0.169 237.323)",600:"oklch(0.588 0.158 241.966)",700:"oklch(0.5 0.134 242.749)",800:"oklch(0.443 0.11 240.79)",900:"oklch(0.391 0.09 240.876)",950:"oklch(0.293 0.066 243.157)"},blue:{50:"oklch(0.97 0.014 254.604)",100:"oklch(0.932 0.032 255.585)",200:"oklch(0.882 0.059 254.128)",300:"oklch(0.809 0.105 251.813)",400:"oklch(0.707 0.165 254.624)",500:"oklch(0.623 0.214 259.815)",600:"oklch(0.546 0.245 262.881)",700:"oklch(0.488 0.243 264.376)",800:"oklch(0.424 0.199 265.638)",900:"oklch(0.379 0.146 265.522)",950:"oklch(0.282 0.091 267.935)"},indigo:{50:"oklch(0.962 0.018 272.314)",100:"oklch(0.93 0.034 272.788)",200:"oklch(0.87 0.065 274.039)",300:"oklch(0.785 0.115 274.713)",400:"oklch(0.673 0.182 276.935)",500:"oklch(0.585 0.233 277.117)",600:"oklch(0.511 0.262 276.966)",700:"oklch(0.457 0.24 277.023)",800:"oklch(0.398 0.195 277.366)",900:"oklch(0.359 0.144 278.697)",950:"oklch(0.257 0.09 281.288)"},violet:{50:"oklch(0.969 0.016 293.756)",100:"oklch(0.943 0.029 294.588)",200:"oklch(0.894 0.057 293.283)",300:"oklch(0.811 0.111 293.571)",400:"oklch(0.702 0.183 293.541)",500:"oklch(0.606 0.25 292.717)",600:"oklch(0.541 0.281 293.009)",700:"oklch(0.491 0.27 292.581)",800:"oklch(0.432 0.232 292.759)",900:"oklch(0.38 0.189 293.745)",950:"oklch(0.283 0.141 291.089)"},purple:{50:"oklch(0.977 0.014 308.299)",100:"oklch(0.946 0.033 307.174)",200:"oklch(0.902 0.063 306.703)",300:"oklch(0.827 0.119 306.383)",400:"oklch(0.714 0.203 305.504)",500:"oklch(0.627 0.265 303.9)",600:"oklch(0.558 0.288 302.321)",700:"oklch(0.496 0.265 301.924)",800:"oklch(0.438 0.218 303.724)",900:"oklch(0.381 0.176 304.987)",950:"oklch(0.291 0.149 302.717)"},fuchsia:{50:"oklch(0.977 0.017 320.058)",100:"oklch(0.952 0.037 318.852)",200:"oklch(0.903 0.076 319.62)",300:"oklch(0.833 0.145 321.434)",400:"oklch(0.74 0.238 322.16)",500:"oklch(0.667 0.295 322.15)",600:"oklch(0.591 0.293 322.896)",700:"oklch(0.518 0.253 323.949)",800:"oklch(0.452 0.211 324.591)",900:"oklch(0.401 0.17 325.612)",950:"oklch(0.293 0.136 325.661)"},pink:{50:"oklch(0.971 0.014 343.198)",100:"oklch(0.948 0.028 342.258)",200:"oklch(0.899 0.061 343.231)",300:"oklch(0.823 0.12 346.018)",400:"oklch(0.718 0.202 349.761)",500:"oklch(0.656 0.241 354.308)",600:"oklch(0.592 0.249 0.584)",700:"oklch(0.525 0.223 3.958)",800:"oklch(0.459 0.187 3.815)",900:"oklch(0.408 0.153 2.432)",950:"oklch(0.284 0.109 3.907)"},rose:{50:"oklch(0.969 0.015 12.422)",100:"oklch(0.941 0.03 12.58)",200:"oklch(0.892 0.058 10.001)",300:"oklch(0.81 0.117 11.638)",400:"oklch(0.712 0.194 13.428)",500:"oklch(0.645 0.246 16.439)",600:"oklch(0.586 0.253 17.585)",700:"oklch(0.514 0.222 16.935)",800:"oklch(0.455 0.188 13.697)",900:"oklch(0.41 0.159 10.272)",950:"oklch(0.271 0.105 12.094)"}};function s(e){return{__BARE_VALUE__:e}}var r=s(e=>{if(i(e.value))return e.value}),o=s(e=>{if(i(e.value))return`${e.value}%`}),a=s(e=>{if(i(e.value))return`${e.value}px`}),b=s(e=>{if(i(e.value))return`${e.value}ms`}),p=s(e=>{if(i(e.value))return`${e.value}deg`}),A=s(e=>{if(e.fraction===null)return;let[c,t]=k(e.fraction,"/");if(!(!i(c)||!i(t)))return e.fraction}),y=s(e=>{if(i(Number(e.value)))return`repeat(${e.value}, minmax(0, 1fr))`}),w={accentColor:({theme:e})=>e("colors"),animation:{none:"none",spin:"spin 1s linear infinite",ping:"ping 1s cubic-bezier(0, 0, 0.2, 1) infinite",pulse:"pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",bounce:"bounce 1s infinite"},aria:{busy:'busy="true"',checked:'checked="true"',disabled:'disabled="true"',expanded:'expanded="true"',hidden:'hidden="true"',pressed:'pressed="true"',readonly:'readonly="true"',required:'required="true"',selected:'selected="true"'},aspectRatio:{auto:"auto",square:"1 / 1",video:"16 / 9",...A},backdropBlur:({theme:e})=>e("blur"),backdropBrightness:({theme:e})=>({...e("brightness"),...o}),backdropContrast:({theme:e})=>({...e("contrast"),...o}),backdropGrayscale:({theme:e})=>({...e("grayscale"),...o}),backdropHueRotate:({theme:e})=>({...e("hueRotate"),...p}),backdropInvert:({theme:e})=>({...e("invert"),...o}),backdropOpacity:({theme:e})=>({...e("opacity"),...o}),backdropSaturate:({theme:e})=>({...e("saturate"),...o}),backdropSepia:({theme:e})=>({...e("sepia"),...o}),backgroundColor:({theme:e})=>e("colors"),backgroundImage:{none:"none","gradient-to-t":"linear-gradient(to top, var(--tw-gradient-stops))","gradient-to-tr":"linear-gradient(to top right, var(--tw-gradient-stops))","gradient-to-r":"linear-gradient(to right, var(--tw-gradient-stops))","gradient-to-br":"linear-gradient(to bottom right, var(--tw-gradient-stops))","gradient-to-b":"linear-gradient(to bottom, var(--tw-gradient-stops))","gradient-to-bl":"linear-gradient(to bottom left, var(--tw-gradient-stops))","gradient-to-l":"linear-gradient(to left, var(--tw-gradient-stops))","gradient-to-tl":"linear-gradient(to top left, var(--tw-gradient-stops))"},backgroundOpacity:({theme:e})=>e("opacity"),backgroundPosition:{bottom:"bottom",center:"center",left:"left","left-bottom":"left bottom","left-top":"left top",right:"right","right-bottom":"right bottom","right-top":"right top",top:"top"},backgroundSize:{auto:"auto",cover:"cover",contain:"contain"},blur:{0:"0",none:"",sm:"4px",DEFAULT:"8px",md:"12px",lg:"16px",xl:"24px","2xl":"40px","3xl":"64px"},borderColor:({theme:e})=>({DEFAULT:"currentColor",...e("colors")}),borderOpacity:({theme:e})=>e("opacity"),borderRadius:{none:"0px",sm:"0.125rem",DEFAULT:"0.25rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem","3xl":"1.5rem",full:"9999px"},borderSpacing:({theme:e})=>e("spacing"),borderWidth:{DEFAULT:"1px",0:"0px",2:"2px",4:"4px",8:"8px",...a},boxShadow:{sm:"0 1px 2px 0 rgb(0 0 0 / 0.05)",DEFAULT:"0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",md:"0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",lg:"0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",xl:"0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)","2xl":"0 25px 50px -12px rgb(0 0 0 / 0.25)",inner:"inset 0 2px 4px 0 rgb(0 0 0 / 0.05)",none:"none"},boxShadowColor:({theme:e})=>e("colors"),brightness:{0:"0",50:".5",75:".75",90:".9",95:".95",100:"1",105:"1.05",110:"1.1",125:"1.25",150:"1.5",200:"2",...o},caretColor:({theme:e})=>e("colors"),colors:()=>({...f}),columns:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12","3xs":"16rem","2xs":"18rem",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem",...r},container:{},content:{none:"none"},contrast:{0:"0",50:".5",75:".75",100:"1",125:"1.25",150:"1.5",200:"2",...o},cursor:{auto:"auto",default:"default",pointer:"pointer",wait:"wait",text:"text",move:"move",help:"help","not-allowed":"not-allowed",none:"none","context-menu":"context-menu",progress:"progress",cell:"cell",crosshair:"crosshair","vertical-text":"vertical-text",alias:"alias",copy:"copy","no-drop":"no-drop",grab:"grab",grabbing:"grabbing","all-scroll":"all-scroll","col-resize":"col-resize","row-resize":"row-resize","n-resize":"n-resize","e-resize":"e-resize","s-resize":"s-resize","w-resize":"w-resize","ne-resize":"ne-resize","nw-resize":"nw-resize","se-resize":"se-resize","sw-resize":"sw-resize","ew-resize":"ew-resize","ns-resize":"ns-resize","nesw-resize":"nesw-resize","nwse-resize":"nwse-resize","zoom-in":"zoom-in","zoom-out":"zoom-out"},divideColor:({theme:e})=>e("borderColor"),divideOpacity:({theme:e})=>e("borderOpacity"),divideWidth:({theme:e})=>({...e("borderWidth"),...a}),dropShadow:{sm:"0 1px 1px rgb(0 0 0 / 0.05)",DEFAULT:["0 1px 2px rgb(0 0 0 / 0.1)","0 1px 1px rgb(0 0 0 / 0.06)"],md:["0 4px 3px rgb(0 0 0 / 0.07)","0 2px 2px rgb(0 0 0 / 0.06)"],lg:["0 10px 8px rgb(0 0 0 / 0.04)","0 4px 3px rgb(0 0 0 / 0.1)"],xl:["0 20px 13px rgb(0 0 0 / 0.03)","0 8px 5px rgb(0 0 0 / 0.08)"],"2xl":"0 25px 25px rgb(0 0 0 / 0.15)",none:"0 0 #0000"},fill:({theme:e})=>e("colors"),flex:{1:"1 1 0%",auto:"1 1 auto",initial:"0 1 auto",none:"none"},flexBasis:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",...e("spacing")}),flexGrow:{0:"0",DEFAULT:"1",...r},flexShrink:{0:"0",DEFAULT:"1",...r},fontFamily:{sans:["ui-sans-serif","system-ui","sans-serif",'"Apple Color Emoji"','"Segoe UI Emoji"','"Segoe UI Symbol"','"Noto Color Emoji"'],serif:["ui-serif","Georgia","Cambria",'"Times New Roman"',"Times","serif"],mono:["ui-monospace","SFMono-Regular","Menlo","Monaco","Consolas",'"Liberation Mono"','"Courier New"',"monospace"]},fontSize:{xs:["0.75rem",{lineHeight:"1rem"}],sm:["0.875rem",{lineHeight:"1.25rem"}],base:["1rem",{lineHeight:"1.5rem"}],lg:["1.125rem",{lineHeight:"1.75rem"}],xl:["1.25rem",{lineHeight:"1.75rem"}],"2xl":["1.5rem",{lineHeight:"2rem"}],"3xl":["1.875rem",{lineHeight:"2.25rem"}],"4xl":["2.25rem",{lineHeight:"2.5rem"}],"5xl":["3rem",{lineHeight:"1"}],"6xl":["3.75rem",{lineHeight:"1"}],"7xl":["4.5rem",{lineHeight:"1"}],"8xl":["6rem",{lineHeight:"1"}],"9xl":["8rem",{lineHeight:"1"}]},fontWeight:{thin:"100",extralight:"200",light:"300",normal:"400",medium:"500",semibold:"600",bold:"700",extrabold:"800",black:"900"},gap:({theme:e})=>e("spacing"),gradientColorStops:({theme:e})=>e("colors"),gradientColorStopPositions:{"0%":"0%","5%":"5%","10%":"10%","15%":"15%","20%":"20%","25%":"25%","30%":"30%","35%":"35%","40%":"40%","45%":"45%","50%":"50%","55%":"55%","60%":"60%","65%":"65%","70%":"70%","75%":"75%","80%":"80%","85%":"85%","90%":"90%","95%":"95%","100%":"100%",...o},grayscale:{0:"0",DEFAULT:"100%",...o},gridAutoColumns:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0, 1fr)"},gridAutoRows:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0, 1fr)"},gridColumn:{auto:"auto","span-1":"span 1 / span 1","span-2":"span 2 / span 2","span-3":"span 3 / span 3","span-4":"span 4 / span 4","span-5":"span 5 / span 5","span-6":"span 6 / span 6","span-7":"span 7 / span 7","span-8":"span 8 / span 8","span-9":"span 9 / span 9","span-10":"span 10 / span 10","span-11":"span 11 / span 11","span-12":"span 12 / span 12","span-full":"1 / -1"},gridColumnEnd:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...r},gridColumnStart:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...r},gridRow:{auto:"auto","span-1":"span 1 / span 1","span-2":"span 2 / span 2","span-3":"span 3 / span 3","span-4":"span 4 / span 4","span-5":"span 5 / span 5","span-6":"span 6 / span 6","span-7":"span 7 / span 7","span-8":"span 8 / span 8","span-9":"span 9 / span 9","span-10":"span 10 / span 10","span-11":"span 11 / span 11","span-12":"span 12 / span 12","span-full":"1 / -1"},gridRowEnd:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...r},gridRowStart:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...r},gridTemplateColumns:{none:"none",subgrid:"subgrid",1:"repeat(1, minmax(0, 1fr))",2:"repeat(2, minmax(0, 1fr))",3:"repeat(3, minmax(0, 1fr))",4:"repeat(4, minmax(0, 1fr))",5:"repeat(5, minmax(0, 1fr))",6:"repeat(6, minmax(0, 1fr))",7:"repeat(7, minmax(0, 1fr))",8:"repeat(8, minmax(0, 1fr))",9:"repeat(9, minmax(0, 1fr))",10:"repeat(10, minmax(0, 1fr))",11:"repeat(11, minmax(0, 1fr))",12:"repeat(12, minmax(0, 1fr))",...y},gridTemplateRows:{none:"none",subgrid:"subgrid",1:"repeat(1, minmax(0, 1fr))",2:"repeat(2, minmax(0, 1fr))",3:"repeat(3, minmax(0, 1fr))",4:"repeat(4, minmax(0, 1fr))",5:"repeat(5, minmax(0, 1fr))",6:"repeat(6, minmax(0, 1fr))",7:"repeat(7, minmax(0, 1fr))",8:"repeat(8, minmax(0, 1fr))",9:"repeat(9, minmax(0, 1fr))",10:"repeat(10, minmax(0, 1fr))",11:"repeat(11, minmax(0, 1fr))",12:"repeat(12, minmax(0, 1fr))",...y},height:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%",full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),hueRotate:{0:"0deg",15:"15deg",30:"30deg",60:"60deg",90:"90deg",180:"180deg",...p},inset:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%",full:"100%",...e("spacing")}),invert:{0:"0",DEFAULT:"100%",...o},keyframes:{spin:{to:{transform:"rotate(360deg)"}},ping:{"75%, 100%":{transform:"scale(2)",opacity:"0"}},pulse:{"50%":{opacity:".5"}},bounce:{"0%, 100%":{transform:"translateY(-25%)",animationTimingFunction:"cubic-bezier(0.8,0,1,1)"},"50%":{transform:"none",animationTimingFunction:"cubic-bezier(0,0,0.2,1)"}}},letterSpacing:{tighter:"-0.05em",tight:"-0.025em",normal:"0em",wide:"0.025em",wider:"0.05em",widest:"0.1em"},lineHeight:{none:"1",tight:"1.25",snug:"1.375",normal:"1.5",relaxed:"1.625",loose:"2",3:".75rem",4:"1rem",5:"1.25rem",6:"1.5rem",7:"1.75rem",8:"2rem",9:"2.25rem",10:"2.5rem"},listStyleType:{none:"none",disc:"disc",decimal:"decimal"},listStyleImage:{none:"none"},margin:({theme:e})=>({auto:"auto",...e("spacing")}),lineClamp:{1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",...r},maxHeight:({theme:e})=>({none:"none",full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),maxWidth:({theme:e})=>({none:"none",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",prose:"65ch",...e("spacing")}),minHeight:({theme:e})=>({full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),minWidth:({theme:e})=>({full:"100%",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),objectPosition:{bottom:"bottom",center:"center",left:"left","left-bottom":"left bottom","left-top":"left top",right:"right","right-bottom":"right bottom","right-top":"right top",top:"top"},opacity:{0:"0",5:"0.05",10:"0.1",15:"0.15",20:"0.2",25:"0.25",30:"0.3",35:"0.35",40:"0.4",45:"0.45",50:"0.5",55:"0.55",60:"0.6",65:"0.65",70:"0.7",75:"0.75",80:"0.8",85:"0.85",90:"0.9",95:"0.95",100:"1",...o},order:{first:"-9999",last:"9999",none:"0",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",...r},outlineColor:({theme:e})=>e("colors"),outlineOffset:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},outlineWidth:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},padding:({theme:e})=>e("spacing"),placeholderColor:({theme:e})=>e("colors"),placeholderOpacity:({theme:e})=>e("opacity"),ringColor:({theme:e})=>({DEFAULT:"currentColor",...e("colors")}),ringOffsetColor:({theme:e})=>e("colors"),ringOffsetWidth:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},ringOpacity:({theme:e})=>({DEFAULT:"0.5",...e("opacity")}),ringWidth:{DEFAULT:"3px",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},rotate:{0:"0deg",1:"1deg",2:"2deg",3:"3deg",6:"6deg",12:"12deg",45:"45deg",90:"90deg",180:"180deg",...p},saturate:{0:"0",50:".5",100:"1",150:"1.5",200:"2",...o},scale:{0:"0",50:".5",75:".75",90:".9",95:".95",100:"1",105:"1.05",110:"1.1",125:"1.25",150:"1.5",...o},screens:{sm:"40rem",md:"48rem",lg:"64rem",xl:"80rem","2xl":"96rem"},scrollMargin:({theme:e})=>e("spacing"),scrollPadding:({theme:e})=>e("spacing"),sepia:{0:"0",DEFAULT:"100%",...o},skew:{0:"0deg",1:"1deg",2:"2deg",3:"3deg",6:"6deg",12:"12deg",...p},space:({theme:e})=>e("spacing"),spacing:{px:"1px",0:"0px",.5:"0.125rem",1:"0.25rem",1.5:"0.375rem",2:"0.5rem",2.5:"0.625rem",3:"0.75rem",3.5:"0.875rem",4:"1rem",5:"1.25rem",6:"1.5rem",7:"1.75rem",8:"2rem",9:"2.25rem",10:"2.5rem",11:"2.75rem",12:"3rem",14:"3.5rem",16:"4rem",20:"5rem",24:"6rem",28:"7rem",32:"8rem",36:"9rem",40:"10rem",44:"11rem",48:"12rem",52:"13rem",56:"14rem",60:"15rem",64:"16rem",72:"18rem",80:"20rem",96:"24rem"},stroke:({theme:e})=>({none:"none",...e("colors")}),strokeWidth:{0:"0",1:"1",2:"2",...r},supports:{},data:{},textColor:({theme:e})=>e("colors"),textDecorationColor:({theme:e})=>e("colors"),textDecorationThickness:{auto:"auto","from-font":"from-font",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},textIndent:({theme:e})=>e("spacing"),textOpacity:({theme:e})=>e("opacity"),textUnderlineOffset:{auto:"auto",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},transformOrigin:{center:"center",top:"top","top-right":"top right",right:"right","bottom-right":"bottom right",bottom:"bottom","bottom-left":"bottom left",left:"left","top-left":"top left"},transitionDelay:{0:"0s",75:"75ms",100:"100ms",150:"150ms",200:"200ms",300:"300ms",500:"500ms",700:"700ms",1e3:"1000ms",...b},transitionDuration:{DEFAULT:"150ms",0:"0s",75:"75ms",100:"100ms",150:"150ms",200:"200ms",300:"300ms",500:"500ms",700:"700ms",1e3:"1000ms",...b},transitionProperty:{none:"none",all:"all",DEFAULT:"color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter",colors:"color, background-color, border-color, outline-color, text-decoration-color, fill, stroke",opacity:"opacity",shadow:"box-shadow",transform:"transform"},transitionTimingFunction:{DEFAULT:"cubic-bezier(0.4, 0, 0.2, 1)",linear:"linear",in:"cubic-bezier(0.4, 0, 1, 1)",out:"cubic-bezier(0, 0, 0.2, 1)","in-out":"cubic-bezier(0.4, 0, 0.2, 1)"},translate:({theme:e})=>({"1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%",full:"100%",...e("spacing")}),size:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),width:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",screen:"100vw",svw:"100svw",lvw:"100lvw",dvw:"100dvw",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),willChange:{auto:"auto",scroll:"scroll-position",contents:"contents",transform:"transform"},zIndex:{auto:"auto",0:"0",10:"10",20:"20",30:"30",40:"40",50:"50",...r}};module.exports=w; diff --git a/packages/engine/test/fixtures/v4/patch/dist/lib.js b/packages/engine/test/fixtures/v4/patch/dist/lib.js new file mode 100644 index 00000000..6a6df745 --- /dev/null +++ b/packages/engine/test/fixtures/v4/patch/dist/lib.js @@ -0,0 +1,33 @@ +"use strict";var Wr=Object.defineProperty;var Br=(t,r)=>{for(var n in r)Wr(t,n,{get:r[n],enumerable:!0})};var Qe={};Br(Qe,{Features:()=>he,__unstable__loadDesignSystem:()=>Ti,compile:()=>Vi,compileAst:()=>Mr,default:()=>Re});var kt="4.0.9";var we=92,Ke=47,Pe=42,Hr=34,Gr=39,Yr=58,_e=59,oe=10,ke=32,De=9,xt=123,Xe=125,rt=40,At=41,Jr=91,Zr=93,Ct=45,et=64,Qr=33;function le(t){t[0]==="\uFEFF"&&(t=t.slice(1)),t=t.replaceAll(`\r +`,` +`);let r=[],n=[],e=[],i=null,s=null,l="",p="",c;for(let d=0;d0&&t[v]===g[g.length-1]&&(g=g.slice(0,-1));let y=tt(l,b);if(!y)throw new Error("Invalid custom property, expected a value");i?i.nodes.push(y):r.push(y),l=""}else if(u===_e&&l.charCodeAt(0)===et)s=xe(l),i?i.nodes.push(s):r.push(s),l="",s=null;else if(u===_e&&p[p.length-1]!==")"){let g=tt(l);if(!g)throw l.length===0?new Error("Unexpected semicolon"):new Error(`Invalid declaration: \`${l.trim()}\``);i?i.nodes.push(g):r.push(g),l=""}else if(u===xt&&p[p.length-1]!==")")p+="}",s=M(l.trim()),i&&i.nodes.push(s),e.push(i),i=s,l="",s=null;else if(u===Xe&&p[p.length-1]!==")"){if(p==="")throw new Error("Missing opening {");if(p=p.slice(0,-1),l.length>0)if(l.charCodeAt(0)===et)s=xe(l),i?i.nodes.push(s):r.push(s),l="",s=null;else{let m=l.indexOf(":");if(i){let b=tt(l,m);if(!b)throw new Error(`Invalid declaration: \`${l.trim()}\``);i.nodes.push(b)}}let g=e.pop()??null;g===null&&i&&r.push(i),i=g,l="",s=null}else if(u===rt)p+=")",l+="(";else if(u===At){if(p[p.length-1]!==")")throw new Error("Missing opening (");p=p.slice(0,-1),l+=")"}else{if(l.length===0&&(u===ke||u===oe||u===De))continue;l+=String.fromCharCode(u)}}}if(l.charCodeAt(0)===et&&r.push(xe(l)),p.length>0&&i){if(i.kind==="rule")throw new Error(`Missing closing } at ${i.selector}`);if(i.kind==="at-rule")throw new Error(`Missing closing } at ${i.name} ${i.params}`)}return n.length>0?n.concat(r):r}function xe(t,r=[]){for(let n=5;n=1&&i<=31||i===127||e===0&&i>=48&&i<=57||e===1&&i>=48&&i<=57&&l===45){s+="\\"+i.toString(16)+" ";continue}if(i>=128||i===45||i===95||i>=48&&i<=57||i>=65&&i<=90||i>=97&&i<=122){s+=r.charAt(e);continue}s+="\\"+r.charAt(e)}return s}function ae(t){return t.replace(/\\([\dA-Fa-f]{1,6}[\t\n\f\r ]?|[\S\s])/g,r=>r.length>2?String.fromCodePoint(Number.parseInt(r.slice(1).trim(),16)):r[1])}var $t=new Map([["--font",["--font-weight","--font-size"]],["--inset",["--inset-shadow","--inset-ring"]],["--text",["--text-color","--text-underline-offset","--text-indent","--text-decoration-thickness","--text-decoration-color"]]]);function Nt(t,r){return($t.get(r)??[]).some(n=>t===n||t.startsWith(`${n}-`))}var je=class{constructor(r=new Map,n=new Set([])){this.values=r;this.keyframes=n}prefix=null;add(r,n,e=0){if(r.endsWith("-*")){if(n!=="initial")throw new Error(`Invalid theme value \`${n}\` for namespace \`${r}\``);r==="--*"?this.values.clear():this.clearNamespace(r.slice(0,-2),0)}if(e&4){let i=this.values.get(r);if(i&&!(i.options&4))return}n==="initial"?this.values.delete(r):this.values.set(r,{value:n,options:e})}keysInNamespaces(r){let n=[];for(let e of r){let i=`${e}-`;for(let s of this.values.keys())s.startsWith(i)&&s.indexOf("--",2)===-1&&(Nt(s,e)||n.push(s.slice(i.length)))}return n}get(r){for(let n of r){let e=this.values.get(n);if(e)return e.value}return null}hasDefault(r){return(this.getOptions(r)&4)===4}getOptions(r){return r=ae(this.#n(r)),this.values.get(r)?.options??0}entries(){return this.prefix?Array.from(this.values,r=>(r[0]=this.#r(r[0]),r)):this.values.entries()}#r(r){return this.prefix?`--${this.prefix}-${r.slice(2)}`:r}#n(r){return this.prefix?`--${r.slice(3+this.prefix.length)}`:r}clearNamespace(r,n){let e=$t.get(r)??[];e:for(let i of this.values.keys())if(i.startsWith(r)){if(n!==0&&(this.getOptions(i)&n)!==n)continue;for(let s of e)if(i.startsWith(s))continue e;this.values.delete(i)}}#e(r,n){for(let e of n){let i=r!==null?`${e}-${r}`:e;if(!this.values.has(i))if(r!==null&&r.includes(".")){if(i=`${e}-${r.replaceAll(".","_")}`,!this.values.has(i))continue}else continue;if(!Nt(i,e))return i}return null}#t(r){let n=this.values.get(r);if(!n)return null;let e=null;return n.options&2&&(e=n.value),`var(${te(this.#r(r))}${e?`, ${e}`:""})`}markUsedVariable(r){let n=ae(this.#n(r)),e=this.values.get(n);e&&(e.options|=16)}resolve(r,n){let e=this.#e(r,n);if(!e)return null;let i=this.values.get(e);return i.options&1?i.value:this.#t(e)}resolveValue(r,n){let e=this.#e(r,n);return e?this.values.get(e).value:null}resolveWith(r,n,e=[]){let i=this.#e(r,n);if(!i)return null;let s={};for(let p of e){let c=`${i}${p}`,d=this.values.get(c);d&&(d.options&1?s[p]=d.value:s[p]=this.#t(c))}let l=this.values.get(i);return l.options&1?[l.value,s]:[this.#t(i),s]}namespace(r){let n=new Map,e=`${r}-`;for(let[i,s]of this.values)i===r?n.set(null,s.value):i.startsWith(`${e}-`)?n.set(i.slice(r.length),s.value):i.startsWith(e)&&n.set(i.slice(e.length),s.value);return n}addKeyframes(r){this.keyframes.add(r)}getKeyframes(){return Array.from(this.keyframes)}};var I=class extends Map{constructor(n){super();this.factory=n}get(n){let e=super.get(n);return e===void 0&&(e=this.factory(n,this),this.set(n,e)),e}};function it(t){return{kind:"word",value:t}}function Xr(t,r){return{kind:"function",value:t,nodes:r}}function en(t){return{kind:"separator",value:t}}function X(t,r,n=null){for(let e=0;e0){let g=it(i);e?e.nodes.push(g):r.push(g),i=""}let c=l,d=l+1;for(;d0){let d=it(i);c.nodes.push(d),i=""}n.length>0?e=n[n.length-1]:e=null;break}default:i+=String.fromCharCode(p)}}return i.length>0&&r.push(it(i)),r}function Fe(t){let r=[];return X(L(t),n=>{if(!(n.kind!=="function"||n.value!=="var"))return X(n.nodes,e=>{e.kind!=="word"||e.value[0]!=="-"||e.value[1]!=="-"||r.push(e.value)}),1}),r}var an=64;function j(t,r=[]){return{kind:"rule",selector:t,nodes:r}}function D(t,r="",n=[]){return{kind:"at-rule",name:t,params:r,nodes:n}}function M(t,r=[]){return t.charCodeAt(0)===an?xe(t,r):j(t,r)}function a(t,r,n=!1){return{kind:"declaration",property:t,value:r,important:n}}function Ue(t){return{kind:"comment",value:t}}function Z(t,r){return{kind:"context",context:t,nodes:r}}function U(t){return{kind:"at-root",nodes:t}}function _(t,r,n=[],e={}){for(let i=0;inew Set),s=new Set,l=new Set,p=new I(()=>new Set);function c(u,g,m={},b=0){if(u.kind==="declaration"){if(u.property==="--tw-sort"||u.value===void 0||u.value===null)return;if(m.theme&&u.property[0]==="-"&&u.property[1]==="-"&&(m.keyframes||i.get(g).add(u)),u.value.includes("var("))if(m.theme&&u.property[0]==="-"&&u.property[1]==="-")for(let y of Fe(u.value))p.get(y).add(u.property);else r.trackUsedVariables(u.value);if(u.property==="animation"){let y=u.value.split(/\s+/);for(let v of y)l.add(v)}g.push(u)}else if(u.kind==="rule")if(u.selector==="&")for(let y of u.nodes){let v=[];c(y,v,m,b+1),v.length>0&&g.push(...v)}else{let y={...u,nodes:[]};for(let v of u.nodes)c(v,y.nodes,m,b+1);y.nodes.length>0&&g.push(y)}else if(u.kind==="at-rule"&&u.name==="@property"&&b===0){if(e.has(u.params))return;e.add(u.params);let y={...u,nodes:[]};for(let v of u.nodes)c(v,y.nodes,m,b+1);g.push(y)}else if(u.kind==="at-rule"){u.name==="@keyframes"&&(m={...m,keyframes:!0});let y={...u,nodes:[]};for(let v of u.nodes)c(v,y.nodes,m,b+1);u.name==="@keyframes"&&m.theme&&s.add(y),(y.nodes.length>0||y.name==="@layer"||y.name==="@charset"||y.name==="@custom-media"||y.name==="@namespace"||y.name==="@import")&&g.push(y)}else if(u.kind==="at-root")for(let y of u.nodes){let v=[];c(y,v,m,0);for(let x of v)n.push(x)}else if(u.kind==="context"){if(u.context.reference)return;for(let y of u.nodes)c(y,g,{...m,...u.context},b)}else u.kind==="comment"&&g.push(u)}let d=[];for(let u of t)c(u,d,{},0);e:for(let[u,g]of i)for(let m of g){if(Ut(m.property,r.theme,p)){if(m.property.startsWith("--animate-")){let v=m.value.split(/\s+/);for(let x of v)l.add(x)}continue}let y=u.indexOf(m);if(u.splice(y,1),u.length===0){let v=sn(d,x=>x.kind==="rule"&&x.nodes===u);if(!v||v.length===0)continue e;v.unshift({kind:"at-root",nodes:d});do{let x=v.pop();if(!x)break;let T=v[v.length-1];if(!T||T.kind!=="at-root"&&T.kind!=="at-rule")break;let S=T.nodes.indexOf(x);if(S===-1)break;T.nodes.splice(S,1)}while(!0);continue e}}for(let u of s)if(!l.has(u.params)){let g=n.indexOf(u);n.splice(g,1)}return d.concat(n)}function G(t){function r(e,i=0){let s="",l=" ".repeat(i);if(e.kind==="declaration")s+=`${l}${e.property}: ${e.value}${e.important?" !important":""}; +`;else if(e.kind==="rule"){s+=`${l}${e.selector} { +`;for(let p of e.nodes)s+=r(p,i+1);s+=`${l}} +`}else if(e.kind==="at-rule"){if(e.nodes.length===0)return`${l}${e.name} ${e.params}; +`;s+=`${l}${e.name}${e.params?` ${e.params} `:" "}{ +`;for(let p of e.nodes)s+=r(p,i+1);s+=`${l}} +`}else if(e.kind==="comment")s+=`${l}/*${e.value}*/ +`;else if(e.kind==="context"||e.kind==="at-root")return"";return s}let n="";for(let e of t){let i=r(e);i!==""&&(n+=i)}return n}function sn(t,r){let n=[];return _(t,(e,{path:i})=>{if(r(e))return n=[...i],2}),n}function Ut(t,r,n,e=new Set){if(e.has(t)||(e.add(t),r.getOptions(t)&24))return!0;{let s=n.get(t)??[];for(let l of s)if(Ut(l,r,n,e))return!0}return!1}var lt=["calc","min","max","clamp","mod","rem","sin","cos","tan","asin","acos","atan","atan2","pow","sqrt","hypot","log","exp","round"],ze=["anchor-size"],jt=new RegExp(`(${ze.join("|")})\\(`,"g");function Ce(t){return t.indexOf("(")!==-1&<.some(r=>t.includes(`${r}(`))}function Ft(t){if(!lt.some(i=>t.includes(i)))return t;let r=!1;ze.some(i=>t.includes(i))&&(jt.lastIndex=0,t=t.replace(jt,(i,s)=>(r=!0,`$${ze.indexOf(s)}$(`)));let n="",e=[];for(let i=0;i=0;c--){let d=t.charCodeAt(c);if(d>=48&&d<=57)l=c;else if(d>=97&&d<=122)l=c;else break}let p=t.slice(l,i);if(lt.includes(p)){e.unshift(!0);continue}else if(e[0]&&p===""){e.unshift(!0);continue}e.unshift(!1);continue}else if(s===")")n+=s,e.shift();else if(s===","&&e[0]){n+=", ";continue}else{if(s===" "&&e[0]&&n[n.length-1]===" ")continue;if((s==="+"||s==="*"||s==="/"||s==="-")&&e[0]){let l=n.trimEnd(),p=l[l.length-1];if(p==="+"||p==="*"||p==="/"||p==="-"){n+=s;continue}else if(p==="("||p===","){n+=s;continue}else t[i-1]===" "?n+=`${s} `:n+=` ${s} `}else if(e[0]&&t.startsWith("to-zero",i)){let l=i;i+=7,n+=t.slice(l,i+1)}else n+=s}}return r?n.replace(/\$(\d+)\$/g,(i,s)=>ze[s]??i):n}function re(t){if(t.indexOf("(")===-1)return pe(t);let r=L(t);return at(r),t=q(r),t=Ft(t),t}function pe(t,r=!1){let n="";for(let e=0;e0&&c===Le[n-1]&&n--;break}}return e.push(t.slice(i)),e}var cn=58,It=45,zt=97,Lt=122;function*Mt(t,r){let n=P(t,":");if(r.theme.prefix){if(n.length===1||n[0]!==r.theme.prefix)return null;n.shift()}let e=n.pop(),i=[];for(let g=n.length-1;g>=0;--g){let m=r.parseVariant(n[g]);if(m===null)return;i.push(m)}let s=!1;e[e.length-1]==="!"?(s=!0,e=e.slice(0,-1)):e[0]==="!"&&(s=!0,e=e.slice(1)),r.utilities.has(e,"static")&&!e.includes("[")&&(yield{kind:"static",root:e,variants:i,important:s,raw:t});let[l,p=null,c]=P(e,"/");if(c)return;let d=p===null?null:st(p);if(p!==null&&d===null)return;if(l[0]==="["){if(l[l.length-1]!=="]")return;let g=l.charCodeAt(1);if(g!==It&&!(g>=zt&&g<=Lt))return;l=l.slice(1,-1);let m=l.indexOf(":");if(m===-1||m===0||m===l.length-1)return;let b=l.slice(0,m),y=re(l.slice(m+1));yield{kind:"arbitrary",property:b,value:y,modifier:d,variants:i,important:s,raw:t};return}let u;if(l[l.length-1]==="]"){let g=l.indexOf("-[");if(g===-1)return;let m=l.slice(0,g);if(!r.utilities.has(m,"functional"))return;let b=l.slice(g+1);u=[[m,b]]}else if(l[l.length-1]===")"){let g=l.indexOf("-(");if(g===-1)return;let m=l.slice(0,g);if(!r.utilities.has(m,"functional"))return;let b=l.slice(g+2,-1),y=P(b,":"),v=null;if(y.length===2&&(v=y[0],b=y[1]),b[0]!=="-"&&b[1]!=="-")return;u=[[m,v===null?`[var(${b})]`:`[${v}:var(${b})]`]]}else u=Bt(l,g=>r.utilities.has(g,"functional"));for(let[g,m]of u){let b={kind:"functional",root:g,modifier:d,value:null,variants:i,important:s,raw:t};if(m===null){yield b;continue}{let y=m.indexOf("[");if(y!==-1){if(m[m.length-1]!=="]")return;let x=re(m.slice(y+1,-1)),T="";for(let S=0;S=zt&&O<=Lt))break}if(x.length===0||x.trim().length===0)continue;b.value={kind:"arbitrary",dataType:T||null,value:x}}else{let x=p===null||b.modifier?.kind==="arbitrary"?null:`${m}/${p}`;b.value={kind:"named",value:m,fraction:x}}}yield b}}function st(t){if(t[0]==="["&&t[t.length-1]==="]"){let r=re(t.slice(1,-1));return r.length===0||r.trim().length===0?null:{kind:"arbitrary",value:r}}if(t[0]==="("&&t[t.length-1]===")"){let r=re(t.slice(1,-1));return r.length===0||r.trim().length===0||r[0]!=="-"&&r[1]!=="-"?null:{kind:"arbitrary",value:`var(${r})`}}return{kind:"named",value:t}}function Wt(t,r){if(t[0]==="["&&t[t.length-1]==="]"){if(t[1]==="@"&&t.includes("&"))return null;let n=re(t.slice(1,-1));if(n.length===0||n.trim().length===0)return null;let e=n[0]===">"||n[0]==="+"||n[0]==="~";return!e&&n[0]!=="@"&&!n.includes("&")&&(n=`&:is(${n})`),{kind:"arbitrary",selector:n,relative:e}}{let[n,e=null,i]=P(t,"/");if(i)return null;let s=Bt(n,l=>r.variants.has(l));for(let[l,p]of s)switch(r.variants.kind(l)){case"static":return p!==null||e!==null?null:{kind:"static",root:l};case"functional":{let c=e===null?null:st(e);if(e!==null&&c===null)return null;if(p===null)return{kind:"functional",root:l,modifier:c,value:null};if(p[p.length-1]==="]"){if(p[0]!=="[")continue;let d=re(p.slice(1,-1));return d.length===0||d.trim().length===0?null:{kind:"functional",root:l,modifier:c,value:{kind:"arbitrary",value:d}}}if(p[p.length-1]===")"){if(p[0]!=="(")continue;let d=re(p.slice(1,-1));return d.length===0||d.trim().length===0||d[0]!=="-"&&d[1]!=="-"?null:{kind:"functional",root:l,modifier:c,value:{kind:"arbitrary",value:`var(${d})`}}}return{kind:"functional",root:l,modifier:c,value:{kind:"named",value:p}}}case"compound":{if(p===null)return null;let c=r.parseVariant(p);if(c===null||!r.variants.compoundsWith(l,c))return null;let d=e===null?null:st(e);return e!==null&&d===null?null:{kind:"compound",root:l,modifier:d,variant:c}}}}return null}function*Bt(t,r){r(t)&&(yield[t,null]);let n=t.lastIndexOf("-");if(n===-1){t[0]==="@"&&r("@")&&(yield["@",t.slice(1)]);return}do{let e=t.slice(0,n);if(r(e)){let i=[e,t.slice(n+1)];if(i[1]==="")break;yield i}n=t.lastIndexOf("-",n-1)}while(n>0)}function ue(t,r,n){if(t===r)return 0;let e=t.indexOf("("),i=r.indexOf("("),s=e===-1?t.replace(/[\d.]+/g,""):t.slice(0,e),l=i===-1?r.replace(/[\d.]+/g,""):r.slice(0,i),p=(s===l?0:s0}function bn(t){return t==="serif"||t==="sans-serif"||t==="monospace"||t==="cursive"||t==="fantasy"||t==="system-ui"||t==="ui-serif"||t==="ui-sans-serif"||t==="ui-monospace"||t==="ui-rounded"||t==="math"||t==="emoji"||t==="fangsong"}function wn(t){let r=0;for(let n of P(t,",")){let e=n.charCodeAt(0);if(e>=48&&e<=57)return!1;n.startsWith("var(")||(r+=1)}return r>0}function kn(t){return t==="xx-small"||t==="x-small"||t==="small"||t==="medium"||t==="large"||t==="x-large"||t==="xx-large"||t==="xxx-large"}function xn(t){return t==="larger"||t==="smaller"}var ee=/[+-]?\d*\.?\d+(?:[eE][+-]?\d+)?/,An=new RegExp(`^${ee.source}$`);function Cn(t){return An.test(t)||Ce(t)}var Nn=new RegExp(`^${ee.source}%$`);function ut(t){return Nn.test(t)||Ce(t)}var $n=new RegExp(`^${ee.source}s*/s*${ee.source}$`);function Vn(t){return $n.test(t)||Ce(t)}var Tn=["cm","mm","Q","in","pc","pt","px","em","ex","ch","rem","lh","rlh","vw","vh","vmin","vmax","vb","vi","svw","svh","lvw","lvh","dvw","dvh","cqw","cqh","cqi","cqb","cqmin","cqmax","rpx"],Sn=new RegExp(`^${ee.source}(${Tn.join("|")})$`);function ct(t){return Sn.test(t)||Ce(t)}function En(t){let r=0;for(let n of P(t," ")){if(n==="center"||n==="top"||n==="right"||n==="bottom"||n==="left"){r+=1;continue}if(!n.startsWith("var(")){if(ct(n)||ut(n)){r+=1;continue}return!1}}return r>0}function Rn(t){let r=0;for(let n of P(t,",")){if(n==="cover"||n==="contain"){r+=1;continue}let e=P(n," ");if(e.length!==1&&e.length!==2)return!1;if(e.every(i=>i==="auto"||ct(i)||ut(i))){r+=1;continue}}return r>0}var On=["deg","rad","grad","turn"],Kn=new RegExp(`^${ee.source}(${On.join("|")})$`);function Pn(t){return Kn.test(t)}var _n=new RegExp(`^${ee.source} +${ee.source} +${ee.source}$`);function Dn(t){return _n.test(t)}function V(t){let r=Number(t);return Number.isInteger(r)&&r>=0&&String(r)===String(t)}function ft(t){let r=Number(t);return Number.isInteger(r)&&r>0&&String(r)===String(t)}function me(t){return Gt(t,.25)}function Me(t){return Gt(t,.25)}function Gt(t,r){let n=Number(t);return n>=0&&n%r===0&&String(n)===String(t)}var Un=new Set(["inset","inherit","initial","revert","unset"]),Yt=/^-?(\d+|\.\d+)(.*?)$/g;function ce(t,r){return P(t,",").map(e=>{e=e.trim();let i=P(e," ").filter(d=>d.trim()!==""),s=null,l=null,p=null;for(let d of i)Un.has(d)||(Yt.test(d)?(l===null?l=d:p===null&&(p=d),Yt.lastIndex=0):s===null&&(s=d));if(l===null||p===null)return e;let c=r(s??"currentcolor");return s!==null?e.replace(s,c):`${e} ${c}`}).join(", ")}var Fn=/^-?[a-z][a-zA-Z0-9/%._-]*$/,In=/^-?[a-z][a-zA-Z0-9/%._-]*-\*$/,dt=class{utilities=new I(()=>[]);completions=new Map;static(r,n){this.utilities.get(r).push({kind:"static",compileFn:n})}functional(r,n,e){this.utilities.get(r).push({kind:"functional",compileFn:n,options:e})}has(r,n){return this.utilities.has(r)&&this.utilities.get(r).some(e=>e.kind===n)}get(r){return this.utilities.has(r)?this.utilities.get(r):[]}getCompletions(r){return this.completions.get(r)?.()??[]}suggest(r,n){this.completions.set(r,n)}keys(r){let n=[];for(let[e,i]of this.utilities.entries())for(let s of i)if(s.kind===r){n.push(e);break}return n}};function N(t,r,n){return D("@property",t,[a("syntax",n?`"${n}"`:'"*"'),a("inherits","false"),...r?[a("initial-value",r)]:[]])}function Y(t,r){if(r===null)return t;let n=Number(r);return Number.isNaN(n)||(r=`${n*100}%`),`color-mix(in oklab, ${t} ${r}, transparent)`}function W(t,r,n){if(!r)return t;if(r.kind==="arbitrary")return Y(t,r.value);let e=n.resolve(r.value,["--opacity"]);return e?Y(t,e):Me(r.value)?Y(t,`${r.value}%`):null}function H(t,r,n){let e=null;switch(t.value.value){case"inherit":{e="inherit";break}case"transparent":{e="transparent";break}case"current":{e="currentColor";break}default:{e=r.resolve(t.value.value,n);break}}return e?W(e,t.modifier,r):null}function Zt(t){let r=new dt;function n(o,f){let h=/(\d+)_(\d+)/g;function*k($){for(let E of t.keysInNamespaces($))yield E.replace(h,(C,A,F)=>`${A}.${F}`)}let w=["1/2","1/3","2/3","1/4","2/4","3/4","1/5","2/5","3/5","4/5","1/6","2/6","3/6","4/6","5/6","1/12","2/12","3/12","4/12","5/12","6/12","7/12","8/12","9/12","10/12","11/12"];r.suggest(o,()=>{let $=[];for(let E of f()){if(typeof E=="string"){$.push({values:[E],modifiers:[]});continue}let C=[...E.values??[],...k(E.valueThemeKeys??[])],A=[...E.modifiers??[],...k(E.modifierThemeKeys??[])];E.supportsFractions&&C.push(...w),E.hasDefaultValue&&C.unshift(null),$.push({supportsNegative:E.supportsNegative,values:C,modifiers:A})}return $})}function e(o,f){r.static(o,()=>f.map(h=>typeof h=="function"?h():a(h[0],h[1])))}function i(o,f){function h({negative:k}){return w=>{let $=null;if(w.value)if(w.value.kind==="arbitrary"){if(w.modifier)return;$=w.value.value}else{if($=t.resolve(w.value.fraction??w.value.value,f.themeKeys??[]),$===null&&f.supportsFractions&&w.value.fraction){let[E,C]=P(w.value.fraction,"/");if(!V(E)||!V(C))return;$=`calc(${w.value.fraction} * 100%)`}if($===null&&k&&f.handleNegativeBareValue){if($=f.handleNegativeBareValue(w.value),!$?.includes("/")&&w.modifier)return;if($!==null)return f.handle($)}if($===null&&f.handleBareValue&&($=f.handleBareValue(w.value),!$?.includes("/")&&w.modifier))return}else{if(w.modifier)return;$=f.defaultValue!==void 0?f.defaultValue:t.resolve(null,f.themeKeys??[])}if($!==null)return f.handle(k?`calc(${$} * -1)`:$)}}f.supportsNegative&&r.functional(`-${o}`,h({negative:!0})),r.functional(o,h({negative:!1})),n(o,()=>[{supportsNegative:f.supportsNegative,valueThemeKeys:f.themeKeys??[],hasDefaultValue:f.defaultValue!==void 0&&f.defaultValue!==null,supportsFractions:f.supportsFractions}])}function s(o,f){r.functional(o,h=>{if(!h.value)return;let k=null;if(h.value.kind==="arbitrary"?(k=h.value.value,k=W(k,h.modifier,t)):k=H(h,t,f.themeKeys),k!==null)return f.handle(k)}),n(o,()=>[{values:["current","inherit","transparent"],valueThemeKeys:f.themeKeys,modifiers:Array.from({length:21},(h,k)=>`${k*5}`)}])}function l(o,f,h,{supportsNegative:k=!1,supportsFractions:w=!1}={}){k&&r.static(`-${o}-px`,()=>h("-1px")),r.static(`${o}-px`,()=>h("1px")),i(o,{themeKeys:f,supportsFractions:w,supportsNegative:k,defaultValue:null,handleBareValue:({value:$})=>{let E=t.resolve(null,["--spacing"]);return!E||!me($)?null:`calc(${E} * ${$})`},handleNegativeBareValue:({value:$})=>{let E=t.resolve(null,["--spacing"]);return!E||!me($)?null:`calc(${E} * -${$})`},handle:h}),n(o,()=>[{values:t.get(["--spacing"])?["0","0.5","1","1.5","2","2.5","3","3.5","4","5","6","7","8","9","10","11","12","14","16","20","24","28","32","36","40","44","48","52","56","60","64","72","80","96"]:[],supportsNegative:k,supportsFractions:w,valueThemeKeys:f}])}e("sr-only",[["position","absolute"],["width","1px"],["height","1px"],["padding","0"],["margin","-1px"],["overflow","hidden"],["clip","rect(0, 0, 0, 0)"],["white-space","nowrap"],["border-width","0"]]),e("not-sr-only",[["position","static"],["width","auto"],["height","auto"],["padding","0"],["margin","0"],["overflow","visible"],["clip","auto"],["white-space","normal"]]),e("pointer-events-none",[["pointer-events","none"]]),e("pointer-events-auto",[["pointer-events","auto"]]),e("visible",[["visibility","visible"]]),e("invisible",[["visibility","hidden"]]),e("collapse",[["visibility","collapse"]]),e("static",[["position","static"]]),e("fixed",[["position","fixed"]]),e("absolute",[["position","absolute"]]),e("relative",[["position","relative"]]),e("sticky",[["position","sticky"]]);for(let[o,f]of[["inset","inset"],["inset-x","inset-inline"],["inset-y","inset-block"],["start","inset-inline-start"],["end","inset-inline-end"],["top","top"],["right","right"],["bottom","bottom"],["left","left"]])e(`${o}-auto`,[[f,"auto"]]),e(`${o}-full`,[[f,"100%"]]),e(`-${o}-full`,[[f,"-100%"]]),l(o,["--inset","--spacing"],h=>[a(f,h)],{supportsNegative:!0,supportsFractions:!0});e("isolate",[["isolation","isolate"]]),e("isolation-auto",[["isolation","auto"]]),e("z-auto",[["z-index","auto"]]),i("z",{supportsNegative:!0,handleBareValue:({value:o})=>V(o)?o:null,themeKeys:["--z-index"],handle:o=>[a("z-index",o)]}),n("z",()=>[{supportsNegative:!0,values:["0","10","20","30","40","50"],valueThemeKeys:["--z-index"]}]),e("order-first",[["order","-9999"]]),e("order-last",[["order","9999"]]),e("order-none",[["order","0"]]),i("order",{supportsNegative:!0,handleBareValue:({value:o})=>V(o)?o:null,themeKeys:["--order"],handle:o=>[a("order",o)]}),n("order",()=>[{supportsNegative:!0,values:Array.from({length:12},(o,f)=>`${f+1}`),valueThemeKeys:["--order"]}]),e("col-auto",[["grid-column","auto"]]),i("col",{themeKeys:["--grid-column"],handle:o=>[a("grid-column",o)]}),e("col-span-full",[["grid-column","1 / -1"]]),i("col-span",{handleBareValue:({value:o})=>V(o)?o:null,handle:o=>[a("grid-column",`span ${o} / span ${o}`)]}),e("col-start-auto",[["grid-column-start","auto"]]),i("col-start",{supportsNegative:!0,handleBareValue:({value:o})=>V(o)?o:null,themeKeys:["--grid-column-start"],handle:o=>[a("grid-column-start",o)]}),e("col-end-auto",[["grid-column-end","auto"]]),i("col-end",{supportsNegative:!0,handleBareValue:({value:o})=>V(o)?o:null,themeKeys:["--grid-column-end"],handle:o=>[a("grid-column-end",o)]}),n("col-span",()=>[{values:Array.from({length:12},(o,f)=>`${f+1}`),valueThemeKeys:[]}]),n("col-start",()=>[{supportsNegative:!0,values:Array.from({length:13},(o,f)=>`${f+1}`),valueThemeKeys:["--grid-column-start"]}]),n("col-end",()=>[{supportsNegative:!0,values:Array.from({length:13},(o,f)=>`${f+1}`),valueThemeKeys:["--grid-column-end"]}]),e("row-auto",[["grid-row","auto"]]),i("row",{themeKeys:["--grid-row"],handle:o=>[a("grid-row",o)]}),e("row-span-full",[["grid-row","1 / -1"]]),i("row-span",{themeKeys:[],handleBareValue:({value:o})=>V(o)?o:null,handle:o=>[a("grid-row",`span ${o} / span ${o}`)]}),e("row-start-auto",[["grid-row-start","auto"]]),i("row-start",{supportsNegative:!0,handleBareValue:({value:o})=>V(o)?o:null,themeKeys:["--grid-row-start"],handle:o=>[a("grid-row-start",o)]}),e("row-end-auto",[["grid-row-end","auto"]]),i("row-end",{supportsNegative:!0,handleBareValue:({value:o})=>V(o)?o:null,themeKeys:["--grid-row-end"],handle:o=>[a("grid-row-end",o)]}),n("row-span",()=>[{values:Array.from({length:12},(o,f)=>`${f+1}`),valueThemeKeys:[]}]),n("row-start",()=>[{supportsNegative:!0,values:Array.from({length:13},(o,f)=>`${f+1}`),valueThemeKeys:["--grid-row-start"]}]),n("row-end",()=>[{supportsNegative:!0,values:Array.from({length:13},(o,f)=>`${f+1}`),valueThemeKeys:["--grid-row-end"]}]),e("float-start",[["float","inline-start"]]),e("float-end",[["float","inline-end"]]),e("float-right",[["float","right"]]),e("float-left",[["float","left"]]),e("float-none",[["float","none"]]),e("clear-start",[["clear","inline-start"]]),e("clear-end",[["clear","inline-end"]]),e("clear-right",[["clear","right"]]),e("clear-left",[["clear","left"]]),e("clear-both",[["clear","both"]]),e("clear-none",[["clear","none"]]);for(let[o,f]of[["m","margin"],["mx","margin-inline"],["my","margin-block"],["ms","margin-inline-start"],["me","margin-inline-end"],["mt","margin-top"],["mr","margin-right"],["mb","margin-bottom"],["ml","margin-left"]])e(`${o}-auto`,[[f,"auto"]]),l(o,["--margin","--spacing"],h=>[a(f,h)],{supportsNegative:!0});e("box-border",[["box-sizing","border-box"]]),e("box-content",[["box-sizing","content-box"]]),e("line-clamp-none",[["overflow","visible"],["display","block"],["-webkit-box-orient","horizontal"],["-webkit-line-clamp","unset"]]),i("line-clamp",{themeKeys:["--line-clamp"],handleBareValue:({value:o})=>V(o)?o:null,handle:o=>[a("overflow","hidden"),a("display","-webkit-box"),a("-webkit-box-orient","vertical"),a("-webkit-line-clamp",o)]}),n("line-clamp",()=>[{values:["1","2","3","4","5","6"],valueThemeKeys:["--line-clamp"]}]),e("block",[["display","block"]]),e("inline-block",[["display","inline-block"]]),e("inline",[["display","inline"]]),e("hidden",[["display","none"]]),e("inline-flex",[["display","inline-flex"]]),e("table",[["display","table"]]),e("inline-table",[["display","inline-table"]]),e("table-caption",[["display","table-caption"]]),e("table-cell",[["display","table-cell"]]),e("table-column",[["display","table-column"]]),e("table-column-group",[["display","table-column-group"]]),e("table-footer-group",[["display","table-footer-group"]]),e("table-header-group",[["display","table-header-group"]]),e("table-row-group",[["display","table-row-group"]]),e("table-row",[["display","table-row"]]),e("flow-root",[["display","flow-root"]]),e("flex",[["display","flex"]]),e("grid",[["display","grid"]]),e("inline-grid",[["display","inline-grid"]]),e("contents",[["display","contents"]]),e("list-item",[["display","list-item"]]),e("field-sizing-content",[["field-sizing","content"]]),e("field-sizing-fixed",[["field-sizing","fixed"]]),e("aspect-auto",[["aspect-ratio","auto"]]),e("aspect-square",[["aspect-ratio","1 / 1"]]),i("aspect",{themeKeys:["--aspect"],handleBareValue:({fraction:o})=>{if(o===null)return null;let[f,h]=P(o,"/");return!V(f)||!V(h)?null:o},handle:o=>[a("aspect-ratio",o)]});for(let[o,f]of[["auto","auto"],["full","100%"],["svw","100svw"],["lvw","100lvw"],["dvw","100dvw"],["svh","100svh"],["lvh","100lvh"],["dvh","100dvh"],["min","min-content"],["max","max-content"],["fit","fit-content"]])e(`size-${o}`,[["--tw-sort","size"],["width",f],["height",f]]),e(`w-${o}`,[["width",f]]),e(`min-w-${o}`,[["min-width",f]]),e(`max-w-${o}`,[["max-width",f]]),e(`h-${o}`,[["height",f]]),e(`min-h-${o}`,[["min-height",f]]),e(`max-h-${o}`,[["max-height",f]]);e("w-screen",[["width","100vw"]]),e("min-w-screen",[["min-width","100vw"]]),e("max-w-screen",[["max-width","100vw"]]),e("h-screen",[["height","100vh"]]),e("min-h-screen",[["min-height","100vh"]]),e("max-h-screen",[["max-height","100vh"]]),e("max-w-none",[["max-width","none"]]),e("max-h-none",[["max-height","none"]]),l("size",["--size","--spacing"],o=>[a("--tw-sort","size"),a("width",o),a("height",o)],{supportsFractions:!0});for(let[o,f,h]of[["w",["--width","--spacing","--container"],"width"],["min-w",["--min-width","--spacing","--container"],"min-width"],["max-w",["--max-width","--spacing","--container"],"max-width"],["h",["--height","--spacing"],"height"],["min-h",["--min-height","--height","--spacing"],"min-height"],["max-h",["--max-height","--height","--spacing"],"max-height"]])l(o,f,k=>[a(h,k)],{supportsFractions:!0});r.static("container",()=>{let o=[...t.namespace("--breakpoint").values()];o.sort((h,k)=>ue(h,k,"asc"));let f=[a("--tw-sort","--tw-container-component"),a("width","100%")];for(let h of o)f.push(D("@media",`(width >= ${h})`,[a("max-width",h)]));return f}),e("flex-auto",[["flex","auto"]]),e("flex-initial",[["flex","0 auto"]]),e("flex-none",[["flex","none"]]),r.functional("flex",o=>{if(o.value){if(o.value.kind==="arbitrary")return o.modifier?void 0:[a("flex",o.value.value)];if(o.value.fraction){let[f,h]=P(o.value.fraction,"/");return!V(f)||!V(h)?void 0:[a("flex",`calc(${o.value.fraction} * 100%)`)]}if(V(o.value.value))return o.modifier?void 0:[a("flex",o.value.value)]}}),n("flex",()=>[{supportsFractions:!0}]),i("shrink",{defaultValue:"1",handleBareValue:({value:o})=>V(o)?o:null,handle:o=>[a("flex-shrink",o)]}),i("grow",{defaultValue:"1",handleBareValue:({value:o})=>V(o)?o:null,handle:o=>[a("flex-grow",o)]}),n("shrink",()=>[{values:["0"],valueThemeKeys:[],hasDefaultValue:!0}]),n("grow",()=>[{values:["0"],valueThemeKeys:[],hasDefaultValue:!0}]),e("basis-auto",[["flex-basis","auto"]]),e("basis-full",[["flex-basis","100%"]]),l("basis",["--flex-basis","--spacing","--container"],o=>[a("flex-basis",o)],{supportsFractions:!0}),e("table-auto",[["table-layout","auto"]]),e("table-fixed",[["table-layout","fixed"]]),e("caption-top",[["caption-side","top"]]),e("caption-bottom",[["caption-side","bottom"]]),e("border-collapse",[["border-collapse","collapse"]]),e("border-separate",[["border-collapse","separate"]]);let p=()=>U([N("--tw-border-spacing-x","0",""),N("--tw-border-spacing-y","0","")]);l("border-spacing",["--border-spacing","--spacing"],o=>[p(),a("--tw-border-spacing-x",o),a("--tw-border-spacing-y",o),a("border-spacing","var(--tw-border-spacing-x) var(--tw-border-spacing-y)")]),l("border-spacing-x",["--border-spacing","--spacing"],o=>[p(),a("--tw-border-spacing-x",o),a("border-spacing","var(--tw-border-spacing-x) var(--tw-border-spacing-y)")]),l("border-spacing-y",["--border-spacing","--spacing"],o=>[p(),a("--tw-border-spacing-y",o),a("border-spacing","var(--tw-border-spacing-x) var(--tw-border-spacing-y)")]),e("origin-center",[["transform-origin","center"]]),e("origin-top",[["transform-origin","top"]]),e("origin-top-right",[["transform-origin","top right"]]),e("origin-right",[["transform-origin","right"]]),e("origin-bottom-right",[["transform-origin","bottom right"]]),e("origin-bottom",[["transform-origin","bottom"]]),e("origin-bottom-left",[["transform-origin","bottom left"]]),e("origin-left",[["transform-origin","left"]]),e("origin-top-left",[["transform-origin","top left"]]),i("origin",{themeKeys:["--transform-origin"],handle:o=>[a("transform-origin",o)]}),e("perspective-origin-center",[["perspective-origin","center"]]),e("perspective-origin-top",[["perspective-origin","top"]]),e("perspective-origin-top-right",[["perspective-origin","top right"]]),e("perspective-origin-right",[["perspective-origin","right"]]),e("perspective-origin-bottom-right",[["perspective-origin","bottom right"]]),e("perspective-origin-bottom",[["perspective-origin","bottom"]]),e("perspective-origin-bottom-left",[["perspective-origin","bottom left"]]),e("perspective-origin-left",[["perspective-origin","left"]]),e("perspective-origin-top-left",[["perspective-origin","top left"]]),i("perspective-origin",{themeKeys:["--perspective-origin"],handle:o=>[a("perspective-origin",o)]}),e("perspective-none",[["perspective","none"]]),i("perspective",{themeKeys:["--perspective"],handle:o=>[a("perspective",o)]});let c=()=>U([N("--tw-translate-x","0"),N("--tw-translate-y","0"),N("--tw-translate-z","0")]);e("translate-none",[["translate","none"]]),e("-translate-full",[c,["--tw-translate-x","-100%"],["--tw-translate-y","-100%"],["translate","var(--tw-translate-x) var(--tw-translate-y)"]]),e("translate-full",[c,["--tw-translate-x","100%"],["--tw-translate-y","100%"],["translate","var(--tw-translate-x) var(--tw-translate-y)"]]),l("translate",["--translate","--spacing"],o=>[c(),a("--tw-translate-x",o),a("--tw-translate-y",o),a("translate","var(--tw-translate-x) var(--tw-translate-y)")],{supportsNegative:!0,supportsFractions:!0});for(let o of["x","y"])e(`-translate-${o}-full`,[c,[`--tw-translate-${o}`,"-100%"],["translate","var(--tw-translate-x) var(--tw-translate-y)"]]),e(`translate-${o}-full`,[c,[`--tw-translate-${o}`,"100%"],["translate","var(--tw-translate-x) var(--tw-translate-y)"]]),l(`translate-${o}`,["--translate","--spacing"],f=>[c(),a(`--tw-translate-${o}`,f),a("translate","var(--tw-translate-x) var(--tw-translate-y)")],{supportsNegative:!0,supportsFractions:!0});l("translate-z",["--translate","--spacing"],o=>[c(),a("--tw-translate-z",o),a("translate","var(--tw-translate-x) var(--tw-translate-y) var(--tw-translate-z)")],{supportsNegative:!0}),e("translate-3d",[c,["translate","var(--tw-translate-x) var(--tw-translate-y) var(--tw-translate-z)"]]);let d=()=>U([N("--tw-scale-x","1"),N("--tw-scale-y","1"),N("--tw-scale-z","1")]);e("scale-none",[["scale","none"]]);function u({negative:o}){return f=>{if(!f.value||f.modifier)return;let h;return f.value.kind==="arbitrary"?(h=f.value.value,[a("scale",h)]):(h=t.resolve(f.value.value,["--scale"]),!h&&V(f.value.value)&&(h=`${f.value.value}%`),h?(h=o?`calc(${h} * -1)`:h,[d(),a("--tw-scale-x",h),a("--tw-scale-y",h),a("--tw-scale-z",h),a("scale","var(--tw-scale-x) var(--tw-scale-y)")]):void 0)}}r.functional("-scale",u({negative:!0})),r.functional("scale",u({negative:!1})),n("scale",()=>[{supportsNegative:!0,values:["0","50","75","90","95","100","105","110","125","150","200"],valueThemeKeys:["--scale"]}]);for(let o of["x","y","z"])i(`scale-${o}`,{supportsNegative:!0,themeKeys:["--scale"],handleBareValue:({value:f})=>V(f)?`${f}%`:null,handle:f=>[d(),a(`--tw-scale-${o}`,f),a("scale",`var(--tw-scale-x) var(--tw-scale-y)${o==="z"?" var(--tw-scale-z)":""}`)]}),n(`scale-${o}`,()=>[{supportsNegative:!0,values:["0","50","75","90","95","100","105","110","125","150","200"],valueThemeKeys:["--scale"]}]);e("scale-3d",[d,["scale","var(--tw-scale-x) var(--tw-scale-y) var(--tw-scale-z)"]]),e("rotate-none",[["rotate","none"]]);function g({negative:o}){return f=>{if(!f.value||f.modifier)return;let h;if(f.value.kind==="arbitrary"){h=f.value.value;let k=f.value.dataType??z(h,["angle","vector"]);if(k==="vector")return[a("rotate",`${h} var(--tw-rotate)`)];if(k!=="angle")return[a("rotate",h)]}else if(h=t.resolve(f.value.value,["--rotate"]),!h&&V(f.value.value)&&(h=`${f.value.value}deg`),!h)return;return[a("rotate",o?`calc(${h} * -1)`:h)]}}r.functional("-rotate",g({negative:!0})),r.functional("rotate",g({negative:!1})),n("rotate",()=>[{supportsNegative:!0,values:["0","1","2","3","6","12","45","90","180"],valueThemeKeys:["--rotate"]}]);{let o=["var(--tw-rotate-x)","var(--tw-rotate-y)","var(--tw-rotate-z)","var(--tw-skew-x)","var(--tw-skew-y)"].join(" "),f=()=>U([N("--tw-rotate-x","rotateX(0)"),N("--tw-rotate-y","rotateY(0)"),N("--tw-rotate-z","rotateZ(0)"),N("--tw-skew-x","skewX(0)"),N("--tw-skew-y","skewY(0)")]);for(let h of["x","y","z"])i(`rotate-${h}`,{supportsNegative:!0,themeKeys:["--rotate"],handleBareValue:({value:k})=>V(k)?`${k}deg`:null,handle:k=>[f(),a(`--tw-rotate-${h}`,`rotate${h.toUpperCase()}(${k})`),a("transform",o)]}),n(`rotate-${h}`,()=>[{supportsNegative:!0,values:["0","1","2","3","6","12","45","90","180"],valueThemeKeys:["--rotate"]}]);i("skew",{supportsNegative:!0,themeKeys:["--skew"],handleBareValue:({value:h})=>V(h)?`${h}deg`:null,handle:h=>[f(),a("--tw-skew-x",`skewX(${h})`),a("--tw-skew-y",`skewY(${h})`),a("transform",o)]}),i("skew-x",{supportsNegative:!0,themeKeys:["--skew"],handleBareValue:({value:h})=>V(h)?`${h}deg`:null,handle:h=>[f(),a("--tw-skew-x",`skewX(${h})`),a("transform",o)]}),i("skew-y",{supportsNegative:!0,themeKeys:["--skew"],handleBareValue:({value:h})=>V(h)?`${h}deg`:null,handle:h=>[f(),a("--tw-skew-y",`skewY(${h})`),a("transform",o)]}),n("skew",()=>[{supportsNegative:!0,values:["0","1","2","3","6","12"],valueThemeKeys:["--skew"]}]),n("skew-x",()=>[{supportsNegative:!0,values:["0","1","2","3","6","12"],valueThemeKeys:["--skew"]}]),n("skew-y",()=>[{supportsNegative:!0,values:["0","1","2","3","6","12"],valueThemeKeys:["--skew"]}]),r.functional("transform",h=>{if(h.modifier)return;let k=null;if(h.value?h.value.kind==="arbitrary"&&(k=h.value.value):k=o,k!==null)return[f(),a("transform",k)]}),n("transform",()=>[{hasDefaultValue:!0}]),e("transform-cpu",[["transform",o]]),e("transform-gpu",[["transform",`translateZ(0) ${o}`]]),e("transform-none",[["transform","none"]])}e("transform-flat",[["transform-style","flat"]]),e("transform-3d",[["transform-style","preserve-3d"]]),e("transform-content",[["transform-box","content-box"]]),e("transform-border",[["transform-box","border-box"]]),e("transform-fill",[["transform-box","fill-box"]]),e("transform-stroke",[["transform-box","stroke-box"]]),e("transform-view",[["transform-box","view-box"]]),e("backface-visible",[["backface-visibility","visible"]]),e("backface-hidden",[["backface-visibility","hidden"]]);for(let o of["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out"])e(`cursor-${o}`,[["cursor",o]]);i("cursor",{themeKeys:["--cursor"],handle:o=>[a("cursor",o)]});for(let o of["auto","none","manipulation"])e(`touch-${o}`,[["touch-action",o]]);let m=()=>U([N("--tw-pan-x"),N("--tw-pan-y"),N("--tw-pinch-zoom")]);for(let o of["x","left","right"])e(`touch-pan-${o}`,[m,["--tw-pan-x",`pan-${o}`],["touch-action","var(--tw-pan-x,) var(--tw-pan-y,) var(--tw-pinch-zoom,)"]]);for(let o of["y","up","down"])e(`touch-pan-${o}`,[m,["--tw-pan-y",`pan-${o}`],["touch-action","var(--tw-pan-x,) var(--tw-pan-y,) var(--tw-pinch-zoom,)"]]);e("touch-pinch-zoom",[m,["--tw-pinch-zoom","pinch-zoom"],["touch-action","var(--tw-pan-x,) var(--tw-pan-y,) var(--tw-pinch-zoom,)"]]);for(let o of["none","text","all","auto"])e(`select-${o}`,[["-webkit-user-select",o],["user-select",o]]);e("resize-none",[["resize","none"]]),e("resize-x",[["resize","horizontal"]]),e("resize-y",[["resize","vertical"]]),e("resize",[["resize","both"]]),e("snap-none",[["scroll-snap-type","none"]]);let b=()=>U([N("--tw-scroll-snap-strictness","proximity","*")]);for(let o of["x","y","both"])e(`snap-${o}`,[b,["scroll-snap-type",`${o} var(--tw-scroll-snap-strictness)`]]);e("snap-mandatory",[b,["--tw-scroll-snap-strictness","mandatory"]]),e("snap-proximity",[b,["--tw-scroll-snap-strictness","proximity"]]),e("snap-align-none",[["scroll-snap-align","none"]]),e("snap-start",[["scroll-snap-align","start"]]),e("snap-end",[["scroll-snap-align","end"]]),e("snap-center",[["scroll-snap-align","center"]]),e("snap-normal",[["scroll-snap-stop","normal"]]),e("snap-always",[["scroll-snap-stop","always"]]);for(let[o,f]of[["scroll-m","scroll-margin"],["scroll-mx","scroll-margin-inline"],["scroll-my","scroll-margin-block"],["scroll-ms","scroll-margin-inline-start"],["scroll-me","scroll-margin-inline-end"],["scroll-mt","scroll-margin-top"],["scroll-mr","scroll-margin-right"],["scroll-mb","scroll-margin-bottom"],["scroll-ml","scroll-margin-left"]])l(o,["--scroll-margin","--spacing"],h=>[a(f,h)],{supportsNegative:!0});for(let[o,f]of[["scroll-p","scroll-padding"],["scroll-px","scroll-padding-inline"],["scroll-py","scroll-padding-block"],["scroll-ps","scroll-padding-inline-start"],["scroll-pe","scroll-padding-inline-end"],["scroll-pt","scroll-padding-top"],["scroll-pr","scroll-padding-right"],["scroll-pb","scroll-padding-bottom"],["scroll-pl","scroll-padding-left"]])l(o,["--scroll-padding","--spacing"],h=>[a(f,h)]);e("list-inside",[["list-style-position","inside"]]),e("list-outside",[["list-style-position","outside"]]),e("list-none",[["list-style-type","none"]]),e("list-disc",[["list-style-type","disc"]]),e("list-decimal",[["list-style-type","decimal"]]),i("list",{themeKeys:["--list-style-type"],handle:o=>[a("list-style-type",o)]}),e("list-image-none",[["list-style-image","none"]]),i("list-image",{themeKeys:["--list-style-image"],handle:o=>[a("list-style-image",o)]}),e("appearance-none",[["appearance","none"]]),e("appearance-auto",[["appearance","auto"]]),e("scheme-normal",[["color-scheme","normal"]]),e("scheme-dark",[["color-scheme","dark"]]),e("scheme-light",[["color-scheme","light"]]),e("scheme-light-dark",[["color-scheme","light dark"]]),e("scheme-only-dark",[["color-scheme","only dark"]]),e("scheme-only-light",[["color-scheme","only light"]]),e("columns-auto",[["columns","auto"]]),i("columns",{themeKeys:["--columns","--container"],handleBareValue:({value:o})=>V(o)?o:null,handle:o=>[a("columns",o)]}),n("columns",()=>[{values:Array.from({length:12},(o,f)=>`${f+1}`),valueThemeKeys:["--columns","--container"]}]);for(let o of["auto","avoid","all","avoid-page","page","left","right","column"])e(`break-before-${o}`,[["break-before",o]]);for(let o of["auto","avoid","avoid-page","avoid-column"])e(`break-inside-${o}`,[["break-inside",o]]);for(let o of["auto","avoid","all","avoid-page","page","left","right","column"])e(`break-after-${o}`,[["break-after",o]]);e("grid-flow-row",[["grid-auto-flow","row"]]),e("grid-flow-col",[["grid-auto-flow","column"]]),e("grid-flow-dense",[["grid-auto-flow","dense"]]),e("grid-flow-row-dense",[["grid-auto-flow","row dense"]]),e("grid-flow-col-dense",[["grid-auto-flow","column dense"]]),e("auto-cols-auto",[["grid-auto-columns","auto"]]),e("auto-cols-min",[["grid-auto-columns","min-content"]]),e("auto-cols-max",[["grid-auto-columns","max-content"]]),e("auto-cols-fr",[["grid-auto-columns","minmax(0, 1fr)"]]),i("auto-cols",{themeKeys:["--grid-auto-columns"],handle:o=>[a("grid-auto-columns",o)]}),e("auto-rows-auto",[["grid-auto-rows","auto"]]),e("auto-rows-min",[["grid-auto-rows","min-content"]]),e("auto-rows-max",[["grid-auto-rows","max-content"]]),e("auto-rows-fr",[["grid-auto-rows","minmax(0, 1fr)"]]),i("auto-rows",{themeKeys:["--grid-auto-rows"],handle:o=>[a("grid-auto-rows",o)]}),e("grid-cols-none",[["grid-template-columns","none"]]),e("grid-cols-subgrid",[["grid-template-columns","subgrid"]]),i("grid-cols",{themeKeys:["--grid-template-columns"],handleBareValue:({value:o})=>ft(o)?`repeat(${o}, minmax(0, 1fr))`:null,handle:o=>[a("grid-template-columns",o)]}),e("grid-rows-none",[["grid-template-rows","none"]]),e("grid-rows-subgrid",[["grid-template-rows","subgrid"]]),i("grid-rows",{themeKeys:["--grid-template-rows"],handleBareValue:({value:o})=>ft(o)?`repeat(${o}, minmax(0, 1fr))`:null,handle:o=>[a("grid-template-rows",o)]}),n("grid-cols",()=>[{values:Array.from({length:12},(o,f)=>`${f+1}`),valueThemeKeys:["--grid-template-columns"]}]),n("grid-rows",()=>[{values:Array.from({length:12},(o,f)=>`${f+1}`),valueThemeKeys:["--grid-template-rows"]}]),e("flex-row",[["flex-direction","row"]]),e("flex-row-reverse",[["flex-direction","row-reverse"]]),e("flex-col",[["flex-direction","column"]]),e("flex-col-reverse",[["flex-direction","column-reverse"]]),e("flex-wrap",[["flex-wrap","wrap"]]),e("flex-nowrap",[["flex-wrap","nowrap"]]),e("flex-wrap-reverse",[["flex-wrap","wrap-reverse"]]),e("place-content-center",[["place-content","center"]]),e("place-content-start",[["place-content","start"]]),e("place-content-end",[["place-content","end"]]),e("place-content-between",[["place-content","space-between"]]),e("place-content-around",[["place-content","space-around"]]),e("place-content-evenly",[["place-content","space-evenly"]]),e("place-content-baseline",[["place-content","baseline"]]),e("place-content-stretch",[["place-content","stretch"]]),e("place-items-center",[["place-items","center"]]),e("place-items-start",[["place-items","start"]]),e("place-items-end",[["place-items","end"]]),e("place-items-baseline",[["place-items","baseline"]]),e("place-items-stretch",[["place-items","stretch"]]),e("content-normal",[["align-content","normal"]]),e("content-center",[["align-content","center"]]),e("content-start",[["align-content","flex-start"]]),e("content-end",[["align-content","flex-end"]]),e("content-between",[["align-content","space-between"]]),e("content-around",[["align-content","space-around"]]),e("content-evenly",[["align-content","space-evenly"]]),e("content-baseline",[["align-content","baseline"]]),e("content-stretch",[["align-content","stretch"]]),e("items-center",[["align-items","center"]]),e("items-start",[["align-items","flex-start"]]),e("items-end",[["align-items","flex-end"]]),e("items-baseline",[["align-items","baseline"]]),e("items-stretch",[["align-items","stretch"]]),e("justify-normal",[["justify-content","normal"]]),e("justify-center",[["justify-content","center"]]),e("justify-start",[["justify-content","flex-start"]]),e("justify-end",[["justify-content","flex-end"]]),e("justify-between",[["justify-content","space-between"]]),e("justify-around",[["justify-content","space-around"]]),e("justify-evenly",[["justify-content","space-evenly"]]),e("justify-baseline",[["justify-content","baseline"]]),e("justify-stretch",[["justify-content","stretch"]]),e("justify-items-normal",[["justify-items","normal"]]),e("justify-items-center",[["justify-items","center"]]),e("justify-items-start",[["justify-items","start"]]),e("justify-items-end",[["justify-items","end"]]),e("justify-items-stretch",[["justify-items","stretch"]]),l("gap",["--gap","--spacing"],o=>[a("gap",o)]),l("gap-x",["--gap","--spacing"],o=>[a("column-gap",o)]),l("gap-y",["--gap","--spacing"],o=>[a("row-gap",o)]),l("space-x",["--space","--spacing"],o=>[U([N("--tw-space-x-reverse","0")]),j(":where(& > :not(:last-child))",[a("--tw-sort","row-gap"),a("--tw-space-x-reverse","0"),a("margin-inline-start",`calc(${o} * var(--tw-space-x-reverse))`),a("margin-inline-end",`calc(${o} * calc(1 - var(--tw-space-x-reverse)))`)])],{supportsNegative:!0}),l("space-y",["--space","--spacing"],o=>[U([N("--tw-space-y-reverse","0")]),j(":where(& > :not(:last-child))",[a("--tw-sort","column-gap"),a("--tw-space-y-reverse","0"),a("margin-block-start",`calc(${o} * var(--tw-space-y-reverse))`),a("margin-block-end",`calc(${o} * calc(1 - var(--tw-space-y-reverse)))`)])],{supportsNegative:!0}),e("space-x-reverse",[()=>U([N("--tw-space-x-reverse","0")]),()=>j(":where(& > :not(:last-child))",[a("--tw-sort","row-gap"),a("--tw-space-x-reverse","1")])]),e("space-y-reverse",[()=>U([N("--tw-space-y-reverse","0")]),()=>j(":where(& > :not(:last-child))",[a("--tw-sort","column-gap"),a("--tw-space-y-reverse","1")])]),e("accent-auto",[["accent-color","auto"]]),s("accent",{themeKeys:["--accent-color","--color"],handle:o=>[a("accent-color",o)]}),s("caret",{themeKeys:["--caret-color","--color"],handle:o=>[a("caret-color",o)]}),s("divide",{themeKeys:["--divide-color","--color"],handle:o=>[j(":where(& > :not(:last-child))",[a("--tw-sort","divide-color"),a("border-color",o)])]}),e("place-self-auto",[["place-self","auto"]]),e("place-self-start",[["place-self","start"]]),e("place-self-end",[["place-self","end"]]),e("place-self-center",[["place-self","center"]]),e("place-self-stretch",[["place-self","stretch"]]),e("self-auto",[["align-self","auto"]]),e("self-start",[["align-self","flex-start"]]),e("self-end",[["align-self","flex-end"]]),e("self-center",[["align-self","center"]]),e("self-stretch",[["align-self","stretch"]]),e("self-baseline",[["align-self","baseline"]]),e("justify-self-auto",[["justify-self","auto"]]),e("justify-self-start",[["justify-self","flex-start"]]),e("justify-self-end",[["justify-self","flex-end"]]),e("justify-self-center",[["justify-self","center"]]),e("justify-self-stretch",[["justify-self","stretch"]]);for(let o of["auto","hidden","clip","visible","scroll"])e(`overflow-${o}`,[["overflow",o]]),e(`overflow-x-${o}`,[["overflow-x",o]]),e(`overflow-y-${o}`,[["overflow-y",o]]);for(let o of["auto","contain","none"])e(`overscroll-${o}`,[["overscroll-behavior",o]]),e(`overscroll-x-${o}`,[["overscroll-behavior-x",o]]),e(`overscroll-y-${o}`,[["overscroll-behavior-y",o]]);e("scroll-auto",[["scroll-behavior","auto"]]),e("scroll-smooth",[["scroll-behavior","smooth"]]),e("truncate",[["overflow","hidden"],["text-overflow","ellipsis"],["white-space","nowrap"]]),e("text-ellipsis",[["text-overflow","ellipsis"]]),e("text-clip",[["text-overflow","clip"]]),e("hyphens-none",[["-webkit-hyphens","none"],["hyphens","none"]]),e("hyphens-manual",[["-webkit-hyphens","manual"],["hyphens","manual"]]),e("hyphens-auto",[["-webkit-hyphens","auto"],["hyphens","auto"]]),e("whitespace-normal",[["white-space","normal"]]),e("whitespace-nowrap",[["white-space","nowrap"]]),e("whitespace-pre",[["white-space","pre"]]),e("whitespace-pre-line",[["white-space","pre-line"]]),e("whitespace-pre-wrap",[["white-space","pre-wrap"]]),e("whitespace-break-spaces",[["white-space","break-spaces"]]),e("text-wrap",[["text-wrap","wrap"]]),e("text-nowrap",[["text-wrap","nowrap"]]),e("text-balance",[["text-wrap","balance"]]),e("text-pretty",[["text-wrap","pretty"]]),e("break-normal",[["overflow-wrap","normal"],["word-break","normal"]]),e("break-words",[["overflow-wrap","break-word"]]),e("break-all",[["word-break","break-all"]]),e("break-keep",[["word-break","keep-all"]]),!1;for(let[o,f]of[["rounded",["border-radius"]],["rounded-s",["border-start-start-radius","border-end-start-radius"]],["rounded-e",["border-start-end-radius","border-end-end-radius"]],["rounded-t",["border-top-left-radius","border-top-right-radius"]],["rounded-r",["border-top-right-radius","border-bottom-right-radius"]],["rounded-b",["border-bottom-right-radius","border-bottom-left-radius"]],["rounded-l",["border-top-left-radius","border-bottom-left-radius"]],["rounded-ss",["border-start-start-radius"]],["rounded-se",["border-start-end-radius"]],["rounded-ee",["border-end-end-radius"]],["rounded-es",["border-end-start-radius"]],["rounded-tl",["border-top-left-radius"]],["rounded-tr",["border-top-right-radius"]],["rounded-br",["border-bottom-right-radius"]],["rounded-bl",["border-bottom-left-radius"]]])e(`${o}-none`,f.map(h=>[h,"0"])),e(`${o}-full`,f.map(h=>[h,"calc(infinity * 1px)"])),i(o,{themeKeys:["--radius"],handle:h=>f.map(k=>a(k,h))});e("border-solid",[["--tw-border-style","solid"],["border-style","solid"]]),e("border-dashed",[["--tw-border-style","dashed"],["border-style","dashed"]]),e("border-dotted",[["--tw-border-style","dotted"],["border-style","dotted"]]),e("border-double",[["--tw-border-style","double"],["border-style","double"]]),e("border-hidden",[["--tw-border-style","hidden"],["border-style","hidden"]]),e("border-none",[["--tw-border-style","none"],["border-style","none"]]);{let f=function(h,k){r.functional(h,w=>{if(!w.value){if(w.modifier)return;let $=t.get(["--default-border-width"])??"1px",E=k.width($);return E?[o(),...E]:void 0}if(w.value.kind==="arbitrary"){let $=w.value.value;switch(w.value.dataType??z($,["color","line-width","length"])){case"line-width":case"length":{if(w.modifier)return;let C=k.width($);return C?[o(),...C]:void 0}default:return $=W($,w.modifier,t),$===null?void 0:k.color($)}}{let $=H(w,t,["--border-color","--color"]);if($)return k.color($)}{if(w.modifier)return;let $=t.resolve(w.value.value,["--border-width"]);if($){let E=k.width($);return E?[o(),...E]:void 0}if(V(w.value.value)){let E=k.width(`${w.value.value}px`);return E?[o(),...E]:void 0}}}),n(h,()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--border-color","--color"],modifiers:Array.from({length:21},(w,$)=>`${$*5}`),hasDefaultValue:!0},{values:["0","2","4","8"],valueThemeKeys:["--border-width"]}])};var x=f;let o=()=>U([N("--tw-border-style","solid")]);f("border",{width:h=>[a("border-style","var(--tw-border-style)"),a("border-width",h)],color:h=>[a("border-color",h)]}),f("border-x",{width:h=>[a("border-inline-style","var(--tw-border-style)"),a("border-inline-width",h)],color:h=>[a("border-inline-color",h)]}),f("border-y",{width:h=>[a("border-block-style","var(--tw-border-style)"),a("border-block-width",h)],color:h=>[a("border-block-color",h)]}),f("border-s",{width:h=>[a("border-inline-start-style","var(--tw-border-style)"),a("border-inline-start-width",h)],color:h=>[a("border-inline-start-color",h)]}),f("border-e",{width:h=>[a("border-inline-end-style","var(--tw-border-style)"),a("border-inline-end-width",h)],color:h=>[a("border-inline-end-color",h)]}),f("border-t",{width:h=>[a("border-top-style","var(--tw-border-style)"),a("border-top-width",h)],color:h=>[a("border-top-color",h)]}),f("border-r",{width:h=>[a("border-right-style","var(--tw-border-style)"),a("border-right-width",h)],color:h=>[a("border-right-color",h)]}),f("border-b",{width:h=>[a("border-bottom-style","var(--tw-border-style)"),a("border-bottom-width",h)],color:h=>[a("border-bottom-color",h)]}),f("border-l",{width:h=>[a("border-left-style","var(--tw-border-style)"),a("border-left-width",h)],color:h=>[a("border-left-color",h)]}),i("divide-x",{defaultValue:t.get(["--default-border-width"])??"1px",themeKeys:["--divide-width","--border-width"],handleBareValue:({value:h})=>V(h)?`${h}px`:null,handle:h=>[U([N("--tw-divide-x-reverse","0")]),j(":where(& > :not(:last-child))",[a("--tw-sort","divide-x-width"),o(),a("--tw-divide-x-reverse","0"),a("border-inline-style","var(--tw-border-style)"),a("border-inline-start-width",`calc(${h} * var(--tw-divide-x-reverse))`),a("border-inline-end-width",`calc(${h} * calc(1 - var(--tw-divide-x-reverse)))`)])]}),i("divide-y",{defaultValue:t.get(["--default-border-width"])??"1px",themeKeys:["--divide-width","--border-width"],handleBareValue:({value:h})=>V(h)?`${h}px`:null,handle:h=>[U([N("--tw-divide-y-reverse","0")]),j(":where(& > :not(:last-child))",[a("--tw-sort","divide-y-width"),o(),a("--tw-divide-y-reverse","0"),a("border-bottom-style","var(--tw-border-style)"),a("border-top-style","var(--tw-border-style)"),a("border-top-width",`calc(${h} * var(--tw-divide-y-reverse))`),a("border-bottom-width",`calc(${h} * calc(1 - var(--tw-divide-y-reverse)))`)])]}),n("divide-x",()=>[{values:["0","2","4","8"],valueThemeKeys:["--divide-width","--border-width"],hasDefaultValue:!0}]),n("divide-y",()=>[{values:["0","2","4","8"],valueThemeKeys:["--divide-width","--border-width"],hasDefaultValue:!0}]),e("divide-x-reverse",[()=>U([N("--tw-divide-x-reverse","0")]),()=>j(":where(& > :not(:last-child))",[a("--tw-divide-x-reverse","1")])]),e("divide-y-reverse",[()=>U([N("--tw-divide-y-reverse","0")]),()=>j(":where(& > :not(:last-child))",[a("--tw-divide-y-reverse","1")])]);for(let h of["solid","dashed","dotted","double","none"])e(`divide-${h}`,[()=>j(":where(& > :not(:last-child))",[a("--tw-sort","divide-style"),a("--tw-border-style",h),a("border-style",h)])])}e("bg-auto",[["background-size","auto"]]),e("bg-cover",[["background-size","cover"]]),e("bg-contain",[["background-size","contain"]]),e("bg-fixed",[["background-attachment","fixed"]]),e("bg-local",[["background-attachment","local"]]),e("bg-scroll",[["background-attachment","scroll"]]),e("bg-center",[["background-position","center"]]),e("bg-top",[["background-position","top"]]),e("bg-right-top",[["background-position","right top"]]),e("bg-right",[["background-position","right"]]),e("bg-right-bottom",[["background-position","right bottom"]]),e("bg-bottom",[["background-position","bottom"]]),e("bg-left-bottom",[["background-position","left bottom"]]),e("bg-left",[["background-position","left"]]),e("bg-left-top",[["background-position","left top"]]),e("bg-repeat",[["background-repeat","repeat"]]),e("bg-no-repeat",[["background-repeat","no-repeat"]]),e("bg-repeat-x",[["background-repeat","repeat-x"]]),e("bg-repeat-y",[["background-repeat","repeat-y"]]),e("bg-repeat-round",[["background-repeat","round"]]),e("bg-repeat-space",[["background-repeat","space"]]),e("bg-none",[["background-image","none"]]);{let h=function($){let E="in oklab";if($?.kind==="named")switch($.value){case"longer":case"shorter":case"increasing":case"decreasing":E=`in oklch ${$.value} hue`;break;default:E=`in ${$.value}`}else $?.kind==="arbitrary"&&(E=$.value);return E},k=function({negative:$}){return E=>{if(!E.value)return;if(E.value.kind==="arbitrary"){if(E.modifier)return;let F=E.value.value;switch(E.value.dataType??z(F,["angle"])){case"angle":return F=$?`calc(${F} * -1)`:`${F}`,[a("--tw-gradient-position",F),a("background-image",`linear-gradient(var(--tw-gradient-stops,${F}))`)];default:return $?void 0:[a("--tw-gradient-position",F),a("background-image",`linear-gradient(var(--tw-gradient-stops,${F}))`)]}}let C=E.value.value;if(!$&&f.has(C))C=f.get(C);else if(V(C))C=$?`calc(${C}deg * -1)`:`${C}deg`;else return;let A=h(E.modifier);return[a("--tw-gradient-position",`${C} ${A}`),a("background-image","linear-gradient(var(--tw-gradient-stops))")]}},w=function({negative:$}){return E=>{if(E.value?.kind==="arbitrary"){if(E.modifier)return;let F=E.value.value;return[a("--tw-gradient-position",F),a("background-image",`conic-gradient(var(--tw-gradient-stops,${F}))`)]}let C=h(E.modifier);if(!E.value)return[a("--tw-gradient-position",C),a("background-image","conic-gradient(var(--tw-gradient-stops))")];let A=E.value.value;if(V(A))return A=$?`calc(${A} * -1)`:`${A}deg`,[a("--tw-gradient-position",`from ${A} ${C}`),a("background-image","conic-gradient(var(--tw-gradient-stops))")]}};var T=h,S=k,O=w;let o=["oklab","oklch","srgb","hsl","longer","shorter","increasing","decreasing"],f=new Map([["to-t","to top"],["to-tr","to top right"],["to-r","to right"],["to-br","to bottom right"],["to-b","to bottom"],["to-bl","to bottom left"],["to-l","to left"],["to-tl","to top left"]]);r.functional("-bg-linear",k({negative:!0})),r.functional("bg-linear",k({negative:!1})),n("bg-linear",()=>[{values:[...f.keys()],modifiers:o},{values:["0","30","60","90","120","150","180","210","240","270","300","330"],supportsNegative:!0,modifiers:o}]),r.functional("-bg-conic",w({negative:!0})),r.functional("bg-conic",w({negative:!1})),n("bg-conic",()=>[{hasDefaultValue:!0,modifiers:o},{values:["0","30","60","90","120","150","180","210","240","270","300","330"],supportsNegative:!0,modifiers:o}]),r.functional("bg-radial",$=>{if(!$.value){let E=h($.modifier);return[a("--tw-gradient-position",E),a("background-image","radial-gradient(var(--tw-gradient-stops))")]}if($.value.kind==="arbitrary"){if($.modifier)return;let E=$.value.value;return[a("--tw-gradient-position",E),a("background-image",`radial-gradient(var(--tw-gradient-stops,${E}))`)]}}),n("bg-radial",()=>[{hasDefaultValue:!0,modifiers:o}])}r.functional("bg",o=>{if(o.value){if(o.value.kind==="arbitrary"){let f=o.value.value;switch(o.value.dataType??z(f,["image","color","percentage","position","bg-size","length","url"])){case"percentage":case"position":return o.modifier?void 0:[a("background-position",f)];case"bg-size":case"length":case"size":return o.modifier?void 0:[a("background-size",f)];case"image":case"url":return o.modifier?void 0:[a("background-image",f)];default:return f=W(f,o.modifier,t),f===null?void 0:[a("background-color",f)]}}{let f=H(o,t,["--background-color","--color"]);if(f)return[a("background-color",f)]}{if(o.modifier)return;let f=t.resolve(o.value.value,["--background-image"]);if(f)return[a("background-image",f)]}}}),n("bg",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--background-color","--color"],modifiers:Array.from({length:21},(o,f)=>`${f*5}`)},{values:[],valueThemeKeys:["--background-image"]}]);let y=()=>U([N("--tw-gradient-position"),N("--tw-gradient-from","#0000",""),N("--tw-gradient-via","#0000",""),N("--tw-gradient-to","#0000",""),N("--tw-gradient-stops"),N("--tw-gradient-via-stops"),N("--tw-gradient-from-position","0%",""),N("--tw-gradient-via-position","50%",""),N("--tw-gradient-to-position","100%","")]);function v(o,f){r.functional(o,h=>{if(h.value){if(h.value.kind==="arbitrary"){let k=h.value.value;switch(h.value.dataType??z(k,["color","length","percentage"])){case"length":case"percentage":return h.modifier?void 0:f.position(k);default:return k=W(k,h.modifier,t),k===null?void 0:f.color(k)}}{let k=H(h,t,["--background-color","--color"]);if(k)return f.color(k)}{if(h.modifier)return;let k=t.resolve(h.value.value,["--gradient-color-stop-positions"]);if(k)return f.position(k);if(h.value.value[h.value.value.length-1]==="%"&&V(h.value.value.slice(0,-1)))return f.position(h.value.value)}}}),n(o,()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--background-color","--color"],modifiers:Array.from({length:21},(h,k)=>`${k*5}`)},{values:Array.from({length:21},(h,k)=>`${k*5}%`),valueThemeKeys:["--gradient-color-stop-positions"]}])}v("from",{color:o=>[y(),a("--tw-sort","--tw-gradient-from"),a("--tw-gradient-from",o),a("--tw-gradient-stops","var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))")],position:o=>[y(),a("--tw-gradient-from-position",o)]}),e("via-none",[["--tw-gradient-via-stops","initial"]]),v("via",{color:o=>[y(),a("--tw-sort","--tw-gradient-via"),a("--tw-gradient-via",o),a("--tw-gradient-via-stops","var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position)"),a("--tw-gradient-stops","var(--tw-gradient-via-stops)")],position:o=>[y(),a("--tw-gradient-via-position",o)]}),v("to",{color:o=>[y(),a("--tw-sort","--tw-gradient-to"),a("--tw-gradient-to",o),a("--tw-gradient-stops","var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))")],position:o=>[y(),a("--tw-gradient-to-position",o)]}),e("box-decoration-slice",[["-webkit-box-decoration-break","slice"],["box-decoration-break","slice"]]),e("box-decoration-clone",[["-webkit-box-decoration-break","clone"],["box-decoration-break","clone"]]),e("bg-clip-text",[["background-clip","text"]]),e("bg-clip-border",[["background-clip","border-box"]]),e("bg-clip-padding",[["background-clip","padding-box"]]),e("bg-clip-content",[["background-clip","content-box"]]),e("bg-origin-border",[["background-origin","border-box"]]),e("bg-origin-padding",[["background-origin","padding-box"]]),e("bg-origin-content",[["background-origin","content-box"]]);for(let o of["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"])e(`bg-blend-${o}`,[["background-blend-mode",o]]),e(`mix-blend-${o}`,[["mix-blend-mode",o]]);e("mix-blend-plus-darker",[["mix-blend-mode","plus-darker"]]),e("mix-blend-plus-lighter",[["mix-blend-mode","plus-lighter"]]),e("fill-none",[["fill","none"]]),r.functional("fill",o=>{if(!o.value)return;if(o.value.kind==="arbitrary"){let h=W(o.value.value,o.modifier,t);return h===null?void 0:[a("fill",h)]}let f=H(o,t,["--fill","--color"]);if(f)return[a("fill",f)]}),n("fill",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--fill","--color"],modifiers:Array.from({length:21},(o,f)=>`${f*5}`)}]),e("stroke-none",[["stroke","none"]]),r.functional("stroke",o=>{if(o.value){if(o.value.kind==="arbitrary"){let f=o.value.value;switch(o.value.dataType??z(f,["color","number","length","percentage"])){case"number":case"length":case"percentage":return o.modifier?void 0:[a("stroke-width",f)];default:return f=W(o.value.value,o.modifier,t),f===null?void 0:[a("stroke",f)]}}{let f=H(o,t,["--stroke","--color"]);if(f)return[a("stroke",f)]}{let f=t.resolve(o.value.value,["--stroke-width"]);if(f)return[a("stroke-width",f)];if(V(o.value.value))return[a("stroke-width",o.value.value)]}}}),n("stroke",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--stroke","--color"],modifiers:Array.from({length:21},(o,f)=>`${f*5}`)},{values:["0","1","2","3"],valueThemeKeys:["--stroke-width"]}]),e("object-contain",[["object-fit","contain"]]),e("object-cover",[["object-fit","cover"]]),e("object-fill",[["object-fit","fill"]]),e("object-none",[["object-fit","none"]]),e("object-scale-down",[["object-fit","scale-down"]]),e("object-bottom",[["object-position","bottom"]]),e("object-center",[["object-position","center"]]),e("object-left",[["object-position","left"]]),e("object-left-bottom",[["object-position","left bottom"]]),e("object-left-top",[["object-position","left top"]]),e("object-right",[["object-position","right"]]),e("object-right-bottom",[["object-position","right bottom"]]),e("object-right-top",[["object-position","right top"]]),e("object-top",[["object-position","top"]]),i("object",{themeKeys:["--object-position"],handle:o=>[a("object-position",o)]});for(let[o,f]of[["p","padding"],["px","padding-inline"],["py","padding-block"],["ps","padding-inline-start"],["pe","padding-inline-end"],["pt","padding-top"],["pr","padding-right"],["pb","padding-bottom"],["pl","padding-left"]])l(o,["--padding","--spacing"],h=>[a(f,h)]);e("text-left",[["text-align","left"]]),e("text-center",[["text-align","center"]]),e("text-right",[["text-align","right"]]),e("text-justify",[["text-align","justify"]]),e("text-start",[["text-align","start"]]),e("text-end",[["text-align","end"]]),l("indent",["--text-indent","--spacing"],o=>[a("text-indent",o)],{supportsNegative:!0}),e("align-baseline",[["vertical-align","baseline"]]),e("align-top",[["vertical-align","top"]]),e("align-middle",[["vertical-align","middle"]]),e("align-bottom",[["vertical-align","bottom"]]),e("align-text-top",[["vertical-align","text-top"]]),e("align-text-bottom",[["vertical-align","text-bottom"]]),e("align-sub",[["vertical-align","sub"]]),e("align-super",[["vertical-align","super"]]),i("align",{themeKeys:[],handle:o=>[a("vertical-align",o)]}),r.functional("font",o=>{if(!(!o.value||o.modifier)){if(o.value.kind==="arbitrary"){let f=o.value.value;switch(o.value.dataType??z(f,["number","generic-name","family-name"])){case"generic-name":case"family-name":return[a("font-family",f)];default:return[U([N("--tw-font-weight")]),a("--tw-font-weight",f),a("font-weight",f)]}}{let f=t.resolveWith(o.value.value,["--font"],["--font-feature-settings","--font-variation-settings"]);if(f){let[h,k={}]=f;return[a("font-family",h),a("font-feature-settings",k["--font-feature-settings"]),a("font-variation-settings",k["--font-variation-settings"])]}}{let f=t.resolve(o.value.value,["--font-weight"]);if(f)return[U([N("--tw-font-weight")]),a("--tw-font-weight",f),a("font-weight",f)]}}}),n("font",()=>[{values:[],valueThemeKeys:["--font"]},{values:[],valueThemeKeys:["--font-weight"]}]),e("uppercase",[["text-transform","uppercase"]]),e("lowercase",[["text-transform","lowercase"]]),e("capitalize",[["text-transform","capitalize"]]),e("normal-case",[["text-transform","none"]]),e("italic",[["font-style","italic"]]),e("not-italic",[["font-style","normal"]]),e("underline",[["text-decoration-line","underline"]]),e("overline",[["text-decoration-line","overline"]]),e("line-through",[["text-decoration-line","line-through"]]),e("no-underline",[["text-decoration-line","none"]]),e("font-stretch-normal",[["font-stretch","normal"]]),e("font-stretch-ultra-condensed",[["font-stretch","ultra-condensed"]]),e("font-stretch-extra-condensed",[["font-stretch","extra-condensed"]]),e("font-stretch-condensed",[["font-stretch","condensed"]]),e("font-stretch-semi-condensed",[["font-stretch","semi-condensed"]]),e("font-stretch-semi-expanded",[["font-stretch","semi-expanded"]]),e("font-stretch-expanded",[["font-stretch","expanded"]]),e("font-stretch-extra-expanded",[["font-stretch","extra-expanded"]]),e("font-stretch-ultra-expanded",[["font-stretch","ultra-expanded"]]),i("font-stretch",{handleBareValue:({value:o})=>{if(!o.endsWith("%"))return null;let f=Number(o.slice(0,-1));return!V(f)||Number.isNaN(f)||f<50||f>200?null:o},handle:o=>[a("font-stretch",o)]}),n("font-stretch",()=>[{values:["50%","75%","90%","95%","100%","105%","110%","125%","150%","200%"]}]),s("placeholder",{themeKeys:["--background-color","--color"],handle:o=>[j("&::placeholder",[a("--tw-sort","placeholder-color"),a("color",o)])]}),e("decoration-solid",[["text-decoration-style","solid"]]),e("decoration-double",[["text-decoration-style","double"]]),e("decoration-dotted",[["text-decoration-style","dotted"]]),e("decoration-dashed",[["text-decoration-style","dashed"]]),e("decoration-wavy",[["text-decoration-style","wavy"]]),e("decoration-auto",[["text-decoration-thickness","auto"]]),e("decoration-from-font",[["text-decoration-thickness","from-font"]]),r.functional("decoration",o=>{if(o.value){if(o.value.kind==="arbitrary"){let f=o.value.value;switch(o.value.dataType??z(f,["color","length","percentage"])){case"length":case"percentage":return o.modifier?void 0:[a("text-decoration-thickness",f)];default:return f=W(f,o.modifier,t),f===null?void 0:[a("text-decoration-color",f)]}}{let f=t.resolve(o.value.value,["--text-decoration-thickness"]);if(f)return o.modifier?void 0:[a("text-decoration-thickness",f)];if(V(o.value.value))return o.modifier?void 0:[a("text-decoration-thickness",`${o.value.value}px`)]}{let f=H(o,t,["--text-decoration-color","--color"]);if(f)return[a("text-decoration-color",f)]}}}),n("decoration",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--text-decoration-color","--color"],modifiers:Array.from({length:21},(o,f)=>`${f*5}`)},{values:["0","1","2"],valueThemeKeys:["--text-decoration-thickness"]}]),e("animate-none",[["animation","none"]]),i("animate",{themeKeys:["--animate"],handle:o=>[a("animation",o)]});{let o=["var(--tw-blur,)","var(--tw-brightness,)","var(--tw-contrast,)","var(--tw-grayscale,)","var(--tw-hue-rotate,)","var(--tw-invert,)","var(--tw-saturate,)","var(--tw-sepia,)","var(--tw-drop-shadow,)"].join(" "),f=["var(--tw-backdrop-blur,)","var(--tw-backdrop-brightness,)","var(--tw-backdrop-contrast,)","var(--tw-backdrop-grayscale,)","var(--tw-backdrop-hue-rotate,)","var(--tw-backdrop-invert,)","var(--tw-backdrop-opacity,)","var(--tw-backdrop-saturate,)","var(--tw-backdrop-sepia,)"].join(" "),h=()=>U([N("--tw-blur"),N("--tw-brightness"),N("--tw-contrast"),N("--tw-grayscale"),N("--tw-hue-rotate"),N("--tw-invert"),N("--tw-opacity"),N("--tw-saturate"),N("--tw-sepia"),N("--tw-drop-shadow")]),k=()=>U([N("--tw-backdrop-blur"),N("--tw-backdrop-brightness"),N("--tw-backdrop-contrast"),N("--tw-backdrop-grayscale"),N("--tw-backdrop-hue-rotate"),N("--tw-backdrop-invert"),N("--tw-backdrop-opacity"),N("--tw-backdrop-saturate"),N("--tw-backdrop-sepia")]);r.functional("filter",w=>{if(!w.modifier){if(w.value===null)return[h(),a("filter",o)];if(w.value.kind==="arbitrary")return[a("filter",w.value.value)];switch(w.value.value){case"none":return[a("filter","none")]}}}),r.functional("backdrop-filter",w=>{if(!w.modifier){if(w.value===null)return[k(),a("-webkit-backdrop-filter",f),a("backdrop-filter",f)];if(w.value.kind==="arbitrary")return[a("-webkit-backdrop-filter",w.value.value),a("backdrop-filter",w.value.value)];switch(w.value.value){case"none":return[a("-webkit-backdrop-filter","none"),a("backdrop-filter","none")]}}}),i("blur",{themeKeys:["--blur"],handle:w=>[h(),a("--tw-blur",`blur(${w})`),a("filter",o)]}),e("blur-none",[h,["--tw-blur"," "],["filter",o]]),i("backdrop-blur",{themeKeys:["--backdrop-blur","--blur"],handle:w=>[k(),a("--tw-backdrop-blur",`blur(${w})`),a("-webkit-backdrop-filter",f),a("backdrop-filter",f)]}),e("backdrop-blur-none",[k,["--tw-backdrop-blur"," "],["-webkit-backdrop-filter",f],["backdrop-filter",f]]),i("brightness",{themeKeys:["--brightness"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,handle:w=>[h(),a("--tw-brightness",`brightness(${w})`),a("filter",o)]}),i("backdrop-brightness",{themeKeys:["--backdrop-brightness","--brightness"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,handle:w=>[k(),a("--tw-backdrop-brightness",`brightness(${w})`),a("-webkit-backdrop-filter",f),a("backdrop-filter",f)]}),n("brightness",()=>[{values:["0","50","75","90","95","100","105","110","125","150","200"],valueThemeKeys:["--brightness"]}]),n("backdrop-brightness",()=>[{values:["0","50","75","90","95","100","105","110","125","150","200"],valueThemeKeys:["--backdrop-brightness","--brightness"]}]),i("contrast",{themeKeys:["--contrast"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,handle:w=>[h(),a("--tw-contrast",`contrast(${w})`),a("filter",o)]}),i("backdrop-contrast",{themeKeys:["--backdrop-contrast","--contrast"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,handle:w=>[k(),a("--tw-backdrop-contrast",`contrast(${w})`),a("-webkit-backdrop-filter",f),a("backdrop-filter",f)]}),n("contrast",()=>[{values:["0","50","75","100","125","150","200"],valueThemeKeys:["--contrast"]}]),n("backdrop-contrast",()=>[{values:["0","50","75","100","125","150","200"],valueThemeKeys:["--backdrop-contrast","--contrast"]}]),i("grayscale",{themeKeys:["--grayscale"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,defaultValue:"100%",handle:w=>[h(),a("--tw-grayscale",`grayscale(${w})`),a("filter",o)]}),i("backdrop-grayscale",{themeKeys:["--backdrop-grayscale","--grayscale"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,defaultValue:"100%",handle:w=>[k(),a("--tw-backdrop-grayscale",`grayscale(${w})`),a("-webkit-backdrop-filter",f),a("backdrop-filter",f)]}),n("grayscale",()=>[{values:["0","25","50","75","100"],valueThemeKeys:["--grayscale"],hasDefaultValue:!0}]),n("backdrop-grayscale",()=>[{values:["0","25","50","75","100"],valueThemeKeys:["--backdrop-grayscale","--grayscale"],hasDefaultValue:!0}]),i("hue-rotate",{supportsNegative:!0,themeKeys:["--hue-rotate"],handleBareValue:({value:w})=>V(w)?`${w}deg`:null,handle:w=>[h(),a("--tw-hue-rotate",`hue-rotate(${w})`),a("filter",o)]}),i("backdrop-hue-rotate",{supportsNegative:!0,themeKeys:["--backdrop-hue-rotate","--hue-rotate"],handleBareValue:({value:w})=>V(w)?`${w}deg`:null,handle:w=>[k(),a("--tw-backdrop-hue-rotate",`hue-rotate(${w})`),a("-webkit-backdrop-filter",f),a("backdrop-filter",f)]}),n("hue-rotate",()=>[{values:["0","15","30","60","90","180"],valueThemeKeys:["--hue-rotate"]}]),n("backdrop-hue-rotate",()=>[{values:["0","15","30","60","90","180"],valueThemeKeys:["--backdrop-hue-rotate","--hue-rotate"]}]),i("invert",{themeKeys:["--invert"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,defaultValue:"100%",handle:w=>[h(),a("--tw-invert",`invert(${w})`),a("filter",o)]}),i("backdrop-invert",{themeKeys:["--backdrop-invert","--invert"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,defaultValue:"100%",handle:w=>[k(),a("--tw-backdrop-invert",`invert(${w})`),a("-webkit-backdrop-filter",f),a("backdrop-filter",f)]}),n("invert",()=>[{values:["0","25","50","75","100"],valueThemeKeys:["--invert"],hasDefaultValue:!0}]),n("backdrop-invert",()=>[{values:["0","25","50","75","100"],valueThemeKeys:["--backdrop-invert","--invert"],hasDefaultValue:!0}]),i("saturate",{themeKeys:["--saturate"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,handle:w=>[h(),a("--tw-saturate",`saturate(${w})`),a("filter",o)]}),i("backdrop-saturate",{themeKeys:["--backdrop-saturate","--saturate"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,handle:w=>[k(),a("--tw-backdrop-saturate",`saturate(${w})`),a("-webkit-backdrop-filter",f),a("backdrop-filter",f)]}),n("saturate",()=>[{values:["0","50","100","150","200"],valueThemeKeys:["--saturate"]}]),n("backdrop-saturate",()=>[{values:["0","50","100","150","200"],valueThemeKeys:["--backdrop-saturate","--saturate"]}]),i("sepia",{themeKeys:["--sepia"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,defaultValue:"100%",handle:w=>[h(),a("--tw-sepia",`sepia(${w})`),a("filter",o)]}),i("backdrop-sepia",{themeKeys:["--backdrop-sepia","--sepia"],handleBareValue:({value:w})=>V(w)?`${w}%`:null,defaultValue:"100%",handle:w=>[k(),a("--tw-backdrop-sepia",`sepia(${w})`),a("-webkit-backdrop-filter",f),a("backdrop-filter",f)]}),n("sepia",()=>[{values:["0","50","100"],valueThemeKeys:["--sepia"],hasDefaultValue:!0}]),n("backdrop-sepia",()=>[{values:["0","50","100"],valueThemeKeys:["--backdrop-sepia","--sepia"],hasDefaultValue:!0}]),e("drop-shadow-none",[h,["--tw-drop-shadow"," "],["filter",o]]),i("drop-shadow",{themeKeys:["--drop-shadow"],handle:w=>[h(),a("--tw-drop-shadow",P(w,",").map($=>`drop-shadow(${$})`).join(" ")),a("filter",o)]}),i("backdrop-opacity",{themeKeys:["--backdrop-opacity","--opacity"],handleBareValue:({value:w})=>Me(w)?`${w}%`:null,handle:w=>[k(),a("--tw-backdrop-opacity",`opacity(${w})`),a("-webkit-backdrop-filter",f),a("backdrop-filter",f)]}),n("backdrop-opacity",()=>[{values:Array.from({length:21},(w,$)=>`${$*5}`),valueThemeKeys:["--backdrop-opacity","--opacity"]}])}{let o=`var(--tw-ease, ${t.resolve(null,["--default-transition-timing-function"])??"ease"})`,f=`var(--tw-duration, ${t.resolve(null,["--default-transition-duration"])??"0s"})`;e("transition-none",[["transition-property","none"]]),e("transition-all",[["transition-property","all"],["transition-timing-function",o],["transition-duration",f]]),e("transition-colors",[["transition-property","color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to"],["transition-timing-function",o],["transition-duration",f]]),e("transition-opacity",[["transition-property","opacity"],["transition-timing-function",o],["transition-duration",f]]),e("transition-shadow",[["transition-property","box-shadow"],["transition-timing-function",o],["transition-duration",f]]),e("transition-transform",[["transition-property","transform, translate, scale, rotate"],["transition-timing-function",o],["transition-duration",f]]),i("transition",{defaultValue:"color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter",themeKeys:["--transition-property"],handle:h=>[a("transition-property",h),a("transition-timing-function",o),a("transition-duration",f)]}),e("transition-discrete",[["transition-behavior","allow-discrete"]]),e("transition-normal",[["transition-behavior","normal"]]),i("delay",{handleBareValue:({value:h})=>V(h)?`${h}ms`:null,themeKeys:["--transition-delay"],handle:h=>[a("transition-delay",h)]});{let h=()=>U([N("--tw-duration")]);e("duration-initial",[h,["--tw-duration","initial"]]),r.functional("duration",k=>{if(k.modifier||!k.value)return;let w=null;if(k.value.kind==="arbitrary"?w=k.value.value:(w=t.resolve(k.value.fraction??k.value.value,["--transition-duration"]),w===null&&V(k.value.value)&&(w=`${k.value.value}ms`)),w!==null)return[h(),a("--tw-duration",w),a("transition-duration",w)]})}n("delay",()=>[{values:["75","100","150","200","300","500","700","1000"],valueThemeKeys:["--transition-delay"]}]),n("duration",()=>[{values:["75","100","150","200","300","500","700","1000"],valueThemeKeys:["--transition-duration"]}])}{let o=()=>U([N("--tw-ease")]);e("ease-initial",[o,["--tw-ease","initial"]]),e("ease-linear",[o,["--tw-ease","linear"],["transition-timing-function","linear"]]),i("ease",{themeKeys:["--ease"],handle:f=>[o(),a("--tw-ease",f),a("transition-timing-function",f)]})}e("will-change-auto",[["will-change","auto"]]),e("will-change-scroll",[["will-change","scroll-position"]]),e("will-change-contents",[["will-change","contents"]]),e("will-change-transform",[["will-change","transform"]]),i("will-change",{themeKeys:[],handle:o=>[a("will-change",o)]}),e("content-none",[["--tw-content","none"],["content","none"]]),i("content",{themeKeys:[],handle:o=>[U([N("--tw-content",'""')]),a("--tw-content",o),a("content","var(--tw-content)")]});{let o="var(--tw-contain-size,) var(--tw-contain-layout,) var(--tw-contain-paint,) var(--tw-contain-style,)",f=()=>U([N("--tw-contain-size"),N("--tw-contain-layout"),N("--tw-contain-paint"),N("--tw-contain-style")]);e("contain-none",[["contain","none"]]),e("contain-content",[["contain","content"]]),e("contain-strict",[["contain","strict"]]),e("contain-size",[f,["--tw-contain-size","size"],["contain",o]]),e("contain-inline-size",[f,["--tw-contain-size","inline-size"],["contain",o]]),e("contain-layout",[f,["--tw-contain-layout","layout"],["contain",o]]),e("contain-paint",[f,["--tw-contain-paint","paint"],["contain",o]]),e("contain-style",[f,["--tw-contain-style","style"],["contain",o]]),i("contain",{themeKeys:[],handle:h=>[a("contain",h)]})}e("forced-color-adjust-none",[["forced-color-adjust","none"]]),e("forced-color-adjust-auto",[["forced-color-adjust","auto"]]),e("leading-none",[()=>U([N("--tw-leading")]),["--tw-leading","1"],["line-height","1"]]),l("leading",["--leading","--spacing"],o=>[U([N("--tw-leading")]),a("--tw-leading",o),a("line-height",o)]),i("tracking",{supportsNegative:!0,themeKeys:["--tracking"],handle:o=>[U([N("--tw-tracking")]),a("--tw-tracking",o),a("letter-spacing",o)]}),e("antialiased",[["-webkit-font-smoothing","antialiased"],["-moz-osx-font-smoothing","grayscale"]]),e("subpixel-antialiased",[["-webkit-font-smoothing","auto"],["-moz-osx-font-smoothing","auto"]]);{let o="var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)",f=()=>U([N("--tw-ordinal"),N("--tw-slashed-zero"),N("--tw-numeric-figure"),N("--tw-numeric-spacing"),N("--tw-numeric-fraction")]);e("normal-nums",[["font-variant-numeric","normal"]]),e("ordinal",[f,["--tw-ordinal","ordinal"],["font-variant-numeric",o]]),e("slashed-zero",[f,["--tw-slashed-zero","slashed-zero"],["font-variant-numeric",o]]),e("lining-nums",[f,["--tw-numeric-figure","lining-nums"],["font-variant-numeric",o]]),e("oldstyle-nums",[f,["--tw-numeric-figure","oldstyle-nums"],["font-variant-numeric",o]]),e("proportional-nums",[f,["--tw-numeric-spacing","proportional-nums"],["font-variant-numeric",o]]),e("tabular-nums",[f,["--tw-numeric-spacing","tabular-nums"],["font-variant-numeric",o]]),e("diagonal-fractions",[f,["--tw-numeric-fraction","diagonal-fractions"],["font-variant-numeric",o]]),e("stacked-fractions",[f,["--tw-numeric-fraction","stacked-fractions"],["font-variant-numeric",o]])}{let o=()=>U([N("--tw-outline-style","solid")]);r.static("outline-hidden",()=>[a("outline-style","none"),D("@media","(forced-colors: active)",[a("outline","2px solid transparent"),a("outline-offset","2px")])]),e("outline-none",[["--tw-outline-style","none"],["outline-style","none"]]),e("outline-solid",[["--tw-outline-style","solid"],["outline-style","solid"]]),e("outline-dashed",[["--tw-outline-style","dashed"],["outline-style","dashed"]]),e("outline-dotted",[["--tw-outline-style","dotted"],["outline-style","dotted"]]),e("outline-double",[["--tw-outline-style","double"],["outline-style","double"]]),r.functional("outline",f=>{if(f.value===null){if(f.modifier)return;let h=t.get(["--default-outline-width"])??"1px";return[o(),a("outline-style","var(--tw-outline-style)"),a("outline-width",h)]}if(f.value.kind==="arbitrary"){let h=f.value.value;switch(f.value.dataType??z(h,["color","length","number","percentage"])){case"length":case"number":case"percentage":return f.modifier?void 0:[o(),a("outline-style","var(--tw-outline-style)"),a("outline-width",h)];default:return h=W(h,f.modifier,t),h===null?void 0:[a("outline-color",h)]}}{let h=H(f,t,["--outline-color","--color"]);if(h)return[a("outline-color",h)]}{if(f.modifier)return;let h=t.resolve(f.value.value,["--outline-width"]);if(h)return[o(),a("outline-style","var(--tw-outline-style)"),a("outline-width",h)];if(V(f.value.value))return[o(),a("outline-style","var(--tw-outline-style)"),a("outline-width",`${f.value.value}px`)]}}),n("outline",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--outline-color","--color"],modifiers:Array.from({length:21},(f,h)=>`${h*5}`),hasDefaultValue:!0},{values:["0","1","2","4","8"],valueThemeKeys:["--outline-width"]}]),i("outline-offset",{supportsNegative:!0,themeKeys:["--outline-offset"],handleBareValue:({value:f})=>V(f)?`${f}px`:null,handle:f=>[a("outline-offset",f)]}),n("outline-offset",()=>[{supportsNegative:!0,values:["0","1","2","4","8"],valueThemeKeys:["--outline-offset"]}])}i("opacity",{themeKeys:["--opacity"],handleBareValue:({value:o})=>Me(o)?`${o}%`:null,handle:o=>[a("opacity",o)]}),n("opacity",()=>[{values:Array.from({length:21},(o,f)=>`${f*5}`),valueThemeKeys:["--opacity"]}]),e("underline-offset-auto",[["text-underline-offset","auto"]]),i("underline-offset",{supportsNegative:!0,themeKeys:["--text-underline-offset"],handleBareValue:({value:o})=>V(o)?`${o}px`:null,handle:o=>[a("text-underline-offset",o)]}),n("underline-offset",()=>[{supportsNegative:!0,values:["0","1","2","4","8"],valueThemeKeys:["--text-underline-offset"]}]),r.functional("text",o=>{if(o.value){if(o.value.kind==="arbitrary"){let f=o.value.value;switch(o.value.dataType??z(f,["color","length","percentage","absolute-size","relative-size"])){case"size":case"length":case"percentage":case"absolute-size":case"relative-size":{if(o.modifier){let k=o.modifier.kind==="arbitrary"?o.modifier.value:t.resolve(o.modifier.value,["--leading"]);if(!k&&me(o.modifier.value)){let w=t.resolve(null,["--spacing"]);if(!w)return null;k=`calc(${w} * ${o.modifier.value})`}return!k&&o.modifier.value==="none"&&(k="1"),k?[a("font-size",f),a("line-height",k)]:null}return[a("font-size",f)]}default:return f=W(f,o.modifier,t),f===null?void 0:[a("color",f)]}}{let f=H(o,t,["--text-color","--color"]);if(f)return[a("color",f)]}{let f=t.resolveWith(o.value.value,["--text"],["--line-height","--letter-spacing","--font-weight"]);if(f){let[h,k={}]=Array.isArray(f)?f:[f];if(o.modifier){let w=o.modifier.kind==="arbitrary"?o.modifier.value:t.resolve(o.modifier.value,["--leading"]);if(!w&&me(o.modifier.value)){let E=t.resolve(null,["--spacing"]);if(!E)return null;w=`calc(${E} * ${o.modifier.value})`}if(!w&&o.modifier.value==="none"&&(w="1"),!w)return null;let $=[a("font-size",h)];return w&&$.push(a("line-height",w)),$}return typeof k=="string"?[a("font-size",h),a("line-height",k)]:[a("font-size",h),a("line-height",k["--line-height"]?`var(--tw-leading, ${k["--line-height"]})`:void 0),a("letter-spacing",k["--letter-spacing"]?`var(--tw-tracking, ${k["--letter-spacing"]})`:void 0),a("font-weight",k["--font-weight"]?`var(--tw-font-weight, ${k["--font-weight"]})`:void 0)]}}}}),n("text",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--text-color","--color"],modifiers:Array.from({length:21},(o,f)=>`${f*5}`)},{values:[],valueThemeKeys:["--text"],modifiers:[],modifierThemeKeys:["--leading"]}]);{let w=function(C){return`var(--tw-ring-inset,) 0 0 0 calc(${C} + var(--tw-ring-offset-width)) var(--tw-ring-color, ${k})`},$=function(C){return`inset 0 0 0 ${C} var(--tw-inset-ring-color, currentColor)`};var R=w,K=$;let o=["var(--tw-inset-shadow)","var(--tw-inset-ring-shadow)","var(--tw-ring-offset-shadow)","var(--tw-ring-shadow)","var(--tw-shadow)"].join(", "),f="0 0 #0000",h=()=>U([N("--tw-shadow",f),N("--tw-shadow-color"),N("--tw-inset-shadow",f),N("--tw-inset-shadow-color"),N("--tw-ring-color"),N("--tw-ring-shadow",f),N("--tw-inset-ring-color"),N("--tw-inset-ring-shadow",f),N("--tw-ring-inset"),N("--tw-ring-offset-width","0px",""),N("--tw-ring-offset-color","#fff"),N("--tw-ring-offset-shadow",f)]);e("shadow-initial",[h,["--tw-shadow-color","initial"]]),r.functional("shadow",C=>{if(!C.value){let A=t.get(["--shadow"]);return A===null?void 0:[h(),a("--tw-shadow",ce(A,F=>`var(--tw-shadow-color, ${F})`)),a("box-shadow",o)]}if(C.value.kind==="arbitrary"){let A=C.value.value;switch(C.value.dataType??z(A,["color"])){case"color":return A=W(A,C.modifier,t),A===null?void 0:[h(),a("--tw-shadow-color",A)];default:return[h(),a("--tw-shadow",ce(A,Oe=>`var(--tw-shadow-color, ${Oe})`)),a("box-shadow",o)]}}switch(C.value.value){case"none":return C.modifier?void 0:[h(),a("--tw-shadow",f),a("box-shadow",o)]}{let A=t.get([`--shadow-${C.value.value}`]);if(A)return C.modifier?void 0:[h(),a("--tw-shadow",ce(A,F=>`var(--tw-shadow-color, ${F})`)),a("box-shadow",o)]}{let A=H(C,t,["--box-shadow-color","--color"]);if(A)return[h(),a("--tw-shadow-color",A)]}}),n("shadow",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--box-shadow-color","--color"],modifiers:Array.from({length:21},(C,A)=>`${A*5}`)},{values:["none"],valueThemeKeys:["--shadow"],hasDefaultValue:!0}]),e("inset-shadow-initial",[h,["--tw-inset-shadow-color","initial"]]),r.functional("inset-shadow",C=>{if(!C.value){let A=t.get(["--inset-shadow"]);return A===null?void 0:[h(),a("--tw-inset-shadow",ce(A,F=>`var(--tw-inset-shadow-color, ${F})`)),a("box-shadow",o)]}if(C.value.kind==="arbitrary"){let A=C.value.value;switch(C.value.dataType??z(A,["color"])){case"color":return A=W(A,C.modifier,t),A===null?void 0:[h(),a("--tw-inset-shadow-color",A)];default:return[h(),a("--tw-inset-shadow",`inset ${ce(A,Oe=>`var(--tw-inset-shadow-color, ${Oe})`)}`),a("box-shadow",o)]}}switch(C.value.value){case"none":return C.modifier?void 0:[h(),a("--tw-inset-shadow",f),a("box-shadow",o)]}{let A=t.get([`--inset-shadow-${C.value.value}`]);if(A)return C.modifier?void 0:[h(),a("--tw-inset-shadow",ce(A,F=>`var(--tw-inset-shadow-color, ${F})`)),a("box-shadow",o)]}{let A=H(C,t,["--box-shadow-color","--color"]);if(A)return[h(),a("--tw-inset-shadow-color",A)]}}),n("inset-shadow",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--box-shadow-color","--color"],modifiers:Array.from({length:21},(C,A)=>`${A*5}`)},{values:[],valueThemeKeys:["--inset-shadow"],hasDefaultValue:!0}]),e("ring-inset",[h,["--tw-ring-inset","inset"]]);let k=t.get(["--default-ring-color"])??"currentColor";r.functional("ring",C=>{if(!C.value){if(C.modifier)return;let A=t.get(["--default-ring-width"])??"1px";return[h(),a("--tw-ring-shadow",w(A)),a("box-shadow",o)]}if(C.value.kind==="arbitrary"){let A=C.value.value;switch(C.value.dataType??z(A,["color","length"])){case"length":return C.modifier?void 0:[h(),a("--tw-ring-shadow",w(A)),a("box-shadow",o)];default:return A=W(A,C.modifier,t),A===null?void 0:[a("--tw-ring-color",A)]}}{let A=H(C,t,["--ring-color","--color"]);if(A)return[a("--tw-ring-color",A)]}{if(C.modifier)return;let A=t.resolve(C.value.value,["--ring-width"]);if(A===null&&V(C.value.value)&&(A=`${C.value.value}px`),A)return[h(),a("--tw-ring-shadow",w(A)),a("box-shadow",o)]}}),n("ring",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--ring-color","--color"],modifiers:Array.from({length:21},(C,A)=>`${A*5}`)},{values:["0","1","2","4","8"],valueThemeKeys:["--ring-width"],hasDefaultValue:!0}]),r.functional("inset-ring",C=>{if(!C.value)return C.modifier?void 0:[h(),a("--tw-inset-ring-shadow",$("1px")),a("box-shadow",o)];if(C.value.kind==="arbitrary"){let A=C.value.value;switch(C.value.dataType??z(A,["color","length"])){case"length":return C.modifier?void 0:[h(),a("--tw-inset-ring-shadow",$(A)),a("box-shadow",o)];default:return A=W(A,C.modifier,t),A===null?void 0:[a("--tw-inset-ring-color",A)]}}{let A=H(C,t,["--ring-color","--color"]);if(A)return[a("--tw-inset-ring-color",A)]}{if(C.modifier)return;let A=t.resolve(C.value.value,["--ring-width"]);if(A===null&&V(C.value.value)&&(A=`${C.value.value}px`),A)return[h(),a("--tw-inset-ring-shadow",$(A)),a("box-shadow",o)]}}),n("inset-ring",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--ring-color","--color"],modifiers:Array.from({length:21},(C,A)=>`${A*5}`)},{values:["0","1","2","4","8"],valueThemeKeys:["--ring-width"],hasDefaultValue:!0}]);let E="var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)";r.functional("ring-offset",C=>{if(C.value){if(C.value.kind==="arbitrary"){let A=C.value.value;switch(C.value.dataType??z(A,["color","length"])){case"length":return C.modifier?void 0:[a("--tw-ring-offset-width",A),a("--tw-ring-offset-shadow",E)];default:return A=W(A,C.modifier,t),A===null?void 0:[a("--tw-ring-offset-color",A)]}}{let A=t.resolve(C.value.value,["--ring-offset-width"]);if(A)return C.modifier?void 0:[a("--tw-ring-offset-width",A),a("--tw-ring-offset-shadow",E)];if(V(C.value.value))return C.modifier?void 0:[a("--tw-ring-offset-width",`${C.value.value}px`),a("--tw-ring-offset-shadow",E)]}{let A=H(C,t,["--ring-offset-color","--color"]);if(A)return[a("--tw-ring-offset-color",A)]}}})}return n("ring-offset",()=>[{values:["current","inherit","transparent"],valueThemeKeys:["--ring-offset-color","--color"],modifiers:Array.from({length:21},(o,f)=>`${f*5}`)},{values:["0","1","2","4","8"],valueThemeKeys:["--ring-offset-width"]}]),r.functional("@container",o=>{let f=null;if(o.value===null?f="inline-size":o.value.kind==="arbitrary"?f=o.value.value:o.value.kind==="named"&&o.value.value==="normal"&&(f="normal"),f!==null)return o.modifier?[a("container-type",f),a("container-name",o.modifier.value)]:[a("container-type",f)]}),n("@container",()=>[{values:["normal"],valueThemeKeys:[],hasDefaultValue:!0}]),r}function Qt(t){let r=t.params;return In.test(r)?n=>{let e=new Set,i=new Set;_(t.nodes,s=>{if(s.kind!=="declaration"||!s.value||!s.value.includes("--value(")&&!s.value.includes("--modifier("))return;let l=L(s.value);X(l,p=>{if(p.kind!=="function"||p.value!=="--value"&&p.value!=="--modifier")return;let c=P(q(p.nodes),",");for(let[d,u]of c.entries())u=u.replace(/\\\*/g,"*"),u=u.replace(/--(.*?)\s--(.*?)/g,"--$1-*--$2"),u=u.replace(/\s+/g,""),u=u.replace(/(-\*){2,}/g,"-*"),u[0]==="-"&&u[1]==="-"&&!u.includes("-*")&&(u+="-*"),c[d]=u;p.nodes=L(c.join(","));for(let d of p.nodes)if(d.kind==="word"&&d.value[0]==="-"&&d.value[1]==="-"){let u=d.value.replace(/-\*.*$/g,"");p.value==="--value"?e.add(u):p.value==="--modifier"&&i.add(u)}}),s.value=q(l)}),n.utilities.functional(r.slice(0,-2),s=>{let l=structuredClone(t),p=s.value,c=s.modifier;if(p===null)return;let d=!1,u=!1,g=!1,m=!1,b=new Map,y=!1;if(_([l],(v,{parent:x,replaceWith:T})=>{if(x?.kind!=="rule"&&x?.kind!=="at-rule"||v.kind!=="declaration"||!v.value)return;let S=L(v.value);(X(S,(R,{replaceWith:K})=>{if(R.kind==="function"){if(R.value==="--value"){d=!0;let o=Jt(p,R,n);return o?(u=!0,o.ratio?y=!0:b.set(v,x),K(o.nodes),1):(d||=!1,T([]),2)}else if(R.value==="--modifier"){if(c===null)return T([]),1;g=!0;let o=Jt(c,R,n);return o?(m=!0,K(o.nodes),1):(g||=!1,T([]),2)}}})??0)===0&&(v.value=q(S))}),d&&!u||g&&!m||y&&m||c&&!y&&!m)return null;if(y)for(let[v,x]of b){let T=x.nodes.indexOf(v);T!==-1&&x.nodes.splice(T,1)}return l.nodes}),n.utilities.suggest(r.slice(0,-2),()=>[{values:n.theme.keysInNamespaces(e).map(s=>s.replaceAll("_",".")),modifiers:n.theme.keysInNamespaces(i).map(s=>s.replaceAll("_","."))}])}:Fn.test(r)?n=>{n.utilities.static(r,()=>structuredClone(t.nodes))}:null}function Jt(t,r,n){for(let e of r.nodes)if(t.kind==="named"&&e.kind==="word"&&e.value[0]==="-"&&e.value[1]==="-"){let i=e.value;if(i.endsWith("-*")){i=i.slice(0,-2);let s=n.theme.resolve(t.value,[i]);if(s)return{nodes:L(s)}}else{let s=i.split("-*");if(s.length<=1)continue;let l=[s.shift()],p=n.theme.resolveWith(t.value,l,s);if(p){let[,c={}]=p;{let d=c[s.pop()];if(d)return{nodes:L(d)}}}}}else if(t.kind==="named"&&e.kind==="word"){if(e.value!=="number"&&e.value!=="integer"&&e.value!=="ratio"&&e.value!=="percentage")continue;let i=e.value==="ratio"&&"fraction"in t?t.fraction:t.value;if(!i)continue;let s=z(i,[e.value]);if(s===null)continue;if(s==="ratio"){let[l,p]=P(i,"/");if(!V(l)||!V(p))continue}else{if(s==="number"&&!me(i))continue;if(s==="percentage"&&!V(i.slice(0,-1)))continue}return{nodes:L(i),ratio:s==="ratio"}}else if(t.kind==="arbitrary"&&e.kind==="word"&&e.value[0]==="["&&e.value[e.value.length-1]==="]"){let i=e.value.slice(1,-1);if(i==="*")return{nodes:L(t.value)};if("dataType"in t&&t.dataType&&t.dataType!==i)continue;if("dataType"in t&&t.dataType)return{nodes:L(t.value)};if(z(t.value,[i])!==null)return{nodes:L(t.value)}}}var pt={"--alpha":zn,"--spacing":Ln,"--theme":Mn,theme:tr};function zn(t,r,...n){let[e,i]=P(r,"/").map(s=>s.trim());if(!e||!i)throw new Error(`The --alpha(\u2026) function requires a color and an alpha value, e.g.: \`--alpha(${e||"var(--my-color)"} / ${i||"50%"})\``);if(n.length>0)throw new Error(`The --alpha(\u2026) function only accepts one argument, e.g.: \`--alpha(${e||"var(--my-color)"} / ${i||"50%"})\``);return Y(e,i)}function Ln(t,r,...n){if(!r)throw new Error("The --spacing(\u2026) function requires an argument, but received none.");if(n.length>0)throw new Error(`The --spacing(\u2026) function only accepts a single argument, but received ${n.length+1}.`);let e=t.theme.resolve(null,["--spacing"]);if(!e)throw new Error("The --spacing(\u2026) function requires that the `--spacing` theme variable exists, but it was not found.");return`calc(${e} * ${r})`}function Mn(t,r,...n){if(!r.startsWith("--"))throw new Error("The --theme(\u2026) function can only be used with CSS variables from your theme.");return tr(t,r,...n)}function tr(t,r,...n){r=Wn(r);let e=t.resolveThemeValue(r);if(!e&&n.length>0)return n.join(", ");if(!e)throw new Error(`Could not resolve value for theme function: \`theme(${r})\`. Consider checking if the path is correct or provide a fallback value to silence this error.`);return e}var Xt=new RegExp(Object.keys(pt).map(t=>`${t}\\(`).join("|"));function ge(t,r){let n=0;return _(t,e=>{if(e.kind==="declaration"&&e.value&&Xt.test(e.value)){n|=8,e.value=er(e.value,r);return}e.kind==="at-rule"&&(e.name==="@media"||e.name==="@custom-media"||e.name==="@container"||e.name==="@supports")&&Xt.test(e.params)&&(n|=8,e.params=er(e.params,r))}),n}function er(t,r){let n=L(t);return X(n,(e,{replaceWith:i})=>{if(e.kind==="function"&&e.value in pt){let s=P(q(e.nodes).trim(),",").map(p=>p.trim()),l=pt[e.value](r,...s);return i(L(l))}}),q(n)}function Wn(t){if(t[0]!=="'"&&t[0]!=='"')return t;let r="",n=t[0];for(let e=1;e=48&&l<=57&&p>=48&&p<=57){let c=s,d=s+1,u=s,g=s+1;for(l=t.charCodeAt(d);l>=48&&l<=57;)l=t.charCodeAt(++d);for(p=r.charCodeAt(g);p>=48&&p<=57;)p=r.charCodeAt(++g);let m=t.slice(c,d),b=r.slice(u,g),y=Number(m)-Number(b);if(y)return y;if(mb)return 1;continue}if(l!==p)return l-p}return t.length-r.length}var Bn=/^\d+\/\d+$/;function rr(t){let r=[];for(let e of t.utilities.keys("static"))r.push({name:e,utility:e,fraction:!1,modifiers:[]});for(let e of t.utilities.keys("functional")){let i=t.utilities.getCompletions(e);for(let s of i)for(let l of s.values){let p=l!==null&&Bn.test(l),c=l===null?e:`${e}-${l}`;r.push({name:c,utility:e,fraction:p,modifiers:s.modifiers}),s.supportsNegative&&r.push({name:`-${c}`,utility:`-${e}`,fraction:p,modifiers:s.modifiers})}}return r.length===0?[]:(r.sort((e,i)=>We(e.name,i.name)),qn(r))}function qn(t){let r=[],n=null,e=new Map,i=new I(()=>[]);for(let l of t){let{utility:p,fraction:c}=l;n||(n={utility:p,items:[]},e.set(p,n)),p!==n.utility&&(r.push(n),n={utility:p,items:[]},e.set(p,n)),c?i.get(p).push(l):n.items.push(l)}n&&r[r.length-1]!==n&&r.push(n);for(let[l,p]of i){let c=e.get(l);c&&c.items.push(...p)}let s=[];for(let l of r)for(let p of l.items)s.push([p.name,{modifiers:p.modifiers}]);return s}function nr(t){let r=[];for(let[e,i]of t.variants.entries()){let p=function({value:c,modifier:d}={}){let u=e;c&&(u+=s?`-${c}`:c),d&&(u+=`/${d}`);let g=t.parseVariant(u);if(!g)return[];let m=j(".__placeholder__",[]);if(ve(m,g,t.variants)===null)return[];let b=[];return Ie(m.nodes,(y,{path:v})=>{if(y.kind!=="rule"&&y.kind!=="at-rule"||y.nodes.length>0)return;v.sort((S,O)=>{let R=S.kind==="at-rule",K=O.kind==="at-rule";return R&&!K?-1:!R&&K?1:0});let x=v.flatMap(S=>S.kind==="rule"?S.selector==="&"?[]:[S.selector]:S.kind==="at-rule"?[`${S.name} ${S.params}`]:[]),T="";for(let S=x.length-1;S>=0;S--)T=T===""?x[S]:`${x[S]} { ${T} }`;b.push(T)}),b};var n=p;if(i.kind==="arbitrary")continue;let s=e!=="@",l=t.variants.getCompletions(e);switch(i.kind){case"static":{r.push({name:e,values:l,isArbitrary:!1,hasDash:s,selectors:p});break}case"functional":{r.push({name:e,values:l,isArbitrary:!0,hasDash:s,selectors:p});break}case"compound":{r.push({name:e,values:l,isArbitrary:!0,hasDash:s,selectors:p});break}}}return r}function ir(t,r){let{astNodes:n,nodeSorting:e}=ne(Array.from(r),t),i=new Map(r.map(l=>[l,null])),s=0n;for(let l of n){let p=e.get(l)?.candidate;p&&i.set(p,i.get(p)??s++)}return r.map(l=>[l,i.get(l)??null])}var Be=/^@?[a-zA-Z0-9_-]*$/;var mt=class{compareFns=new Map;variants=new Map;completions=new Map;groupOrder=null;lastOrder=0;static(r,n,{compounds:e,order:i}={}){this.set(r,{kind:"static",applyFn:n,compoundsWith:0,compounds:e??2,order:i})}fromAst(r,n){let e=[];_(n,i=>{i.kind==="rule"?e.push(i.selector):i.kind==="at-rule"&&i.name!=="@slot"&&e.push(`${i.name} ${i.params}`)}),this.static(r,i=>{let s=structuredClone(n);gt(s,i.nodes),i.nodes=s},{compounds:fe(e)})}functional(r,n,{compounds:e,order:i}={}){this.set(r,{kind:"functional",applyFn:n,compoundsWith:0,compounds:e??2,order:i})}compound(r,n,e,{compounds:i,order:s}={}){this.set(r,{kind:"compound",applyFn:e,compoundsWith:n,compounds:i??2,order:s})}group(r,n){this.groupOrder=this.nextOrder(),n&&this.compareFns.set(this.groupOrder,n),r(),this.groupOrder=null}has(r){return this.variants.has(r)}get(r){return this.variants.get(r)}kind(r){return this.variants.get(r)?.kind}compoundsWith(r,n){let e=this.variants.get(r),i=typeof n=="string"?this.variants.get(n):n.kind==="arbitrary"?{compounds:fe([n.selector])}:this.variants.get(n.root);return!(!e||!i||e.kind!=="compound"||i.compounds===0||e.compoundsWith===0||!(e.compoundsWith&i.compounds))}suggest(r,n){this.completions.set(r,n)}getCompletions(r){return this.completions.get(r)?.()??[]}compare(r,n){if(r===n)return 0;if(r===null)return-1;if(n===null)return 1;if(r.kind==="arbitrary"&&n.kind==="arbitrary")return r.selector{m.nodes=u.map(b=>M(b,m.nodes))},{compounds:g})}n("*",[":is(& > *)"],{compounds:0}),n("**",[":is(& *)"],{compounds:0});function e(d,u){return u.map(g=>{g=g.trim();let m=P(g," ");return m[0]==="not"?m.slice(1).join(" "):d==="@container"?m[0][0]==="("?`not ${g}`:m[1]==="not"?`${m[0]} ${m.slice(2).join(" ")}`:`${m[0]} not ${m.slice(1).join(" ")}`:`not ${g}`})}let i=["@media","@supports","@container"];function s(d){for(let u of i){if(u!==d.name)continue;let g=P(d.params,",");return g.length>1?null:(g=e(d.name,g),D(d.name,g.join(", ")))}return null}function l(d){return d.includes("::")?null:`&:not(${P(d,",").map(g=>(g.startsWith("&:is(")&&g.endsWith(")")&&(g=g.slice(5,-1)),g=g.replaceAll("&","*"),g)).join(", ")})`}r.compound("not",3,(d,u)=>{if(u.variant.kind==="arbitrary"&&u.variant.relative||u.modifier)return null;let g=!1;if(_([d],(m,{path:b})=>{if(m.kind!=="rule"&&m.kind!=="at-rule")return 0;if(m.nodes.length>0)return 0;let y=[],v=[];for(let T of b)T.kind==="at-rule"?y.push(T):T.kind==="rule"&&v.push(T);if(y.length>1)return 2;if(v.length>1)return 2;let x=[];for(let T of v){let S=l(T.selector);if(!S)return g=!1,2;x.push(j(S,[]))}for(let T of y){let S=s(T);if(!S)return g=!1,2;x.push(S)}return Object.assign(d,j("&",x)),g=!0,1}),d.kind==="rule"&&d.selector==="&"&&d.nodes.length===1&&Object.assign(d,d.nodes[0]),!g)return null}),r.suggest("not",()=>Array.from(r.keys()).filter(d=>r.compoundsWith("not",d))),r.compound("group",2,(d,u)=>{if(u.variant.kind==="arbitrary"&&u.variant.relative)return null;let g=u.modifier?`:where(.${t.prefix?`${t.prefix}\\:`:""}group\\/${u.modifier.value})`:`:where(.${t.prefix?`${t.prefix}\\:`:""}group)`,m=!1;if(_([d],(b,{path:y})=>{if(b.kind!=="rule")return 0;for(let x of y.slice(0,-1))if(x.kind==="rule")return m=!1,2;let v=b.selector.replaceAll("&",g);P(v,",").length>1&&(v=`:is(${v})`),b.selector=`&:is(${v} *)`,m=!0}),!m)return null}),r.suggest("group",()=>Array.from(r.keys()).filter(d=>r.compoundsWith("group",d))),r.compound("peer",2,(d,u)=>{if(u.variant.kind==="arbitrary"&&u.variant.relative)return null;let g=u.modifier?`:where(.${t.prefix?`${t.prefix}\\:`:""}peer\\/${u.modifier.value})`:`:where(.${t.prefix?`${t.prefix}\\:`:""}peer)`,m=!1;if(_([d],(b,{path:y})=>{if(b.kind!=="rule")return 0;for(let x of y.slice(0,-1))if(x.kind==="rule")return m=!1,2;let v=b.selector.replaceAll("&",g);P(v,",").length>1&&(v=`:is(${v})`),b.selector=`&:is(${v} ~ *)`,m=!0}),!m)return null}),r.suggest("peer",()=>Array.from(r.keys()).filter(d=>r.compoundsWith("peer",d))),n("first-letter",["&::first-letter"]),n("first-line",["&::first-line"]),n("marker",["& *::marker","&::marker"]),n("selection",["& *::selection","&::selection"]),n("file",["&::file-selector-button"]),n("placeholder",["&::placeholder"]),n("backdrop",["&::backdrop"]);{let d=function(){return U([D("@property","--tw-content",[a("syntax",'"*"'),a("initial-value",'""'),a("inherits","false")])])};var p=d;r.static("before",u=>{u.nodes=[j("&::before",[d(),a("content","var(--tw-content)"),...u.nodes])]},{compounds:0}),r.static("after",u=>{u.nodes=[j("&::after",[d(),a("content","var(--tw-content)"),...u.nodes])]},{compounds:0})}n("first",["&:first-child"]),n("last",["&:last-child"]),n("only",["&:only-child"]),n("odd",["&:nth-child(odd)"]),n("even",["&:nth-child(even)"]),n("first-of-type",["&:first-of-type"]),n("last-of-type",["&:last-of-type"]),n("only-of-type",["&:only-of-type"]),n("visited",["&:visited"]),n("target",["&:target"]),n("open",["&:is([open], :popover-open, :open)"]),n("default",["&:default"]),n("checked",["&:checked"]),n("indeterminate",["&:indeterminate"]),n("placeholder-shown",["&:placeholder-shown"]),n("autofill",["&:autofill"]),n("optional",["&:optional"]),n("required",["&:required"]),n("valid",["&:valid"]),n("invalid",["&:invalid"]),!1,n("in-range",["&:in-range"]),n("out-of-range",["&:out-of-range"]),n("read-only",["&:read-only"]),n("empty",["&:empty"]),n("focus-within",["&:focus-within"]),r.static("hover",d=>{d.nodes=[j("&:hover",[D("@media","(hover: hover)",d.nodes)])]}),n("focus",["&:focus"]),n("focus-visible",["&:focus-visible"]),n("active",["&:active"]),n("enabled",["&:enabled"]),n("disabled",["&:disabled"]),n("inert",["&:is([inert], [inert] *)"]),r.compound("in",2,(d,u)=>{if(u.modifier)return null;let g=!1;if(_([d],(m,{path:b})=>{if(m.kind!=="rule")return 0;for(let y of b.slice(0,-1))if(y.kind==="rule")return g=!1,2;m.selector=`:where(${m.selector.replaceAll("&","*")}) &`,g=!0}),!g)return null}),r.suggest("in",()=>Array.from(r.keys()).filter(d=>r.compoundsWith("in",d))),r.compound("has",2,(d,u)=>{if(u.modifier)return null;let g=!1;if(_([d],(m,{path:b})=>{if(m.kind!=="rule")return 0;for(let y of b.slice(0,-1))if(y.kind==="rule")return g=!1,2;m.selector=`&:has(${m.selector.replaceAll("&","*")})`,g=!0}),!g)return null}),r.suggest("has",()=>Array.from(r.keys()).filter(d=>r.compoundsWith("has",d))),r.functional("aria",(d,u)=>{if(!u.value||u.modifier)return null;u.value.kind==="arbitrary"?d.nodes=[j(`&[aria-${or(u.value.value)}]`,d.nodes)]:d.nodes=[j(`&[aria-${u.value.value}="true"]`,d.nodes)]}),r.suggest("aria",()=>["busy","checked","disabled","expanded","hidden","pressed","readonly","required","selected"]),r.functional("data",(d,u)=>{if(!u.value||u.modifier)return null;d.nodes=[j(`&[data-${or(u.value.value)}]`,d.nodes)]}),r.functional("nth",(d,u)=>{if(!u.value||u.modifier||u.value.kind==="named"&&!V(u.value.value))return null;d.nodes=[j(`&:nth-child(${u.value.value})`,d.nodes)]}),r.functional("nth-last",(d,u)=>{if(!u.value||u.modifier||u.value.kind==="named"&&!V(u.value.value))return null;d.nodes=[j(`&:nth-last-child(${u.value.value})`,d.nodes)]}),r.functional("nth-of-type",(d,u)=>{if(!u.value||u.modifier||u.value.kind==="named"&&!V(u.value.value))return null;d.nodes=[j(`&:nth-of-type(${u.value.value})`,d.nodes)]}),r.functional("nth-last-of-type",(d,u)=>{if(!u.value||u.modifier||u.value.kind==="named"&&!V(u.value.value))return null;d.nodes=[j(`&:nth-last-of-type(${u.value.value})`,d.nodes)]}),r.functional("supports",(d,u)=>{if(!u.value||u.modifier)return null;let g=u.value.value;if(g===null)return null;if(/^[\w-]*\s*\(/.test(g)){let m=g.replace(/\b(and|or|not)\b/g," $1 ");d.nodes=[D("@supports",m,d.nodes)];return}g.includes(":")||(g=`${g}: var(--tw)`),(g[0]!=="("||g[g.length-1]!==")")&&(g=`(${g})`),d.nodes=[D("@supports",g,d.nodes)]},{compounds:1}),n("motion-safe",["@media (prefers-reduced-motion: no-preference)"]),n("motion-reduce",["@media (prefers-reduced-motion: reduce)"]),n("contrast-more",["@media (prefers-contrast: more)"]),n("contrast-less",["@media (prefers-contrast: less)"]);{let d=function(u,g,m,b){if(u===g)return 0;let y=b.get(u);if(y===null)return m==="asc"?-1:1;let v=b.get(g);return v===null?m==="asc"?1:-1:ue(y,v,m)};var c=d;{let u=t.namespace("--breakpoint"),g=new I(m=>{switch(m.kind){case"static":return t.resolveValue(m.root,["--breakpoint"])??null;case"functional":{if(!m.value||m.modifier)return null;let b=null;return m.value.kind==="arbitrary"?b=m.value.value:m.value.kind==="named"&&(b=t.resolveValue(m.value.value,["--breakpoint"])),!b||b.includes("var(")?null:b}case"arbitrary":case"compound":return null}});r.group(()=>{r.functional("max",(m,b)=>{if(b.modifier)return null;let y=g.get(b);if(y===null)return null;m.nodes=[D("@media",`(width < ${y})`,m.nodes)]},{compounds:1})},(m,b)=>d(m,b,"desc",g)),r.suggest("max",()=>Array.from(u.keys()).filter(m=>m!==null)),r.group(()=>{for(let[m,b]of t.namespace("--breakpoint"))m!==null&&r.static(m,y=>{y.nodes=[D("@media",`(width >= ${b})`,y.nodes)]},{compounds:1});r.functional("min",(m,b)=>{if(b.modifier)return null;let y=g.get(b);if(y===null)return null;m.nodes=[D("@media",`(width >= ${y})`,m.nodes)]},{compounds:1})},(m,b)=>d(m,b,"asc",g)),r.suggest("min",()=>Array.from(u.keys()).filter(m=>m!==null))}{let u=t.namespace("--container"),g=new I(m=>{switch(m.kind){case"functional":{if(m.value===null)return null;let b=null;return m.value.kind==="arbitrary"?b=m.value.value:m.value.kind==="named"&&(b=t.resolveValue(m.value.value,["--container"])),!b||b.includes("var(")?null:b}case"static":case"arbitrary":case"compound":return null}});r.group(()=>{r.functional("@max",(m,b)=>{let y=g.get(b);if(y===null)return null;m.nodes=[D("@container",b.modifier?`${b.modifier.value} (width < ${y})`:`(width < ${y})`,m.nodes)]},{compounds:1})},(m,b)=>d(m,b,"desc",g)),r.suggest("@max",()=>Array.from(u.keys()).filter(m=>m!==null)),r.group(()=>{r.functional("@",(m,b)=>{let y=g.get(b);if(y===null)return null;m.nodes=[D("@container",b.modifier?`${b.modifier.value} (width >= ${y})`:`(width >= ${y})`,m.nodes)]},{compounds:1}),r.functional("@min",(m,b)=>{let y=g.get(b);if(y===null)return null;m.nodes=[D("@container",b.modifier?`${b.modifier.value} (width >= ${y})`:`(width >= ${y})`,m.nodes)]},{compounds:1})},(m,b)=>d(m,b,"asc",g)),r.suggest("@min",()=>Array.from(u.keys()).filter(m=>m!==null)),r.suggest("@",()=>Array.from(u.keys()).filter(m=>m!==null))}}return n("portrait",["@media (orientation: portrait)"]),n("landscape",["@media (orientation: landscape)"]),n("ltr",['&:where(:dir(ltr), [dir="ltr"], [dir="ltr"] *)']),n("rtl",['&:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *)']),n("dark",["@media (prefers-color-scheme: dark)"]),n("starting",["@starting-style"]),n("print",["@media print"]),n("forced-colors",["@media (forced-colors: active)"]),!1,r}function or(t){if(t.includes("=")){let[r,...n]=P(t,"="),e=n.join("=").trim();if(e[0]==="'"||e[0]==='"')return t;if(e.length>1){let i=e[e.length-1];if(e[e.length-2]===" "&&(i==="i"||i==="I"||i==="s"||i==="S"))return`${r}="${e.slice(0,-2)}" ${i}`}return`${r}="${e}"`}return t}function gt(t,r){_(t,(n,{replaceWith:e})=>{if(n.kind==="at-rule"&&n.name==="@slot")e(r);else if(n.kind==="at-rule"&&(n.name==="@keyframes"||n.name==="@property"))return Object.assign(n,U([D(n.name,n.params,n.nodes)])),1})}function ar(t){let r=Zt(t),n=lr(t),e=new I(c=>Wt(c,p)),i=new I(c=>Array.from(Mt(c,p))),s=new I(c=>{let d=sr(c,p);try{ge(d.map(({node:u})=>u),p)}catch{return[]}return d}),l=new I(c=>{for(let d of Fe(c))t.markUsedVariable(d)}),p={theme:t,utilities:r,variants:n,invalidCandidates:new Set,important:!1,candidatesToCss(c){let d=[];for(let u of c){let g=!1,{astNodes:m}=ne([u],this,{onInvalidCandidate(){g=!0}});m=se(m,p),m.length===0||g?d.push(null):d.push(G(m))}return d},getClassOrder(c){return ir(this,c)},getClassList(){return rr(this)},getVariants(){return nr(this)},parseCandidate(c){return i.get(c)},parseVariant(c){return e.get(c)},compileAstNodes(c){return s.get(c)},getVariantOrder(){let c=Array.from(e.values());c.sort((m,b)=>this.variants.compare(m,b));let d=new Map,u,g=0;for(let m of c)m!==null&&(u!==void 0&&this.variants.compare(u,m)!==0&&g++,d.set(m,g),u=m);return d},resolveThemeValue(c){let d=c.lastIndexOf("/"),u=null;d!==-1&&(u=c.slice(d+1).trim(),c=c.slice(0,d).trim());let g=t.get([c])??void 0;return u&&g?Y(g,u):g},trackUsedVariables(c){l.get(c)}};return p}var ht=["container-type","pointer-events","visibility","position","inset","inset-inline","inset-block","inset-inline-start","inset-inline-end","top","right","bottom","left","isolation","z-index","order","grid-column","grid-column-start","grid-column-end","grid-row","grid-row-start","grid-row-end","float","clear","--tw-container-component","margin","margin-inline","margin-block","margin-inline-start","margin-inline-end","margin-top","margin-right","margin-bottom","margin-left","box-sizing","display","field-sizing","aspect-ratio","height","max-height","min-height","width","max-width","min-width","flex","flex-shrink","flex-grow","flex-basis","table-layout","caption-side","border-collapse","border-spacing","transform-origin","translate","--tw-translate-x","--tw-translate-y","--tw-translate-z","scale","--tw-scale-x","--tw-scale-y","--tw-scale-z","rotate","--tw-rotate-x","--tw-rotate-y","--tw-rotate-z","--tw-skew-x","--tw-skew-y","transform","animation","cursor","touch-action","--tw-pan-x","--tw-pan-y","--tw-pinch-zoom","resize","scroll-snap-type","--tw-scroll-snap-strictness","scroll-snap-align","scroll-snap-stop","scroll-margin","scroll-margin-inline","scroll-margin-block","scroll-margin-inline-start","scroll-margin-inline-end","scroll-margin-top","scroll-margin-right","scroll-margin-bottom","scroll-margin-left","scroll-padding","scroll-padding-inline","scroll-padding-block","scroll-padding-inline-start","scroll-padding-inline-end","scroll-padding-top","scroll-padding-right","scroll-padding-bottom","scroll-padding-left","list-style-position","list-style-type","list-style-image","appearance","columns","break-before","break-inside","break-after","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-template-columns","grid-template-rows","flex-direction","flex-wrap","place-content","place-items","align-content","align-items","justify-content","justify-items","gap","column-gap","row-gap","--tw-space-x-reverse","--tw-space-y-reverse","divide-x-width","divide-y-width","--tw-divide-y-reverse","divide-style","divide-color","place-self","align-self","justify-self","overflow","overflow-x","overflow-y","overscroll-behavior","overscroll-behavior-x","overscroll-behavior-y","scroll-behavior","border-radius","border-start-radius","border-end-radius","border-top-radius","border-right-radius","border-bottom-radius","border-left-radius","border-start-start-radius","border-start-end-radius","border-end-end-radius","border-end-start-radius","border-top-left-radius","border-top-right-radius","border-bottom-right-radius","border-bottom-left-radius","border-width","border-inline-width","border-block-width","border-inline-start-width","border-inline-end-width","border-top-width","border-right-width","border-bottom-width","border-left-width","border-style","border-inline-style","border-block-style","border-inline-start-style","border-inline-end-style","border-top-style","border-right-style","border-bottom-style","border-left-style","border-color","border-inline-color","border-block-color","border-inline-start-color","border-inline-end-color","border-top-color","border-right-color","border-bottom-color","border-left-color","background-color","background-image","--tw-gradient-position","--tw-gradient-stops","--tw-gradient-via-stops","--tw-gradient-from","--tw-gradient-from-position","--tw-gradient-via","--tw-gradient-via-position","--tw-gradient-to","--tw-gradient-to-position","box-decoration-break","background-size","background-attachment","background-clip","background-position","background-repeat","background-origin","fill","stroke","stroke-width","object-fit","object-position","padding","padding-inline","padding-block","padding-inline-start","padding-inline-end","padding-top","padding-right","padding-bottom","padding-left","text-align","text-indent","vertical-align","font-family","font-size","line-height","font-weight","letter-spacing","text-wrap","overflow-wrap","word-break","text-overflow","hyphens","white-space","color","text-transform","font-style","font-stretch","font-variant-numeric","text-decoration-line","text-decoration-color","text-decoration-style","text-decoration-thickness","text-underline-offset","-webkit-font-smoothing","placeholder-color","caret-color","accent-color","color-scheme","opacity","background-blend-mode","mix-blend-mode","box-shadow","--tw-shadow","--tw-shadow-color","--tw-ring-shadow","--tw-ring-color","--tw-inset-shadow","--tw-inset-shadow-color","--tw-inset-ring-shadow","--tw-inset-ring-color","--tw-ring-offset-width","--tw-ring-offset-color","outline","outline-width","outline-offset","outline-color","--tw-blur","--tw-brightness","--tw-contrast","--tw-drop-shadow","--tw-grayscale","--tw-hue-rotate","--tw-invert","--tw-saturate","--tw-sepia","filter","--tw-backdrop-blur","--tw-backdrop-brightness","--tw-backdrop-contrast","--tw-backdrop-grayscale","--tw-backdrop-hue-rotate","--tw-backdrop-invert","--tw-backdrop-opacity","--tw-backdrop-saturate","--tw-backdrop-sepia","backdrop-filter","transition-property","transition-behavior","transition-delay","transition-duration","transition-timing-function","will-change","contain","content","forced-color-adjust"];function ne(t,r,{onInvalidCandidate:n}={}){let e=new Map,i=[],s=new Map;for(let p of t){if(r.invalidCandidates.has(p)){n?.(p);continue}let c=r.parseCandidate(p);if(c.length===0){n?.(p);continue}s.set(p,c)}let l=r.getVariantOrder();for(let[p,c]of s){let d=!1;for(let u of c){let g=r.compileAstNodes(u);if(g.length!==0){d=!0;for(let{node:m,propertySort:b}of g){let y=0n;for(let v of u.variants)y|=1n<{let d=e.get(p),u=e.get(c);if(d.variants-u.variants!==0n)return Number(d.variants-u.variants);let g=0;for(;g1)return null;for(let c of l.nodes)if(c.kind!=="rule"&&c.kind!=="at-rule"||i(c,r)===null)return null;_(l.nodes,c=>{if((c.kind==="rule"||c.kind==="at-rule")&&c.nodes.length<=0)return c.nodes=t.nodes,1}),t.nodes=l.nodes;return}if(i(t,r)===null)return null}function ur(t){let r=t.options?.types??[];return r.length>1&&r.includes("any")}function Yn(t,r){if(t.kind==="arbitrary"){let l=t.value;return t.modifier&&(l=W(l,t.modifier,r.theme)),l===null?[]:[[a(t.property,l)]]}let n=r.utilities.get(t.root)??[],e=[],i=n.filter(l=>!ur(l));for(let l of i){if(l.kind!==t.kind)continue;let p=l.compileFn(t);if(p!==void 0){if(p===null)return e;e.push(p)}}if(e.length>0)return e;let s=n.filter(l=>ur(l));for(let l of s){if(l.kind!==t.kind)continue;let p=l.compileFn(t);if(p!==void 0){if(p===null)return e;e.push(p)}}return e}function cr(t){for(let r of t)r.kind!=="at-root"&&(r.kind==="declaration"&&!(r.property[0]==="-"&&r.property[1]==="-")?r.important=!0:(r.kind==="rule"||r.kind==="at-rule")&&cr(r.nodes))}function Jn(t){let r=new Set,n=0,e=t.slice(),i=!1;for(;e.length>0;){let s=e.shift();if(s.kind==="declaration"){if(s.value!==void 0&&n++,i)continue;if(s.property==="--tw-sort"){let p=ht.indexOf(s.value??"");if(p!==-1){r.add(p),i=!0;continue}}let l=ht.indexOf(s.property);l!==-1&&r.add(l)}else if(s.kind==="rule"||s.kind==="at-rule")for(let l of s.nodes)e.push(l)}return{order:Array.from(r).sort((s,l)=>s-l),count:n}}function $e(t,r){let n=0,e=M("&",t),i=new Set,s=new I(()=>new Set),l=new I(()=>new Set);_([e],(g,{parent:m})=>{if(g.kind==="at-rule"){if(g.name==="@keyframes")return _(g.nodes,b=>{if(b.kind==="at-rule"&&b.name==="@apply")throw new Error("You cannot use `@apply` inside `@keyframes`.")}),1;if(g.name==="@utility"){let b=g.params.replace(/-\*$/,"");l.get(b).add(g),_(g.nodes,y=>{if(!(y.kind!=="at-rule"||y.name!=="@apply")){i.add(g);for(let v of fr(y,r))s.get(g).add(v)}});return}if(g.name==="@apply"){if(m===null)return;n|=1,i.add(m);for(let b of fr(g,r))s.get(m).add(b)}}});let p=new Set,c=[],d=new Set;function u(g,m=[]){if(!p.has(g)){if(d.has(g)){let b=m[(m.indexOf(g)+1)%m.length];throw g.kind==="at-rule"&&g.name==="@utility"&&b.kind==="at-rule"&&b.name==="@utility"&&_(g.nodes,y=>{if(y.kind!=="at-rule"||y.name!=="@apply")return;let v=y.params.split(/\s+/g);for(let x of v)for(let T of r.parseCandidate(x))switch(T.kind){case"arbitrary":break;case"static":case"functional":if(b.params.replace(/-\*$/,"")===T.root)throw new Error(`You cannot \`@apply\` the \`${x}\` utility here because it creates a circular dependency.`);break;default:}}),new Error(`Circular dependency detected: + +${G([g])} +Relies on: + +${G([b])}`)}d.add(g);for(let b of s.get(g))for(let y of l.get(b))m.push(g),u(y,m),m.pop();p.add(g),d.delete(g),c.push(g)}}for(let g of i)u(g);return _(c,(g,{replaceWith:m})=>{if(g.kind!=="at-rule"||g.name!=="@apply")return;let b=g.params.split(/\s+/g);{let y=ne(b,r,{onInvalidCandidate:x=>{throw new Error(`Cannot apply unknown utility class: ${x}`)}}).astNodes,v=[];for(let x of y)if(x.kind==="rule")for(let T of x.nodes)v.push(T);else v.push(x);m(v)}}),n}function*fr(t,r){for(let n of t.params.split(/\s+/g))for(let e of r.parseCandidate(n))switch(e.kind){case"arbitrary":break;case"static":case"functional":yield e.root;break;default:}}async function vt(t,r,n,e=0){let i=0,s=[];return _(t,(l,{replaceWith:p})=>{if(l.kind==="at-rule"&&(l.name==="@import"||l.name==="@reference")){let c=Zn(L(l.params));if(c===null)return;l.name==="@reference"&&(c.media="reference"),i|=2;let{uri:d,layer:u,media:g,supports:m}=c;if(d.startsWith("data:")||d.startsWith("http://")||d.startsWith("https://"))return;let b=Z({},[]);return s.push((async()=>{if(e>100)throw new Error(`Exceeded maximum recursion depth while resolving \`${d}\` in \`${r}\`)`);let y=await n(d,r),v=le(y.content);await vt(v,y.base,n,e+1),b.nodes=Qn([Z({base:y.base},v)],u,g,m)})()),p(b),1}}),s.length>0&&await Promise.all(s),i}function Zn(t){let r,n=null,e=null,i=null;for(let s=0;s/g,"1")),e[0]==="opacity"&&(typeof i=="number"||typeof i=="string")){let l=typeof i=="string"?parseFloat(i):i;l>=0&&l<=1&&(i=l*100+"%")}let s=qe(e);s&&t.theme.add(`--${s}`,""+i,7)}if(Object.hasOwn(r,"fontFamily")){let e=5;{let i=ye(r.fontFamily.sans);i&&t.theme.hasDefault("--font-sans")&&(t.theme.add("--default-font-family",i,e),t.theme.add("--default-font-feature-settings",ye(r.fontFamily.sans,"fontFeatureSettings")??"normal",e),t.theme.add("--default-font-variation-settings",ye(r.fontFamily.sans,"fontVariationSettings")??"normal",e))}{let i=ye(r.fontFamily.mono);i&&t.theme.hasDefault("--font-mono")&&(t.theme.add("--default-mono-font-family",i,e),t.theme.add("--default-mono-font-feature-settings",ye(r.fontFamily.mono,"fontFeatureSettings")??"normal",e),t.theme.add("--default-mono-font-variation-settings",ye(r.fontFamily.mono,"fontVariationSettings")??"normal",e))}}return r}function Xn(t){let r=[];return pr(t,[],(n,e)=>{if(ti(n))return r.push([e,n]),1;if(ri(n)){r.push([e,n[0]]);for(let i of Reflect.ownKeys(n[1]))r.push([[...e,`-${i}`],n[1][i]]);return 1}if(Array.isArray(n)&&n.every(i=>typeof i=="string"))return r.push([e,n.join(", ")]),1}),r}var ei=/^[a-zA-Z0-9-_%/\.]+$/;function qe(t){if(t[0]==="container")return null;t=structuredClone(t),t[0]==="animation"&&(t[0]="animate"),t[0]==="aspectRatio"&&(t[0]="aspect"),t[0]==="borderRadius"&&(t[0]="radius"),t[0]==="boxShadow"&&(t[0]="shadow"),t[0]==="colors"&&(t[0]="color"),t[0]==="containers"&&(t[0]="container"),t[0]==="fontFamily"&&(t[0]="font"),t[0]==="fontSize"&&(t[0]="text"),t[0]==="letterSpacing"&&(t[0]="tracking"),t[0]==="lineHeight"&&(t[0]="leading"),t[0]==="maxWidth"&&(t[0]="container"),t[0]==="screens"&&(t[0]="breakpoint"),t[0]==="transitionTimingFunction"&&(t[0]="ease");for(let r of t)if(!ei.test(r))return null;return t.map((r,n,e)=>r==="1"&&n!==e.length-1?"":r).map(r=>r.replaceAll(".","_").replace(/([a-z])([A-Z])/g,(n,e,i)=>`${e}-${i.toLowerCase()}`)).filter((r,n)=>r!=="DEFAULT"||n!==t.length-1).join("-")}function ti(t){return typeof t=="number"||typeof t=="string"}function ri(t){if(!Array.isArray(t)||t.length!==2||typeof t[0]!="string"&&typeof t[0]!="number"||t[1]===void 0||t[1]===null||typeof t[1]!="object")return!1;for(let r of Reflect.ownKeys(t[1]))if(typeof r!="string"||typeof t[1][r]!="string"&&typeof t[1][r]!="number")return!1;return!0}function pr(t,r=[],n){for(let e of Reflect.ownKeys(t)){let i=t[e];if(i==null)continue;let s=[...r,e],l=n(i,s)??0;if(l!==1){if(l===2)return 2;if(!(!Array.isArray(i)&&typeof i!="object")&&pr(i,s,n)===2)return 2}}}function He(t){let r=[];for(let n of P(t,".")){if(!n.includes("[")){r.push(n);continue}let e=0;for(;;){let i=n.indexOf("[",e),s=n.indexOf("]",i);if(i===-1||s===-1)break;i>e&&r.push(n.slice(e,i)),r.push(n.slice(i+1,s)),e=s+1}e<=n.length-1&&r.push(n.slice(e))}return r}function be(t){if(Object.prototype.toString.call(t)!=="[object Object]")return!1;let r=Object.getPrototypeOf(t);return r===null||Object.getPrototypeOf(r)===null}function Ve(t,r,n,e=[]){for(let i of r)if(i!=null)for(let s of Reflect.ownKeys(i)){e.push(s);let l=n(t[s],i[s],e);l!==void 0?t[s]=l:!be(t[s])||!be(i[s])?t[s]=i[s]:t[s]=Ve({},[t[s],i[s]],n,e),e.pop()}return t}function Ge(t,r,n){return function(i,s){let l=i.lastIndexOf("/"),p=null;l!==-1&&(p=i.slice(l+1).trim(),i=i.slice(0,l).trim());let c=(()=>{let d=He(i),[u,g]=ni(t.theme,d),m=n(mr(r()??{},d)??null);if(typeof m=="string"&&(m=m.replace("","1")),typeof u!="object")return typeof g!="object"&&g&4?m??u:u;if(m!==null&&typeof m=="object"&&!Array.isArray(m)){let b=Ve({},[m],(y,v)=>v);if(u===null&&Object.hasOwn(m,"__CSS_VALUES__")){let y={};for(let v in m.__CSS_VALUES__)y[v]=m[v],delete b[v];u=y}for(let y in u)y!=="__CSS_VALUES__"&&(m?.__CSS_VALUES__?.[y]&4&&mr(b,y.split("-"))!==void 0||(b[ae(y)]=u[y]));return b}if(Array.isArray(u)&&Array.isArray(g)&&Array.isArray(m)){let b=u[0],y=u[1];g[0]&4&&(b=m[0]??b);for(let v of Object.keys(y))g[1][v]&4&&(y[v]=m[1][v]??y[v]);return[b,y]}return u??m})();return p&&typeof c=="string"&&(c=Y(c,p)),c??s}}function ni(t,r){if(r.length===1&&r[0].startsWith("--"))return[t.get([r[0]]),t.getOptions(r[0])];let n=qe(r),e=new Map,i=new I(()=>new Map),s=t.namespace(`--${n}`);if(s.size===0)return[null,0];let l=new Map;for(let[u,g]of s){if(!u||!u.includes("--")){e.set(u,g),l.set(u,t.getOptions(u?`--${n}-${u}`:`--${n}`));continue}let m=u.indexOf("--"),b=u.slice(0,m),y=u.slice(m+2);y=y.replace(/-([a-z])/g,(v,x)=>x.toUpperCase()),i.get(b===""?null:b).set(y,[g,t.getOptions(`--${n}${u}`)])}let p=t.getOptions(`--${n}`);for(let[u,g]of i){let m=e.get(u);if(typeof m!="string")continue;let b={},y={};for(let[v,[x,T]]of g)b[v]=x,y[v]=T;e.set(u,[m,b]),l.set(u,[p,y])}let c={},d={};for(let[u,g]of e)gr(c,[u??"DEFAULT"],g);for(let[u,g]of l)gr(d,[u??"DEFAULT"],g);return r[r.length-1]==="DEFAULT"?[c?.DEFAULT??null,d.DEFAULT??0]:"DEFAULT"in c&&Object.keys(c).length===1?[c.DEFAULT,d.DEFAULT??0]:(c.__CSS_VALUES__=d,[c,d])}function mr(t,r){for(let n=0;n0){let m=Te(i);e?e.nodes.push(m):r.push(m),i=""}let c=l,d=l+1;for(;d0){let d=Te(i);c.nodes.push(d),i=""}n.length>0?e=n[n.length-1]:e=null;break}case fi:case ui:case di:{if(i.length>0){let c=Te(i);e?e.nodes.push(c):r.push(c)}i=String.fromCharCode(p);break}case kr:{if(i.length>0){let u=Te(i);e?e.nodes.push(u):r.push(u)}i="";let c=l,d=0;for(let u=l+1;u0&&r.push(Te(i)),r}var Vr=/^[a-z@][a-zA-Z0-9/%._-]*$/;function yt({designSystem:t,ast:r,resolvedConfig:n,featuresRef:e,referenceMode:i}){let s={addBase(l){if(i)return;let p=Q(l);e.current|=ge(p,t),r.push(D("@layer","base",p))},addVariant(l,p){if(!Be.test(l))throw new Error(`\`addVariant('${l}')\` defines an invalid variant name. Variants should only contain alphanumeric, dashes or underscore characters.`);typeof p=="string"||Array.isArray(p)?t.variants.static(l,c=>{c.nodes=Tr(p,c.nodes)},{compounds:fe(typeof p=="string"?[p]:p)}):typeof p=="object"&&t.variants.fromAst(l,Q(p))},matchVariant(l,p,c){function d(g,m,b){let y=p(g,{modifier:m?.value??null});return Tr(y,b)}let u=Object.keys(c?.values??{});t.variants.group(()=>{t.variants.functional(l,(g,m)=>{if(!m.value){if(c?.values&&"DEFAULT"in c.values){g.nodes=d(c.values.DEFAULT,m.modifier,g.nodes);return}return null}if(m.value.kind==="arbitrary")g.nodes=d(m.value.value,m.modifier,g.nodes);else if(m.value.kind==="named"&&c?.values){let b=c.values[m.value.value];if(typeof b!="string")return;g.nodes=d(b,m.modifier,g.nodes)}})},(g,m)=>{if(g.kind!=="functional"||m.kind!=="functional")return 0;let b=g.value?g.value.value:"DEFAULT",y=m.value?m.value.value:"DEFAULT",v=c?.values?.[b]??b,x=c?.values?.[y]??y;if(c&&typeof c.sort=="function")return c.sort({value:v,modifier:g.modifier?.value??null},{value:x,modifier:m.modifier?.value??null});let T=u.indexOf(b),S=u.indexOf(y);return T=T===-1?u.length:T,S=S===-1?u.length:S,T!==S?T-S:vObject.entries(d));p=p.flatMap(([d,u])=>P(d,",").map(g=>[g.trim(),u]));let c=new I(()=>[]);for(let[d,u]of p){if(d.startsWith("@keyframes ")){i||r.push(M(d,Q(u)));continue}let g=Ye(d),m=!1;if(Se(g,b=>{if(b.kind==="selector"&&b.value[0]==="."&&Vr.test(b.value.slice(1))){let y=b.value;b.value="&";let v=Ee(g),x=y.slice(1),T=v==="&"?Q(u):[M(v,Q(u))];c.get(x).push(...T),m=!0,b.value=y;return}if(b.kind==="function"&&b.value===":not")return 1}),!m)throw new Error(`\`addUtilities({ '${d}' : \u2026 })\` defines an invalid utility selector. Utilities must be a single class name and start with a lowercase letter, eg. \`.scrollbar-none\`.`)}for(let[d,u]of c)t.theme.prefix&&_(u,g=>{if(g.kind==="rule"){let m=Ye(g.selector);Se(m,b=>{b.kind==="selector"&&b.value[0]==="."&&(b.value=`.${t.theme.prefix}\\:${b.value.slice(1)}`)}),g.selector=Ee(m)}}),t.utilities.static(d,g=>{let m=structuredClone(u);return Sr(m,d,g.raw),e.current|=$e(m,t),m})},matchUtilities(l,p){let c=p?.type?Array.isArray(p?.type)?p.type:[p.type]:["any"];for(let[u,g]of Object.entries(l)){let m=function({negative:b}){return y=>{if(y.value?.kind==="arbitrary"&&c.length>0&&!c.includes("any")&&(y.value.dataType&&!c.includes(y.value.dataType)||!y.value.dataType&&!z(y.value.value,c)))return;let v=c.includes("color"),x=null,T=!1;{let R=p?.values??{};v&&(R=Object.assign({inherit:"inherit",transparent:"transparent",current:"currentColor"},R)),y.value?y.value.kind==="arbitrary"?x=y.value.value:y.value.fraction&&R[y.value.fraction]?(x=R[y.value.fraction],T=!0):R[y.value.value]?x=R[y.value.value]:R.__BARE_VALUE__&&(x=R.__BARE_VALUE__(y.value)??null,T=(y.value.fraction!==null&&x?.includes("/"))??!1):x=R.DEFAULT??null}if(x===null)return;let S;{let R=p?.modifiers??null;y.modifier?R==="any"||y.modifier.kind==="arbitrary"?S=y.modifier.value:R?.[y.modifier.value]?S=R[y.modifier.value]:v&&!Number.isNaN(Number(y.modifier.value))?S=`${y.modifier.value}%`:S=null:S=null}if(y.modifier&&S===null&&!T)return y.value?.kind==="arbitrary"?null:void 0;v&&S!==null&&(x=Y(x,S)),b&&(x=`calc(${x} * -1)`);let O=Q(g(x,{modifier:S}));return Sr(O,u,y.raw),e.current|=$e(O,t),O}};var d=m;if(!Vr.test(u))throw new Error(`\`matchUtilities({ '${u}' : \u2026 })\` defines an invalid utility name. Utilities should be alphanumeric and start with a lowercase letter, eg. \`scrollbar\`.`);p?.supportsNegativeValues&&t.utilities.functional(`-${u}`,m({negative:!0}),{types:c}),t.utilities.functional(u,m({negative:!1}),{types:c}),t.utilities.suggest(u,()=>{let b=p?.values??{},y=new Set(Object.keys(b));y.delete("__BARE_VALUE__"),y.has("DEFAULT")&&(y.delete("DEFAULT"),y.add(null));let v=p?.modifiers??{},x=v==="any"?[]:Object.keys(v);return[{supportsNegative:p?.supportsNegativeValues??!1,values:Array.from(y),modifiers:x}]})}},addComponents(l,p){this.addUtilities(l,p)},matchComponents(l,p){this.matchUtilities(l,p)},theme:Ge(t,()=>n.theme??{},l=>l),prefix(l){return l},config(l,p){let c=n;if(!l)return c;let d=He(l);for(let u=0;uObject.entries(e));for(let[e,i]of n)if(typeof i!="object"){if(!e.startsWith("--")){if(i==="@slot"){r.push(M(e,[D("@slot")]));continue}e=e.replace(/([A-Z])/g,"-$1").toLowerCase()}r.push(a(e,String(i)))}else if(Array.isArray(i))for(let s of i)typeof s=="string"?r.push(a(e,s)):r.push(M(e,Q(s)));else i!==null&&r.push(M(e,Q(i)));return r}function Tr(t,r){return(typeof t=="string"?[t]:t).flatMap(e=>{if(e.trim().endsWith("}")){let i=e.replace("}","{@slot}}"),s=le(i);return gt(s,r),s}else return M(e,r)})}function Sr(t,r,n){_(t,e=>{if(e.kind==="rule"){let i=Ye(e.selector);Se(i,s=>{s.kind==="selector"&&s.value===`.${r}`&&(s.value=`.${te(n)}`)}),e.selector=Ee(i)}})}function Er(t,r,n){for(let e of gi(r))t.theme.addKeyframes(e)}function gi(t){let r=[];if("keyframes"in t.theme)for(let[n,e]of Object.entries(t.theme.keyframes))r.push(D("@keyframes",n,Q(e)));return r}var Je={inherit:"inherit",current:"currentColor",transparent:"transparent",black:"#000",white:"#fff",slate:{50:"oklch(0.984 0.003 247.858)",100:"oklch(0.968 0.007 247.896)",200:"oklch(0.929 0.013 255.508)",300:"oklch(0.869 0.022 252.894)",400:"oklch(0.704 0.04 256.788)",500:"oklch(0.554 0.046 257.417)",600:"oklch(0.446 0.043 257.281)",700:"oklch(0.372 0.044 257.287)",800:"oklch(0.279 0.041 260.031)",900:"oklch(0.208 0.042 265.755)",950:"oklch(0.129 0.042 264.695)"},gray:{50:"oklch(0.985 0.002 247.839)",100:"oklch(0.967 0.003 264.542)",200:"oklch(0.928 0.006 264.531)",300:"oklch(0.872 0.01 258.338)",400:"oklch(0.707 0.022 261.325)",500:"oklch(0.551 0.027 264.364)",600:"oklch(0.446 0.03 256.802)",700:"oklch(0.373 0.034 259.733)",800:"oklch(0.278 0.033 256.848)",900:"oklch(0.21 0.034 264.665)",950:"oklch(0.13 0.028 261.692)"},zinc:{50:"oklch(0.985 0 0)",100:"oklch(0.967 0.001 286.375)",200:"oklch(0.92 0.004 286.32)",300:"oklch(0.871 0.006 286.286)",400:"oklch(0.705 0.015 286.067)",500:"oklch(0.552 0.016 285.938)",600:"oklch(0.442 0.017 285.786)",700:"oklch(0.37 0.013 285.805)",800:"oklch(0.274 0.006 286.033)",900:"oklch(0.21 0.006 285.885)",950:"oklch(0.141 0.005 285.823)"},neutral:{50:"oklch(0.985 0 0)",100:"oklch(0.97 0 0)",200:"oklch(0.922 0 0)",300:"oklch(0.87 0 0)",400:"oklch(0.708 0 0)",500:"oklch(0.556 0 0)",600:"oklch(0.439 0 0)",700:"oklch(0.371 0 0)",800:"oklch(0.269 0 0)",900:"oklch(0.205 0 0)",950:"oklch(0.145 0 0)"},stone:{50:"oklch(0.985 0.001 106.423)",100:"oklch(0.97 0.001 106.424)",200:"oklch(0.923 0.003 48.717)",300:"oklch(0.869 0.005 56.366)",400:"oklch(0.709 0.01 56.259)",500:"oklch(0.553 0.013 58.071)",600:"oklch(0.444 0.011 73.639)",700:"oklch(0.374 0.01 67.558)",800:"oklch(0.268 0.007 34.298)",900:"oklch(0.216 0.006 56.043)",950:"oklch(0.147 0.004 49.25)"},red:{50:"oklch(0.971 0.013 17.38)",100:"oklch(0.936 0.032 17.717)",200:"oklch(0.885 0.062 18.334)",300:"oklch(0.808 0.114 19.571)",400:"oklch(0.704 0.191 22.216)",500:"oklch(0.637 0.237 25.331)",600:"oklch(0.577 0.245 27.325)",700:"oklch(0.505 0.213 27.518)",800:"oklch(0.444 0.177 26.899)",900:"oklch(0.396 0.141 25.723)",950:"oklch(0.258 0.092 26.042)"},orange:{50:"oklch(0.98 0.016 73.684)",100:"oklch(0.954 0.038 75.164)",200:"oklch(0.901 0.076 70.697)",300:"oklch(0.837 0.128 66.29)",400:"oklch(0.75 0.183 55.934)",500:"oklch(0.705 0.213 47.604)",600:"oklch(0.646 0.222 41.116)",700:"oklch(0.553 0.195 38.402)",800:"oklch(0.47 0.157 37.304)",900:"oklch(0.408 0.123 38.172)",950:"oklch(0.266 0.079 36.259)"},amber:{50:"oklch(0.987 0.022 95.277)",100:"oklch(0.962 0.059 95.617)",200:"oklch(0.924 0.12 95.746)",300:"oklch(0.879 0.169 91.605)",400:"oklch(0.828 0.189 84.429)",500:"oklch(0.769 0.188 70.08)",600:"oklch(0.666 0.179 58.318)",700:"oklch(0.555 0.163 48.998)",800:"oklch(0.473 0.137 46.201)",900:"oklch(0.414 0.112 45.904)",950:"oklch(0.279 0.077 45.635)"},yellow:{50:"oklch(0.987 0.026 102.212)",100:"oklch(0.973 0.071 103.193)",200:"oklch(0.945 0.129 101.54)",300:"oklch(0.905 0.182 98.111)",400:"oklch(0.852 0.199 91.936)",500:"oklch(0.795 0.184 86.047)",600:"oklch(0.681 0.162 75.834)",700:"oklch(0.554 0.135 66.442)",800:"oklch(0.476 0.114 61.907)",900:"oklch(0.421 0.095 57.708)",950:"oklch(0.286 0.066 53.813)"},lime:{50:"oklch(0.986 0.031 120.757)",100:"oklch(0.967 0.067 122.328)",200:"oklch(0.938 0.127 124.321)",300:"oklch(0.897 0.196 126.665)",400:"oklch(0.841 0.238 128.85)",500:"oklch(0.768 0.233 130.85)",600:"oklch(0.648 0.2 131.684)",700:"oklch(0.532 0.157 131.589)",800:"oklch(0.453 0.124 130.933)",900:"oklch(0.405 0.101 131.063)",950:"oklch(0.274 0.072 132.109)"},green:{50:"oklch(0.982 0.018 155.826)",100:"oklch(0.962 0.044 156.743)",200:"oklch(0.925 0.084 155.995)",300:"oklch(0.871 0.15 154.449)",400:"oklch(0.792 0.209 151.711)",500:"oklch(0.723 0.219 149.579)",600:"oklch(0.627 0.194 149.214)",700:"oklch(0.527 0.154 150.069)",800:"oklch(0.448 0.119 151.328)",900:"oklch(0.393 0.095 152.535)",950:"oklch(0.266 0.065 152.934)"},emerald:{50:"oklch(0.979 0.021 166.113)",100:"oklch(0.95 0.052 163.051)",200:"oklch(0.905 0.093 164.15)",300:"oklch(0.845 0.143 164.978)",400:"oklch(0.765 0.177 163.223)",500:"oklch(0.696 0.17 162.48)",600:"oklch(0.596 0.145 163.225)",700:"oklch(0.508 0.118 165.612)",800:"oklch(0.432 0.095 166.913)",900:"oklch(0.378 0.077 168.94)",950:"oklch(0.262 0.051 172.552)"},teal:{50:"oklch(0.984 0.014 180.72)",100:"oklch(0.953 0.051 180.801)",200:"oklch(0.91 0.096 180.426)",300:"oklch(0.855 0.138 181.071)",400:"oklch(0.777 0.152 181.912)",500:"oklch(0.704 0.14 182.503)",600:"oklch(0.6 0.118 184.704)",700:"oklch(0.511 0.096 186.391)",800:"oklch(0.437 0.078 188.216)",900:"oklch(0.386 0.063 188.416)",950:"oklch(0.277 0.046 192.524)"},cyan:{50:"oklch(0.984 0.019 200.873)",100:"oklch(0.956 0.045 203.388)",200:"oklch(0.917 0.08 205.041)",300:"oklch(0.865 0.127 207.078)",400:"oklch(0.789 0.154 211.53)",500:"oklch(0.715 0.143 215.221)",600:"oklch(0.609 0.126 221.723)",700:"oklch(0.52 0.105 223.128)",800:"oklch(0.45 0.085 224.283)",900:"oklch(0.398 0.07 227.392)",950:"oklch(0.302 0.056 229.695)"},sky:{50:"oklch(0.977 0.013 236.62)",100:"oklch(0.951 0.026 236.824)",200:"oklch(0.901 0.058 230.902)",300:"oklch(0.828 0.111 230.318)",400:"oklch(0.746 0.16 232.661)",500:"oklch(0.685 0.169 237.323)",600:"oklch(0.588 0.158 241.966)",700:"oklch(0.5 0.134 242.749)",800:"oklch(0.443 0.11 240.79)",900:"oklch(0.391 0.09 240.876)",950:"oklch(0.293 0.066 243.157)"},blue:{50:"oklch(0.97 0.014 254.604)",100:"oklch(0.932 0.032 255.585)",200:"oklch(0.882 0.059 254.128)",300:"oklch(0.809 0.105 251.813)",400:"oklch(0.707 0.165 254.624)",500:"oklch(0.623 0.214 259.815)",600:"oklch(0.546 0.245 262.881)",700:"oklch(0.488 0.243 264.376)",800:"oklch(0.424 0.199 265.638)",900:"oklch(0.379 0.146 265.522)",950:"oklch(0.282 0.091 267.935)"},indigo:{50:"oklch(0.962 0.018 272.314)",100:"oklch(0.93 0.034 272.788)",200:"oklch(0.87 0.065 274.039)",300:"oklch(0.785 0.115 274.713)",400:"oklch(0.673 0.182 276.935)",500:"oklch(0.585 0.233 277.117)",600:"oklch(0.511 0.262 276.966)",700:"oklch(0.457 0.24 277.023)",800:"oklch(0.398 0.195 277.366)",900:"oklch(0.359 0.144 278.697)",950:"oklch(0.257 0.09 281.288)"},violet:{50:"oklch(0.969 0.016 293.756)",100:"oklch(0.943 0.029 294.588)",200:"oklch(0.894 0.057 293.283)",300:"oklch(0.811 0.111 293.571)",400:"oklch(0.702 0.183 293.541)",500:"oklch(0.606 0.25 292.717)",600:"oklch(0.541 0.281 293.009)",700:"oklch(0.491 0.27 292.581)",800:"oklch(0.432 0.232 292.759)",900:"oklch(0.38 0.189 293.745)",950:"oklch(0.283 0.141 291.089)"},purple:{50:"oklch(0.977 0.014 308.299)",100:"oklch(0.946 0.033 307.174)",200:"oklch(0.902 0.063 306.703)",300:"oklch(0.827 0.119 306.383)",400:"oklch(0.714 0.203 305.504)",500:"oklch(0.627 0.265 303.9)",600:"oklch(0.558 0.288 302.321)",700:"oklch(0.496 0.265 301.924)",800:"oklch(0.438 0.218 303.724)",900:"oklch(0.381 0.176 304.987)",950:"oklch(0.291 0.149 302.717)"},fuchsia:{50:"oklch(0.977 0.017 320.058)",100:"oklch(0.952 0.037 318.852)",200:"oklch(0.903 0.076 319.62)",300:"oklch(0.833 0.145 321.434)",400:"oklch(0.74 0.238 322.16)",500:"oklch(0.667 0.295 322.15)",600:"oklch(0.591 0.293 322.896)",700:"oklch(0.518 0.253 323.949)",800:"oklch(0.452 0.211 324.591)",900:"oklch(0.401 0.17 325.612)",950:"oklch(0.293 0.136 325.661)"},pink:{50:"oklch(0.971 0.014 343.198)",100:"oklch(0.948 0.028 342.258)",200:"oklch(0.899 0.061 343.231)",300:"oklch(0.823 0.12 346.018)",400:"oklch(0.718 0.202 349.761)",500:"oklch(0.656 0.241 354.308)",600:"oklch(0.592 0.249 0.584)",700:"oklch(0.525 0.223 3.958)",800:"oklch(0.459 0.187 3.815)",900:"oklch(0.408 0.153 2.432)",950:"oklch(0.284 0.109 3.907)"},rose:{50:"oklch(0.969 0.015 12.422)",100:"oklch(0.941 0.03 12.58)",200:"oklch(0.892 0.058 10.001)",300:"oklch(0.81 0.117 11.638)",400:"oklch(0.712 0.194 13.428)",500:"oklch(0.645 0.246 16.439)",600:"oklch(0.586 0.253 17.585)",700:"oklch(0.514 0.222 16.935)",800:"oklch(0.455 0.188 13.697)",900:"oklch(0.41 0.159 10.272)",950:"oklch(0.271 0.105 12.094)"}};function de(t){return{__BARE_VALUE__:t}}var J=de(t=>{if(V(t.value))return t.value}),B=de(t=>{if(V(t.value))return`${t.value}%`}),ie=de(t=>{if(V(t.value))return`${t.value}px`}),Rr=de(t=>{if(V(t.value))return`${t.value}ms`}),Ze=de(t=>{if(V(t.value))return`${t.value}deg`}),hi=de(t=>{if(t.fraction===null)return;let[r,n]=P(t.fraction,"/");if(!(!V(r)||!V(n)))return t.fraction}),Or=de(t=>{if(V(Number(t.value)))return`repeat(${t.value}, minmax(0, 1fr))`}),Kr={accentColor:({theme:t})=>t("colors"),animation:{none:"none",spin:"spin 1s linear infinite",ping:"ping 1s cubic-bezier(0, 0, 0.2, 1) infinite",pulse:"pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",bounce:"bounce 1s infinite"},aria:{busy:'busy="true"',checked:'checked="true"',disabled:'disabled="true"',expanded:'expanded="true"',hidden:'hidden="true"',pressed:'pressed="true"',readonly:'readonly="true"',required:'required="true"',selected:'selected="true"'},aspectRatio:{auto:"auto",square:"1 / 1",video:"16 / 9",...hi},backdropBlur:({theme:t})=>t("blur"),backdropBrightness:({theme:t})=>({...t("brightness"),...B}),backdropContrast:({theme:t})=>({...t("contrast"),...B}),backdropGrayscale:({theme:t})=>({...t("grayscale"),...B}),backdropHueRotate:({theme:t})=>({...t("hueRotate"),...Ze}),backdropInvert:({theme:t})=>({...t("invert"),...B}),backdropOpacity:({theme:t})=>({...t("opacity"),...B}),backdropSaturate:({theme:t})=>({...t("saturate"),...B}),backdropSepia:({theme:t})=>({...t("sepia"),...B}),backgroundColor:({theme:t})=>t("colors"),backgroundImage:{none:"none","gradient-to-t":"linear-gradient(to top, var(--tw-gradient-stops))","gradient-to-tr":"linear-gradient(to top right, var(--tw-gradient-stops))","gradient-to-r":"linear-gradient(to right, var(--tw-gradient-stops))","gradient-to-br":"linear-gradient(to bottom right, var(--tw-gradient-stops))","gradient-to-b":"linear-gradient(to bottom, var(--tw-gradient-stops))","gradient-to-bl":"linear-gradient(to bottom left, var(--tw-gradient-stops))","gradient-to-l":"linear-gradient(to left, var(--tw-gradient-stops))","gradient-to-tl":"linear-gradient(to top left, var(--tw-gradient-stops))"},backgroundOpacity:({theme:t})=>t("opacity"),backgroundPosition:{bottom:"bottom",center:"center",left:"left","left-bottom":"left bottom","left-top":"left top",right:"right","right-bottom":"right bottom","right-top":"right top",top:"top"},backgroundSize:{auto:"auto",cover:"cover",contain:"contain"},blur:{0:"0",none:"",sm:"4px",DEFAULT:"8px",md:"12px",lg:"16px",xl:"24px","2xl":"40px","3xl":"64px"},borderColor:({theme:t})=>({DEFAULT:"currentColor",...t("colors")}),borderOpacity:({theme:t})=>t("opacity"),borderRadius:{none:"0px",sm:"0.125rem",DEFAULT:"0.25rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem","3xl":"1.5rem",full:"9999px"},borderSpacing:({theme:t})=>t("spacing"),borderWidth:{DEFAULT:"1px",0:"0px",2:"2px",4:"4px",8:"8px",...ie},boxShadow:{sm:"0 1px 2px 0 rgb(0 0 0 / 0.05)",DEFAULT:"0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",md:"0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",lg:"0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",xl:"0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)","2xl":"0 25px 50px -12px rgb(0 0 0 / 0.25)",inner:"inset 0 2px 4px 0 rgb(0 0 0 / 0.05)",none:"none"},boxShadowColor:({theme:t})=>t("colors"),brightness:{0:"0",50:".5",75:".75",90:".9",95:".95",100:"1",105:"1.05",110:"1.1",125:"1.25",150:"1.5",200:"2",...B},caretColor:({theme:t})=>t("colors"),colors:()=>({...Je}),columns:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12","3xs":"16rem","2xs":"18rem",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem",...J},container:{},content:{none:"none"},contrast:{0:"0",50:".5",75:".75",100:"1",125:"1.25",150:"1.5",200:"2",...B},cursor:{auto:"auto",default:"default",pointer:"pointer",wait:"wait",text:"text",move:"move",help:"help","not-allowed":"not-allowed",none:"none","context-menu":"context-menu",progress:"progress",cell:"cell",crosshair:"crosshair","vertical-text":"vertical-text",alias:"alias",copy:"copy","no-drop":"no-drop",grab:"grab",grabbing:"grabbing","all-scroll":"all-scroll","col-resize":"col-resize","row-resize":"row-resize","n-resize":"n-resize","e-resize":"e-resize","s-resize":"s-resize","w-resize":"w-resize","ne-resize":"ne-resize","nw-resize":"nw-resize","se-resize":"se-resize","sw-resize":"sw-resize","ew-resize":"ew-resize","ns-resize":"ns-resize","nesw-resize":"nesw-resize","nwse-resize":"nwse-resize","zoom-in":"zoom-in","zoom-out":"zoom-out"},divideColor:({theme:t})=>t("borderColor"),divideOpacity:({theme:t})=>t("borderOpacity"),divideWidth:({theme:t})=>({...t("borderWidth"),...ie}),dropShadow:{sm:"0 1px 1px rgb(0 0 0 / 0.05)",DEFAULT:["0 1px 2px rgb(0 0 0 / 0.1)","0 1px 1px rgb(0 0 0 / 0.06)"],md:["0 4px 3px rgb(0 0 0 / 0.07)","0 2px 2px rgb(0 0 0 / 0.06)"],lg:["0 10px 8px rgb(0 0 0 / 0.04)","0 4px 3px rgb(0 0 0 / 0.1)"],xl:["0 20px 13px rgb(0 0 0 / 0.03)","0 8px 5px rgb(0 0 0 / 0.08)"],"2xl":"0 25px 25px rgb(0 0 0 / 0.15)",none:"0 0 #0000"},fill:({theme:t})=>t("colors"),flex:{1:"1 1 0%",auto:"1 1 auto",initial:"0 1 auto",none:"none"},flexBasis:({theme:t})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",...t("spacing")}),flexGrow:{0:"0",DEFAULT:"1",...J},flexShrink:{0:"0",DEFAULT:"1",...J},fontFamily:{sans:["ui-sans-serif","system-ui","sans-serif",'"Apple Color Emoji"','"Segoe UI Emoji"','"Segoe UI Symbol"','"Noto Color Emoji"'],serif:["ui-serif","Georgia","Cambria",'"Times New Roman"',"Times","serif"],mono:["ui-monospace","SFMono-Regular","Menlo","Monaco","Consolas",'"Liberation Mono"','"Courier New"',"monospace"]},fontSize:{xs:["0.75rem",{lineHeight:"1rem"}],sm:["0.875rem",{lineHeight:"1.25rem"}],base:["1rem",{lineHeight:"1.5rem"}],lg:["1.125rem",{lineHeight:"1.75rem"}],xl:["1.25rem",{lineHeight:"1.75rem"}],"2xl":["1.5rem",{lineHeight:"2rem"}],"3xl":["1.875rem",{lineHeight:"2.25rem"}],"4xl":["2.25rem",{lineHeight:"2.5rem"}],"5xl":["3rem",{lineHeight:"1"}],"6xl":["3.75rem",{lineHeight:"1"}],"7xl":["4.5rem",{lineHeight:"1"}],"8xl":["6rem",{lineHeight:"1"}],"9xl":["8rem",{lineHeight:"1"}]},fontWeight:{thin:"100",extralight:"200",light:"300",normal:"400",medium:"500",semibold:"600",bold:"700",extrabold:"800",black:"900"},gap:({theme:t})=>t("spacing"),gradientColorStops:({theme:t})=>t("colors"),gradientColorStopPositions:{"0%":"0%","5%":"5%","10%":"10%","15%":"15%","20%":"20%","25%":"25%","30%":"30%","35%":"35%","40%":"40%","45%":"45%","50%":"50%","55%":"55%","60%":"60%","65%":"65%","70%":"70%","75%":"75%","80%":"80%","85%":"85%","90%":"90%","95%":"95%","100%":"100%",...B},grayscale:{0:"0",DEFAULT:"100%",...B},gridAutoColumns:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0, 1fr)"},gridAutoRows:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0, 1fr)"},gridColumn:{auto:"auto","span-1":"span 1 / span 1","span-2":"span 2 / span 2","span-3":"span 3 / span 3","span-4":"span 4 / span 4","span-5":"span 5 / span 5","span-6":"span 6 / span 6","span-7":"span 7 / span 7","span-8":"span 8 / span 8","span-9":"span 9 / span 9","span-10":"span 10 / span 10","span-11":"span 11 / span 11","span-12":"span 12 / span 12","span-full":"1 / -1"},gridColumnEnd:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...J},gridColumnStart:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...J},gridRow:{auto:"auto","span-1":"span 1 / span 1","span-2":"span 2 / span 2","span-3":"span 3 / span 3","span-4":"span 4 / span 4","span-5":"span 5 / span 5","span-6":"span 6 / span 6","span-7":"span 7 / span 7","span-8":"span 8 / span 8","span-9":"span 9 / span 9","span-10":"span 10 / span 10","span-11":"span 11 / span 11","span-12":"span 12 / span 12","span-full":"1 / -1"},gridRowEnd:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...J},gridRowStart:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...J},gridTemplateColumns:{none:"none",subgrid:"subgrid",1:"repeat(1, minmax(0, 1fr))",2:"repeat(2, minmax(0, 1fr))",3:"repeat(3, minmax(0, 1fr))",4:"repeat(4, minmax(0, 1fr))",5:"repeat(5, minmax(0, 1fr))",6:"repeat(6, minmax(0, 1fr))",7:"repeat(7, minmax(0, 1fr))",8:"repeat(8, minmax(0, 1fr))",9:"repeat(9, minmax(0, 1fr))",10:"repeat(10, minmax(0, 1fr))",11:"repeat(11, minmax(0, 1fr))",12:"repeat(12, minmax(0, 1fr))",...Or},gridTemplateRows:{none:"none",subgrid:"subgrid",1:"repeat(1, minmax(0, 1fr))",2:"repeat(2, minmax(0, 1fr))",3:"repeat(3, minmax(0, 1fr))",4:"repeat(4, minmax(0, 1fr))",5:"repeat(5, minmax(0, 1fr))",6:"repeat(6, minmax(0, 1fr))",7:"repeat(7, minmax(0, 1fr))",8:"repeat(8, minmax(0, 1fr))",9:"repeat(9, minmax(0, 1fr))",10:"repeat(10, minmax(0, 1fr))",11:"repeat(11, minmax(0, 1fr))",12:"repeat(12, minmax(0, 1fr))",...Or},height:({theme:t})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%",full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...t("spacing")}),hueRotate:{0:"0deg",15:"15deg",30:"30deg",60:"60deg",90:"90deg",180:"180deg",...Ze},inset:({theme:t})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%",full:"100%",...t("spacing")}),invert:{0:"0",DEFAULT:"100%",...B},keyframes:{spin:{to:{transform:"rotate(360deg)"}},ping:{"75%, 100%":{transform:"scale(2)",opacity:"0"}},pulse:{"50%":{opacity:".5"}},bounce:{"0%, 100%":{transform:"translateY(-25%)",animationTimingFunction:"cubic-bezier(0.8,0,1,1)"},"50%":{transform:"none",animationTimingFunction:"cubic-bezier(0,0,0.2,1)"}}},letterSpacing:{tighter:"-0.05em",tight:"-0.025em",normal:"0em",wide:"0.025em",wider:"0.05em",widest:"0.1em"},lineHeight:{none:"1",tight:"1.25",snug:"1.375",normal:"1.5",relaxed:"1.625",loose:"2",3:".75rem",4:"1rem",5:"1.25rem",6:"1.5rem",7:"1.75rem",8:"2rem",9:"2.25rem",10:"2.5rem"},listStyleType:{none:"none",disc:"disc",decimal:"decimal"},listStyleImage:{none:"none"},margin:({theme:t})=>({auto:"auto",...t("spacing")}),lineClamp:{1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",...J},maxHeight:({theme:t})=>({none:"none",full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...t("spacing")}),maxWidth:({theme:t})=>({none:"none",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",prose:"65ch",...t("spacing")}),minHeight:({theme:t})=>({full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...t("spacing")}),minWidth:({theme:t})=>({full:"100%",min:"min-content",max:"max-content",fit:"fit-content",...t("spacing")}),objectPosition:{bottom:"bottom",center:"center",left:"left","left-bottom":"left bottom","left-top":"left top",right:"right","right-bottom":"right bottom","right-top":"right top",top:"top"},opacity:{0:"0",5:"0.05",10:"0.1",15:"0.15",20:"0.2",25:"0.25",30:"0.3",35:"0.35",40:"0.4",45:"0.45",50:"0.5",55:"0.55",60:"0.6",65:"0.65",70:"0.7",75:"0.75",80:"0.8",85:"0.85",90:"0.9",95:"0.95",100:"1",...B},order:{first:"-9999",last:"9999",none:"0",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",...J},outlineColor:({theme:t})=>t("colors"),outlineOffset:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...ie},outlineWidth:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...ie},padding:({theme:t})=>t("spacing"),placeholderColor:({theme:t})=>t("colors"),placeholderOpacity:({theme:t})=>t("opacity"),ringColor:({theme:t})=>({DEFAULT:"currentColor",...t("colors")}),ringOffsetColor:({theme:t})=>t("colors"),ringOffsetWidth:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...ie},ringOpacity:({theme:t})=>({DEFAULT:"0.5",...t("opacity")}),ringWidth:{DEFAULT:"3px",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...ie},rotate:{0:"0deg",1:"1deg",2:"2deg",3:"3deg",6:"6deg",12:"12deg",45:"45deg",90:"90deg",180:"180deg",...Ze},saturate:{0:"0",50:".5",100:"1",150:"1.5",200:"2",...B},scale:{0:"0",50:".5",75:".75",90:".9",95:".95",100:"1",105:"1.05",110:"1.1",125:"1.25",150:"1.5",...B},screens:{sm:"40rem",md:"48rem",lg:"64rem",xl:"80rem","2xl":"96rem"},scrollMargin:({theme:t})=>t("spacing"),scrollPadding:({theme:t})=>t("spacing"),sepia:{0:"0",DEFAULT:"100%",...B},skew:{0:"0deg",1:"1deg",2:"2deg",3:"3deg",6:"6deg",12:"12deg",...Ze},space:({theme:t})=>t("spacing"),spacing:{px:"1px",0:"0px",.5:"0.125rem",1:"0.25rem",1.5:"0.375rem",2:"0.5rem",2.5:"0.625rem",3:"0.75rem",3.5:"0.875rem",4:"1rem",5:"1.25rem",6:"1.5rem",7:"1.75rem",8:"2rem",9:"2.25rem",10:"2.5rem",11:"2.75rem",12:"3rem",14:"3.5rem",16:"4rem",20:"5rem",24:"6rem",28:"7rem",32:"8rem",36:"9rem",40:"10rem",44:"11rem",48:"12rem",52:"13rem",56:"14rem",60:"15rem",64:"16rem",72:"18rem",80:"20rem",96:"24rem"},stroke:({theme:t})=>({none:"none",...t("colors")}),strokeWidth:{0:"0",1:"1",2:"2",...J},supports:{},data:{},textColor:({theme:t})=>t("colors"),textDecorationColor:({theme:t})=>t("colors"),textDecorationThickness:{auto:"auto","from-font":"from-font",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...ie},textIndent:({theme:t})=>t("spacing"),textOpacity:({theme:t})=>t("opacity"),textUnderlineOffset:{auto:"auto",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...ie},transformOrigin:{center:"center",top:"top","top-right":"top right",right:"right","bottom-right":"bottom right",bottom:"bottom","bottom-left":"bottom left",left:"left","top-left":"top left"},transitionDelay:{0:"0s",75:"75ms",100:"100ms",150:"150ms",200:"200ms",300:"300ms",500:"500ms",700:"700ms",1e3:"1000ms",...Rr},transitionDuration:{DEFAULT:"150ms",0:"0s",75:"75ms",100:"100ms",150:"150ms",200:"200ms",300:"300ms",500:"500ms",700:"700ms",1e3:"1000ms",...Rr},transitionProperty:{none:"none",all:"all",DEFAULT:"color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter",colors:"color, background-color, border-color, outline-color, text-decoration-color, fill, stroke",opacity:"opacity",shadow:"box-shadow",transform:"transform"},transitionTimingFunction:{DEFAULT:"cubic-bezier(0.4, 0, 0.2, 1)",linear:"linear",in:"cubic-bezier(0.4, 0, 1, 1)",out:"cubic-bezier(0, 0, 0.2, 1)","in-out":"cubic-bezier(0.4, 0, 0.2, 1)"},translate:({theme:t})=>({"1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%",full:"100%",...t("spacing")}),size:({theme:t})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",...t("spacing")}),width:({theme:t})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",screen:"100vw",svw:"100svw",lvw:"100lvw",dvw:"100dvw",min:"min-content",max:"max-content",fit:"fit-content",...t("spacing")}),willChange:{auto:"auto",scroll:"scroll-position",contents:"contents",transform:"transform"},zIndex:{auto:"auto",0:"0",10:"10",20:"20",30:"30",40:"40",50:"50",...J}};function Pr(t){return{theme:{...Kr,colors:({theme:r})=>r("color",{}),extend:{fontSize:({theme:r})=>({...r("text",{})}),boxShadow:({theme:r})=>({...r("shadow",{})}),animation:({theme:r})=>({...r("animate",{})}),aspectRatio:({theme:r})=>({...r("aspect",{})}),borderRadius:({theme:r})=>({...r("radius",{})}),screens:({theme:r})=>({...r("breakpoint",{})}),letterSpacing:({theme:r})=>({...r("tracking",{})}),lineHeight:({theme:r})=>({...r("leading",{})}),transitionDuration:{DEFAULT:t.get(["--default-transition-duration"])??null},transitionTimingFunction:{DEFAULT:t.get(["--default-transition-timing-function"])??null},maxWidth:({theme:r})=>({...r("container",{})})}}}}var vi={blocklist:[],future:{},prefix:"",important:!1,darkMode:null,theme:{},plugins:[],content:{files:[]}};function wt(t,r){let n={design:t,configs:[],plugins:[],content:{files:[]},theme:{},extend:{},result:structuredClone(vi)};for(let i of r)bt(n,i);for(let i of n.configs)"darkMode"in i&&i.darkMode!==void 0&&(n.result.darkMode=i.darkMode??null),"prefix"in i&&i.prefix!==void 0&&(n.result.prefix=i.prefix??""),"blocklist"in i&&i.blocklist!==void 0&&(n.result.blocklist=i.blocklist??[]),"important"in i&&i.important!==void 0&&(n.result.important=i.important??!1);let e=bi(n);return{resolvedConfig:{...n.result,content:n.content,theme:n.theme,plugins:n.plugins},replacedThemeKeys:e}}function yi(t,r){if(Array.isArray(t)&&be(t[0]))return t.concat(r);if(Array.isArray(r)&&be(r[0])&&be(t))return[t,...r];if(Array.isArray(r))return r}function bt(t,{config:r,base:n,path:e,reference:i}){let s=[];for(let c of r.plugins??[])"__isOptionsFunction"in c?s.push({...c(),reference:i}):"handler"in c?s.push({...c,reference:i}):s.push({handler:c,reference:i});if(Array.isArray(r.presets)&&r.presets.length===0)throw new Error("Error in the config file/plugin/preset. An empty preset (`preset: []`) is not currently supported.");for(let c of r.presets??[])bt(t,{path:e,base:n,config:c,reference:i});for(let c of s)t.plugins.push(c),c.config&&bt(t,{path:e,base:n,config:c.config,reference:!!c.reference});let l=r.content??[],p=Array.isArray(l)?l:l.files;for(let c of p)t.content.files.push(typeof c=="object"?c:{base:n,pattern:c});t.configs.push(r)}function bi(t){let r=new Set,n=Ge(t.design,()=>t.theme,i),e=Object.assign(n,{theme:n,colors:Je});function i(s){return typeof s=="function"?s(e)??null:s??null}for(let s of t.configs){let l=s.theme??{},p=l.extend??{};for(let c in l)c!=="extend"&&r.add(c);Object.assign(t.theme,l);for(let c in p)t.extend[c]??=[],t.extend[c].push(p[c])}delete t.theme.extend;for(let s in t.extend){let l=[t.theme[s],...t.extend[s]];t.theme[s]=()=>{let p=l.map(i);return Ve({},p,yi)}}for(let s in t.theme)t.theme[s]=i(t.theme[s]);if(t.theme.screens&&typeof t.theme.screens=="object")for(let s of Object.keys(t.theme.screens)){let l=t.theme.screens[s];l&&typeof l=="object"&&("raw"in l||"max"in l||"min"in l&&(t.theme.screens[s]=l.min))}return r}function _r(t,r){let n=t.theme.container||{};if(typeof n!="object"||n===null)return;let e=wi(n,r);e.length!==0&&r.utilities.static("container",()=>structuredClone(e))}function wi({center:t,padding:r,screens:n},e){let i=[],s=null;if(t&&i.push(a("margin-inline","auto")),(typeof r=="string"||typeof r=="object"&&r!==null&&"DEFAULT"in r)&&i.push(a("padding-inline",typeof r=="string"?r:r.DEFAULT)),typeof n=="object"&&n!==null){s=new Map;let l=Array.from(e.theme.namespace("--breakpoint").entries());if(l.sort((p,c)=>ue(p[1],c[1],"asc")),l.length>0){let[p]=l[0];i.push(D("@media",`(width >= --theme(--breakpoint-${p}))`,[a("max-width","none")]))}for(let[p,c]of Object.entries(n)){if(typeof c=="object")if("min"in c)c=c.min;else continue;s.set(p,D("@media",`(width >= ${c})`,[a("max-width",c)]))}}if(typeof r=="object"&&r!==null){let l=Object.entries(r).filter(([p])=>p!=="DEFAULT").map(([p,c])=>[p,e.theme.resolveValue(p,["--breakpoint"]),c]).filter(Boolean);l.sort((p,c)=>ue(p[1],c[1],"asc"));for(let[p,,c]of l)if(s&&s.has(p))s.get(p).nodes.push(a("padding-inline",c));else{if(s)continue;i.push(D("@media",`(width >= theme(--breakpoint-${p}))`,[a("padding-inline",c)]))}}if(s)for(let[,l]of s)i.push(l);return i}function Dr({addVariant:t,config:r}){let n=r("darkMode",null),[e,i=".dark"]=Array.isArray(n)?n:[n];if(e==="variant"){let s;if(Array.isArray(i)||typeof i=="function"?s=i:typeof i=="string"&&(s=[i]),Array.isArray(s))for(let l of s)l===".dark"?(e=!1,console.warn('When using `variant` for `darkMode`, you must provide a selector.\nExample: `darkMode: ["variant", ".your-selector &"]`')):l.includes("&")||(e=!1,console.warn('When using `variant` for `darkMode`, your selector must contain `&`.\nExample `darkMode: ["variant", ".your-selector &"]`'));i=s}e===null||(e==="selector"?t("dark",`&:where(${i}, ${i} *)`):e==="media"?t("dark","@media (prefers-color-scheme: dark)"):e==="variant"?t("dark",i):e==="class"&&t("dark",`&:is(${i} *)`))}function Ur(t){for(let[r,n]of[["t","top"],["tr","top right"],["r","right"],["br","bottom right"],["b","bottom"],["bl","bottom left"],["l","left"],["tl","top left"]])t.utilities.static(`bg-gradient-to-${r}`,()=>[a("--tw-gradient-position",`to ${n} in oklab`),a("background-image","linear-gradient(var(--tw-gradient-stops))")]);t.utilities.functional("max-w-screen",r=>{if(!r.value||r.value.kind==="arbitrary")return;let n=t.theme.resolve(r.value.value,["--breakpoint"]);if(n)return[a("max-width",n)]}),t.utilities.static("overflow-ellipsis",()=>[a("text-overflow","ellipsis")]),t.utilities.static("decoration-slice",()=>[a("-webkit-box-decoration-break","slice"),a("box-decoration-break","slice")]),t.utilities.static("decoration-clone",()=>[a("-webkit-box-decoration-break","clone"),a("box-decoration-break","clone")]),t.utilities.functional("flex-shrink",r=>{if(!r.modifier){if(!r.value)return[a("flex-shrink","1")];if(r.value.kind==="arbitrary")return[a("flex-shrink",r.value.value)];if(V(r.value.value))return[a("flex-shrink",r.value.value)]}}),t.utilities.functional("flex-grow",r=>{if(!r.modifier){if(!r.value)return[a("flex-grow","1")];if(r.value.kind==="arbitrary")return[a("flex-grow",r.value.value)];if(V(r.value.value))return[a("flex-grow",r.value.value)]}})}function jr(t,r){let n=t.theme.screens||{},e=r.variants.get("min")?.order??0,i=[];for(let[l,p]of Object.entries(n)){let m=function(b){r.variants.static(l,y=>{y.nodes=[D("@media",g,y.nodes)]},{order:b})};var s=m;let c=r.variants.get(l),d=r.theme.resolveValue(l,["--breakpoint"]);if(c&&d&&!r.theme.hasDefault(`--breakpoint-${l}`))continue;let u=!0;typeof p=="string"&&(u=!1);let g=ki(p);u?i.push(m):m(e)}if(i.length!==0){for(let[,l]of r.variants.variants)l.order>e&&(l.order+=i.length);r.variants.compareFns=new Map(Array.from(r.variants.compareFns).map(([l,p])=>(l>e&&(l+=i.length),[l,p])));for(let[l,p]of i.entries())p(e+l+1)}}function ki(t){return(Array.isArray(t)?t:[t]).map(n=>typeof n=="string"?{min:n}:n&&typeof n=="object"?n:null).map(n=>{if(n===null)return null;if("raw"in n)return n.raw;let e="";return n.max!==void 0&&(e+=`${n.max} >= `),e+="width",n.min!==void 0&&(e+=` >= ${n.min}`),`(${e})`}).filter(Boolean).join(", ")}function Fr(t,r){let n=t.theme.aria||{},e=t.theme.supports||{},i=t.theme.data||{};if(Object.keys(n).length>0){let s=r.variants.get("aria"),l=s?.applyFn,p=s?.compounds;r.variants.functional("aria",(c,d)=>{let u=d.value;return u&&u.kind==="named"&&u.value in n?l?.(c,{...d,value:{kind:"arbitrary",value:n[u.value]}}):l?.(c,d)},{compounds:p})}if(Object.keys(e).length>0){let s=r.variants.get("supports"),l=s?.applyFn,p=s?.compounds;r.variants.functional("supports",(c,d)=>{let u=d.value;return u&&u.kind==="named"&&u.value in e?l?.(c,{...d,value:{kind:"arbitrary",value:e[u.value]}}):l?.(c,d)},{compounds:p})}if(Object.keys(i).length>0){let s=r.variants.get("data"),l=s?.applyFn,p=s?.compounds;r.variants.functional("data",(c,d)=>{let u=d.value;return u&&u.kind==="named"&&u.value in i?l?.(c,{...d,value:{kind:"arbitrary",value:i[u.value]}}):l?.(c,d)},{compounds:p})}}var xi=/^[a-z]+$/;async function zr({designSystem:t,base:r,ast:n,loadModule:e,globs:i}){let s=0,l=[],p=[];_(n,(g,{parent:m,replaceWith:b,context:y})=>{if(g.kind==="at-rule"){if(g.name==="@plugin"){if(m!==null)throw new Error("`@plugin` cannot be nested.");let v=g.params.slice(1,-1);if(v.length===0)throw new Error("`@plugin` must have a path.");let x={};for(let T of g.nodes??[]){if(T.kind!=="declaration")throw new Error(`Unexpected \`@plugin\` option: + +${G([T])} + +\`@plugin\` options must be a flat list of declarations.`);if(T.value===void 0)continue;let S=T.value,O=P(S,",").map(R=>{if(R=R.trim(),R==="null")return null;if(R==="true")return!0;if(R==="false")return!1;if(Number.isNaN(Number(R))){if(R[0]==='"'&&R[R.length-1]==='"'||R[0]==="'"&&R[R.length-1]==="'")return R.slice(1,-1);if(R[0]==="{"&&R[R.length-1]==="}")throw new Error(`Unexpected \`@plugin\` option: Value of declaration \`${G([T]).trim()}\` is not supported. + +Using an object as a plugin option is currently only supported in JavaScript configuration files.`)}else return Number(R);return R});x[T.property]=O.length===1?O[0]:O}l.push([{id:v,base:y.base,reference:!!y.reference},Object.keys(x).length>0?x:null]),b([]),s|=4;return}if(g.name==="@config"){if(g.nodes.length>0)throw new Error("`@config` cannot have a body.");if(m!==null)throw new Error("`@config` cannot be nested.");p.push({id:g.params.slice(1,-1),base:y.base,reference:!!y.reference}),b([]),s|=4;return}}}),Ur(t);let c=t.resolveThemeValue;if(t.resolveThemeValue=function(m){return m.startsWith("--")?c(m):(s|=Ir({designSystem:t,base:r,ast:n,globs:i,configs:[],pluginDetails:[]}),t.resolveThemeValue(m))},!l.length&&!p.length)return 0;let[d,u]=await Promise.all([Promise.all(p.map(async({id:g,base:m,reference:b})=>{let y=await e(g,m,"config");return{path:g,base:y.base,config:y.module,reference:b}})),Promise.all(l.map(async([{id:g,base:m,reference:b},y])=>{let v=await e(g,m,"plugin");return{path:g,base:v.base,plugin:v.module,options:y,reference:b}}))]);return s|=Ir({designSystem:t,base:r,ast:n,globs:i,configs:d,pluginDetails:u}),s}function Ir({designSystem:t,base:r,ast:n,globs:e,configs:i,pluginDetails:s}){let l=0,c=[...s.map(v=>{if(!v.options)return{config:{plugins:[v.plugin]},base:v.base,reference:v.reference};if("__isOptionsFunction"in v.plugin)return{config:{plugins:[v.plugin(v.options)]},base:v.base,reference:v.reference};throw new Error(`The plugin "${v.path}" does not accept options`)}),...i],{resolvedConfig:d}=wt(t,[{config:Pr(t.theme),base:r,reference:!0},...c,{config:{plugins:[Dr]},base:r,reference:!0}]),{resolvedConfig:u,replacedThemeKeys:g}=wt(t,c);t.resolveThemeValue=function(x,T){let S=b.theme(x,T);if(Array.isArray(S)&&S.length===2)return S[0];if(Array.isArray(S))return S.join(", ");if(typeof S=="string")return S};let m={designSystem:t,ast:n,resolvedConfig:d,featuresRef:{set current(v){l|=v}}},b=yt({...m,referenceMode:!1}),y;for(let{handler:v,reference:x}of d.plugins)x?(y||=yt({...m,referenceMode:!0}),v(y)):v(b);if(dr(t,u,g),Er(t,u,g),Fr(u,t),jr(u,t),_r(u,t),!t.theme.prefix&&d.prefix){if(d.prefix.endsWith("-")&&(d.prefix=d.prefix.slice(0,-1),console.warn(`The prefix "${d.prefix}" is invalid. Prefixes must be lowercase ASCII letters (a-z) only and is written as a variant before all utilities. We have fixed up the prefix for you. Remove the trailing \`-\` to silence this warning.`)),!xi.test(d.prefix))throw new Error(`The prefix "${d.prefix}" is invalid. Prefixes must be lowercase ASCII letters (a-z) only.`);t.theme.prefix=d.prefix}if(!t.important&&d.important===!0&&(t.important=!0),typeof d.important=="string"){let v=d.important;_(n,(x,{replaceWith:T,parent:S})=>{if(x.kind==="at-rule"&&!(x.name!=="@tailwind"||x.params!=="utilities"))return S?.kind==="rule"&&S.selector===v?2:(T(j(v,[x])),2)})}for(let v of d.blocklist)t.invalidCandidates.add(v);for(let v of d.content.files){if("raw"in v)throw new Error(`Error in the config file/plugin/preset. The \`content\` key contains a \`raw\` entry: + +${JSON.stringify(v,null,2)} + +This feature is not currently supported.`);e.push(v)}return l}var Ai=/^[a-z]+$/;function Ci(){throw new Error("No `loadModule` function provided to `compile`")}function Ni(){throw new Error("No `loadStylesheet` function provided to `compile`")}function $i(t){let r=0,n=null;for(let e of P(t," "))e==="reference"?r|=2:e==="inline"?r|=1:e==="default"?r|=4:e==="static"?r|=8:e.startsWith("prefix(")&&e.endsWith(")")&&(n=e.slice(7,-1));return[r,n]}var he=(p=>(p[p.None=0]="None",p[p.AtApply=1]="AtApply",p[p.AtImport=2]="AtImport",p[p.JsPluginCompat=4]="JsPluginCompat",p[p.ThemeFunction=8]="ThemeFunction",p[p.Utilities=16]="Utilities",p[p.Variants=32]="Variants",p))(he||{});async function Lr(t,{base:r="",loadModule:n=Ci,loadStylesheet:e=Ni}={}){let i=0;t=[Z({base:r},t)],i|=await vt(t,r,e);let s=null,l=new je,p=[],c=[],d=null,u=null,g=[],m=[],b=null;_(t,(v,{parent:x,replaceWith:T,context:S})=>{if(v.kind==="at-rule"){if(v.name==="@tailwind"&&(v.params==="utilities"||v.params.startsWith("utilities"))){if(u!==null){T([]);return}let O=P(v.params," ");for(let R of O)if(R.startsWith("source(")){let K=R.slice(7,-1);if(K==="none"){b=K;continue}if(K[0]==='"'&&K[K.length-1]!=='"'||K[0]==="'"&&K[K.length-1]!=="'"||K[0]!=="'"&&K[0]!=='"')throw new Error("`source(\u2026)` paths must be quoted.");b={base:S.sourceBase??S.base,pattern:K.slice(1,-1)}}u=v,i|=16}if(v.name==="@utility"){if(x!==null)throw new Error("`@utility` cannot be nested.");if(v.nodes.length===0)throw new Error(`\`@utility ${v.params}\` is empty. Utilities should include at least one property.`);let O=Qt(v);if(O===null)throw new Error(`\`@utility ${v.params}\` defines an invalid utility name. Utilities should be alphanumeric and start with a lowercase letter.`);c.push(O)}if(v.name==="@source"){if(v.nodes.length>0)throw new Error("`@source` cannot have a body.");if(x!==null)throw new Error("`@source` cannot be nested.");let O=v.params;if(O[0]==='"'&&O[O.length-1]!=='"'||O[0]==="'"&&O[O.length-1]!=="'"||O[0]!=="'"&&O[0]!=='"')throw new Error("`@source` paths must be quoted.");m.push({base:S.base,pattern:O.slice(1,-1)}),T([]);return}if(v.name==="@variant"&&(x===null?v.nodes.length===0?v.name="@custom-variant":(_(v.nodes,O=>{if(O.kind==="at-rule"&&O.name==="@slot")return v.name="@custom-variant",2}),v.name==="@variant"&&g.push(v)):g.push(v)),v.name==="@custom-variant"){if(x!==null)throw new Error("`@custom-variant` cannot be nested.");T([]);let[O,R]=P(v.params," ");if(!Be.test(O))throw new Error(`\`@custom-variant ${O}\` defines an invalid variant name. Variants should only contain alphanumeric, dashes or underscore characters.`);if(v.nodes.length>0&&R)throw new Error(`\`@custom-variant ${O}\` cannot have both a selector and a body.`);if(v.nodes.length===0){if(!R)throw new Error(`\`@custom-variant ${O}\` has no selector or body.`);let K=P(R.slice(1,-1),",");if(K.length===0||K.some(h=>h.trim()===""))throw new Error(`\`@custom-variant ${O} (${K.join(",")})\` selector is invalid.`);let o=[],f=[];for(let h of K)h=h.trim(),h[0]==="@"?o.push(h):f.push(h);p.push(h=>{h.variants.static(O,k=>{let w=[];f.length>0&&w.push(j(f.join(", "),k.nodes));for(let $ of o)w.push(M($,k.nodes));k.nodes=w},{compounds:fe([...f,...o])})});return}else{p.push(K=>{K.variants.fromAst(O,v.nodes)});return}}if(v.name==="@media"){let O=P(v.params," "),R=[];for(let K of O)if(K.startsWith("source(")){let o=K.slice(7,-1);_(v.nodes,(f,{replaceWith:h})=>{if(f.kind==="at-rule"&&f.name==="@tailwind"&&f.params==="utilities")return f.params+=` source(${o})`,h([Z({sourceBase:S.base},[f])]),2})}else if(K.startsWith("theme(")){let o=K.slice(6,-1),f=o.includes("reference");_(v.nodes,h=>{if(h.kind!=="at-rule"){if(f)throw new Error('Files imported with `@import "\u2026" theme(reference)` must only contain `@theme` blocks.\nUse `@reference "\u2026";` instead.');return 0}if(h.name==="@theme")return h.params+=" "+o,1})}else if(K.startsWith("prefix(")){let o=K.slice(7,-1);_(v.nodes,f=>{if(f.kind==="at-rule"&&f.name==="@theme")return f.params+=` prefix(${o})`,1})}else K==="important"?s=!0:K==="reference"?v.nodes=[Z({reference:!0},v.nodes)]:R.push(K);R.length>0?v.params=R.join(" "):O.length>0&&T(v.nodes)}if(v.name==="@theme"){let[O,R]=$i(v.params);if(S.reference&&(O|=2),R){if(!Ai.test(R))throw new Error(`The prefix "${R}" is invalid. Prefixes must be lowercase ASCII letters (a-z) only.`);l.prefix=R}return _(v.nodes,K=>{if(K.kind==="at-rule"&&K.name==="@keyframes")return l.addKeyframes(K),1;if(K.kind==="comment")return;if(K.kind==="declaration"&&K.property.startsWith("--")){l.add(ae(K.property),K.value??"",O);return}let o=G([D(v.name,v.params,[K])]).split(` +`).map((f,h,k)=>`${h===0||h>=k.length-2?" ":">"} ${f}`).join(` +`);throw new Error(`\`@theme\` blocks must only contain custom properties or \`@keyframes\`. + +${o}`)}),d?T([]):(d=j(":root, :host",[]),T([d])),1}}});let y=ar(l);s&&(y.important=s),i|=await zr({designSystem:y,base:r,ast:t,loadModule:n,globs:m});for(let v of p)v(y);for(let v of c)v(y);if(d){let v=[];for(let[T,S]of y.theme.entries())S.options&2||v.push(a(te(T),S.value));let x=y.theme.getKeyframes();for(let T of x)t.push(Z({theme:!0},[U([T])]));d.nodes=[Z({theme:!0},v)]}if(u){let v=u;v.kind="context",v.context={}}if(g.length>0){for(let v of g){let x=j("&",v.nodes),T=v.params,S=y.parseVariant(T);if(S===null)throw new Error(`Cannot use \`@variant\` with unknown variant: ${T}`);if(ve(x,S,y.variants)===null)throw new Error(`Cannot use \`@variant\` with variant: ${T}`);Object.assign(v,x)}i|=32}return i|=ge(t,y),i|=$e(t,y),_(t,(v,{replaceWith:x})=>{if(v.kind==="at-rule")return v.name==="@utility"&&x([]),1}),{designSystem:y,ast:t,globs:m,root:b,utilitiesNode:u,features:i}}async function Mr(t,r={}){let{designSystem:n,ast:e,globs:i,root:s,utilitiesNode:l,features:p}=await Lr(t,r);e.unshift(Ue(`! tailwindcss v${kt} | MIT License | https://tailwindcss.com `));function c(m){n.invalidCandidates.add(m)}let d=new Set,u=null,g=0;return{globs:i,root:s,features:p,build(m){if(p===0)return t;if(!l)return u??=se(e,n),u;let b=!1,y=d.size;for(let x of m)n.invalidCandidates.has(x)||(x[0]==="-"&&x[1]==="-"?n.theme.markUsedVariable(x):d.add(x),b||=d.size!==y);if(!b)return u??=se(e,n),u;let v=ne(d,n,{onInvalidCandidate:c}).astNodes;return g===v.length?(u??=se(e,n),u):(g=v.length,l.nodes=v,u=se(e,n),u)}}}async function Vi(t,r={}){let n=le(t),e=await Mr(n,r),i=n,s=t;return{...e,build(l){let p=e.build(l);return p===i||(s=G(p),i=p),s}}}async function Ti(t,r={}){return(await Lr(le(t),r)).designSystem}function Re(){throw new Error("It looks like you're trying to use `tailwindcss` directly as a PostCSS plugin. The PostCSS plugin has moved to a separate package, so to continue using Tailwind CSS with PostCSS you'll need to install `@tailwindcss/postcss` and update your PostCSS configuration.")}for(let t in Qe)t!=="default"&&(Re[t]=Qe[t]);module.exports=Re; diff --git a/packages/engine/test/fixtures/versions/.eslintignore b/packages/engine/test/fixtures/versions/.eslintignore new file mode 100644 index 00000000..3ce21311 --- /dev/null +++ b/packages/engine/test/fixtures/versions/.eslintignore @@ -0,0 +1,2 @@ +lts +3.* \ No newline at end of file diff --git a/packages/engine/test/fixtures/versions/.eslintrc.cjs b/packages/engine/test/fixtures/versions/.eslintrc.cjs new file mode 100644 index 00000000..d65598a5 --- /dev/null +++ b/packages/engine/test/fixtures/versions/.eslintrc.cjs @@ -0,0 +1,16 @@ +module.exports = { + root: true, + env: { + es2021: true, + node: true + }, + extends: [ + 'standard' + ], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module' + }, + rules: { + } +} diff --git a/packages/engine/test/fixtures/versions/2/lib/index.js b/packages/engine/test/fixtures/versions/2/lib/index.js new file mode 100644 index 00000000..d8d4d6a5 --- /dev/null +++ b/packages/engine/test/fixtures/versions/2/lib/index.js @@ -0,0 +1,103 @@ +"use strict"; + +var _path = _interopRequireDefault(require("path")); + +var _fs = _interopRequireDefault(require("fs")); + +var _lodash = _interopRequireDefault(require("lodash")); + +var _postcss = _interopRequireDefault(require("postcss")); + +var _getModuleDependencies = _interopRequireDefault(require("./lib/getModuleDependencies")); + +var _registerConfigAsDependency = _interopRequireDefault(require("./lib/registerConfigAsDependency")); + +var _processTailwindFeatures = _interopRequireDefault(require("./processTailwindFeatures")); + +var _formatCSS = _interopRequireDefault(require("./lib/formatCSS")); + +var _resolveConfig = _interopRequireDefault(require("./util/resolveConfig")); + +var _getAllConfigs = _interopRequireDefault(require("./util/getAllConfigs")); + +var _constants = require("./constants"); + +var _defaultConfigStub = _interopRequireDefault(require("../stubs/defaultConfig.stub.js")); + +var _jit = _interopRequireDefault(require("./jit")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function resolveConfigPath(filePath) { + // require('tailwindcss')({ theme: ..., variants: ... }) + if (_lodash.default.isObject(filePath) && !_lodash.default.has(filePath, 'config') && !_lodash.default.isEmpty(filePath)) { + return undefined; + } // require('tailwindcss')({ config: 'custom-config.js' }) + + + if (_lodash.default.isObject(filePath) && _lodash.default.has(filePath, 'config') && _lodash.default.isString(filePath.config)) { + return _path.default.resolve(filePath.config); + } // require('tailwindcss')({ config: { theme: ..., variants: ... } }) + + + if (_lodash.default.isObject(filePath) && _lodash.default.has(filePath, 'config') && _lodash.default.isObject(filePath.config)) { + return undefined; + } // require('tailwindcss')('custom-config.js') + + + if (_lodash.default.isString(filePath)) { + return _path.default.resolve(filePath); + } // require('tailwindcss') + + + for (const configFile of _constants.supportedConfigFiles) { + try { + const configPath = _path.default.resolve(configFile); + + _fs.default.accessSync(configPath); + + return configPath; + } catch (err) {} + } + + return undefined; +} + +const getConfigFunction = config => () => { + if (_lodash.default.isUndefined(config)) { + return (0, _resolveConfig.default)([...(0, _getAllConfigs.default)(_defaultConfigStub.default)]); + } // Skip this if Jest is running: https://github.com/facebook/jest/pull/9841#issuecomment-621417584 + + + if (process.env.JEST_WORKER_ID === undefined) { + if (!_lodash.default.isObject(config)) { + (0, _getModuleDependencies.default)(config).forEach(mdl => { + delete require.cache[require.resolve(mdl.file)]; + }); + } + } + + const configObject = _lodash.default.isObject(config) ? _lodash.default.get(config, 'config', config) : require(config); + return (0, _resolveConfig.default)([...(0, _getAllConfigs.default)(configObject)]); +}; + +const plugin = _postcss.default.plugin('tailwindcss', config => { + const resolvedConfigPath = resolveConfigPath(config); + const getConfig = getConfigFunction(resolvedConfigPath || config); + + const mode = _lodash.default.get(getConfig(), 'mode', 'aot'); + + if (mode === 'jit') { + return (0, _postcss.default)((0, _jit.default)(config)); + } + + const plugins = []; + + if (!_lodash.default.isUndefined(resolvedConfigPath)) { + plugins.push((0, _registerConfigAsDependency.default)(resolvedConfigPath)); + } + + return (0, _postcss.default)([...plugins, (0, _processTailwindFeatures.default)(getConfig), _formatCSS.default]); +}); + +module.exports = plugin; \ No newline at end of file diff --git a/packages/engine/test/fixtures/versions/2/lib/jit/index.js b/packages/engine/test/fixtures/versions/2/lib/jit/index.js new file mode 100644 index 00000000..8edcc0b6 --- /dev/null +++ b/packages/engine/test/fixtures/versions/2/lib/jit/index.js @@ -0,0 +1,31 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = _default; + +var _setupTrackingContext = _interopRequireDefault(require("./lib/setupTrackingContext")); + +var _setupWatchingContext = _interopRequireDefault(require("./lib/setupWatchingContext")); + +var _sharedState = require("./lib/sharedState"); + +var _processTailwindFeatures = _interopRequireDefault(require("./processTailwindFeatures")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _default(configOrPath = {}) { + return [_sharedState.env.DEBUG && function (root) { + console.log('\n'); + console.time('JIT TOTAL'); + return root; + }, function (root, result) { + let setupContext = _sharedState.env.TAILWIND_MODE === 'watch' ? (0, _setupWatchingContext.default)(configOrPath) : (0, _setupTrackingContext.default)(configOrPath); + (0, _processTailwindFeatures.default)(setupContext)(root, result); + }, _sharedState.env.DEBUG && function (root) { + console.timeEnd('JIT TOTAL'); + console.log('\n'); + return root; + }].filter(Boolean); +} \ No newline at end of file diff --git a/packages/engine/test/fixtures/versions/2/lib/jit/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/2/lib/jit/processTailwindFeatures.js new file mode 100644 index 00000000..271ffe9a --- /dev/null +++ b/packages/engine/test/fixtures/versions/2/lib/jit/processTailwindFeatures.js @@ -0,0 +1,67 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = processTailwindFeatures; + +var _normalizeTailwindDirectives = _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); + +var _expandTailwindAtRules = _interopRequireDefault(require("./lib/expandTailwindAtRules")); + +var _expandApplyAtRules = _interopRequireDefault(require("./lib/expandApplyAtRules")); + +var _evaluateTailwindFunctions = _interopRequireDefault(require("../lib/evaluateTailwindFunctions")); + +var _substituteScreenAtRules = _interopRequireDefault(require("../lib/substituteScreenAtRules")); + +var _resolveDefaultsAtRules = _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); + +var _collapseAdjacentRules = _interopRequireDefault(require("./lib/collapseAdjacentRules")); + +var _setupContextUtils = require("./lib/setupContextUtils"); + +var _log = _interopRequireDefault(require("../util/log")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +let warned = false; + +function processTailwindFeatures(setupContext) { + return function (root, result) { + if (!warned) { + _log.default.warn([`You have enabled the JIT engine which is currently in preview.`, 'Preview features are not covered by semver, may introduce breaking changes, and can change at any time.']); + + warned = true; + } + + let tailwindDirectives = (0, _normalizeTailwindDirectives.default)(root); + let context = setupContext({ + tailwindDirectives, + + registerDependency(dependency) { + result.messages.push({ + plugin: 'tailwindcss', + parent: result.opts.from, + ...dependency + }); + }, + + createContext(tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, tailwindDirectives, root); + } + + })(root, result); + + if (context.tailwindConfig.separator === '-') { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + + (0, _expandTailwindAtRules.default)(context)(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + }; +} \ No newline at end of file diff --git a/packages/engine/test/fixtures/versions/2/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/2/lib/processTailwindFeatures.js new file mode 100644 index 00000000..dae2363d --- /dev/null +++ b/packages/engine/test/fixtures/versions/2/lib/processTailwindFeatures.js @@ -0,0 +1,91 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = _default; + +var _lodash = _interopRequireDefault(require("lodash")); + +var _postcss = _interopRequireDefault(require("postcss")); + +var _substituteTailwindAtRules = _interopRequireDefault(require("./lib/substituteTailwindAtRules")); + +var _evaluateTailwindFunctions = _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); + +var _substituteVariantsAtRules = _interopRequireDefault(require("./lib/substituteVariantsAtRules")); + +var _substituteResponsiveAtRules = _interopRequireDefault(require("./lib/substituteResponsiveAtRules")); + +var _convertLayerAtRulesToControlComments = _interopRequireDefault(require("./lib/convertLayerAtRulesToControlComments")); + +var _substituteScreenAtRules = _interopRequireDefault(require("./lib/substituteScreenAtRules")); + +var _substituteClassApplyAtRules = _interopRequireDefault(require("./lib/substituteClassApplyAtRules")); + +var _applyImportantConfiguration = _interopRequireDefault(require("./lib/applyImportantConfiguration")); + +var _purgeUnusedStyles = _interopRequireDefault(require("./lib/purgeUnusedStyles")); + +var _corePlugins = _interopRequireDefault(require("./corePlugins")); + +var _processPlugins = _interopRequireDefault(require("./util/processPlugins")); + +var _cloneNodes = _interopRequireDefault(require("./util/cloneNodes")); + +var _featureFlags = require("./featureFlags"); + +var _hashConfig = _interopRequireDefault(require("./util/hashConfig")); + +var _log = _interopRequireDefault(require("./util/log")); + +var _disposables = require("./util/disposables"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +let previousConfig = null; +let processedPlugins = null; +let getProcessedPlugins = null; + +function _default(getConfig) { + return function (css, result) { + const config = getConfig(); + const configChanged = (0, _hashConfig.default)(previousConfig) !== (0, _hashConfig.default)(config); + previousConfig = config; + + if (configChanged) { + _disposables.shared.dispose(); + + if (config.target) { + _log.default.warn(['The `target` feature has been removed in Tailwind CSS v2.0.', 'Please remove this option from your config file to silence this warning.']); + } + + (0, _featureFlags.issueFlagNotices)(config); + processedPlugins = (0, _processPlugins.default)([...(0, _corePlugins.default)(config), ..._lodash.default.get(config, 'plugins', [])], config); + + getProcessedPlugins = function () { + return { ...processedPlugins, + base: (0, _cloneNodes.default)(processedPlugins.base), + components: (0, _cloneNodes.default)(processedPlugins.components), + utilities: (0, _cloneNodes.default)(processedPlugins.utilities) + }; + }; + } + + function registerDependency(dependency) { + result.messages.push({ + plugin: 'tailwindcss', + parent: result.opts.from, + ...dependency + }); + } + + return (0, _postcss.default)([(0, _substituteTailwindAtRules.default)(config, getProcessedPlugins()), (0, _evaluateTailwindFunctions.default)({ + tailwindConfig: config + }), (0, _substituteVariantsAtRules.default)(config, getProcessedPlugins()), (0, _substituteResponsiveAtRules.default)(config), (0, _convertLayerAtRulesToControlComments.default)(config), (0, _substituteScreenAtRules.default)({ + tailwindConfig: config + }), (0, _substituteClassApplyAtRules.default)(config, getProcessedPlugins, configChanged), (0, _applyImportantConfiguration.default)(config), (0, _purgeUnusedStyles.default)(config, configChanged, registerDependency)]).process(css, { + from: _lodash.default.get(css, 'source.input.file') + }); + }; +} \ No newline at end of file diff --git a/packages/engine/test/fixtures/versions/2/package.json b/packages/engine/test/fixtures/versions/2/package.json new file mode 100644 index 00000000..c40db75f --- /dev/null +++ b/packages/engine/test/fixtures/versions/2/package.json @@ -0,0 +1,137 @@ +{ + "name": "@tailwindcss/postcss7-compat", + "version": "2.2.17", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "style": "dist/tailwind.css", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "contributors": [ + "Adam Wathan ", + "Jonathan Reinink ", + "David Hemphill " + ], + "scripts": { + "prebabelify": "npm run generate:plugin-list && rimraf lib", + "babelify": "babel src --out-dir lib --copy-files", + "postbabelify": "ncc build lib/cli-peer-dependencies.js -o peers", + "rebuild-fixtures": "npm run babelify && babel-node scripts/rebuildFixtures.js", + "prepublishOnly": "npm install --force && npm run babelify && babel-node scripts/build.js && node scripts/build-plugins.js", + "style": "eslint .", + "test": "cross-env TAILWIND_MODE=build jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "posttest": "npm run style", + "compat": "node scripts/compat.js --prepare", + "compat:restore": "node scripts/compat.js --restore", + "generate:plugin-list": "babel-node scripts/create-plugin-list.js" + }, + "files": [ + "dist/*.css", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*.stub.js", + "nesting/*", + "*.css", + "*.js" + ], + "devDependencies": { + "@babel/cli": "^7.14.8", + "@babel/core": "^7.15.0", + "@babel/node": "^7.12.13", + "@babel/preset-env": "^7.15.0", + "@tailwindcss/aspect-ratio": "^0.2.1", + "@vercel/ncc": "^0.30.0", + "autoprefixer": "^10.3.3", + "babel-jest": "^27.0.6", + "clean-css": "5.1.4", + "cross-env": "^7.0.3", + "cssnano": "^4", + "eslint": "^7.32.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-prettier": "^3.4.1", + "jest": "^27.0.6", + "jest-diff": "^27.0.2", + "prettier": "^2.3.2", + "rimraf": "^3.0.0" + }, + "dependencies": { + "arg": "^5.0.1", + "autoprefixer": "^9", + "bytes": "^3.0.0", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "color": "^4.0.1", + "cosmiconfig": "^7.0.1", + "detective": "^5.2.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.7", + "fs-extra": "^10.0.0", + "glob-parent": "^6.0.1", + "html-tags": "^3.1.0", + "is-color-stop": "^1.1.0", + "is-glob": "^4.0.1", + "lodash": "^4.17.21", + "lodash.topath": "^4.5.2", + "modern-normalize": "^1.1.0", + "node-emoji": "^1.11.0", + "normalize-path": "^3.0.0", + "object-hash": "^2.2.0", + "postcss": "^7", + "postcss-functions": "^3", + "postcss-js": "^2", + "postcss-load-config": "^3.1.0", + "postcss-nested": "^4", + "postcss-selector-parser": "^6.0.6", + "postcss-value-parser": "^4.1.0", + "pretty-hrtime": "^1.0.3", + "purgecss": "^4.0.3", + "quick-lru": "^5.1.1", + "reduce-css-calc": "^2.1.8", + "resolve": "^1.20.0", + "tmp": "^0.2.1" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "babel": { + "presets": [ + [ + "@babel/preset-env", + { + "targets": { + "node": "12.13.0" + } + } + ] + ] + }, + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/" + ] + }, + "engines": { + "node": ">=12.13.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/engine/test/fixtures/versions/3.0.0/lib/index.js b/packages/engine/test/fixtures/versions/3.0.0/lib/index.js new file mode 100644 index 00000000..d60e29c6 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.0.0/lib/index.js @@ -0,0 +1,32 @@ +"use strict"; +var _setupTrackingContext = _interopRequireDefault(require("./lib/setupTrackingContext")); +var _setupWatchingContext = _interopRequireDefault(require("./lib/setupWatchingContext")); +var _processTailwindFeatures = _interopRequireDefault(require("./processTailwindFeatures")); +var _sharedState = require("./lib/sharedState"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: 'tailwindcss', + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log('\n'); + console.time('JIT TOTAL'); + return root; + }, + function(root, result) { + let setupContext = _sharedState.env.TAILWIND_MODE === 'watch' ? (0, _setupWatchingContext).default(configOrPath) : (0, _setupTrackingContext).default(configOrPath); + (0, _processTailwindFeatures).default(setupContext)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd('JIT TOTAL'); + console.log('\n'); + return root; + }, + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.0.0/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.0.0/lib/processTailwindFeatures.js new file mode 100644 index 00000000..c319ed91 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.0.0/lib/processTailwindFeatures.js @@ -0,0 +1,51 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = processTailwindFeatures; +var _normalizeTailwindDirectives = _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); +var _expandTailwindAtRules = _interopRequireDefault(require("./lib/expandTailwindAtRules")); +var _expandApplyAtRules = _interopRequireDefault(require("./lib/expandApplyAtRules")); +var _evaluateTailwindFunctions = _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); +var _substituteScreenAtRules = _interopRequireDefault(require("./lib/substituteScreenAtRules")); +var _resolveDefaultsAtRules = _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); +var _collapseAdjacentRules = _interopRequireDefault(require("./lib/collapseAdjacentRules")); +var _collapseDuplicateDeclarations = _interopRequireDefault(require("./lib/collapseDuplicateDeclarations")); +var _detectNesting = _interopRequireDefault(require("./lib/detectNesting")); +var _setupContextUtils = require("./lib/setupContextUtils"); +var _featureFlags = require("./featureFlags"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return function(root, result) { + let tailwindDirectives = (0, _normalizeTailwindDirectives).default(root); + let context = setupContext({ + tailwindDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: 'tailwindcss', + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils).createContext(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === '-') { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags).issueFlagNotices(context.tailwindConfig); + (0, _detectNesting).default(context)(root, result); + (0, _expandTailwindAtRules).default(context)(root, result); + (0, _expandApplyAtRules).default(context)(root, result); + (0, _evaluateTailwindFunctions).default(context)(root, result); + (0, _substituteScreenAtRules).default(context)(root, result); + (0, _resolveDefaultsAtRules).default(context)(root, result); + (0, _collapseAdjacentRules).default(context)(root, result); + (0, _collapseDuplicateDeclarations).default(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.0.0/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.0.0/lib/util/dataTypes.js new file mode 100644 index 00000000..5fd5aa24 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.0.0/lib/util/dataTypes.js @@ -0,0 +1,233 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.normalize = normalize; +exports.url = url; +exports.number = number; +exports.percentage = percentage; +exports.length = length; +exports.lineWidth = lineWidth; +exports.shadow = shadow; +exports.color = color; +exports.image = image; +exports.gradient = gradient; +exports.position = position; +exports.familyName = familyName; +exports.genericName = genericName; +exports.absoluteSize = absoluteSize; +exports.relativeSize = relativeSize; +var _color = require("./color"); +var _parseBoxShadowValue = require("./parseBoxShadowValue"); +let cssFunctions = [ + 'min', + 'max', + 'clamp', + 'calc' +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +let COMMA = /,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count. +; +let UNDERSCORE = /_(?![^(]*\))/g // Underscore separator that is not located between brackets. E.g.: `rgba(255,_255,_255)_black` these don't count. +; +function normalize(value, isRoot = true) { + // Keep raw strings if it starts with `url(` + if (value.includes('url(')) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(''); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + ' '.repeat(fullMatch.length - 1) + ).replace(/^_/g, ' ').replace(/\\_/g, '_'); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + // Add spaces around operators inside calc() that do not follow an operator + // or '('. + return value.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, '$1 $2 '); +} +function url(value) { + return value.startsWith('url('); +} +function number(value) { + return !isNaN(Number(value)) || cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.+?`).test(value) + ); +} +function percentage(value) { + return /%$/g.test(value) || cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.+?%`).test(value) + ); +} +let lengthUnits = [ + 'cm', + 'mm', + 'Q', + 'in', + 'pc', + 'pt', + 'px', + 'em', + 'ex', + 'ch', + 'rem', + 'lh', + 'vw', + 'vh', + 'vmin', + 'vmax', +]; +let lengthUnitsPattern = `(?:${lengthUnits.join('|')})`; +function length(value) { + return value.split(UNDERSCORE).every((part)=>{ + return part === '0' || new RegExp(`${lengthUnitsPattern}$`).test(part) || cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.+?${lengthUnitsPattern}`).test(part) + ); + }); +} +let lineWidths = new Set([ + 'thin', + 'medium', + 'thick' +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue).parseBoxShadowValue(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = value.split(UNDERSCORE).every((part)=>{ + part = normalize(part); + if (part.startsWith('var(')) return true; + if ((0, _color).parseColor(part) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = value.split(COMMA).every((part)=>{ + part = normalize(part); + if (part.startsWith('var(')) return true; + if (url(part) || gradient(part) || [ + 'element(', + 'image(', + 'cross-fade(', + 'image-set(' + ].some((fn)=>part.startsWith(fn) + )) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + 'linear-gradient', + 'radial-gradient', + 'repeating-linear-gradient', + 'repeating-radial-gradient', + 'conic-gradient', +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + 'center', + 'top', + 'right', + 'bottom', + 'left' +]); +function position(value) { + let positions = 0; + let result = value.split(UNDERSCORE).every((part)=>{ + part = normalize(part); + if (part.startsWith('var(')) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = value.split(COMMA).every((part)=>{ + part = normalize(part); + if (part.startsWith('var(')) return true; + // If it contains spaces, then it should be quoted + if (part.includes(' ')) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + 'serif', + 'sans-serif', + 'monospace', + 'cursive', + 'fantasy', + 'system-ui', + 'ui-serif', + 'ui-sans-serif', + 'ui-monospace', + 'ui-rounded', + 'math', + 'emoji', + 'fangsong', +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + 'xx-small', + 'x-small', + 'small', + 'medium', + 'large', + 'x-large', + 'x-large', + 'xxx-large', +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + 'larger', + 'smaller' +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.0.0/package.json b/packages/engine/test/fixtures/versions/3.0.0/package.json new file mode 100644 index 00000000..59bd90d5 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.0.0/package.json @@ -0,0 +1,113 @@ +{ + "name": "tailwindcss", + "version": "3.0.0", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "style": "dist/tailwind.css", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "contributors": [ + "Adam Wathan ", + "Jonathan Reinink ", + "David Hemphill " + ], + "scripts": { + "preswcify": "npm run generate:plugin-list && rimraf lib", + "swcify": "swc src --out-dir lib --copy-files", + "postswcify": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js", + "rebuild-fixtures": "npm run swcify && node -r @swc/register scripts/rebuildFixtures.js", + "prepublishOnly": "npm install --force && npm run swcify", + "style": "eslint .", + "pretest": "npm run generate:plugin-list", + "test": "cross-env TAILWIND_MODE=build jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "posttest": "npm run style", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*.stub.js", + "nesting/*", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.52", + "@swc/core": "^1.2.118", + "@swc/jest": "^0.1.5", + "@swc/register": "^0.1.7", + "autoprefixer": "^10.4.0", + "cross-env": "^7.0.3", + "cssnano": "^5.0.12", + "esbuild": "^0.13.12", + "eslint": "^8.2.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-prettier": "^4.0.0", + "jest": "^27.4.3", + "jest-diff": "^27.4.2", + "postcss": "^8.4.4", + "postcss-cli": "^8.3.1", + "prettier": "^2.5.0", + "rimraf": "^3.0.0" + }, + "peerDependencies": { + "autoprefixer": "^10.0.2", + "postcss": "^8.0.9" + }, + "dependencies": { + "arg": "^5.0.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "color-name": "^1.1.4", + "cosmiconfig": "^7.0.1", + "detective": "^5.2.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "normalize-path": "^3.0.0", + "object-hash": "^2.2.0", + "postcss-js": "^3.0.3", + "postcss-load-config": "^3.1.0", + "postcss-nested": "5.0.6", + "postcss-selector-parser": "^6.0.6", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.20.0", + "tmp": "^0.2.1" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/" + ], + "transform": { + "\\.js$": "@swc/jest" + } + }, + "engines": { + "node": ">=12.13.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.2.1/lib/index.js b/packages/engine/test/fixtures/versions/3.2.1/lib/index.js new file mode 100644 index 00000000..08c432c5 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.1/lib/index.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interopRequireDefault(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + function(root, result) { + var ref; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (ref = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && ref !== void 0 ? ref : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root1 of roots){ + if (root1.type === "root") { + (0, _processTailwindFeatures.default)(context)(root1, result); + } + } + return; + } + (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.2.1/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.2.1/lib/processTailwindFeatures.js new file mode 100644 index 00000000..72cd530a --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.1/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: ()=>processTailwindFeatures +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interopRequireDefault(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.2.1/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.2.1/lib/util/dataTypes.js new file mode 100644 index 00000000..d04b2e39 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.1/lib/util/dataTypes.js @@ -0,0 +1,239 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: ()=>normalize, + url: ()=>url, + number: ()=>number, + percentage: ()=>percentage, + length: ()=>length, + lineWidth: ()=>lineWidth, + shadow: ()=>shadow, + color: ()=>color, + image: ()=>image, + gradient: ()=>gradient, + position: ()=>position, + familyName: ()=>familyName, + genericName: ()=>genericName, + absoluteSize: ()=>absoluteSize, + relativeSize: ()=>relativeSize +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +function normalize(value, isRoot = true) { + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + // Add spaces around operators inside math functions like calc() that do not follow an operator + // or '('. + value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + return match.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 "); + }); + return value; +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "vw", + "vh", + "vmin", + "vmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "linear-gradient", + "radial-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient", + "conic-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.2.1/package.json b/packages/engine/test/fixtures/versions/3.2.1/package.json new file mode 100644 index 00000000..b2f60694 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.1/package.json @@ -0,0 +1,114 @@ +{ + "name": "tailwindcss", + "version": "3.2.1", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "preswcify": "npm run generate && rimraf lib", + "swcify": "swc src --out-dir lib --copy-files", + "postswcify": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js", + "rebuild-fixtures": "npm run swcify && node -r @swc/register scripts/rebuildFixtures.js", + "prepublishOnly": "npm install --force && npm run swcify", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*.stub.js", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.57", + "@swc/core": "^1.3.4", + "@swc/jest": "^0.2.23", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.12", + "cssnano": "^5.1.13", + "esbuild": "^0.15.10", + "eslint": "^8.25.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.1.3", + "jest-diff": "^28.1.3", + "prettier": "^2.7.1", + "rimraf": "^3.0.0", + "source-map-js": "^1.0.2" + }, + "peerDependencies": { + "postcss": "^8.0.9" + }, + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "detective": "^5.2.1", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.17", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.10", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transform": { + "\\.js$": "@swc/jest" + } + }, + "engines": { + "node": ">=12.13.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.2.2/lib/index.js b/packages/engine/test/fixtures/versions/3.2.2/lib/index.js new file mode 100644 index 00000000..08c432c5 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.2/lib/index.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interopRequireDefault(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + function(root, result) { + var ref; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (ref = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && ref !== void 0 ? ref : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root1 of roots){ + if (root1.type === "root") { + (0, _processTailwindFeatures.default)(context)(root1, result); + } + } + return; + } + (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.2.2/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.2.2/lib/processTailwindFeatures.js new file mode 100644 index 00000000..72cd530a --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.2/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: ()=>processTailwindFeatures +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interopRequireDefault(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.2.2/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.2.2/lib/util/dataTypes.js new file mode 100644 index 00000000..d04b2e39 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.2/lib/util/dataTypes.js @@ -0,0 +1,239 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: ()=>normalize, + url: ()=>url, + number: ()=>number, + percentage: ()=>percentage, + length: ()=>length, + lineWidth: ()=>lineWidth, + shadow: ()=>shadow, + color: ()=>color, + image: ()=>image, + gradient: ()=>gradient, + position: ()=>position, + familyName: ()=>familyName, + genericName: ()=>genericName, + absoluteSize: ()=>absoluteSize, + relativeSize: ()=>relativeSize +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +function normalize(value, isRoot = true) { + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + // Add spaces around operators inside math functions like calc() that do not follow an operator + // or '('. + value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + return match.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 "); + }); + return value; +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "vw", + "vh", + "vmin", + "vmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "linear-gradient", + "radial-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient", + "conic-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.2.2/package.json b/packages/engine/test/fixtures/versions/3.2.2/package.json new file mode 100644 index 00000000..a8437407 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.2/package.json @@ -0,0 +1,114 @@ +{ + "name": "tailwindcss", + "version": "3.2.2", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "preswcify": "npm run generate && rimraf lib", + "swcify": "swc src --out-dir lib --copy-files", + "postswcify": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js", + "rebuild-fixtures": "npm run swcify && node -r @swc/register scripts/rebuildFixtures.js", + "prepublishOnly": "npm install --force && npm run swcify", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*.stub.js", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.57", + "@swc/core": "^1.3.11", + "@swc/jest": "^0.2.23", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.13", + "cssnano": "^5.1.14", + "esbuild": "^0.15.12", + "eslint": "^8.25.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.1.3", + "jest-diff": "^28.1.3", + "prettier": "^2.7.1", + "rimraf": "^3.0.0", + "source-map-js": "^1.0.2" + }, + "peerDependencies": { + "postcss": "^8.0.9" + }, + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "detective": "^5.2.1", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.18", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.10", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transform": { + "\\.js$": "@swc/jest" + } + }, + "engines": { + "node": ">=12.13.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.2.3/lib/index.js b/packages/engine/test/fixtures/versions/3.2.3/lib/index.js new file mode 100644 index 00000000..08c432c5 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.3/lib/index.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interopRequireDefault(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + function(root, result) { + var ref; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (ref = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && ref !== void 0 ? ref : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root1 of roots){ + if (root1.type === "root") { + (0, _processTailwindFeatures.default)(context)(root1, result); + } + } + return; + } + (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.2.3/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.2.3/lib/processTailwindFeatures.js new file mode 100644 index 00000000..72cd530a --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.3/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: ()=>processTailwindFeatures +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interopRequireDefault(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.2.3/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.2.3/lib/util/dataTypes.js new file mode 100644 index 00000000..d04b2e39 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.3/lib/util/dataTypes.js @@ -0,0 +1,239 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: ()=>normalize, + url: ()=>url, + number: ()=>number, + percentage: ()=>percentage, + length: ()=>length, + lineWidth: ()=>lineWidth, + shadow: ()=>shadow, + color: ()=>color, + image: ()=>image, + gradient: ()=>gradient, + position: ()=>position, + familyName: ()=>familyName, + genericName: ()=>genericName, + absoluteSize: ()=>absoluteSize, + relativeSize: ()=>relativeSize +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +function normalize(value, isRoot = true) { + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + // Add spaces around operators inside math functions like calc() that do not follow an operator + // or '('. + value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + return match.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 "); + }); + return value; +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "vw", + "vh", + "vmin", + "vmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "linear-gradient", + "radial-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient", + "conic-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.2.3/package.json b/packages/engine/test/fixtures/versions/3.2.3/package.json new file mode 100644 index 00000000..737cdfbc --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.3/package.json @@ -0,0 +1,114 @@ +{ + "name": "tailwindcss", + "version": "3.2.3", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "preswcify": "npm run generate && rimraf lib", + "swcify": "swc src --out-dir lib --copy-files", + "postswcify": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js", + "rebuild-fixtures": "npm run swcify && node -r @swc/register scripts/rebuildFixtures.js", + "prepublishOnly": "npm install --force && npm run swcify", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*.stub.js", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.57", + "@swc/core": "^1.3.11", + "@swc/jest": "^0.2.23", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.13", + "cssnano": "^5.1.14", + "esbuild": "^0.15.12", + "eslint": "^8.26.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.1.3", + "jest-diff": "^28.1.3", + "prettier": "^2.7.1", + "rimraf": "^3.0.0", + "source-map-js": "^1.0.2" + }, + "peerDependencies": { + "postcss": "^8.0.9" + }, + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "detective": "^5.2.1", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.18", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.10", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transform": { + "\\.js$": "@swc/jest" + } + }, + "engines": { + "node": ">=12.13.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.2.4/lib/index.js b/packages/engine/test/fixtures/versions/3.2.4/lib/index.js new file mode 100644 index 00000000..08c432c5 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.4/lib/index.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interopRequireDefault(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + function(root, result) { + var ref; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (ref = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && ref !== void 0 ? ref : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root1 of roots){ + if (root1.type === "root") { + (0, _processTailwindFeatures.default)(context)(root1, result); + } + } + return; + } + (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.2.4/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.2.4/lib/processTailwindFeatures.js new file mode 100644 index 00000000..72cd530a --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.4/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: ()=>processTailwindFeatures +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interopRequireDefault(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.2.4/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.2.4/lib/util/dataTypes.js new file mode 100644 index 00000000..d04b2e39 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.4/lib/util/dataTypes.js @@ -0,0 +1,239 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: ()=>normalize, + url: ()=>url, + number: ()=>number, + percentage: ()=>percentage, + length: ()=>length, + lineWidth: ()=>lineWidth, + shadow: ()=>shadow, + color: ()=>color, + image: ()=>image, + gradient: ()=>gradient, + position: ()=>position, + familyName: ()=>familyName, + genericName: ()=>genericName, + absoluteSize: ()=>absoluteSize, + relativeSize: ()=>relativeSize +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +function normalize(value, isRoot = true) { + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + // Add spaces around operators inside math functions like calc() that do not follow an operator + // or '('. + value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + return match.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 "); + }); + return value; +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "vw", + "vh", + "vmin", + "vmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "linear-gradient", + "radial-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient", + "conic-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.2.4/package.json b/packages/engine/test/fixtures/versions/3.2.4/package.json new file mode 100644 index 00000000..0d36d64d --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.4/package.json @@ -0,0 +1,114 @@ +{ + "name": "tailwindcss", + "version": "3.2.4", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "preswcify": "npm run generate && rimraf lib", + "swcify": "swc src --out-dir lib --copy-files", + "postswcify": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js", + "rebuild-fixtures": "npm run swcify && node -r @swc/register scripts/rebuildFixtures.js", + "prepublishOnly": "npm install --force && npm run swcify", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*.stub.js", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.57", + "@swc/core": "^1.3.11", + "@swc/jest": "^0.2.23", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.13", + "cssnano": "^5.1.14", + "esbuild": "^0.15.12", + "eslint": "^8.26.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.1.3", + "jest-diff": "^28.1.3", + "prettier": "^2.7.1", + "rimraf": "^3.0.0", + "source-map-js": "^1.0.2" + }, + "peerDependencies": { + "postcss": "^8.0.9" + }, + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "detective": "^5.2.1", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.18", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.10", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transform": { + "\\.js$": "@swc/jest" + } + }, + "engines": { + "node": ">=12.13.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.2.6/lib/index.js b/packages/engine/test/fixtures/versions/3.2.6/lib/index.js new file mode 100644 index 00000000..15e68381 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.6/lib/index.js @@ -0,0 +1,6 @@ +"use strict"; +if (process.env.OXIDE) { + module.exports = require("./oxide/postcss-plugin"); +} else { + module.exports = require("./plugin"); +} diff --git a/packages/engine/test/fixtures/versions/3.2.6/lib/plugin.js b/packages/engine/test/fixtures/versions/3.2.6/lib/plugin.js new file mode 100644 index 00000000..61b9189d --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.6/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interopRequireDefault(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root1 of roots){ + if (root1.type === "root") { + (0, _processTailwindFeatures.default)(context)(root1, result); + } + } + return; + } + (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.OXIDE && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.2.6/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.2.6/lib/processTailwindFeatures.js new file mode 100644 index 00000000..72cd530a --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.6/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: ()=>processTailwindFeatures +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interopRequireDefault(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.2.6/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.2.6/lib/util/dataTypes.js new file mode 100644 index 00000000..4f13f25f --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.6/lib/util/dataTypes.js @@ -0,0 +1,263 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: ()=>normalize, + url: ()=>url, + number: ()=>number, + percentage: ()=>percentage, + length: ()=>length, + lineWidth: ()=>lineWidth, + shadow: ()=>shadow, + color: ()=>color, + image: ()=>image, + gradient: ()=>gradient, + position: ()=>position, + familyName: ()=>familyName, + genericName: ()=>genericName, + absoluteSize: ()=>absoluteSize, + relativeSize: ()=>relativeSize +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +const placeholder = "--tw-placeholder"; +const placeholderRe = new RegExp(placeholder, "g"); +function normalize(value, isRoot = true) { + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + // Add spaces around operators inside math functions like calc() that do not follow an operator + // or '('. + value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let vars = []; + return match.replace(/var\((--.+?)[,)]/g, (match, g1)=>{ + vars.push(g1); + return match.replace(g1, placeholder); + }).replace(/(-?\d*\.?\d(?!\b-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 ").replace(placeholderRe, ()=>vars.shift()); + }); + return value; +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "linear-gradient", + "radial-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient", + "conic-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.2.6/package.json b/packages/engine/test/fixtures/versions/3.2.6/package.json new file mode 100644 index 00000000..74a90de6 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.6/package.json @@ -0,0 +1,125 @@ +{ + "name": "tailwindcss", + "version": "3.2.6", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*.stub.js", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "0.1.59", + "@swc/core": "1.3.24", + "@swc/jest": "0.2.24", + "@swc/register": "0.1.10", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "concurrently": "^7.5.0", + "cssnano": "^5.1.14", + "esbuild": "^0.16.10", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.1.3", + "jest-diff": "^28.1.3", + "lightningcss": "^1.18.0", + "prettier": "^2.8.1", + "rimraf": "^3.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.6.3" + }, + "peerDependencies": { + "postcss": "^8.0.9" + }, + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "detective": "^5.2.1", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.0.9", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=12.13.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.2.7/lib/index.js b/packages/engine/test/fixtures/versions/3.2.7/lib/index.js new file mode 100644 index 00000000..15e68381 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.7/lib/index.js @@ -0,0 +1,6 @@ +"use strict"; +if (process.env.OXIDE) { + module.exports = require("./oxide/postcss-plugin"); +} else { + module.exports = require("./plugin"); +} diff --git a/packages/engine/test/fixtures/versions/3.2.7/lib/plugin.js b/packages/engine/test/fixtures/versions/3.2.7/lib/plugin.js new file mode 100644 index 00000000..61b9189d --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.7/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interopRequireDefault(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root1 of roots){ + if (root1.type === "root") { + (0, _processTailwindFeatures.default)(context)(root1, result); + } + } + return; + } + (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.OXIDE && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.2.7/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.2.7/lib/processTailwindFeatures.js new file mode 100644 index 00000000..72cd530a --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.7/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: ()=>processTailwindFeatures +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interopRequireDefault(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.2.7/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.2.7/lib/util/dataTypes.js new file mode 100644 index 00000000..4f13f25f --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.7/lib/util/dataTypes.js @@ -0,0 +1,263 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: ()=>normalize, + url: ()=>url, + number: ()=>number, + percentage: ()=>percentage, + length: ()=>length, + lineWidth: ()=>lineWidth, + shadow: ()=>shadow, + color: ()=>color, + image: ()=>image, + gradient: ()=>gradient, + position: ()=>position, + familyName: ()=>familyName, + genericName: ()=>genericName, + absoluteSize: ()=>absoluteSize, + relativeSize: ()=>relativeSize +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +const placeholder = "--tw-placeholder"; +const placeholderRe = new RegExp(placeholder, "g"); +function normalize(value, isRoot = true) { + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + // Add spaces around operators inside math functions like calc() that do not follow an operator + // or '('. + value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let vars = []; + return match.replace(/var\((--.+?)[,)]/g, (match, g1)=>{ + vars.push(g1); + return match.replace(g1, placeholder); + }).replace(/(-?\d*\.?\d(?!\b-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 ").replace(placeholderRe, ()=>vars.shift()); + }); + return value; +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "linear-gradient", + "radial-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient", + "conic-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.2.7/package.json b/packages/engine/test/fixtures/versions/3.2.7/package.json new file mode 100644 index 00000000..952da91f --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.2.7/package.json @@ -0,0 +1,125 @@ +{ + "name": "tailwindcss", + "version": "3.2.7", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*.stub.js", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "0.1.59", + "@swc/core": "1.3.24", + "@swc/jest": "0.2.24", + "@swc/register": "0.1.10", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "concurrently": "^7.5.0", + "cssnano": "^5.1.14", + "esbuild": "^0.16.10", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.1.3", + "jest-diff": "^28.1.3", + "lightningcss": "^1.18.0", + "prettier": "^2.8.1", + "rimraf": "^3.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.6.3" + }, + "peerDependencies": { + "postcss": "^8.0.9" + }, + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "detective": "^5.2.1", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.0.9", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=12.13.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.3.0/lib/index.js b/packages/engine/test/fixtures/versions/3.3.0/lib/index.js new file mode 100644 index 00000000..15e68381 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.0/lib/index.js @@ -0,0 +1,6 @@ +"use strict"; +if (process.env.OXIDE) { + module.exports = require("./oxide/postcss-plugin"); +} else { + module.exports = require("./plugin"); +} diff --git a/packages/engine/test/fixtures/versions/3.3.0/lib/plugin.js b/packages/engine/test/fixtures/versions/3.3.0/lib/plugin.js new file mode 100644 index 00000000..61b9189d --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.0/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interopRequireDefault(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root1 of roots){ + if (root1.type === "root") { + (0, _processTailwindFeatures.default)(context)(root1, result); + } + } + return; + } + (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.OXIDE && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.3.0/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.3.0/lib/processTailwindFeatures.js new file mode 100644 index 00000000..72cd530a --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.0/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: ()=>processTailwindFeatures +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interopRequireDefault(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.3.0/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.3.0/lib/util/dataTypes.js new file mode 100644 index 00000000..140d3ff5 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.0/lib/util/dataTypes.js @@ -0,0 +1,266 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: ()=>normalize, + url: ()=>url, + number: ()=>number, + percentage: ()=>percentage, + length: ()=>length, + lineWidth: ()=>lineWidth, + shadow: ()=>shadow, + color: ()=>color, + image: ()=>image, + gradient: ()=>gradient, + position: ()=>position, + familyName: ()=>familyName, + genericName: ()=>genericName, + absoluteSize: ()=>absoluteSize, + relativeSize: ()=>relativeSize +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +const placeholder = "--tw-placeholder"; +const placeholderRe = new RegExp(placeholder, "g"); +function normalize(value, isRoot = true) { + if (value.startsWith("--")) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + // Add spaces around operators inside math functions like calc() that do not follow an operator + // or '('. + value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let vars = []; + return match.replace(/var\((--.+?)[,)]/g, (match, g1)=>{ + vars.push(g1); + return match.replace(g1, placeholder); + }).replace(/(-?\d*\.?\d(?!\b-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 ").replace(placeholderRe, ()=>vars.shift()); + }); + return value; +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "linear-gradient", + "radial-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient", + "conic-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.3.0/package.json b/packages/engine/test/fixtures/versions/3.3.0/package.json new file mode 100644 index 00000000..787afeb1 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.0/package.json @@ -0,0 +1,126 @@ +{ + "name": "tailwindcss", + "version": "3.3.0", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "0.1.59", + "@swc/core": "1.3.24", + "@swc/jest": "0.2.24", + "@swc/register": "0.1.10", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "concurrently": "^7.5.0", + "cssnano": "^5.1.14", + "esbuild": "^0.16.10", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.1.3", + "jest-diff": "^28.1.3", + "lightningcss": "^1.18.0", + "prettier": "^2.8.1", + "rimraf": "^3.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.6.3" + }, + "peerDependencies": { + "postcss": "^8.0.9" + }, + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.17.2", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.0.9", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1", + "sucrase": "^3.29.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=12.13.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.3.1/lib/index.js b/packages/engine/test/fixtures/versions/3.3.1/lib/index.js new file mode 100644 index 00000000..15e68381 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.1/lib/index.js @@ -0,0 +1,6 @@ +"use strict"; +if (process.env.OXIDE) { + module.exports = require("./oxide/postcss-plugin"); +} else { + module.exports = require("./plugin"); +} diff --git a/packages/engine/test/fixtures/versions/3.3.1/lib/plugin.js b/packages/engine/test/fixtures/versions/3.3.1/lib/plugin.js new file mode 100644 index 00000000..61b9189d --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.1/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interopRequireDefault(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root1 of roots){ + if (root1.type === "root") { + (0, _processTailwindFeatures.default)(context)(root1, result); + } + } + return; + } + (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.OXIDE && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.3.1/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.3.1/lib/processTailwindFeatures.js new file mode 100644 index 00000000..72cd530a --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.1/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: ()=>processTailwindFeatures +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interopRequireDefault(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interopRequireDefault(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interopRequireDefault(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interopRequireDefault(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interopRequireDefault(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.3.1/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.3.1/lib/util/dataTypes.js new file mode 100644 index 00000000..140d3ff5 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.1/lib/util/dataTypes.js @@ -0,0 +1,266 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: ()=>normalize, + url: ()=>url, + number: ()=>number, + percentage: ()=>percentage, + length: ()=>length, + lineWidth: ()=>lineWidth, + shadow: ()=>shadow, + color: ()=>color, + image: ()=>image, + gradient: ()=>gradient, + position: ()=>position, + familyName: ()=>familyName, + genericName: ()=>genericName, + absoluteSize: ()=>absoluteSize, + relativeSize: ()=>relativeSize +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +const placeholder = "--tw-placeholder"; +const placeholderRe = new RegExp(placeholder, "g"); +function normalize(value, isRoot = true) { + if (value.startsWith("--")) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + // Add spaces around operators inside math functions like calc() that do not follow an operator + // or '('. + value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let vars = []; + return match.replace(/var\((--.+?)[,)]/g, (match, g1)=>{ + vars.push(g1); + return match.replace(g1, placeholder); + }).replace(/(-?\d*\.?\d(?!\b-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 ").replace(placeholderRe, ()=>vars.shift()); + }); + return value; +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "linear-gradient", + "radial-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient", + "conic-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.3.1/package.json b/packages/engine/test/fixtures/versions/3.3.1/package.json new file mode 100644 index 00000000..642ebaf4 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.1/package.json @@ -0,0 +1,126 @@ +{ + "name": "tailwindcss", + "version": "3.3.1", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "0.1.59", + "@swc/core": "1.3.24", + "@swc/jest": "0.2.24", + "@swc/register": "0.1.10", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "concurrently": "^7.5.0", + "cssnano": "^5.1.14", + "esbuild": "^0.16.10", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.1.3", + "jest-diff": "^28.1.3", + "lightningcss": "^1.18.0", + "prettier": "^2.8.1", + "rimraf": "^3.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.6.3" + }, + "peerDependencies": { + "postcss": "^8.0.9" + }, + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.17.2", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.0.9", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1", + "sucrase": "^3.29.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=12.13.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.3.2/lib/index.js b/packages/engine/test/fixtures/versions/3.3.2/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.2/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.3.2/lib/plugin.js b/packages/engine/test/fixtures/versions/3.3.2/lib/plugin.js new file mode 100644 index 00000000..b6a0a500 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.2/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + (0, _processTailwindFeatures.default)(context)(root, result); + }, + false && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.3.2/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.3.2/lib/processTailwindFeatures.js new file mode 100644 index 00000000..78030404 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.2/lib/processTailwindFeatures.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interop_require_default(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.3.2/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.3.2/lib/util/dataTypes.js new file mode 100644 index 00000000..bf5897d5 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.2/lib/util/dataTypes.js @@ -0,0 +1,296 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +const placeholder = "--tw-placeholder"; +const placeholderRe = new RegExp(placeholder, "g"); +function normalize(value, isRoot = true) { + if (value.startsWith("--")) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + // Add spaces around operators inside math functions like calc() that do not follow an operator + // or '('. + value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let vars = []; + return match.replace(/var\((--.+?)[,)]/g, (match, g1)=>{ + vars.push(g1); + return match.replace(g1, placeholder); + }).replace(/(-?\d*\.?\d(?!\b-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 ").replace(placeholderRe, ()=>vars.shift()); + }); + return value; +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "linear-gradient", + "radial-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient", + "conic-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.3.2/package.json b/packages/engine/test/fixtures/versions/3.3.2/package.json new file mode 100644 index 00000000..30874050 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.2/package.json @@ -0,0 +1,122 @@ +{ + "name": "tailwindcss", + "version": "3.3.2", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.17.18", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.5.0", + "jest-diff": "^29.5.0", + "lightningcss": "1.18.0", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.18.2", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.3.3/lib/index.js b/packages/engine/test/fixtures/versions/3.3.3/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.3/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.3.3/lib/plugin.js b/packages/engine/test/fixtures/versions/3.3.3/lib/plugin.js new file mode 100644 index 00000000..8c984a3e --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.3/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + false && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.3.3/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.3.3/lib/processTailwindFeatures.js new file mode 100644 index 00000000..7831d5ec --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.3/lib/processTailwindFeatures.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interop_require_default(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.3.3/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.3.3/lib/util/dataTypes.js new file mode 100644 index 00000000..48f0a242 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.3/lib/util/dataTypes.js @@ -0,0 +1,304 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +const placeholder = "--tw-placeholder"; +const placeholderRe = new RegExp(placeholder, "g"); +function normalize(value, isRoot = true) { + if (value.startsWith("--")) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator or '('. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let vars = []; + return match.replace(/var\((--.+?)[,)]/g, (match, g1)=>{ + vars.push(g1); + return match.replace(g1, placeholder); + }).replace(/(-?\d*\.?\d(?!\b-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 ").replace(placeholderRe, ()=>vars.shift()); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.3.3/package.json b/packages/engine/test/fixtures/versions/3.3.3/package.json new file mode 100644 index 00000000..8fde0df9 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.3/package.json @@ -0,0 +1,121 @@ +{ + "name": "tailwindcss", + "version": "3.3.3", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.17.18", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.5.0", + "jest-diff": "^29.5.0", + "lightningcss": "1.18.0", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.18.2", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.3.4/lib/index.js b/packages/engine/test/fixtures/versions/3.3.4/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.4/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.3.4/lib/plugin.js b/packages/engine/test/fixtures/versions/3.3.4/lib/plugin.js new file mode 100644 index 00000000..8c984a3e --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.4/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + false && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.3.4/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.3.4/lib/processTailwindFeatures.js new file mode 100644 index 00000000..7831d5ec --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.4/lib/processTailwindFeatures.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interop_require_default(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.3.4/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.3.4/lib/util/dataTypes.js new file mode 100644 index 00000000..bcfeecac --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.4/lib/util/dataTypes.js @@ -0,0 +1,380 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator or '('. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/" + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.3.4/package.json b/packages/engine/test/fixtures/versions/3.3.4/package.json new file mode 100644 index 00000000..0e9960d2 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.4/package.json @@ -0,0 +1,121 @@ +{ + "name": "tailwindcss", + "version": "3.3.4", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.17.18", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.18.0", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.3.5/lib/index.js b/packages/engine/test/fixtures/versions/3.3.5/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.5/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.3.5/lib/plugin.js b/packages/engine/test/fixtures/versions/3.3.5/lib/plugin.js new file mode 100644 index 00000000..8c984a3e --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.5/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + false && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.3.5/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.3.5/lib/processTailwindFeatures.js new file mode 100644 index 00000000..7831d5ec --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.5/lib/processTailwindFeatures.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interop_require_default(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.3.5/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.3.5/lib/util/dataTypes.js new file mode 100644 index 00000000..1facc6cc --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.5/lib/util/dataTypes.js @@ -0,0 +1,404 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator or '('. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/" + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.3.5/package.json b/packages/engine/test/fixtures/versions/3.3.5/package.json new file mode 100644 index 00000000..4bef33cb --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.5/package.json @@ -0,0 +1,121 @@ +{ + "name": "tailwindcss", + "version": "3.3.5", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.17.18", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.18.0", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.3.6/lib/index.js b/packages/engine/test/fixtures/versions/3.3.6/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.6/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.3.6/lib/plugin.js b/packages/engine/test/fixtures/versions/3.3.6/lib/plugin.js new file mode 100644 index 00000000..8c984a3e --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.6/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + false && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.3.6/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.3.6/lib/processTailwindFeatures.js new file mode 100644 index 00000000..7831d5ec --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.6/lib/processTailwindFeatures.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interop_require_default(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.3.6/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.3.6/lib/util/dataTypes.js new file mode 100644 index 00000000..1302a9bd --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.6/lib/util/dataTypes.js @@ -0,0 +1,405 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.3.6/package.json b/packages/engine/test/fixtures/versions/3.3.6/package.json new file mode 100644 index 00000000..ecd4304f --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.6/package.json @@ -0,0 +1,121 @@ +{ + "name": "tailwindcss", + "version": "3.3.6", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.17.18", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.18.0", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.3.7/lib/index.js b/packages/engine/test/fixtures/versions/3.3.7/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.7/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.3.7/lib/plugin.js b/packages/engine/test/fixtures/versions/3.3.7/lib/plugin.js new file mode 100644 index 00000000..8c984a3e --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.7/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + false && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.3.7/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.3.7/lib/processTailwindFeatures.js new file mode 100644 index 00000000..7831d5ec --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.7/lib/processTailwindFeatures.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interop_require_default(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.3.7/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.3.7/lib/util/dataTypes.js new file mode 100644 index 00000000..1302a9bd --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.7/lib/util/dataTypes.js @@ -0,0 +1,405 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.3.7/package.json b/packages/engine/test/fixtures/versions/3.3.7/package.json new file mode 100644 index 00000000..b49c407a --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.3.7/package.json @@ -0,0 +1,121 @@ +{ + "name": "tailwindcss", + "version": "3.3.7", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.17.18", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.18.0", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.0/lib/index.js b/packages/engine/test/fixtures/versions/3.4.0/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.0/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.0/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.0/lib/plugin.js new file mode 100644 index 00000000..8c984a3e --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.0/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + false && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.0/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.0/lib/processTailwindFeatures.js new file mode 100644 index 00000000..7831d5ec --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.0/lib/processTailwindFeatures.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interop_require_default(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.0/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.0/lib/util/dataTypes.js new file mode 100644 index 00000000..1302a9bd --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.0/lib/util/dataTypes.js @@ -0,0 +1,405 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.0/package.json b/packages/engine/test/fixtures/versions/3.4.0/package.json new file mode 100644 index 00000000..c4b32ccd --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.0/package.json @@ -0,0 +1,121 @@ +{ + "name": "tailwindcss", + "version": "3.4.0", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.17.18", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.18.0", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.1/lib/index.js b/packages/engine/test/fixtures/versions/3.4.1/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.1/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.1/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.1/lib/plugin.js new file mode 100644 index 00000000..8c984a3e --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.1/lib/plugin.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + false && function lightningCssPlugin(_root, result) { + let postcss = require("postcss"); + let lightningcss = require("lightningcss"); + let browserslist = require("browserslist"); + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: typeof process !== "undefined" && process.env.JEST_WORKER_ID ? { + chrome: 106 << 16 + } : lightningcss.browserslistToTargets(browserslist(require("../package.json").browserslist)), + drafts: { + nesting: true, + customMedia: true + } + }); + var _result_map; + result.map = Object.assign((_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : {}, { + toJSON () { + return transformed.map.toJSON(); + }, + toString () { + return transformed.map.toString(); + } + }); + result.root = postcss.parse(transformed.code.toString("utf8")); + } catch (err) { + if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) { + let lines = err.source.split("\n"); + err = new Error([ + "Error formatting using Lightning CSS:", + "", + ...[ + "```css", + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + " ".repeat(err.loc.column - 1) + "^-- " + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + "```" + ] + ].join("\n")); + } + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin); + } + throw err; + } + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.1/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.1/lib/processTailwindFeatures.js new file mode 100644 index 00000000..7831d5ec --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.1/lib/processTailwindFeatures.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _detectNesting = /*#__PURE__*/ _interop_require_default(require("./lib/detectNesting")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + (0, _detectNesting.default)()(root, result); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.1/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.1/lib/util/dataTypes.js new file mode 100644 index 00000000..d6676de7 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.1/lib/util/dataTypes.js @@ -0,0 +1,415 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "x-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.1/package.json b/packages/engine/test/fixtures/versions/3.4.1/package.json new file mode 100644 index 00000000..2f024849 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.1/package.json @@ -0,0 +1,121 @@ +{ + "name": "tailwindcss", + "version": "3.4.1", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "tailwindcss": { + "engine": "stable" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.17.18", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.18.0", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.12/lib/index.js b/packages/engine/test/fixtures/versions/3.4.12/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.12/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.12/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.12/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.12/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.12/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.12/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.12/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.12/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.12/lib/util/dataTypes.js new file mode 100644 index 00000000..01f51037 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.12/lib/util/dataTypes.js @@ -0,0 +1,444 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + normalizeAttributeSelectors: function() { + return normalizeAttributeSelectors; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// - https://www.w3.org/TR/css-anchor-position-1 +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + "anchor-name", + "anchor-scope", + "position-anchor", + "position-try-options", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline", + "position-try" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +function normalizeAttributeSelectors(value) { + // Wrap values in attribute selectors with quotes + if (value.includes("=")) { + value = value.replace(/(=.*)/g, (_fullMatch, match)=>{ + if (match[1] === "'" || match[1] === '"') { + return match; + } + // Handle regex flags on unescaped values + if (match.length > 2) { + let trailingCharacter = match[match.length - 1]; + if (match[match.length - 2] === " " && (trailingCharacter === "i" || trailingCharacter === "I" || trailingCharacter === "s" || trailingCharacter === "S")) { + return `="${match.slice(1, -2)}" ${match[match.length - 1]}`; + } + } + return `="${match.slice(1)}"`; + }); + } + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient", + "anchor-size" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.12/package.json b/packages/engine/test/fixtures/versions/3.4.12/package.json new file mode 100644 index 00000000..556933bd --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.12/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.12", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.1.2", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.14/lib/index.js b/packages/engine/test/fixtures/versions/3.4.14/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.14/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.14/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.14/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.14/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.14/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.14/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.14/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.14/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.14/lib/util/dataTypes.js new file mode 100644 index 00000000..01f51037 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.14/lib/util/dataTypes.js @@ -0,0 +1,444 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + normalizeAttributeSelectors: function() { + return normalizeAttributeSelectors; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// - https://www.w3.org/TR/css-anchor-position-1 +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + "anchor-name", + "anchor-scope", + "position-anchor", + "position-try-options", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline", + "position-try" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +function normalizeAttributeSelectors(value) { + // Wrap values in attribute selectors with quotes + if (value.includes("=")) { + value = value.replace(/(=.*)/g, (_fullMatch, match)=>{ + if (match[1] === "'" || match[1] === '"') { + return match; + } + // Handle regex flags on unescaped values + if (match.length > 2) { + let trailingCharacter = match[match.length - 1]; + if (match[match.length - 2] === " " && (trailingCharacter === "i" || trailingCharacter === "I" || trailingCharacter === "s" || trailingCharacter === "S")) { + return `="${match.slice(1, -2)}" ${match[match.length - 1]}`; + } + } + return `="${match.slice(1)}"`; + }); + } + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient", + "anchor-size" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.14/package.json b/packages/engine/test/fixtures/versions/3.4.14/package.json new file mode 100644 index 00000000..e08c5dfc --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.14/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.14", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.1.2", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.17/lib/index.js b/packages/engine/test/fixtures/versions/3.4.17/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.17/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.17/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.17/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.17/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.17/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.17/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.17/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.17/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.17/lib/util/dataTypes.js new file mode 100644 index 00000000..01f51037 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.17/lib/util/dataTypes.js @@ -0,0 +1,444 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + normalizeAttributeSelectors: function() { + return normalizeAttributeSelectors; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// - https://www.w3.org/TR/css-anchor-position-1 +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + "anchor-name", + "anchor-scope", + "position-anchor", + "position-try-options", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline", + "position-try" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +function normalizeAttributeSelectors(value) { + // Wrap values in attribute selectors with quotes + if (value.includes("=")) { + value = value.replace(/(=.*)/g, (_fullMatch, match)=>{ + if (match[1] === "'" || match[1] === '"') { + return match; + } + // Handle regex flags on unescaped values + if (match.length > 2) { + let trailingCharacter = match[match.length - 1]; + if (match[match.length - 2] === " " && (trailingCharacter === "i" || trailingCharacter === "I" || trailingCharacter === "s" || trailingCharacter === "S")) { + return `="${match.slice(1, -2)}" ${match[match.length - 1]}`; + } + } + return `="${match.slice(1)}"`; + }); + } + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient", + "anchor-size" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.17/package.json b/packages/engine/test/fixtures/versions/3.4.17/package.json new file mode 100644 index 00000000..e08c5dfc --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.17/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.14", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.1.2", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.18/lib/index.js b/packages/engine/test/fixtures/versions/3.4.18/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.18/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.18/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.18/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.18/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.18/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.18/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.18/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.18/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.18/lib/util/dataTypes.js new file mode 100644 index 00000000..01f51037 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.18/lib/util/dataTypes.js @@ -0,0 +1,444 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + normalizeAttributeSelectors: function() { + return normalizeAttributeSelectors; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// - https://www.w3.org/TR/css-anchor-position-1 +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + "anchor-name", + "anchor-scope", + "position-anchor", + "position-try-options", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline", + "position-try" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +function normalizeAttributeSelectors(value) { + // Wrap values in attribute selectors with quotes + if (value.includes("=")) { + value = value.replace(/(=.*)/g, (_fullMatch, match)=>{ + if (match[1] === "'" || match[1] === '"') { + return match; + } + // Handle regex flags on unescaped values + if (match.length > 2) { + let trailingCharacter = match[match.length - 1]; + if (match[match.length - 2] === " " && (trailingCharacter === "i" || trailingCharacter === "I" || trailingCharacter === "s" || trailingCharacter === "S")) { + return `="${match.slice(1, -2)}" ${match[match.length - 1]}`; + } + } + return `="${match.slice(1)}"`; + }); + } + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient", + "anchor-size" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.18/package.json b/packages/engine/test/fixtures/versions/3.4.18/package.json new file mode 100644 index 00000000..e08c5dfc --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.18/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.14", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.1.2", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.2/lib/index.js b/packages/engine/test/fixtures/versions/3.4.2/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.2/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.2/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.2/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.2/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.2/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.2/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.2/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.2/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.2/lib/util/dataTypes.js new file mode 100644 index 00000000..90b2877c --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.2/lib/util/dataTypes.js @@ -0,0 +1,415 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.2/package.json b/packages/engine/test/fixtures/versions/3.4.2/package.json new file mode 100644 index 00000000..ce74242a --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.2/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.2", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.3/lib/index.js b/packages/engine/test/fixtures/versions/3.4.3/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.3/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.3/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.3/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.3/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.3/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.3/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.3/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.3/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.3/lib/util/dataTypes.js new file mode 100644 index 00000000..90b2877c --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.3/lib/util/dataTypes.js @@ -0,0 +1,415 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.3/package.json b/packages/engine/test/fixtures/versions/3.4.3/package.json new file mode 100644 index 00000000..32e40189 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.3/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.3", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.4/lib/index.js b/packages/engine/test/fixtures/versions/3.4.4/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.4/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.4/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.4/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.4/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.4/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.4/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.4/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.4/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.4/lib/util/dataTypes.js new file mode 100644 index 00000000..90b2877c --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.4/lib/util/dataTypes.js @@ -0,0 +1,415 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.4/package.json b/packages/engine/test/fixtures/versions/3.4.4/package.json new file mode 100644 index 00000000..ec4a212f --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.4/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.4", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.5/lib/index.js b/packages/engine/test/fixtures/versions/3.4.5/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.5/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.5/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.5/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.5/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.5/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.5/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.5/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.5/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.5/lib/util/dataTypes.js new file mode 100644 index 00000000..f16f0f19 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.5/lib/util/dataTypes.js @@ -0,0 +1,421 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// - https://www.w3.org/TR/css-anchor-position-1 +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + "anchor-name", + "anchor-scope", + "position-anchor", + "position-try-options", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline", + "position-try" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.5/package.json b/packages/engine/test/fixtures/versions/3.4.5/package.json new file mode 100644 index 00000000..6c8cb1a0 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.5/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.5", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.6/lib/index.js b/packages/engine/test/fixtures/versions/3.4.6/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.6/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.6/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.6/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.6/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.6/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.6/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.6/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.6/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.6/lib/util/dataTypes.js new file mode 100644 index 00000000..f16f0f19 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.6/lib/util/dataTypes.js @@ -0,0 +1,421 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// - https://www.w3.org/TR/css-anchor-position-1 +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + "anchor-name", + "anchor-scope", + "position-anchor", + "position-try-options", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline", + "position-try" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.6/package.json b/packages/engine/test/fixtures/versions/3.4.6/package.json new file mode 100644 index 00000000..728e2c1e --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.6/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.6", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/3.4.7/lib/index.js b/packages/engine/test/fixtures/versions/3.4.7/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.7/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/3.4.7/lib/plugin.js b/packages/engine/test/fixtures/versions/3.4.7/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.7/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/3.4.7/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/3.4.7/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.7/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/3.4.7/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/3.4.7/lib/util/dataTypes.js new file mode 100644 index 00000000..9ab786e1 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.7/lib/util/dataTypes.js @@ -0,0 +1,443 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + normalizeAttributeSelectors: function() { + return normalizeAttributeSelectors; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// - https://www.w3.org/TR/css-anchor-position-1 +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + "anchor-name", + "anchor-scope", + "position-anchor", + "position-try-options", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline", + "position-try" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +function normalizeAttributeSelectors(value) { + // Wrap values in attribute selectors with quotes + if (value.includes("=")) { + value = value.replace(/(=.*)/g, (_fullMatch, match)=>{ + if (match[1] === "'" || match[1] === '"') { + return match; + } + // Handle regex flags on unescaped values + if (match.length > 2) { + let trailingCharacter = match[match.length - 1]; + if (match[match.length - 2] === " " && (trailingCharacter === "i" || trailingCharacter === "I" || trailingCharacter === "s" || trailingCharacter === "S")) { + return `="${match.slice(1, -2)}" ${match[match.length - 1]}`; + } + } + return `="${match.slice(1)}"`; + }); + } + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/3.4.7/package.json b/packages/engine/test/fixtures/versions/3.4.7/package.json new file mode 100644 index 00000000..1120edd2 --- /dev/null +++ b/packages/engine/test/fixtures/versions/3.4.7/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.7", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.0.0", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/README.md b/packages/engine/test/fixtures/versions/README.md new file mode 100644 index 00000000..966a76a0 --- /dev/null +++ b/packages/engine/test/fixtures/versions/README.md @@ -0,0 +1,3 @@ +# tailwindcss-versions + +yarn add tailwindcss diff --git a/packages/engine/test/fixtures/versions/copy.js b/packages/engine/test/fixtures/versions/copy.js new file mode 100644 index 00000000..881b1814 --- /dev/null +++ b/packages/engine/test/fixtures/versions/copy.js @@ -0,0 +1,68 @@ +import fs from 'node:fs/promises' +import path from 'pathe' + +import { copyFiles, ensureDir, getCurrentFilename, pathExists } from './utils.js' +function getTailwindcssVersion(str) { + // eslint-disable-next-line no-useless-escape + const match = /^tailwindcss([\d\.]*)$/.exec(str) + if (match === null) { + // 不是 tailwindcss + return false + } else if (match[1] === '') { + return 'lts' + } else { + return match[1] + } +} + +const relativePaths = [ + 'package.json', 'lib/index.js', 'lib/plugin.js', 'lib/processTailwindFeatures.js', 'lib/util/dataTypes.js', + 'lib/jit/index.js', 'lib/jit/processTailwindFeatures.js' +] +// async function copyTargetFile() { + +// } + +async function main() { + const filename = getCurrentFilename(import.meta.url) + const dirname = path.dirname(filename) + const nodeModulesPath = path.resolve(dirname, 'node_modules') + const packageJsonPath = path.resolve(dirname, 'package.json') + + if (!(await pathExists(nodeModulesPath))) { + console.warn('[versions] node_modules directory not found. Run `yarn install` inside fixtures/versions first.') + return + } + + const filenames = await fs.readdir(nodeModulesPath) + const pkgJson = await fs.readFile(packageJsonPath, 'utf8').then(res => JSON.parse(res)) + const dependencies = pkgJson.dependencies ?? {} + const entries = Object.entries(dependencies) + + if (entries.length === 0) { + console.warn('[versions] No dependencies found in fixtures/versions package.json.') + return + } + + for (let i = 0; i < entries.length; i++) { + const [localPkgName] = entries[i] + + const version = getTailwindcssVersion(localPkgName) + if (version && filenames.includes(localPkgName)) { + const targetDir = path.resolve(dirname, version) + await ensureDir(targetDir) + await copyFiles(relativePaths.map(x => { + return { + src: path.resolve(nodeModulesPath, localPkgName, x), + dest: path.resolve(targetDir, x) + } + })) + } else if (version) { + console.warn(`[versions] Package ${localPkgName} is listed but not installed. Re-run install.js for ${version}.`) + } + } + + console.log('[versions] TailwindCSS snapshots updated.') +} + +main() diff --git a/packages/engine/test/fixtures/versions/install.js b/packages/engine/test/fixtures/versions/install.js new file mode 100644 index 00000000..3d756bdb --- /dev/null +++ b/packages/engine/test/fixtures/versions/install.js @@ -0,0 +1,60 @@ +import { execa } from 'execa' +import { fileURLToPath } from 'node:url' + +const versions = process.argv.slice(2).map(arg => arg.trim()).filter(Boolean) +const workspaceRoot = fileURLToPath(new URL('.', import.meta.url)) + +if (!versions.length) { + console.error('[versions] Expected at least one Tailwind CSS version, e.g. `node install.js 3.4.18`.') + process.exitCode = 1 +} else { + try { + for (const version of versions) { + await installVersion(version) + } + console.log('[versions] Installation complete.') + } catch (error) { + console.error('[versions] Failed to install requested version(s).') + console.error(error) + process.exitCode = 1 + } +} + +function normalizeVersion(version) { + if (!version) { + throw new Error('Version must be a non-empty string.') + } + + const trimmed = version.trim() + if (trimmed === 'lts' || trimmed === 'latest') { + return { + display: 'tailwindcss@latest', + spec: 'tailwindcss', + } + } + + const withoutPrefix = trimmed.replace(/^tailwindcss/i, '').replace(/^v/, '') + if (!withoutPrefix) { + throw new Error(`Unable to determine Tailwind CSS version from "${version}".`) + } + + const alias = `tailwindcss${withoutPrefix}` + return { + display: `tailwindcss@${withoutPrefix}`, + spec: `${alias}@npm:tailwindcss@${withoutPrefix}`, + } +} + +async function installVersion(version) { + const { display, spec } = normalizeVersion(version) + console.log(`[versions] Installing ${display} via yarn…`) + const child = execa('yarn', ['add', spec], { + cwd: workspaceRoot, + stdio: 'pipe', + }) + + child.stdout?.pipe(process.stdout) + child.stderr?.pipe(process.stderr) + + await child +} diff --git a/packages/engine/test/fixtures/versions/lts/lib/index.js b/packages/engine/test/fixtures/versions/lts/lib/index.js new file mode 100644 index 00000000..c947d974 --- /dev/null +++ b/packages/engine/test/fixtures/versions/lts/lib/index.js @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./plugin"); diff --git a/packages/engine/test/fixtures/versions/lts/lib/plugin.js b/packages/engine/test/fixtures/versions/lts/lib/plugin.js new file mode 100644 index 00000000..a234003b --- /dev/null +++ b/packages/engine/test/fixtures/versions/lts/lib/plugin.js @@ -0,0 +1,48 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext")); +const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures")); +const _sharedState = require("./lib/sharedState"); +const _findAtConfigPath = require("./lib/findAtConfigPath"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +module.exports = function tailwindcss(configOrPath) { + return { + postcssPlugin: "tailwindcss", + plugins: [ + _sharedState.env.DEBUG && function(root) { + console.log("\n"); + console.time("JIT TOTAL"); + return root; + }, + async function(root, result) { + var _findAtConfigPath1; + // Use the path for the `@config` directive if it exists, otherwise use the + // path for the file being processed + configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath; + let context = (0, _setupTrackingContext.default)(configOrPath); + if (root.type === "document") { + let roots = root.nodes.filter((node)=>node.type === "root"); + for (const root of roots){ + if (root.type === "root") { + await (0, _processTailwindFeatures.default)(context)(root, result); + } + } + return; + } + await (0, _processTailwindFeatures.default)(context)(root, result); + }, + _sharedState.env.DEBUG && function(root) { + console.timeEnd("JIT TOTAL"); + console.log("\n"); + return root; + } + ].filter(Boolean) + }; +}; +module.exports.postcss = true; diff --git a/packages/engine/test/fixtures/versions/lts/lib/processTailwindFeatures.js b/packages/engine/test/fixtures/versions/lts/lib/processTailwindFeatures.js new file mode 100644 index 00000000..a23f5df3 --- /dev/null +++ b/packages/engine/test/fixtures/versions/lts/lib/processTailwindFeatures.js @@ -0,0 +1,62 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "default", { + enumerable: true, + get: function() { + return processTailwindFeatures; + } +}); +const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives")); +const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules")); +const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules")); +const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions")); +const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules")); +const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules")); +const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules")); +const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations")); +const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules")); +const _setupContextUtils = require("./lib/setupContextUtils"); +const _featureFlags = require("./featureFlags"); +function _interop_require_default(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; +} +function processTailwindFeatures(setupContext) { + return async function(root, result) { + let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root); + // Partition apply rules that are found in the css + // itself. + (0, _partitionApplyAtRules.default)()(root, result); + let context = setupContext({ + tailwindDirectives, + applyDirectives, + registerDependency (dependency) { + result.messages.push({ + plugin: "tailwindcss", + parent: result.opts.from, + ...dependency + }); + }, + createContext (tailwindConfig, changedContent) { + return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root); + } + })(root, result); + if (context.tailwindConfig.separator === "-") { + throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."); + } + (0, _featureFlags.issueFlagNotices)(context.tailwindConfig); + await (0, _expandTailwindAtRules.default)(context)(root, result); + // Partition apply rules that are generated by + // addComponents, addUtilities and so on. + (0, _partitionApplyAtRules.default)()(root, result); + (0, _expandApplyAtRules.default)(context)(root, result); + (0, _evaluateTailwindFunctions.default)(context)(root, result); + (0, _substituteScreenAtRules.default)(context)(root, result); + (0, _resolveDefaultsAtRules.default)(context)(root, result); + (0, _collapseAdjacentRules.default)(context)(root, result); + (0, _collapseDuplicateDeclarations.default)(context)(root, result); + }; +} diff --git a/packages/engine/test/fixtures/versions/lts/lib/util/dataTypes.js b/packages/engine/test/fixtures/versions/lts/lib/util/dataTypes.js new file mode 100644 index 00000000..01f51037 --- /dev/null +++ b/packages/engine/test/fixtures/versions/lts/lib/util/dataTypes.js @@ -0,0 +1,444 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +function _export(target, all) { + for(var name in all)Object.defineProperty(target, name, { + enumerable: true, + get: all[name] + }); +} +_export(exports, { + normalize: function() { + return normalize; + }, + normalizeAttributeSelectors: function() { + return normalizeAttributeSelectors; + }, + url: function() { + return url; + }, + number: function() { + return number; + }, + percentage: function() { + return percentage; + }, + length: function() { + return length; + }, + lineWidth: function() { + return lineWidth; + }, + shadow: function() { + return shadow; + }, + color: function() { + return color; + }, + image: function() { + return image; + }, + gradient: function() { + return gradient; + }, + position: function() { + return position; + }, + familyName: function() { + return familyName; + }, + genericName: function() { + return genericName; + }, + absoluteSize: function() { + return absoluteSize; + }, + relativeSize: function() { + return relativeSize; + } +}); +const _color = require("./color"); +const _parseBoxShadowValue = require("./parseBoxShadowValue"); +const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly"); +let cssFunctions = [ + "min", + "max", + "clamp", + "calc" +]; +// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types +function isCSSFunction(value) { + return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value)); +} +// These properties accept a `` as one of the values. This means that you can use them +// as: `timeline-scope: --tl;` +// +// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add +// the `var()` yourself. +// +// More info: +// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope +// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident +// - https://www.w3.org/TR/css-anchor-position-1 +// +const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([ + // Concrete properties + "scroll-timeline-name", + "timeline-scope", + "view-timeline-name", + "font-palette", + "anchor-name", + "anchor-scope", + "position-anchor", + "position-try-options", + // Shorthand properties + "scroll-timeline", + "animation-timeline", + "view-timeline", + "position-try" +]); +function normalize(value, context = null, isRoot = true) { + let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property); + if (value.startsWith("--") && !isVarException) { + return `var(${value})`; + } + // Keep raw strings if it starts with `url(` + if (value.includes("url(")) { + return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{ + if (/^url\(.*?\)$/.test(part)) { + return part; + } + return normalize(part, context, false); + }).join(""); + } + // Convert `_` to ` `, except for escaped underscores `\_` + value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_"); + // Remove leftover whitespace + if (isRoot) { + value = value.trim(); + } + value = normalizeMathOperatorSpacing(value); + return value; +} +function normalizeAttributeSelectors(value) { + // Wrap values in attribute selectors with quotes + if (value.includes("=")) { + value = value.replace(/(=.*)/g, (_fullMatch, match)=>{ + if (match[1] === "'" || match[1] === '"') { + return match; + } + // Handle regex flags on unescaped values + if (match.length > 2) { + let trailingCharacter = match[match.length - 1]; + if (match[match.length - 2] === " " && (trailingCharacter === "i" || trailingCharacter === "I" || trailingCharacter === "s" || trailingCharacter === "S")) { + return `="${match.slice(1, -2)}" ${match[match.length - 1]}`; + } + } + return `="${match.slice(1)}"`; + }); + } + return value; +} +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator, '(', or `,`. + * + * @param {string} value + * @returns {string} + */ function normalizeMathOperatorSpacing(value) { + let preventFormattingInFunctions = [ + "theme" + ]; + let preventFormattingKeywords = [ + "min-content", + "max-content", + "fit-content", + // Env + "safe-area-inset-top", + "safe-area-inset-right", + "safe-area-inset-bottom", + "safe-area-inset-left", + "titlebar-area-x", + "titlebar-area-y", + "titlebar-area-width", + "titlebar-area-height", + "keyboard-inset-top", + "keyboard-inset-right", + "keyboard-inset-bottom", + "keyboard-inset-left", + "keyboard-inset-width", + "keyboard-inset-height", + "radial-gradient", + "linear-gradient", + "conic-gradient", + "repeating-radial-gradient", + "repeating-linear-gradient", + "repeating-conic-gradient", + "anchor-size" + ]; + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{ + let result = ""; + function lastChar() { + let char = result.trimEnd(); + return char[char.length - 1]; + } + for(let i = 0; i < match.length; i++){ + function peek(word) { + return word.split("").every((char, j)=>match[i + j] === char); + } + function consumeUntil(chars) { + let minIndex = Infinity; + for (let char of chars){ + let index = match.indexOf(char, i); + if (index !== -1 && index < minIndex) { + minIndex = index; + } + } + let result = match.slice(i, minIndex); + i += result.length - 1; + return result; + } + let char = match[i]; + // Handle `var(--variable)` + if (peek("var")) { + // When we consume until `)`, then we are dealing with this scenario: + // `var(--example)` + // + // When we consume until `,`, then we are dealing with this scenario: + // `var(--example, 1rem)` + // + // In this case we do want to "format", the default value as well + result += consumeUntil([ + ")", + "," + ]); + } else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) { + let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword)); + result += keyword; + i += keyword.length - 1; + } else if (preventFormattingInFunctions.some((fn)=>peek(fn))) { + result += consumeUntil([ + ")" + ]); + } else if (peek("[")) { + result += consumeUntil([ + "]" + ]); + } else if ([ + "+", + "-", + "*", + "/" + ].includes(char) && ![ + "(", + "+", + "-", + "*", + "/", + "," + ].includes(lastChar())) { + result += ` ${char} `; + } else { + result += char; + } + } + // Simplify multiple spaces + return result.replace(/\s+/g, " "); + }); +} +function url(value) { + return value.startsWith("url("); +} +function number(value) { + return !isNaN(Number(value)) || isCSSFunction(value); +} +function percentage(value) { + return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value); +} +// Please refer to MDN when updating this list: +// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units +// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units +let lengthUnits = [ + "cm", + "mm", + "Q", + "in", + "pc", + "pt", + "px", + "em", + "ex", + "ch", + "rem", + "lh", + "rlh", + "vw", + "vh", + "vmin", + "vmax", + "vb", + "vi", + "svw", + "svh", + "lvw", + "lvh", + "dvw", + "dvh", + "cqw", + "cqh", + "cqi", + "cqb", + "cqmin", + "cqmax" +]; +let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`; +function length(value) { + return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value); +} +let lineWidths = new Set([ + "thin", + "medium", + "thick" +]); +function lineWidth(value) { + return lineWidths.has(value); +} +function shadow(value) { + let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value)); + for (let parsedShadow of parsedShadows){ + if (!parsedShadow.valid) { + return false; + } + } + return true; +} +function color(value) { + let colors = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if ((0, _color.parseColor)(part, { + loose: true + }) !== null) return colors++, true; + return false; + }); + if (!result) return false; + return colors > 0; +} +function image(value) { + let images = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (url(part) || gradient(part) || [ + "element(", + "image(", + "cross-fade(", + "image-set(" + ].some((fn)=>part.startsWith(fn))) { + images++; + return true; + } + return false; + }); + if (!result) return false; + return images > 0; +} +let gradientTypes = new Set([ + "conic-gradient", + "linear-gradient", + "radial-gradient", + "repeating-conic-gradient", + "repeating-linear-gradient", + "repeating-radial-gradient" +]); +function gradient(value) { + value = normalize(value); + for (let type of gradientTypes){ + if (value.startsWith(`${type}(`)) { + return true; + } + } + return false; +} +let validPositions = new Set([ + "center", + "top", + "right", + "bottom", + "left" +]); +function position(value) { + let positions = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + if (validPositions.has(part) || length(part) || percentage(part)) { + positions++; + return true; + } + return false; + }); + if (!result) return false; + return positions > 0; +} +function familyName(value) { + let fonts = 0; + let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{ + part = normalize(part); + if (part.startsWith("var(")) return true; + // If it contains spaces, then it should be quoted + if (part.includes(" ")) { + if (!/(['"])([^"']+)\1/g.test(part)) { + return false; + } + } + // If it starts with a number, it's invalid + if (/^\d/g.test(part)) { + return false; + } + fonts++; + return true; + }); + if (!result) return false; + return fonts > 0; +} +let genericNames = new Set([ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui", + "ui-serif", + "ui-sans-serif", + "ui-monospace", + "ui-rounded", + "math", + "emoji", + "fangsong" +]); +function genericName(value) { + return genericNames.has(value); +} +let absoluteSizes = new Set([ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "xxx-large" +]); +function absoluteSize(value) { + return absoluteSizes.has(value); +} +let relativeSizes = new Set([ + "larger", + "smaller" +]); +function relativeSize(value) { + return relativeSizes.has(value); +} diff --git a/packages/engine/test/fixtures/versions/lts/package.json b/packages/engine/test/fixtures/versions/lts/package.json new file mode 100644 index 00000000..e08c5dfc --- /dev/null +++ b/packages/engine/test/fixtures/versions/lts/package.json @@ -0,0 +1,118 @@ +{ + "name": "tailwindcss", + "version": "3.4.14", + "description": "A utility-first CSS framework for rapidly building custom user interfaces.", + "license": "MIT", + "main": "lib/index.js", + "types": "types/index.d.ts", + "repository": "https://github.com/tailwindlabs/tailwindcss.git", + "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", + "homepage": "https://tailwindcss.com", + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "scripts": { + "prebuild": "npm run generate && rimraf lib", + "build": "swc src --out-dir lib --copy-files", + "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", + "style": "eslint .", + "pretest": "npm run generate", + "test": "jest", + "test:integrations": "npm run test --prefix ./integrations", + "install:integrations": "node scripts/install-integrations.js", + "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", + "generate:types": "node -r @swc/register scripts/generate-types.js", + "generate": "npm run generate:plugin-list && npm run generate:types", + "release-channel": "node ./scripts/release-channel.js", + "release-notes": "node ./scripts/release-notes.js", + "prepublishOnly": "npm install --force && npm run build" + }, + "files": [ + "src/*", + "cli/*", + "lib/*", + "peers/*", + "scripts/*.js", + "stubs/*", + "nesting/*", + "types/**/*", + "*.d.ts", + "*.css", + "*.js" + ], + "devDependencies": { + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.55", + "@swc/jest": "^0.2.26", + "@swc/register": "^0.1.10", + "autoprefixer": "^10.4.14", + "browserslist": "^4.21.5", + "concurrently": "^8.0.1", + "cssnano": "^6.1.2", + "esbuild": "^0.20.2", + "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^29.6.0", + "jest-diff": "^29.6.0", + "lightningcss": "1.24.1", + "prettier": "^2.8.8", + "rimraf": "^5.0.0", + "source-map-js": "^1.0.2", + "turbo": "^1.9.3" + }, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "browserslist": [ + "> 1%", + "not edge <= 18", + "not ie 11", + "not op_mini all" + ], + "jest": { + "testTimeout": 30000, + "setupFilesAfterEnv": [ + "/jest/customMatchers.js" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/integrations/", + "/standalone-cli/", + "\\.test\\.skip\\.js$" + ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], + "transform": { + "\\.js$": "@swc/jest", + "\\.ts$": "@swc/jest" + } + }, + "engines": { + "node": ">=14.0.0" + } +} diff --git a/packages/engine/test/fixtures/versions/package.json b/packages/engine/test/fixtures/versions/package.json new file mode 100644 index 00000000..ed0305dd --- /dev/null +++ b/packages/engine/test/fixtures/versions/package.json @@ -0,0 +1,53 @@ +{ + "name": "tailwindcss-versions", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "get": "node ./install.js", + "sample": "yarn add tailwindcss3.2.6@npm:tailwindcss@3.2.6", + "copy": "node ./copy.js", + "postinstall": "npm run copy", + "-": "----------------------------------------------------------", + "usage": "npm run get {version}" + }, + "keywords": [], + "author": "", + "packageManager": "yarn@1.22.22", + "license": "ISC", + "dependencies": { + "tailwindcss": "^3.4.14", + "tailwindcss2": "npm:@tailwindcss/postcss7-compat", + "tailwindcss3.0.0": "npm:tailwindcss@3.0.0", + "tailwindcss3.2.1": "npm:tailwindcss@3.2.1", + "tailwindcss3.2.2": "npm:tailwindcss@3.2.2", + "tailwindcss3.2.3": "npm:tailwindcss@3.2.3", + "tailwindcss3.2.4": "npm:tailwindcss@3.2.4", + "tailwindcss3.2.6": "npm:tailwindcss@3.2.6", + "tailwindcss3.2.7": "npm:tailwindcss@3.2.7", + "tailwindcss3.3.0": "npm:tailwindcss@3.3.0", + "tailwindcss3.3.1": "npm:tailwindcss@3.3.1", + "tailwindcss3.3.2": "npm:tailwindcss@3.3.2", + "tailwindcss3.3.3": "npm:tailwindcss@3.3.3", + "tailwindcss3.3.4": "npm:tailwindcss@3.3.4", + "tailwindcss3.3.5": "npm:tailwindcss@3.3.5", + "tailwindcss3.3.6": "npm:tailwindcss@3.3.6", + "tailwindcss3.3.7": "npm:tailwindcss@3.3.7", + "tailwindcss3.4.0": "npm:tailwindcss@3.4.0", + "tailwindcss3.4.1": "npm:tailwindcss@3.4.1", + "tailwindcss3.4.12": "npm:tailwindcss@3.4.12", + "tailwindcss3.4.14": "npm:tailwindcss@3.4.14", + "tailwindcss3.4.17": "npm:tailwindcss@3.4.17", + "tailwindcss3.4.18": "npm:tailwindcss@3.4.18", + "tailwindcss3.4.2": "npm:tailwindcss@3.4.2", + "tailwindcss3.4.3": "npm:tailwindcss@3.4.3", + "tailwindcss3.4.4": "npm:tailwindcss@3.4.4", + "tailwindcss3.4.5": "npm:tailwindcss@3.4.5", + "tailwindcss3.4.6": "npm:tailwindcss@3.4.6", + "tailwindcss3.4.7": "npm:tailwindcss@3.4.7" + }, + "devDependencies": { + "execa": "^7.1.1" + } +} diff --git a/packages/engine/test/fixtures/versions/utils.js b/packages/engine/test/fixtures/versions/utils.js new file mode 100644 index 00000000..2e24989d --- /dev/null +++ b/packages/engine/test/fixtures/versions/utils.js @@ -0,0 +1,39 @@ +import fs from 'node:fs/promises' +import path from 'pathe' +import { fileURLToPath } from 'node:url' + +export function getCurrentFilename (importMetaUrl) { + return fileURLToPath(importMetaUrl) +} + +export async function ensureDir (p) { + await fs.mkdir(p, { + recursive: true + }) +} + +export async function copyFiles (arr) { + if (Array.isArray(arr)) { + for (let i = 0; i < arr.length; i++) { + const { src, dest } = arr[i] + await ensureDir(path.dirname(dest)) + + const isExisted = await pathExists(src) + + if (isExisted) { + await fs.copyFile(src, dest) + } else { + console.warn(`[warning]: 404 ${src}`) + } + } + } +} + +export async function pathExists (target) { + try { + await fs.access(target) + return true + } catch { + return false + } +} diff --git a/packages/engine/test/fixtures/versions/yarn.lock b/packages/engine/test/fixtures/versions/yarn.lock new file mode 100644 index 00000000..18ccc390 --- /dev/null +++ b/packages/engine/test/fixtures/versions/yarn.lock @@ -0,0 +1,2505 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.npmmirror.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + +"@babel/code-frame@^7.0.0": + version "7.18.6" + resolved "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/helper-validator-identifier@^7.18.6": + version "7.19.1" + resolved "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.npmmirror.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.18" + resolved "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.npmmirror.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +acorn-node@^1.8.2: + version "1.8.2" + resolved "https://registry.npmmirror.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" + integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== + dependencies: + acorn "^7.0.0" + acorn-walk "^7.0.0" + xtend "^4.0.2" + +acorn-walk@^7.0.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.0.0: + version "7.4.1" + resolved "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1" + integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^6.1.0: + version "6.2.3" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" + integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^5.0.1, arg@^5.0.2: + version "5.0.2" + resolved "https://registry.npmmirror.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" + integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== + +autoprefixer@^9: + version "9.8.8" + resolved "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-9.8.8.tgz#fd4bd4595385fa6f06599de749a4d5f7a474957a" + integrity sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA== + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + picocolors "^0.2.1" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.12.0: + version "4.23.2" + resolved "https://registry.npmmirror.com/browserslist/-/browserslist-4.23.2.tgz#244fe803641f1c19c28c48c4b6ec9736eb3d32ed" + integrity sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA== + dependencies: + caniuse-lite "^1.0.30001640" + electron-to-chromium "^1.4.820" + node-releases "^2.0.14" + update-browserslist-db "^1.1.0" + +bytes@^3.0.0: + version "3.1.2" + resolved "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001640: + version "1.0.30001642" + resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz#6aa6610eb24067c246d30c57f055a9d0a7f8d05f" + integrity sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA== + +chalk@^2.0.0, chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^3.5.2, chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chokidar@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.9.0: + version "1.9.1" + resolved "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^4.0.1: + version "4.2.3" + resolved "https://registry.npmmirror.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== + dependencies: + color-convert "^2.0.1" + color-string "^1.9.0" + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commander@^8.0.0: + version "8.3.0" + resolved "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +cosmiconfig@^7.0.1: + version "7.1.0" + resolved "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.npmmirror.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + integrity sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q== + +css-unit-converter@^1.1.1: + version "1.1.2" + resolved "https://registry.npmmirror.com/css-unit-converter/-/css-unit-converter-1.1.2.tgz#4c77f5a1954e6dbff60695ecb214e3270436ab21" + integrity sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +defined@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" + integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== + +detective@^5.2.0, detective@^5.2.1: + version "5.2.1" + resolved "https://registry.npmmirror.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034" + integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw== + dependencies: + acorn-node "^1.8.2" + defined "^1.0.0" + minimist "^1.2.6" + +didyoumean@^1.2.2: + version "1.2.2" + resolved "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== + +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.npmmirror.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +electron-to-chromium@^1.4.820: + version "1.4.830" + resolved "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.830.tgz#a11899bc3343bc28f57a87fcf83060e0d28038d4" + integrity sha512-TrPKKH20HeN0J1LHzsYLs2qwXrp8TF4nHdu4sq61ozGbzMpWhI7iIOPYPPkxeq1azMT9PZ8enPFcftbs/Npcjg== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.npmmirror.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +execa@^7.1.1: + version "7.1.1" + resolved "https://registry.npmmirror.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43" + integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + +fast-glob@^3.2.12, fast-glob@^3.2.7: + version "3.2.12" + resolved "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-glob@^3.3.0: + version "3.3.1" + resolved "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +foreground-child@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + +fs-extra@^10.0.0: + version "10.1.0" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1, glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + +glob@^7.1.2, glob@^7.1.3, glob@^7.1.7: + version "7.2.3" + resolved "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== + +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + integrity sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A== + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + integrity sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA== + +html-tags@^3.1.0: + version "3.3.1" + resolved "https://registry.npmmirror.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce" + integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ== + +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.npmmirror.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-color-stop@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + integrity sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA== + dependencies: + css-color-names "^0.0.4" + hex-color-regex "^1.1.0" + hsl-regex "^1.0.0" + hsla-regex "^1.0.0" + rgb-regex "^1.0.1" + rgba-regex "^1.0.0" + +is-core-module@^2.11.0: + version "2.12.0" + resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4" + integrity sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ== + dependencies: + has "^1.0.3" + +is-core-module@^2.16.1: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jiti@^1.17.2, jiti@^1.18.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.18.2.tgz#80c3ef3d486ebf2450d9335122b32d121f2a83cd" + integrity sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg== + +jiti@^1.19.1: + version "1.20.0" + resolved "https://registry.npmmirror.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42" + integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA== + +jiti@^1.21.0: + version "1.21.3" + resolved "https://registry.npmmirror.com/jiti/-/jiti-1.21.3.tgz#b2adb07489d7629b344d59082bbedb8c21c5f755" + integrity sha512-uy2bNX5zQ+tESe+TiC7ilGRz8AtRGmnJH55NC5S0nSUjvvvM2hJHmefHErugGXN4pNv4Qx7vLsnNw9qJ9mtIsw== + +jiti@^1.21.6, jiti@^1.21.7: + version "1.21.7" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.7.tgz#9dd81043424a3d28458b193d965f0d18a2300ba9" + integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +lilconfig@^2.0.5, lilconfig@^2.0.6, lilconfig@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +lilconfig@^3.0.0, lilconfig@^3.1.1, lilconfig@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" + integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lodash.topath@^4.5.2: + version "4.5.2" + resolved "https://registry.npmmirror.com/lodash.topath/-/lodash.topath-4.5.2.tgz#3616351f3bba61994a0931989660bd03254fd009" + integrity sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +modern-normalize@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/modern-normalize/-/modern-normalize-1.1.0.tgz#da8e80140d9221426bd4f725c6e11283d34f90b7" + integrity sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA== + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +nanoid@^3.3.4, nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +node-emoji@^1.11.0: + version "1.11.0" + resolved "https://registry.npmmirror.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c" + integrity sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A== + dependencies: + lodash "^4.17.21" + +node-releases@^2.0.14: + version "2.0.17" + resolved "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.17.tgz#d74bc4fec38d839eec5db2a3c9c963d4f33cb366" + integrity sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.npmmirror.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== + +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.npmmirror.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg== + +object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-hash@^2.2.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== + +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.npmmirror.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pirates@^4.0.1: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + +postcss-functions@^3: + version "3.0.0" + resolved "https://registry.npmmirror.com/postcss-functions/-/postcss-functions-3.0.0.tgz#0e94d01444700a481de20de4d55fb2640564250e" + integrity sha512-N5yWXWKA+uhpLQ9ZhBRl2bIAdM6oVJYpDojuI1nF2SzXBimJcdjFwiAouBVbO5VuOF3qA6BSFWFc3wXbbj72XQ== + dependencies: + glob "^7.1.2" + object-assign "^4.1.1" + postcss "^6.0.9" + postcss-value-parser "^3.3.0" + +postcss-import@^14.1.0: + version "14.1.0" + resolved "https://registry.npmmirror.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0" + integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-import@^15.1.0: + version "15.1.0" + resolved "https://registry.npmmirror.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" + integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-js@^2: + version "2.0.3" + resolved "https://registry.npmmirror.com/postcss-js/-/postcss-js-2.0.3.tgz#a96f0f23ff3d08cec7dc5b11bf11c5f8077cdab9" + integrity sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w== + dependencies: + camelcase-css "^2.0.1" + postcss "^7.0.18" + +postcss-js@^3.0.3: + version "3.0.3" + resolved "https://registry.npmmirror.com/postcss-js/-/postcss-js-3.0.3.tgz#2f0bd370a2e8599d45439f6970403b5873abda33" + integrity sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw== + dependencies: + camelcase-css "^2.0.1" + postcss "^8.1.6" + +postcss-js@^4.0.0, postcss-js@^4.0.1: + version "4.0.1" + resolved "https://registry.npmmirror.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" + integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== + dependencies: + camelcase-css "^2.0.1" + +postcss-load-config@^3.1.0, postcss-load-config@^3.1.4: + version "3.1.4" + resolved "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855" + integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg== + dependencies: + lilconfig "^2.0.5" + yaml "^1.10.2" + +postcss-load-config@^4.0.1: + version "4.0.1" + resolved "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-4.0.1.tgz#152383f481c2758274404e4962743191d73875bd" + integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA== + dependencies: + lilconfig "^2.0.5" + yaml "^2.1.1" + +postcss-load-config@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" + integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== + dependencies: + lilconfig "^3.0.0" + yaml "^2.3.4" + +"postcss-load-config@^4.0.2 || ^5.0 || ^6.0": + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz#6fd7dcd8ae89badcf1b2d644489cbabf83aa8096" + integrity sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g== + dependencies: + lilconfig "^3.1.1" + +postcss-nested@5.0.6: + version "5.0.6" + resolved "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc" + integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA== + dependencies: + postcss-selector-parser "^6.0.6" + +postcss-nested@6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.0.0.tgz#1572f1984736578f360cffc7eb7dca69e30d1735" + integrity sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w== + dependencies: + postcss-selector-parser "^6.0.10" + +postcss-nested@^4: + version "4.2.3" + resolved "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-4.2.3.tgz#c6f255b0a720549776d220d00c4b70cd244136f6" + integrity sha512-rOv0W1HquRCamWy2kFl3QazJMMe1ku6rCFoAAH+9AcxdbpDeBr6k968MLWuLjvjMcGEip01ak09hKOEgpK9hvw== + dependencies: + postcss "^7.0.32" + postcss-selector-parser "^6.0.2" + +postcss-nested@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.0.1.tgz#f83dc9846ca16d2f4fa864f16e9d9f7d0961662c" + integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ== + dependencies: + postcss-selector-parser "^6.0.11" + +postcss-nested@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131" + integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ== + dependencies: + postcss-selector-parser "^6.1.1" + +postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.6: + version "6.0.11" + resolved "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" + integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-selector-parser@^6.0.2: + version "6.1.1" + resolved "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz#5be94b277b8955904476a2400260002ce6c56e38" + integrity sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-selector-parser@^6.1.1, postcss-selector-parser@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" + integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^3.3.0: + version "3.3.1" + resolved "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^6.0.9: + version "6.0.23" + resolved "https://registry.npmmirror.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" + integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.4.0" + +postcss@^7, postcss@^7.0.18, postcss@^7.0.32: + version "7.0.39" + resolved "https://registry.npmmirror.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + +postcss@^8.0.9, postcss@^8.1.6, postcss@^8.4.17, postcss@^8.4.18: + version "8.4.21" + resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" + integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.3.5: + version "8.4.39" + resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.39.tgz#aa3c94998b61d3a9c259efa51db4b392e1bde0e3" + integrity sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.1" + source-map-js "^1.2.0" + +postcss@^8.4.23: + version "8.4.23" + resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.23.tgz#df0aee9ac7c5e53e1075c24a3613496f9e6552ab" + integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.4.47: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +pretty-hrtime@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" + integrity sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A== + +purgecss@^4.0.3: + version "4.1.3" + resolved "https://registry.npmmirror.com/purgecss/-/purgecss-4.1.3.tgz#683f6a133c8c4de7aa82fe2746d1393b214918f7" + integrity sha512-99cKy4s+VZoXnPxaoM23e5ABcP851nC2y2GROkkjS8eJaJtlciGavd7iYAw2V84WeBqggZ12l8ef44G99HmTaw== + dependencies: + commander "^8.0.0" + glob "^7.1.7" + postcss "^8.3.5" + postcss-selector-parser "^6.0.6" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== + dependencies: + pify "^2.3.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +reduce-css-calc@^2.1.8: + version "2.1.8" + resolved "https://registry.npmmirror.com/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz#7ef8761a28d614980dc0c982f772c93f7a99de03" + integrity sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg== + dependencies: + css-unit-converter "^1.1.1" + postcss-value-parser "^3.3.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.1.7, resolve@^1.20.0, resolve@^1.22.1: + version "1.22.1" + resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^1.22.2: + version "1.22.2" + resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + dependencies: + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^1.22.8: + version "1.22.11" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" + integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== + dependencies: + is-core-module "^2.16.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + integrity sha512-gDK5mkALDFER2YLqH6imYvK6g02gpNGM4ILDZ472EwWfXZnC2ZEpoB2ECXTyOVUKuk/bPJZMzwQPBYICzP+D3w== + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + integrity sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg== + +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-js@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba" + integrity sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA== + dependencies: + ansi-regex "^6.0.1" + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +sucrase@^3.29.0: + version "3.31.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.31.0.tgz#daae4fd458167c5d4ba1cce6aef57b988b417b33" + integrity sha512-6QsHnkqyVEzYcaiHsOKkzOtOgdJcb8i54x6AV2hDwyZcY9ZyykGZVw6L/YN98xC0evwTP6utsWWrKRaa8QlfEQ== + dependencies: + commander "^4.0.0" + glob "7.1.6" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + +sucrase@^3.32.0: + version "3.32.0" + resolved "https://registry.npmmirror.com/sucrase/-/sucrase-3.32.0.tgz#c4a95e0f1e18b6847127258a75cf360bc568d4a7" + integrity sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "7.1.6" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + +sucrase@^3.35.0: + version "3.35.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" + integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "^10.3.10" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + +supports-color@^5.3.0, supports-color@^5.4.0: + version "5.5.0" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +"tailwindcss2@npm:@tailwindcss/postcss7-compat": + version "2.2.17" + resolved "https://registry.npmmirror.com/@tailwindcss/postcss7-compat/-/postcss7-compat-2.2.17.tgz#dc78f3880a2af84163150ff426a39e42b9ae8922" + integrity sha512-3h2svqQAqYHxRZ1KjsJjZOVTQ04m29LjfrLjXyZZEJuvUuJN+BCIF9GI8vhE1s0plS0mogd6E6YLg6mu4Wv/Vw== + dependencies: + arg "^5.0.1" + autoprefixer "^9" + bytes "^3.0.0" + chalk "^4.1.2" + chokidar "^3.5.2" + color "^4.0.1" + cosmiconfig "^7.0.1" + detective "^5.2.0" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.7" + fs-extra "^10.0.0" + glob-parent "^6.0.1" + html-tags "^3.1.0" + is-color-stop "^1.1.0" + is-glob "^4.0.1" + lodash "^4.17.21" + lodash.topath "^4.5.2" + modern-normalize "^1.1.0" + node-emoji "^1.11.0" + normalize-path "^3.0.0" + object-hash "^2.2.0" + postcss "^7" + postcss-functions "^3" + postcss-js "^2" + postcss-load-config "^3.1.0" + postcss-nested "^4" + postcss-selector-parser "^6.0.6" + postcss-value-parser "^4.1.0" + pretty-hrtime "^1.0.3" + purgecss "^4.0.3" + quick-lru "^5.1.1" + reduce-css-calc "^2.1.8" + resolve "^1.20.0" + tmp "^0.2.1" + +"tailwindcss3.0.0@npm:tailwindcss@3.0.0": + version "3.0.0" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.0.0.tgz#f7dfd30996b3b1a84d656aaf3c8b6810b70d3d42" + integrity sha512-UPAp2PS5vojAvGClJFIkdh2hfFyaSWo09Ma9j2vZYW+ANhTvpUHFjY85JgtrvvXXREtDvOXy2BxW1yHOz8apCg== + dependencies: + arg "^5.0.1" + chalk "^4.1.2" + chokidar "^3.5.2" + color-name "^1.1.4" + cosmiconfig "^7.0.1" + detective "^5.2.0" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.7" + glob-parent "^6.0.2" + is-glob "^4.0.3" + normalize-path "^3.0.0" + object-hash "^2.2.0" + postcss-js "^3.0.3" + postcss-load-config "^3.1.0" + postcss-nested "5.0.6" + postcss-selector-parser "^6.0.6" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.20.0" + tmp "^0.2.1" + +"tailwindcss3.2.1@npm:tailwindcss@3.2.1": + version "3.2.1" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.2.1.tgz#1bd828fff3172489962357f8d531c184080a6786" + integrity sha512-Uw+GVSxp5CM48krnjHObqoOwlCt5Qo6nw1jlCRwfGy68dSYb/LwS9ZFidYGRiM+w6rMawkZiu1mEMAsHYAfoLg== + dependencies: + arg "^5.0.2" + chokidar "^3.5.3" + color-name "^1.1.4" + detective "^5.2.1" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + lilconfig "^2.0.6" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.17" + postcss-import "^14.1.0" + postcss-js "^4.0.0" + postcss-load-config "^3.1.4" + postcss-nested "6.0.0" + postcss-selector-parser "^6.0.10" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.1" + +"tailwindcss3.2.2@npm:tailwindcss@3.2.2": + version "3.2.2" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.2.2.tgz#705f78cec8f4de2feb52abdb7a8a056e67f2d736" + integrity sha512-c2GtSdqg+harR4QeoTmex0Ngfg8IIHNeLQH5yr2B9uZbZR1Xt1rYbjWOWTcj3YLTZhrmZnPowoQDbSRFyZHQ5Q== + dependencies: + arg "^5.0.2" + chokidar "^3.5.3" + color-name "^1.1.4" + detective "^5.2.1" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + lilconfig "^2.0.6" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.18" + postcss-import "^14.1.0" + postcss-js "^4.0.0" + postcss-load-config "^3.1.4" + postcss-nested "6.0.0" + postcss-selector-parser "^6.0.10" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.1" + +"tailwindcss3.2.3@npm:tailwindcss@3.2.3": + version "3.2.3" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.2.3.tgz#c5ee3cb95dae7a80592d43a460d277915c7b2938" + integrity sha512-Xt9D4PK4zuuQCEB8bwK9JUCKmTgUwyac/6b0/42Vqhgl6YJkep+Wf5wq+5uXYfmrupdAD0YY2NY1hyZp1HjRrg== + dependencies: + arg "^5.0.2" + chokidar "^3.5.3" + color-name "^1.1.4" + detective "^5.2.1" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + lilconfig "^2.0.6" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.18" + postcss-import "^14.1.0" + postcss-js "^4.0.0" + postcss-load-config "^3.1.4" + postcss-nested "6.0.0" + postcss-selector-parser "^6.0.10" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.1" + +"tailwindcss3.2.4@npm:tailwindcss@3.2.4": + version "3.2.4" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.2.4.tgz#afe3477e7a19f3ceafb48e4b083e292ce0dc0250" + integrity sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ== + dependencies: + arg "^5.0.2" + chokidar "^3.5.3" + color-name "^1.1.4" + detective "^5.2.1" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + lilconfig "^2.0.6" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.18" + postcss-import "^14.1.0" + postcss-js "^4.0.0" + postcss-load-config "^3.1.4" + postcss-nested "6.0.0" + postcss-selector-parser "^6.0.10" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.1" + +"tailwindcss3.2.6@npm:tailwindcss@3.2.6": + version "3.2.6" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.2.6.tgz#9bedbc744a4a85d6120ce0cc3db024c551a5c733" + integrity sha512-BfgQWZrtqowOQMC2bwaSNe7xcIjdDEgixWGYOd6AL0CbKHJlvhfdbINeAW76l1sO+1ov/MJ93ODJ9yluRituIw== + dependencies: + arg "^5.0.2" + chokidar "^3.5.3" + color-name "^1.1.4" + detective "^5.2.1" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + lilconfig "^2.0.6" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.0.9" + postcss-import "^14.1.0" + postcss-js "^4.0.0" + postcss-load-config "^3.1.4" + postcss-nested "6.0.0" + postcss-selector-parser "^6.0.11" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.1" + +"tailwindcss3.2.7@npm:tailwindcss@3.2.7": + version "3.2.7" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.2.7.tgz#5936dd08c250b05180f0944500c01dce19188c07" + integrity sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ== + dependencies: + arg "^5.0.2" + chokidar "^3.5.3" + color-name "^1.1.4" + detective "^5.2.1" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + lilconfig "^2.0.6" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.0.9" + postcss-import "^14.1.0" + postcss-js "^4.0.0" + postcss-load-config "^3.1.4" + postcss-nested "6.0.0" + postcss-selector-parser "^6.0.11" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.1" + +"tailwindcss3.3.0@npm:tailwindcss@3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.0.tgz#8cab40e5a10a10648118c0859ba8bfbc744a761e" + integrity sha512-hOXlFx+YcklJ8kXiCAfk/FMyr4Pm9ck477G0m/us2344Vuj355IpoEDB5UmGAsSpTBmr+4ZhjzW04JuFXkb/fw== + dependencies: + arg "^5.0.2" + chokidar "^3.5.3" + color-name "^1.1.4" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.17.2" + lilconfig "^2.0.6" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.0.9" + postcss-import "^14.1.0" + postcss-js "^4.0.0" + postcss-load-config "^3.1.4" + postcss-nested "6.0.0" + postcss-selector-parser "^6.0.11" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.1" + sucrase "^3.29.0" + +"tailwindcss3.3.1@npm:tailwindcss@3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.1.tgz#b6662fab6a9b704779e48d083a9fef5a81d2b81e" + integrity sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g== + dependencies: + arg "^5.0.2" + chokidar "^3.5.3" + color-name "^1.1.4" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.17.2" + lilconfig "^2.0.6" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.0.9" + postcss-import "^14.1.0" + postcss-js "^4.0.0" + postcss-load-config "^3.1.4" + postcss-nested "6.0.0" + postcss-selector-parser "^6.0.11" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.1" + sucrase "^3.29.0" + +"tailwindcss3.3.2@npm:tailwindcss@3.3.2": + version "3.3.2" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.3.2.tgz#2f9e35d715fdf0bbf674d90147a0684d7054a2d3" + integrity sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.18.2" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + postcss-value-parser "^4.2.0" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.3.3@npm:tailwindcss@3.3.3": + version "3.3.3" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf" + integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.18.2" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.3.4@npm:tailwindcss@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.3.4.tgz#f08c493ff3ddf03081c40e780e98f129e1c8214d" + integrity sha512-JXZNOkggUAc9T5E7nCrimoXHcSf9h3NWFe5sh36CGD/3M5TRLuQeFnQoDsit2uVTqgoOZHLx5rTykLUu16vsMQ== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.19.1" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.3.5@npm:tailwindcss@3.3.5": + version "3.3.5" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.3.5.tgz#22a59e2fbe0ecb6660809d9cc5f3976b077be3b8" + integrity sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.19.1" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.3.6@npm:tailwindcss@3.3.6": + version "3.3.6" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.3.6.tgz#4dd7986bf4902ad385d90d45fd4b2fa5fab26d5f" + integrity sha512-AKjF7qbbLvLaPieoKeTjG1+FyNZT6KaJMJPFeQyLfIp7l82ggH1fbHJSsYIvnbTFQOlkh+gBYpyby5GT1LIdLw== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.19.1" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.3.7@npm:tailwindcss@3.3.7": + version "3.3.7" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.3.7.tgz#9e3c0cb7c6867b4cda4557a447bd2bb6fe20c6fa" + integrity sha512-pjgQxDZPvyS/nG3ZYkyCvsbONJl7GdOejfm24iMt2ElYQQw8Jc4p0m8RdMp7mznPD0kUhfzwV3zAwa80qI0zmQ== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.19.1" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.4.0@npm:tailwindcss@3.4.0": + version "3.4.0" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.0.tgz#045a9c474e6885ebd0436354e611a76af1c76839" + integrity sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.19.1" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.4.12@npm:tailwindcss@3.4.12": + version "3.4.12" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.12.tgz#fd3b67c6d2c04d9d7bfa13e3fc70ccef9fef0455" + integrity sha512-Htf/gHj2+soPb9UayUNci/Ja3d8pTmu9ONTfh4QY8r3MATTZOzmv6UYWF7ZwikEIC8okpfqmGqrmDehua8mF8w== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.4.14@npm:tailwindcss@3.4.14": + version "3.4.14" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.14.tgz#6dd23a7f54ec197b19159e91e3bb1e55e7aa73ac" + integrity sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.4.17@npm:tailwindcss@3.4.17": + version "3.4.17" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.17.tgz#ae8406c0f96696a631c790768ff319d46d5e5a63" + integrity sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.6.0" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.2" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.6" + lilconfig "^3.1.3" + micromatch "^4.0.8" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.1.1" + postcss "^8.4.47" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.2" + postcss-nested "^6.2.0" + postcss-selector-parser "^6.1.2" + resolve "^1.22.8" + sucrase "^3.35.0" + +"tailwindcss3.4.18@npm:tailwindcss@3.4.18": + version "3.4.18" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.18.tgz#9fa9650aace186644b608242f1e57d2d55593301" + integrity sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.6.0" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.2" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.7" + lilconfig "^3.1.3" + micromatch "^4.0.8" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.1.1" + postcss "^8.4.47" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.2 || ^5.0 || ^6.0" + postcss-nested "^6.2.0" + postcss-selector-parser "^6.1.2" + resolve "^1.22.8" + sucrase "^3.35.0" + +"tailwindcss3.4.1@npm:tailwindcss@3.4.1": + version "3.4.1" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.1.tgz#f512ca5d1dd4c9503c7d3d28a968f1ad8f5c839d" + integrity sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.19.1" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.4.2@npm:tailwindcss@3.4.2": + version "3.4.2" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.2.tgz#c983ea21ec1e561ede9a2fe98aadb840bee89fda" + integrity sha512-1kIzVecynNKMhhX8mPTOwTkkVHupUTMbEvk4n1ByxdM8sQTJ8fE41Y4TdORG6GmiVXHhfZ/++0hiIFJFwfadsA== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.4.3@npm:tailwindcss@3.4.3": + version "3.4.3" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.3.tgz#be48f5283df77dfced705451319a5dffb8621519" + integrity sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.4.4@npm:tailwindcss@3.4.4": + version "3.4.4" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.4.tgz#351d932273e6abfa75ce7d226b5bf3a6cb257c05" + integrity sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.4.5@npm:tailwindcss@3.4.5": + version "3.4.5" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.5.tgz#0de2e92ed4d00fb015feb962fa0781605761724d" + integrity sha512-DlTxttYcogpDfx3tf/8jfnma1nfAYi2cBUYV2YNoPPecwmO3YGiFlOX9D8tGAu+EDF38ryBzvrDKU/BLMsUwbw== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.4.6@npm:tailwindcss@3.4.6": + version "3.4.6" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.6.tgz#41faae16607e0916da1eaa4a3b44053457ba70dd" + integrity sha512-1uRHzPB+Vzu57ocybfZ4jh5Q3SdlH7XW23J5sQoM9LhE9eIOlzxer/3XPSsycvih3rboRsvt0QCmzSrqyOYUIA== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +"tailwindcss3.4.7@npm:tailwindcss@3.4.7": + version "3.4.7" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.7.tgz#6092f18767f5933f59375b9afe558e592fc77201" + integrity sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +tailwindcss@^3.4.14: + version "3.4.14" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.14.tgz#6dd23a7f54ec197b19159e91e3bb1e55e7aa73ac" + integrity sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.npmmirror.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmmirror.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +xtend@^4.0.2: + version "4.0.2" + resolved "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yaml@^1.10.0, yaml@^1.10.2: + version "1.10.2" + resolved "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yaml@^2.1.1: + version "2.2.2" + resolved "https://registry.npmmirror.com/yaml/-/yaml-2.2.2.tgz#ec551ef37326e6d42872dad1970300f8eb83a073" + integrity sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA== + +yaml@^2.3.4: + version "2.8.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" + integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== diff --git a/packages/engine/test/style-generator.test.ts b/packages/engine/test/style-generator.test.ts new file mode 100644 index 00000000..df9fdbf8 --- /dev/null +++ b/packages/engine/test/style-generator.test.ts @@ -0,0 +1,210 @@ +import { createRequire } from 'node:module' +import path from 'pathe' +import postcss from 'postcss' +import tailwindcss3 from 'tailwindcss-3' +import { describe, expect, it, vi } from 'vitest' +import { + collectTailwindStyleCandidates, + escapeCssClassName, + generateCustomStyle, + generateTailwindStyle, + generateTailwindV3RawStyle, + generateTailwindV3Style, +} from '@/index' + +const require = createRequire(import.meta.url) +const packageRoot = path.resolve(__dirname, '..') +const tailwindNodeBase = path.dirname(require.resolve('@tailwindcss/node')) + +describe('Tailwind style generator', () => { + it('collects candidates for all style generation engines', async () => { + const candidates = await collectTailwindStyleCandidates({ + bareArbitraryValues: true, + candidates: ['text-red-500'], + sources: [ + { + content: '', + extension: 'tsx', + }, + { + content: '.primary { @apply inline-flex items-center; }', + extension: 'css', + }, + ], + }) + + expect(candidates).toEqual(new Set([ + 'text-red-500', + 'min-h-screen', + 'rounded-[18px]', + 'p-10%', + 'inline-flex', + 'items-center', + ])) + }) + + it('generates Tailwind v3 css with Tailwind v3 internal JIT engine', async () => { + const result = await generateTailwindV3Style({ + cwd: packageRoot, + packageName: 'tailwindcss-3', + candidates: ['text-red-500', 'not-a-real-class'], + sources: [ + { + content: '', + extension: 'wxml', + }, + ], + config: { + corePlugins: { + preflight: false, + }, + }, + }) + + expect(result.version).toBe(3) + expect(result.tokens).toEqual(new Set([ + 'text-red-500', + 'not-a-real-class', + 'min-h-screen', + 'rounded-[18px]', + 'hover:bg-blue-500', + ])) + expect(result.classSet).toEqual(new Set([ + 'text-red-500', + 'min-h-screen', + 'rounded-[18px]', + 'hover:bg-blue-500', + ])) + expect(result.css).toContain('.min-h-screen') + expect(result.css).toContain('.rounded-\\[18px\\]') + expect(result.css).toContain('.text-red-500') + expect(result.css).toContain('.hover\\:bg-blue-500:hover') + expect(result.css).not.toContain('not-a-real-class') + }) + + it('matches Tailwind v3 PostCSS output while using the internal engine path', async () => { + const candidates = [ + 'rounded-[18px]', + 'text-red-500', + 'hover:bg-blue-500', + ] + const internal = await generateTailwindV3Style({ + cwd: packageRoot, + packageName: 'tailwindcss-3', + candidates, + config: { + corePlugins: { + preflight: false, + }, + }, + }) + const postcssResult = await postcss([ + tailwindcss3({ + content: [ + { + raw: candidates.join(' '), + extension: 'html', + }, + ], + corePlugins: { + preflight: false, + }, + }), + ]).process('@tailwind utilities;', { + from: undefined, + }) + + expect(internal.css).toBe(postcssResult.css) + }) + + it('generates raw Tailwind v3 css from an entry source without the PostCSS plugin', async () => { + const result = await generateTailwindV3RawStyle({ + cwd: packageRoot, + packageName: 'tailwindcss-3', + css: '@tailwind base; @tailwind components; @tailwind utilities;', + candidates: ['container', 'text-red-500'], + config: { + corePlugins: { + preflight: false, + }, + }, + }) + + expect(result.version).toBe(3) + expect(result.tokens).toEqual(new Set(['container', 'text-red-500'])) + expect(result.classSet).toContain('container') + expect(result.classSet).toContain('text-red-500') + expect(result.css).toContain('.container') + expect(result.css).toContain('.text-red-500') + expect(result.dependencies).toEqual([]) + }) + + it('keeps Tailwind v3 raw direct utilities output aligned with the high-level v3 generator', async () => { + const options = { + cwd: packageRoot, + packageName: 'tailwindcss-3', + candidates: ['rounded-[18px]', 'text-red-500', 'hover:bg-blue-500'], + config: { + corePlugins: { + preflight: false, + }, + }, + } + const raw = await generateTailwindV3RawStyle(options) + const highLevel = await generateTailwindV3Style(options) + + expect(raw.css).toBe(highLevel.css) + expect(raw.classSet).toEqual(highLevel.classSet) + }) + + it('routes Tailwind v3 and v4 through the unified generator', async () => { + const v3 = await generateTailwindStyle({ + version: 3, + cwd: packageRoot, + packageName: 'tailwindcss-3', + candidates: ['text-red-500'], + }) + const v4 = await generateTailwindStyle({ + version: 4, + projectRoot: packageRoot, + cwd: packageRoot, + base: tailwindNodeBase, + css: '@import "tailwindcss";', + candidates: ['text-red-500'], + }) + + expect(v3.version).toBe(3) + expect(v3.css).toContain('.text-red-500') + expect(v4.version).toBe(4) + expect(v4.css).toContain('.text-red-500') + }) + + it('lets callers fully customize css generation', async () => { + const generate = vi.fn(({ tokens }: { tokens: Set }) => { + return [...tokens] + .sort() + .map(token => `.${escapeCssClassName(token)}{--tw-engine-token:"${token}"}`) + .join('\n') + }) + + const result = await generateCustomStyle({ + candidates: ['text-red-500'], + sources: [ + { + content: '', + extension: 'wxml', + }, + ], + generate, + }) + + expect(generate).toHaveBeenCalledOnce() + expect(result.version).toBe('custom') + expect(result.tokens).toEqual(new Set(['text-red-500', 'rounded-[18px]'])) + expect(result.classSet).toEqual(result.tokens) + expect(result.css).toBe([ + '.rounded-\\[18px\\]{--tw-engine-token:"rounded-[18px]"}', + '.text-red-500{--tw-engine-token:"text-red-500"}', + ].join('\n')) + }) +}) diff --git a/packages/engine/test/v4.bare-arbitrary-values.test.ts b/packages/engine/test/v4.bare-arbitrary-values.test.ts new file mode 100644 index 00000000..ddf2c181 --- /dev/null +++ b/packages/engine/test/v4.bare-arbitrary-values.test.ts @@ -0,0 +1,101 @@ +import { describe, expect, it } from 'vitest' +import { resolveBareArbitraryValueCandidate } from '@/v4/bare-arbitrary-values' + +describe('bare arbitrary value resolver', () => { + it('resolves common UnoCSS-style bare arbitrary values', () => { + expect(resolveBareArbitraryValueCandidate('p-10%', true)).toEqual({ + candidate: 'p-10%', + canonicalCandidate: 'p-[10%]', + }) + expect(resolveBareArbitraryValueCandidate('p-2.5px', true)).toEqual({ + candidate: 'p-2.5px', + canonicalCandidate: 'p-[2.5px]', + }) + expect(resolveBareArbitraryValueCandidate('m-4rem', true)).toEqual({ + candidate: 'm-4rem', + canonicalCandidate: 'm-[4rem]', + }) + }) + + it('supports variants, negative values and important modifiers', () => { + expect(resolveBareArbitraryValueCandidate('hover:!-mt-2rem', true)).toEqual({ + candidate: 'hover:!-mt-2rem', + canonicalCandidate: 'hover:!-mt-[2rem]', + }) + expect(resolveBareArbitraryValueCandidate('sm:-top-1.5rem', true)).toEqual({ + candidate: 'sm:-top-1.5rem', + canonicalCandidate: 'sm:-top-[1.5rem]', + }) + }) + + it('supports hex colors and function values', () => { + expect(resolveBareArbitraryValueCandidate('bg-#fff', true)).toEqual({ + candidate: 'bg-#fff', + canonicalCandidate: 'bg-[#fff]', + }) + expect(resolveBareArbitraryValueCandidate('bg-\\#fff', true)).toEqual({ + candidate: 'bg-\\#fff', + canonicalCandidate: 'bg-[#fff]', + }) + expect(resolveBareArbitraryValueCandidate('text-rgb(255,0,0)', true)).toEqual({ + candidate: 'text-rgb(255,0,0)', + canonicalCandidate: 'text-[rgb(255,0,0)]', + }) + expect(resolveBareArbitraryValueCandidate('w-[calc(100%-1rem)]', true)).toBeUndefined() + expect(resolveBareArbitraryValueCandidate('w-calc(100vh)', true)).toEqual({ + candidate: 'w-calc(100vh)', + canonicalCandidate: 'w-[calc(100vh)]', + }) + expect(resolveBareArbitraryValueCandidate('w-calc(100%_-_1rem)', true)).toEqual({ + candidate: 'w-calc(100%_-_1rem)', + canonicalCandidate: 'w-[calc(100%_-_1rem)]', + }) + }) + + it('keeps escaped underscores inside arbitrary values', () => { + expect(resolveBareArbitraryValueCandidate('content-"hello_world"', true)).toEqual({ + candidate: 'content-"hello_world"', + canonicalCandidate: 'content-["hello_world"]', + }) + expect(resolveBareArbitraryValueCandidate('content-"hello\\_world"', true)).toEqual({ + candidate: 'content-"hello\\_world"', + canonicalCandidate: 'content-["hello\\_world"]', + }) + expect(resolveBareArbitraryValueCandidate('content-"hello\\5f world"', true)).toEqual({ + candidate: 'content-"hello\\5f world"', + canonicalCandidate: 'content-["hello\\_world"]', + }) + }) + + it('prefers the longest utility prefix before bare function values', () => { + expect(resolveBareArbitraryValueCandidate('grid-cols-repeat(2,_minmax(0,_1fr))', true)).toEqual({ + candidate: 'grid-cols-repeat(2,_minmax(0,_1fr))', + canonicalCandidate: 'grid-cols-[repeat(2,_minmax(0,_1fr))]', + }) + }) + + it('rejects ambiguous or unsupported values', () => { + expect(resolveBareArbitraryValueCandidate('p-4', true)).toBeUndefined() + expect(resolveBareArbitraryValueCandidate('bg-red-500', true)).toBeUndefined() + expect(resolveBareArbitraryValueCandidate('text-var(--brand)', true)).toEqual({ + candidate: 'text-var(--brand)', + canonicalCandidate: 'text-[color:var(--brand)]', + }) + expect(resolveBareArbitraryValueCandidate('w-calc(100%-1rem', true)).toBeUndefined() + }) + + it('supports UnoCSS aspect ratio shorthand', () => { + expect(resolveBareArbitraryValueCandidate('aspect-16/9', true)).toEqual({ + candidate: 'aspect-16/9', + canonicalCandidate: 'aspect-[16/9]', + }) + }) + + it('respects custom unit allow lists', () => { + expect(resolveBareArbitraryValueCandidate('p-10%', { units: ['px'] })).toBeUndefined() + expect(resolveBareArbitraryValueCandidate('p-10px', { units: ['px'] })).toEqual({ + candidate: 'p-10px', + canonicalCandidate: 'p-[10px]', + }) + }) +}) diff --git a/packages/engine/test/v4.engine.test.ts b/packages/engine/test/v4.engine.test.ts new file mode 100644 index 00000000..dcab3ba2 --- /dev/null +++ b/packages/engine/test/v4.engine.test.ts @@ -0,0 +1,498 @@ +import { promises as fs } from 'node:fs' +import { createRequire } from 'node:module' +import os from 'node:os' +import path from 'pathe' +import { afterEach, describe, expect, it } from 'vitest' +import { + createTailwindV4Engine, + resolveTailwindV4Source, +} from '@/v4' + +const require = createRequire(import.meta.url) +const packageRoot = path.resolve(__dirname, '..') +const tailwindNodeBase = path.dirname(require.resolve('@tailwindcss/node')) +const tempDirs: string[] = [] + +async function createTempDir() { + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'tw-engine-v4-engine-')) + tempDirs.push(tempDir) + return tempDir +} + +async function createDefaultSource(css = '@import "tailwindcss";') { + return resolveTailwindV4Source({ + projectRoot: packageRoot, + base: tailwindNodeBase, + css, + }) +} + +afterEach(async () => { + await Promise.all(tempDirs.splice(0).map(tempDir => fs.rm(tempDir, { recursive: true, force: true }))) +}) + +describe('Tailwind v4 engine', () => { + it('generates CSS from inline css and explicit candidates', async () => { + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + candidates: ['text-red-500'], + }) + + expect(result.classSet).toContain('text-red-500') + expect(result.css).toContain('.text-red-500') + }) + + it('does not include invalid candidates in classSet', async () => { + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + candidates: ['text-red-500', 'definitely-not-a-tailwind-class'], + }) + + expect(result.classSet).toContain('text-red-500') + expect(result.classSet).not.toContain('definitely-not-a-tailwind-class') + expect(result.css).not.toContain('definitely-not-a-tailwind-class') + }) + + it('generates arbitrary value utilities', async () => { + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + candidates: ['w-[100px]'], + }) + + expect(result.classSet).toContain('w-[100px]') + expect(result.css).toContain('width: 100px') + }) + + it('keeps UnoCSS-style bare arbitrary values disabled by default', async () => { + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + candidates: ['p-10%', 'p-2.5px', 'm-4rem'], + }) + + expect(result.rawCandidates).toContain('p-10%') + expect(result.classSet).not.toContain('p-10%') + expect(result.css).not.toContain('.p-10\\%') + }) + + it('generates CSS for UnoCSS-style bare arbitrary values when enabled', async () => { + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + bareArbitraryValues: true, + candidates: ['p-10%', 'p-2.5px', 'm-4rem'], + }) + + expect(result.classSet).toEqual(new Set(['p-10%', 'p-2.5px', 'm-4rem'])) + expect(result.css).toContain('.p-10\\%') + expect(result.css).toContain('padding: 10%') + expect(result.css).toContain('.p-2\\.5px') + expect(result.css).toContain('padding: 2.5px') + expect(result.css).toContain('.m-4rem') + expect(result.css).toContain('margin: 4rem') + expect(result.css).not.toContain('.p-\\[10\\%\\]') + expect(result.css).not.toContain('.p-\\[2\\.5px\\]') + }) + + it('supports broader bare arbitrary value forms when enabled', async () => { + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + bareArbitraryValues: true, + candidates: [ + 'bg-#fff', + 'bg-\\#000', + 'text-rgb(255,0,0)', + 'grid-cols-repeat(2,_minmax(0,_1fr))', + 'w-calc(100%_-_1rem)', + 'w-calc(100vh)', + 'sm:-top-1.5rem', + ], + }) + + expect(result.classSet).toEqual(new Set([ + 'bg-#fff', + 'bg-\\#000', + 'text-rgb(255,0,0)', + 'grid-cols-repeat(2,_minmax(0,_1fr))', + 'w-calc(100%_-_1rem)', + 'w-calc(100vh)', + 'sm:-top-1.5rem', + ])) + expect(result.css).toContain('.bg-\\#fff') + expect(result.css).toContain('background-color: #fff') + expect(result.css).toContain('.bg-\\\\\\#000') + expect(result.css).toContain('background-color: #000') + expect(result.css).toContain('.text-rgb\\(255\\,0\\,0\\)') + expect(result.css).toContain('color: rgb(255,0,0)') + expect(result.css).toContain('.grid-cols-repeat\\(2\\,_minmax\\(0\\,_1fr\\)\\)') + expect(result.css).toContain('grid-template-columns: repeat(2, minmax(0, 1fr))') + expect(result.css).toContain('.w-calc\\(100\\%_-_1rem\\)') + expect(result.css).toContain('width: calc(100% - 1rem)') + expect(result.css).toContain('.w-calc\\(100vh\\)') + expect(result.css).toContain('width: calc(100vh)') + expect(result.css).toContain('.sm\\:-top-1\\.5rem') + expect(result.css).toContain('top: calc(1.5rem * -1)') + }) + + it('extracts UnoCSS-style bare arbitrary values from inline sources when enabled', async () => { + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + bareArbitraryValues: true, + sources: [{ + extension: 'html', + content: '', + }], + }) + + expect([...result.rawCandidates]).toEqual(expect.arrayContaining([ + 'text-var(--brand)', + 'w-calc(100%-1rem)', + 'bg-#fff', + 'text-rgb(255,0,0)', + ])) + expect(result.classSet).toEqual(new Set([ + 'text-var(--brand)', + 'w-calc(100%-1rem)', + 'bg-#fff', + 'text-rgb(255,0,0)', + ])) + expect(result.css).toContain('.text-var\\(--brand\\)') + expect(result.css).toContain('color: var(--brand)') + expect(result.css).toContain('.w-calc\\(100\\%-1rem\\)') + expect(result.css).toContain('width: calc(100% - 1rem)') + expect(result.css).toContain('.bg-\\#fff') + expect(result.css).toContain('.text-rgb\\(255\\,0\\,0\\)') + }) + + it('extracts UnoCSS-style bare arbitrary values from scanned files when enabled', async () => { + const tempDir = await createTempDir() + await fs.writeFile( + path.join(tempDir, 'page.html'), + '', + 'utf8', + ) + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + bareArbitraryValues: true, + scanSources: [{ + base: tempDir, + pattern: '*.html', + negated: false, + }], + }) + + expect(result.classSet).toEqual(new Set([ + 'text-var(--brand)', + 'w-calc(100%-1rem)', + 'bg-#fff', + ])) + expect(result.css).toContain('color: var(--brand)') + expect(result.css).toContain('width: calc(100% - 1rem)') + expect(result.css).toContain('background-color: #fff') + }) + + it('preserves escaped underscores in bare arbitrary values', async () => { + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + bareArbitraryValues: true, + candidates: [ + 'content-"hello_world"', + 'content-"hello\\_world"', + 'content-"hello\\5f world"', + ], + }) + + expect(result.classSet).toEqual(new Set([ + 'content-"hello_world"', + 'content-"hello\\_world"', + 'content-"hello\\5f world"', + ])) + expect(result.css).toContain('.content-\\"hello_world\\"') + expect(result.css).toContain('--tw-content: "hello world"') + expect(result.css).toContain('.content-\\"hello\\\\_world\\"') + expect(result.css).toContain('--tw-content: "hello_world"') + expect(result.css).toContain('.content-\\"hello\\\\5f\\ world\\"') + }) + + it('includes @source inline candidates in classSet', async () => { + const engine = createTailwindV4Engine(await createDefaultSource([ + '@import "tailwindcss";', + '@source inline("w-4");', + ].join('\n'))) + const result = await engine.generate() + + expect(result.rawCandidates).toContain('w-4') + expect(result.classSet).toContain('w-4') + expect(result.css).toContain('.w-4') + }) + + it('expands official @source inline variant and range syntax', async () => { + const engine = createTailwindV4Engine(await createDefaultSource([ + '@import "tailwindcss";', + '@source inline("{hover:,focus:,}underline");', + '@source inline("p-{2..6..2}");', + ].join('\n'))) + const result = await engine.generate() + + expect(result.classSet).toEqual(new Set([ + 'hover:underline', + 'focus:underline', + 'underline', + 'p-2', + 'p-4', + 'p-6', + ])) + expect(result.css).toContain('.underline') + expect(result.css).toContain('.hover\\:underline') + expect(result.css).toContain('.focus\\:underline') + expect(result.css).toContain('.p-2') + expect(result.css).toContain('.p-4') + expect(result.css).toContain('.p-6') + }) + + it('applies @source not inline exclusions after explicit candidates', async () => { + const engine = createTailwindV4Engine(await createDefaultSource([ + '@import "tailwindcss";', + '@source not inline("bg-red-{200..300..100}");', + ].join('\n'))) + const result = await engine.generate({ + candidates: ['bg-red-100', 'bg-red-200', 'bg-red-300'], + }) + + expect(result.classSet).toContain('bg-red-100') + expect(result.classSet).not.toContain('bg-red-200') + expect(result.classSet).not.toContain('bg-red-300') + expect(result.css).toContain('.bg-red-100') + expect(result.css).not.toContain('.bg-red-200') + expect(result.css).not.toContain('.bg-red-300') + }) + + it('reads available cssEntries and records dependencies', async () => { + const tempDir = await createTempDir() + const entry = path.join(tempDir, 'app.css') + await fs.writeFile(entry, [ + '@import "tailwindcss";', + '@source inline("w-4");', + ].join('\n'), 'utf8') + + const source = await resolveTailwindV4Source({ + projectRoot: packageRoot, + base: tailwindNodeBase, + cssEntries: [entry], + }) + + expect(source.css).toContain('@source inline("w-4");') + expect(source.dependencies).toContain(entry) + }) + + it('reads in-memory cssSources and records file dependencies', async () => { + const tempDir = await createTempDir() + const cssDir = path.join(tempDir, 'styles') + const cssFile = path.join(cssDir, 'app.css') + const source = await resolveTailwindV4Source({ + projectRoot: tempDir, + baseFallbacks: [tailwindNodeBase], + cssSources: [ + { + file: cssFile, + css: [ + '@import "tailwindcss";', + '@source inline("text-green-500");', + ].join('\n'), + }, + ], + }) + const engine = createTailwindV4Engine(source) + const result = await engine.generate() + + expect(source.base).toBe(cssDir) + expect(source.dependencies).toContain(cssFile) + expect(result.classSet).toContain('text-green-500') + expect(result.css).toContain('.text-green-500') + }) + + it('combines cssEntries and in-memory cssSources', async () => { + const tempDir = await createTempDir() + const entry = path.join(tempDir, 'app.css') + const virtualFile = path.join(tempDir, 'virtual.css') + await fs.writeFile(entry, [ + '@import "tailwindcss";', + '@source inline("w-4");', + ].join('\n'), 'utf8') + + const source = await resolveTailwindV4Source({ + projectRoot: packageRoot, + base: tailwindNodeBase, + cssEntries: [entry], + cssSources: [ + { + file: virtualFile, + css: '@source inline("h-4");', + }, + ], + }) + const engine = createTailwindV4Engine(source) + const result = await engine.generate() + + expect(source.dependencies).toEqual(expect.arrayContaining([entry, virtualFile])) + expect(result.classSet).toContain('w-4') + expect(result.classSet).toContain('h-4') + }) + + it('keeps missing cssEntries as imports and records dependencies', async () => { + const tempDir = await createTempDir() + const entry = path.join(tempDir, 'missing.css') + + const source = await resolveTailwindV4Source({ + projectRoot: packageRoot, + base: tailwindNodeBase, + cssEntries: [entry], + }) + + expect(source.css).toContain('@import "') + expect(source.css).toContain('missing.css') + expect(source.css).not.toContain('\\') + expect(source.dependencies).toContain(entry) + }) + + it('falls back to tailwindcss when packageName is a PostCSS plugin', async () => { + const source = await resolveTailwindV4Source({ + projectRoot: packageRoot, + base: tailwindNodeBase, + packageName: '@tailwindcss/postcss', + }) + const engine = createTailwindV4Engine(source) + const result = await engine.generate({ + candidates: ['w-4'], + }) + + expect(source.css).toBe('@import "tailwindcss";') + expect(result.classSet).toContain('w-4') + expect(result.css).toContain('.w-4') + }) + + it('uses the same validity check in validateCandidates and generate', async () => { + const engine = createTailwindV4Engine(await createDefaultSource()) + const candidates = ['w-4', 'w-[100px]', 'definitely-not-a-tailwind-class'] + const validated = await engine.validateCandidates(candidates) + const generated = await engine.generate({ candidates }) + + expect(generated.classSet).toEqual(validated) + }) + + it('scans candidate sources with the raw candidate scanner', async () => { + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + sources: [ + { + content: '
', + extension: 'html', + }, + ], + }) + + expect(result.rawCandidates).toContain('text-blue-500') + expect(result.classSet).toContain('text-blue-500') + expect(result.classSet).not.toContain('invalid-token') + }) + + it('scans explicit filesystem sources when requested', async () => { + const tempDir = await createTempDir() + await fs.writeFile( + path.join(tempDir, 'index.html'), + '
', + 'utf8', + ) + const engine = createTailwindV4Engine(await createDefaultSource()) + const result = await engine.generate({ + scanSources: [ + { + base: tempDir, + pattern: '**/*.html', + negated: false, + }, + ], + }) + + expect(result.rawCandidates).toContain('text-green-500') + expect(result.classSet).toContain('text-green-500') + expect(result.classSet).not.toContain('invalid-token') + expect(result.css).toContain('.text-green-500') + }) + + it('uses compiled @source entries when scanSources is true', async () => { + const tempDir = await createTempDir() + const srcDir = path.join(tempDir, 'src') + await fs.mkdir(srcDir, { recursive: true }) + await fs.writeFile(path.join(srcDir, 'index.html'), '
', 'utf8') + await fs.writeFile(path.join(srcDir, 'ignored.html'), '
', 'utf8') + const css = [ + '@import "tailwindcss";', + '@source "./src/**/*.html";', + '@source not "./src/ignored.html";', + ].join('\n') + const source = await resolveTailwindV4Source({ + projectRoot: tempDir, + base: tempDir, + baseFallbacks: [tailwindNodeBase], + css, + }) + const engine = createTailwindV4Engine(source) + + const withoutScan = await engine.generate() + const withScan = await engine.generate({ scanSources: true }) + + expect(withoutScan.classSet).not.toContain('text-green-500') + expect(withScan.classSet).toContain('text-green-500') + expect(withScan.classSet).not.toContain('text-red-500') + expect(withScan.css).toContain('.text-green-500') + expect(withScan.css).not.toContain('.text-red-500') + }) + + it('uses @import source() root and @source not entries when scanSources is true', async () => { + const tempDir = await createTempDir() + await fs.mkdir(path.join(tempDir, 'src/legacy'), { recursive: true }) + await fs.mkdir(path.join(tempDir, 'outside'), { recursive: true }) + await fs.writeFile(path.join(tempDir, 'src/index.html'), '
', 'utf8') + await fs.writeFile(path.join(tempDir, 'src/legacy/index.html'), '
', 'utf8') + await fs.writeFile(path.join(tempDir, 'outside/index.html'), '
', 'utf8') + const source = await resolveTailwindV4Source({ + projectRoot: tempDir, + base: tempDir, + baseFallbacks: [tailwindNodeBase], + css: [ + '@import "tailwindcss" source("./src");', + '@source not "./src/legacy";', + ].join('\n'), + }) + const engine = createTailwindV4Engine(source) + const result = await engine.generate({ scanSources: true }) + + expect(result.root).toEqual({ base: tempDir, pattern: './src' }) + expect(result.sources).toEqual([{ base: tempDir, pattern: './src/legacy', negated: true }]) + expect(result.classSet).toContain('text-green-500') + expect(result.classSet).not.toContain('text-red-500') + expect(result.classSet).not.toContain('text-blue-500') + }) + + it('uses source(none) to disable automatic source detection when scanSources is true', async () => { + const tempDir = await createTempDir() + await fs.mkdir(path.join(tempDir, 'src'), { recursive: true }) + await fs.mkdir(path.join(tempDir, 'admin'), { recursive: true }) + await fs.writeFile(path.join(tempDir, 'src/index.html'), '
', 'utf8') + await fs.writeFile(path.join(tempDir, 'admin/index.html'), '
', 'utf8') + const source = await resolveTailwindV4Source({ + projectRoot: tempDir, + base: tempDir, + baseFallbacks: [tailwindNodeBase], + css: [ + '@import "tailwindcss" source(none);', + '@source "./admin";', + ].join('\n'), + }) + const engine = createTailwindV4Engine(source) + const result = await engine.generate({ scanSources: true }) + + expect(result.root).toBe('none') + expect(result.classSet).toContain('text-red-500') + expect(result.classSet).not.toContain('text-green-500') + }) +}) diff --git a/packages/engine/test/v4.source-scan.test.ts b/packages/engine/test/v4.source-scan.test.ts new file mode 100644 index 00000000..e41e7b7e --- /dev/null +++ b/packages/engine/test/v4.source-scan.test.ts @@ -0,0 +1,134 @@ +import { promises as fs } from 'node:fs' +import os from 'node:os' +import path from 'pathe' +import { afterEach, describe, expect, it } from 'vitest' +import { + createTailwindV4CompiledSourceEntries, + createTailwindV4DefaultIgnoreSources, + createTailwindV4SourceEntryMatcher, + expandTailwindV4SourceEntries, + isFileExcludedByTailwindV4SourceEntries, + isFileMatchedByTailwindV4SourceEntries, + normalizeTailwindV4ScannerSources, + normalizeTailwindV4SourceEntries, + resolveTailwindV4SourceEntry, +} from '@/v4' + +const tempDirs: string[] = [] + +async function createTempDir(prefix: string) { + const tempDir = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), prefix))) + tempDirs.push(tempDir) + return tempDir +} + +async function writeTempFile(file: string, content = '') { + await fs.mkdir(path.dirname(file), { recursive: true }) + await fs.writeFile(file, content, 'utf8') +} + +afterEach(async () => { + await Promise.all(tempDirs.splice(0).map(tempDir => fs.rm(tempDir, { recursive: true, force: true }))) +}) + +describe('Tailwind v4 source scan helpers', () => { + it('normalizes @source directory, glob, file, and not entries like Tailwind v4 public sources', async () => { + const root = await createTempDir('tw-engine-v4-source-scan-') + await fs.mkdir(path.join(root, 'src'), { recursive: true }) + await writeTempFile(path.join(root, 'templates/card.html')) + + await expect(Promise.all([ + resolveTailwindV4SourceEntry('./src', root, false), + resolveTailwindV4SourceEntry('./src/**/*.{html,js}', root, false), + resolveTailwindV4SourceEntry('./templates/card.html', root, false), + resolveTailwindV4SourceEntry('./src/legacy', root, true), + ])).resolves.toEqual([ + { base: path.join(root, 'src'), pattern: '**/*', negated: false }, + { base: path.join(root, 'src'), pattern: '**/*.{html,js}', negated: false }, + { base: root, pattern: 'templates/card.html', negated: false }, + { base: root, pattern: 'src/legacy', negated: true }, + ]) + }) + + it('merges source(none), source roots, and @source entries from compiled CSS metadata', () => { + const root = '/project' + + expect(createTailwindV4CompiledSourceEntries('none', [{ base: root, pattern: './admin', negated: false }], root)) + .toEqual([{ base: root, pattern: './admin', negated: false }]) + + expect(createTailwindV4CompiledSourceEntries(null, [], root)) + .toEqual([{ base: root, pattern: '**/*', negated: false }]) + + expect(createTailwindV4CompiledSourceEntries( + { base: root, pattern: './src' }, + [{ base: root, pattern: './legacy', negated: true }], + root, + )).toEqual([ + { base: root, pattern: './src', negated: false }, + { base: root, pattern: './legacy', negated: true }, + ]) + }) + + it('expands brace source patterns before they are passed to the oxide scanner', () => { + const root = '/project' + + expect(normalizeTailwindV4ScannerSources([ + { base: root, pattern: 'src/**/*.{html,tsx}', negated: false }, + ], root)).toEqual([ + { base: root, pattern: 'src/**/*.html', negated: false }, + { base: root, pattern: 'src/**/*.tsx', negated: false }, + ]) + }) + + it('matches files with positive sources and excludes negative entries', async () => { + const root = await createTempDir('tw-engine-v4-source-match-') + const srcFile = path.join(root, 'src/page.html') + const ignoredFile = path.join(root, 'src/legacy/page.html') + const outsideFile = path.join(root, 'outside/page.html') + await writeTempFile(srcFile) + await writeTempFile(ignoredFile) + await writeTempFile(outsideFile) + + const entries = await normalizeTailwindV4SourceEntries([ + { base: root, pattern: './src', negated: false }, + { base: root, pattern: './src/legacy', negated: true }, + ], { cwd: root }) + const matcher = createTailwindV4SourceEntryMatcher(entries) + + expect(matcher?.(srcFile)).toBe(true) + expect(matcher?.(ignoredFile)).toBe(false) + expect(matcher?.(outsideFile)).toBe(false) + expect(isFileMatchedByTailwindV4SourceEntries(srcFile, entries)).toBe(true) + expect(isFileExcludedByTailwindV4SourceEntries(ignoredFile, entries)).toBe(true) + }) + + it('keeps explicit @source paths capable of entering otherwise ignored content directories', async () => { + const root = await createTempDir('tw-engine-v4-source-external-') + const sourceFile = path.join(root, 'node_modules/design-system/button.html') + await writeTempFile(sourceFile, '') + + const files = await expandTailwindV4SourceEntries([ + { base: path.join(root, 'node_modules/design-system'), pattern: '**/*', negated: false }, + ], async ({ sources }) => { + expect(sources).toEqual([ + { base: path.join(root, 'node_modules/design-system'), pattern: '**/*', negated: false }, + ]) + return [sourceFile] + }) + + expect(files).toEqual([sourceFile]) + }) + + it('exposes official Tailwind v4 default ignored directory, extension, and file rules', () => { + const root = '/project' + const ignoredSources = createTailwindV4DefaultIgnoreSources(root) + + expect(ignoredSources).toEqual(expect.arrayContaining([ + { base: root, pattern: '**/node_modules/**', negated: true }, + { base: root, pattern: '**/.git/**', negated: true }, + { base: root, pattern: '**/*.scss', negated: true }, + { base: root, pattern: '**/package-lock.json', negated: true }, + { base: root, pattern: '**/.env.*', negated: true }, + ])) + }) +}) diff --git a/packages/engine/tsconfig.json b/packages/engine/tsconfig.json new file mode 100644 index 00000000..b59a1776 --- /dev/null +++ b/packages/engine/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": [ + "src/*" + ] + } + }, + "include": [ + "src", + "test" + ], + "exclude": [ + "dist", + "coverage", + "node_modules", + "test/fixtures/**/*" + ] +} diff --git a/packages/engine/tsdown.config.ts b/packages/engine/tsdown.config.ts new file mode 100644 index 00000000..25a0b58b --- /dev/null +++ b/packages/engine/tsdown.config.ts @@ -0,0 +1,32 @@ +import { defineConfig } from 'tsdown' + +export default defineConfig({ + entry: { + 'index': 'src/index.ts', + 'style-candidates': 'src/style-candidates.ts', + 'style-generator': 'src/style-generator.ts', + 'types': 'src/types.ts', + 'extraction/candidate-extractor': 'src/extraction/candidate-extractor.ts', + 'extraction/split-candidate-tokens': 'src/extraction/split-candidate-tokens.ts', + 'v3/index': 'src/v3/index.ts', + 'v3/style-generator': 'src/v3/style-generator.ts', + 'v4/index': 'src/v4/index.ts', + 'v4/bare-arbitrary-values': 'src/v4/bare-arbitrary-values.ts', + 'v4/candidates': 'src/v4/candidates.ts', + 'v4/engine': 'src/v4/engine.ts', + 'v4/node-adapter': 'src/v4/node-adapter.ts', + 'v4/source': 'src/v4/source.ts', + 'v4/source-scan': 'src/v4/source-scan.ts', + 'v4/style-generator': 'src/v4/style-generator.ts', + 'v4/types': 'src/v4/types.ts', + }, + shims: true, + format: ['cjs', 'esm'], + clean: true, + dts: true, + fixedExtension: false, + deps: { + skipNodeModulesBundle: true, + neverBundle: ['tailwindcss', '@tailwindcss/node', '@tailwindcss/oxide'], + }, +}) diff --git a/packages/engine/vitest.config.ts b/packages/engine/vitest.config.ts new file mode 100644 index 00000000..7ed4a165 --- /dev/null +++ b/packages/engine/vitest.config.ts @@ -0,0 +1,19 @@ +import path from 'pathe' +import { defineProject } from 'vitest/config' + +export default defineProject({ + test: { + alias: [ + { + find: '@', + replacement: path.resolve(__dirname, './src'), + }, + ], + globals: true, + testTimeout: 60_000, + coverage: { + enabled: true, + all: false, + }, + }, +}) diff --git a/packages/tailwindcss-patch/package.json b/packages/tailwindcss-patch/package.json index c3a6a016..cd298db6 100644 --- a/packages/tailwindcss-patch/package.json +++ b/packages/tailwindcss-patch/package.json @@ -5,7 +5,7 @@ "author": "ice breaker <1324318532@qq.com>", "license": "MIT", "engines": { - "node": ">=18.0.0" + "node": ">=22.13.0" }, "homepage": "https://mangle.icebreaker.top/", "repository": { @@ -94,6 +94,7 @@ "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7", "@tailwindcss-mangle/config": "workspace:*", + "@tailwindcss-mangle/engine": "workspace:*", "@tailwindcss/node": "^4.3.1", "@tailwindcss/oxide": "^4.3.1", "cac": "6.7.14", diff --git a/packages/tailwindcss-patch/src/extraction/candidate-extractor.ts b/packages/tailwindcss-patch/src/extraction/candidate-extractor.ts index 54145fbb..44d60a3f 100644 --- a/packages/tailwindcss-patch/src/extraction/candidate-extractor.ts +++ b/packages/tailwindcss-patch/src/extraction/candidate-extractor.ts @@ -1,701 +1,17 @@ -import type { SourceEntry } from '@tailwindcss/oxide' -import type { - TailwindTokenByFileMap, - TailwindTokenFileKey, - TailwindTokenLocation, - TailwindTokenReport, -} from '../types' -import type { BareArbitraryValueOptions } from '../v4/bare-arbitrary-values' -import { promises as fs } from 'node:fs' -import process from 'node:process' -import path from 'pathe' -import { - extractBareArbitraryValueSourceCandidatesWithPositions, - resolveBareArbitraryValueCandidate, -} from '../v4/bare-arbitrary-values' -import { extractTailwindV4InlineSourceCandidates, resolveValidTailwindV4Candidates } from '../v4/candidates' -import { compileTailwindV4Source, getTailwindV4DesignSystemCacheKey, loadTailwindV4DesignSystem } from '../v4/node-adapter' -import { - createTailwindV4CompiledSourceEntries, - normalizeTailwindV4ScannerSources, -} from '../v4/source-scan' - -let oxideImportPromise: ReturnType | undefined -const designSystemCandidateCache = new Map>() - -function createOxideRuntimeDependencyError(cause: unknown) { - return new Error( - [ - 'tailwindcss-patch could not load @tailwindcss/oxide, which is required for source candidate scanning.', - 'This dependency should be installed automatically by tailwindcss-patch.', - 'Reinstall dependencies without disabling optional dependencies, or install @tailwindcss/oxide@^4.2.4 manually if your package manager omitted it.', - ].join(' '), - { cause }, - ) -} - -async function importOxide() { - try { - return await import('@tailwindcss/oxide') - } - catch (error) { - throw createOxideRuntimeDependencyError(error) - } -} - -function getOxideModule() { - oxideImportPromise ??= importOxide() - oxideImportPromise.catch(() => { - oxideImportPromise = undefined - }) - return oxideImportPromise -} - -export interface ExtractValidCandidatesOption { - sources?: SourceEntry[] - base?: string - baseFallbacks?: string[] - css?: string - cwd?: string - bareArbitraryValues?: boolean | BareArbitraryValueOptions -} - -export interface ExtractCandidateOptions { - bareArbitraryValues?: boolean | BareArbitraryValueOptions -} - -export interface ExtractSourceCandidate { - rawCandidate: string - start: number - end: number -} - -interface ExtractSourceCandidateWithContext extends ExtractSourceCandidate { - content: string - extension: string - localStart: number -} - -const HTML_ATTRIBUTE_NAME_CANDIDATE_RE = /^(?:class|className|hover-class|hoverClass)$/ -const CSS_DIRECTIVE_CANDIDATE_RE = /^@(?:apply|tailwind|source|config|plugin|theme|utility|custom-variant|variant)$/ -const CSS_APPLY_IMPORTANT = '!important' -const CSS_APPLY_RE = /@apply\s+([^;{}]+)/g -const JS_LIKE_SOURCE_EXTENSION_RE = /^[cm]?[jt]sx?$/ -const MIXED_TEMPLATE_SOURCE_EXTENSION_RE = /^(?:vue|uvue|nvue|svelte|mpx)$/ -const CSS_LIKE_SOURCE_EXTENSION_RE = /^(?:css|wxss|acss|jxss|ttss|qss|tyss|scss|sass|less|styl|stylus)$/ -const SFC_SCRIPT_BLOCK_RE = /]*>([\s\S]*?)<\/script>/gi - -function isWhitespace(value: string | undefined) { - return value === ' ' || value === '\n' || value === '\r' || value === '\t' || value === '\f' -} - -function isHtmlAttributeNameCandidate(content: string, candidate: ExtractSourceCandidate) { - if (!HTML_ATTRIBUTE_NAME_CANDIDATE_RE.test(candidate.rawCandidate)) { - return false - } - let index = candidate.end - while (isWhitespace(content[index])) { - index++ - } - return content[index] === '=' -} - -function isInsideHtmlTagText(content: string, candidate: ExtractSourceCandidate) { - const open = content.lastIndexOf('<', candidate.start) - const close = content.lastIndexOf('>', candidate.start) - if (open > close) { - return false - } - const nextOpen = content.indexOf('<', candidate.end) - return nextOpen !== -1 && (nextOpen < content.indexOf('>', candidate.end) || !content.includes('>', candidate.end)) -} - -function isCssDirectiveCandidate(candidate: string) { - return candidate === CSS_APPLY_IMPORTANT || CSS_DIRECTIVE_CANDIDATE_RE.test(candidate) -} - -function isCandidateInCssApplyParams(content: string, candidate: ExtractSourceCandidate) { - const apply = content.lastIndexOf('@apply', candidate.start) - if (apply === -1) { - return false - } - const boundary = content.slice(apply + '@apply'.length, candidate.start) - return !/[;{}]/.test(boundary) -} - -function isCandidateInsideJsStringStaticContent(content: string, start: number) { - let quote: '"' | '\'' | '`' | undefined - let templateExpressionDepth = 0 - for (let index = 0; index < start; index++) { - const char = content[index] - const next = content[index + 1] - - if (quote && char === '\\') { - index++ - continue - } - - if (quote === '`' && templateExpressionDepth > 0) { - if (char === '"' || char === '\'') { - const nestedQuote = char - index++ - while (index < start) { - const nestedChar = content[index] - if (nestedChar === '\\') { - index += 2 - continue - } - if (nestedChar === nestedQuote) { - break - } - index++ - } - continue - } - if (char === '`') { - index++ - while (index < start) { - const nestedChar = content[index] - if (nestedChar === '\\') { - index += 2 - continue - } - if (nestedChar === '`') { - break - } - index++ - } - continue - } - if (char === '{') { - templateExpressionDepth++ - continue - } - if (char === '}') { - templateExpressionDepth-- - continue - } - continue - } - - if (quote) { - if (quote === '`' && char === '$' && next === '{') { - templateExpressionDepth = 1 - index++ - continue - } - if (char === quote) { - quote = undefined - } - continue - } - - if (char === '"' || char === '\'' || char === '`') { - quote = char - } - } - - return quote !== undefined && templateExpressionDepth === 0 -} - -function shouldKeepSourceCandidate(content: string, extension: string, candidate: ExtractSourceCandidate) { - if (!candidate.rawCandidate || isCssDirectiveCandidate(candidate.rawCandidate)) { - return false - } - if (CSS_LIKE_SOURCE_EXTENSION_RE.test(extension) && !isCandidateInCssApplyParams(content, candidate)) { - return false - } - if (isHtmlAttributeNameCandidate(content, candidate)) { - return false - } - if (isInsideHtmlTagText(content, candidate)) { - return false - } - if ( - JS_LIKE_SOURCE_EXTENSION_RE.test(extension) - && !isCandidateInsideJsStringStaticContent(content, candidate.start) - ) { - return false - } - return true -} - -function createLocalCandidate(candidate: ExtractSourceCandidateWithContext): ExtractSourceCandidate { - return { - rawCandidate: candidate.rawCandidate, - start: candidate.localStart, - end: candidate.localStart + candidate.rawCandidate.length, - } -} - -function dedupeCandidatesWithPositions(candidates: ExtractSourceCandidate[]) { - const seen = new Set() - return candidates.filter((candidate) => { - const key = `${candidate.start}:${candidate.end}:${candidate.rawCandidate}` - if (seen.has(key)) { - return false - } - seen.add(key) - return true - }) -} - -function createBareArbitraryValueCandidateContexts( - content: string, - extension: string, - offset: number, - options?: ExtractCandidateOptions, -): ExtractSourceCandidateWithContext[] { - return extractBareArbitraryValueSourceCandidatesWithPositions(content, options?.bareArbitraryValues) - .map(candidate => ({ - content, - extension, - localStart: candidate.start, - rawCandidate: candidate.rawCandidate, - start: candidate.start + offset, - end: candidate.end + offset, - })) -} - -async function extractCssApplyCandidates(content: string, extension: string, options?: ExtractCandidateOptions) { - const candidates: ExtractSourceCandidateWithContext[] = [] - CSS_APPLY_RE.lastIndex = 0 - let match = CSS_APPLY_RE.exec(content) - while (match !== null) { - const applyParams = match[1] ?? '' - const applyParamsStart = match.index + match[0].indexOf(applyParams) - const applyCandidates = await extractRawCandidatesWithPositions(applyParams, extension) - candidates.push(...applyCandidates.map(candidate => ({ - content: applyParams, - extension: 'html', - localStart: candidate.start, - rawCandidate: candidate.rawCandidate, - start: candidate.start + applyParamsStart, - end: candidate.end + applyParamsStart, - }))) - candidates.push(...createBareArbitraryValueCandidateContexts(applyParams, 'html', applyParamsStart, options)) - match = CSS_APPLY_RE.exec(content) - } - return candidates -} - -async function extractMixedSourceScriptCandidates(content: string, options?: ExtractCandidateOptions) { - const candidates: ExtractSourceCandidateWithContext[] = [] - SFC_SCRIPT_BLOCK_RE.lastIndex = 0 - let match = SFC_SCRIPT_BLOCK_RE.exec(content) - while (match !== null) { - const scriptContent = match[1] ?? '' - const scriptStart = match.index + match[0].indexOf(scriptContent) - const scriptCandidates = await extractRawCandidatesWithPositions(scriptContent, 'js') - candidates.push(...scriptCandidates.map(candidate => ({ - content: scriptContent, - extension: 'js', - localStart: candidate.start, - rawCandidate: candidate.rawCandidate, - start: candidate.start + scriptStart, - end: candidate.end + scriptStart, - }))) - candidates.push(...createBareArbitraryValueCandidateContexts(scriptContent, 'js', scriptStart, options)) - match = SFC_SCRIPT_BLOCK_RE.exec(content) - } - return candidates -} - -function createCandidateCacheKey( - designSystemKey: string, - options: Pick, -) { - if (options.bareArbitraryValues == null || options.bareArbitraryValues === false) { - return designSystemKey - } - return `${designSystemKey}:bare-arbitrary:${JSON.stringify(options.bareArbitraryValues)}` -} - -export async function extractRawCandidatesWithPositions( - content: string, - extension: string = 'html', - options?: ExtractCandidateOptions, -): Promise { - const { Scanner } = await getOxideModule() - const scanner = new Scanner({}) - const result = scanner.getCandidatesWithPositions({ content, extension }) - - const candidates = result.map(({ candidate, position }) => ({ - rawCandidate: candidate, - start: position, - end: position + candidate.length, - })) - candidates.push(...extractBareArbitraryValueSourceCandidatesWithPositions(content, options?.bareArbitraryValues)) - return dedupeCandidatesWithPositions(candidates) -} - -export async function extractSourceCandidatesWithPositions( - content: string, - extension: string = 'html', - options?: ExtractCandidateOptions, -): Promise { - const normalizedExtension = extension.replace(/^\./, '') - const candidates: ExtractSourceCandidateWithContext[] = CSS_LIKE_SOURCE_EXTENSION_RE.test(normalizedExtension) - ? await extractCssApplyCandidates(content, normalizedExtension, options) - : (await extractRawCandidatesWithPositions(content, normalizedExtension, options)) - .map(candidate => ({ - ...candidate, - content, - extension: normalizedExtension, - localStart: candidate.start, - })) - if (MIXED_TEMPLATE_SOURCE_EXTENSION_RE.test(normalizedExtension)) { - candidates.push(...await extractMixedSourceScriptCandidates(content, options)) - } - const seen = new Set() - return candidates.filter((candidate) => { - if (!shouldKeepSourceCandidate(candidate.content, candidate.extension, createLocalCandidate(candidate))) { - return false - } - const key = `${candidate.start}:${candidate.end}:${candidate.rawCandidate}` - if (seen.has(key)) { - return false - } - seen.add(key) - return true - }).map(({ rawCandidate, start, end }) => ({ rawCandidate, start, end })) -} - -export async function extractSourceCandidates( - content: string, - extension: string = 'html', - options?: ExtractCandidateOptions, -): Promise { - const candidates = await extractSourceCandidatesWithPositions(content, extension, options) - return [...new Set(candidates.map(candidate => candidate.rawCandidate))] -} - -export async function extractRawCandidates( - sources?: SourceEntry[], - options?: ExtractCandidateOptions, -): Promise { - const { Scanner } = await getOxideModule() - const scanner = new Scanner(sources === undefined ? {} : { sources }) - - const candidates = new Set(scanner.scan()) - if (options?.bareArbitraryValues !== undefined && options.bareArbitraryValues !== false) { - await Promise.all((scanner.files ?? []).map(async (file) => { - try { - const content = await fs.readFile(file, 'utf8') - const extension = toExtension(file) - for (const candidate of extractBareArbitraryValueSourceCandidatesWithPositions(content, options.bareArbitraryValues)) { - if (shouldKeepSourceCandidate(content, extension, candidate)) { - candidates.add(candidate.rawCandidate) - } - } - } - catch { - // 文件可能在扫描和读取之间被移除,保持与 Tailwind 原扫描结果一致。 - } - })) - } - return [...candidates] -} - -export async function extractValidCandidates(options?: ExtractValidCandidatesOption) { - const providedOptions = options ?? {} - const defaultCwd = providedOptions.cwd ?? process.cwd() - - const base = providedOptions.base ?? defaultCwd - const baseFallbacks = providedOptions.baseFallbacks ?? [] - const css = providedOptions.css ?? '@import "tailwindcss";' - const sources = (providedOptions.sources ?? [ - { - base: defaultCwd, - pattern: '**/*', - negated: false, - }, - ]).map(source => ({ - base: source.base ?? defaultCwd, - pattern: source.pattern, - negated: source.negated, - })) - - const source = { - projectRoot: defaultCwd, - base, - baseFallbacks, - css, - dependencies: [], - } - const designSystemKey = getTailwindV4DesignSystemCacheKey(source) - const designSystem = await loadTailwindV4DesignSystem(source) - const candidateCacheKey = createCandidateCacheKey(designSystemKey, providedOptions) - const candidateCache = designSystemCandidateCache.get(candidateCacheKey) ?? new Map() - designSystemCandidateCache.set(candidateCacheKey, candidateCache) - - const candidates = await extractRawCandidates( - sources, - providedOptions.bareArbitraryValues === undefined - ? undefined - : { bareArbitraryValues: providedOptions.bareArbitraryValues }, - ) - const inlineSources = extractTailwindV4InlineSourceCandidates(css) - for (const candidate of inlineSources.included) { - candidates.push(candidate) - } - for (const candidate of inlineSources.excluded) { - let index = candidates.indexOf(candidate) - while (index !== -1) { - candidates.splice(index, 1) - index = candidates.indexOf(candidate) - } - } - const validCandidates: string[] = [] - const uncachedCandidates: string[] = [] - - for (const rawCandidate of candidates) { - const cached = candidateCache.get(rawCandidate) - if (cached === true) { - validCandidates.push(rawCandidate) - continue - } - - if (cached === false) { - continue - } - - const bareArbitrary = resolveBareArbitraryValueCandidate(rawCandidate, providedOptions.bareArbitraryValues) - if ( - designSystem.parseCandidate(rawCandidate).length > 0 - || (bareArbitrary && designSystem.parseCandidate(bareArbitrary.canonicalCandidate).length > 0) - ) { - uncachedCandidates.push(rawCandidate) - continue - } - - candidateCache.set(rawCandidate, false) - } - - if (uncachedCandidates.length === 0) { - return validCandidates - } - - const validUncachedCandidates = resolveValidTailwindV4Candidates( - designSystem, - uncachedCandidates, - providedOptions.bareArbitraryValues === undefined - ? undefined - : { bareArbitraryValues: providedOptions.bareArbitraryValues }, - ) - - for (const candidate of uncachedCandidates) { - const isValid = validUncachedCandidates.has(candidate) - candidateCache.set(candidate, isValid) - if (!isValid) { - continue - } - validCandidates.push(candidate) - } - - return validCandidates -} - -function buildLineOffsets(content: string) { - const offsets: number[] = [0] - for (let i = 0; i < content.length; i++) { - if (content[i] === '\n') { - offsets.push(i + 1) - } - } - // Push a sentinel to simplify bounds checks during binary search. - if (offsets[offsets.length - 1] !== content.length) { - offsets.push(content.length) - } - return offsets -} - -function resolveLineMeta(content: string, offsets: number[], index: number) { - let low = 0 - let high = offsets.length - 1 - while (low <= high) { - const mid = Math.floor((low + high) / 2) - const start = offsets[mid] - if (start === undefined) { - break - } - const nextStart = offsets[mid + 1] ?? content.length - - if (index < start) { - high = mid - 1 - continue - } - - if (index >= nextStart) { - low = mid + 1 - continue - } - - const line = mid + 1 - const column = index - start + 1 - const lineEnd = content.indexOf('\n', start) - const lineText = content.slice(start, lineEnd === -1 ? content.length : lineEnd) - - return { line, column, lineText } - } - - const lastStart = offsets[offsets.length - 2] ?? 0 - return { - line: offsets.length - 1, - column: index - lastStart + 1, - lineText: content.slice(lastStart), - } -} - -function toExtension(filename: string) { - const ext = path.extname(filename).replace(/^\./, '') - return ext || 'txt' -} - -function toRelativeFile(cwd: string, filename: string) { - const relative = path.relative(cwd, filename) - return relative === '' ? path.basename(filename) : relative -} - -export interface ExtractProjectCandidatesOptions { - cwd?: string - sources?: SourceEntry[] - base?: string - baseFallbacks?: string[] - css?: string -} - -export interface ResolveProjectSourceFilesOptions { - cwd?: string - sources?: SourceEntry[] - ignoredSources?: SourceEntry[] - base?: string - baseFallbacks?: string[] - css?: string - filter?: (file: string) => boolean -} - -async function resolveScannerSources(options?: ResolveProjectSourceFilesOptions) { - const cwd = options?.cwd ? path.resolve(options.cwd) : process.cwd() - if (options?.sources?.length || options?.css === undefined) { - return { - cwd, - sources: normalizeTailwindV4ScannerSources(options?.sources, cwd, options?.ignoredSources), - } - } - - const base = options.base ? path.resolve(options.base) : cwd - const { compiled } = await compileTailwindV4Source({ - projectRoot: cwd, - base, - baseFallbacks: options.baseFallbacks?.map(baseFallback => path.resolve(baseFallback)) ?? [], - css: options.css, - dependencies: [], - }) - return { - cwd, - sources: normalizeTailwindV4ScannerSources( - createTailwindV4CompiledSourceEntries(compiled.root, compiled.sources, base), - cwd, - options.ignoredSources, - ), - } -} - -export async function resolveProjectSourceFiles(options?: ResolveProjectSourceFilesOptions): Promise { - const { sources } = await resolveScannerSources(options) - const { Scanner } = await getOxideModule() - const scanner = new Scanner({ - sources, - }) - const files = scanner.files ?? [] - return options?.filter - ? files.filter(options.filter) - : files -} - -export async function extractProjectCandidatesWithPositions( - options?: ExtractProjectCandidatesOptions, -): Promise { - const { cwd, sources } = await resolveScannerSources(options) - const { Scanner } = await getOxideModule() - const scanner = new Scanner({ - sources, - }) - - const files = scanner.files ?? [] - const entries: TailwindTokenLocation[] = [] - const skipped: TailwindTokenReport['skippedFiles'] = [] - - for (const file of files) { - let content: string - try { - content = await fs.readFile(file, 'utf8') - } - catch (error) { - skipped.push({ - file, - reason: error instanceof Error ? error.message : 'Unknown error', - }) - continue - } - - const extension = toExtension(file) - const matches = scanner.getCandidatesWithPositions({ - file, - content, - extension, - }) - - if (!matches.length) { - continue - } - - const offsets = buildLineOffsets(content) - const relativeFile = toRelativeFile(cwd, file) - - for (const match of matches) { - const info = resolveLineMeta(content, offsets, match.position) - entries.push({ - rawCandidate: match.candidate, - file, - relativeFile, - extension, - start: match.position, - end: match.position + match.candidate.length, - length: match.candidate.length, - line: info.line, - column: info.column, - lineText: info.lineText, - }) - } - } - - return { - entries, - filesScanned: files.length, - skippedFiles: skipped, - sources, - } -} - -export function groupTokensByFile( - report: TailwindTokenReport, - options?: { key?: TailwindTokenFileKey, stripAbsolutePaths?: boolean }, -): TailwindTokenByFileMap { - const key = options?.key ?? 'relative' - const stripAbsolute = options?.stripAbsolutePaths ?? key !== 'absolute' - - return report.entries.reduce((acc, entry) => { - const bucketKey = key === 'absolute' ? entry.file : entry.relativeFile - const bucket = acc[bucketKey] ?? (acc[bucketKey] = []) - const value = stripAbsolute - ? { - ...entry, - file: entry.relativeFile, - } - : entry - bucket.push(value) - return acc - }, {}) -} +export { + extractProjectCandidatesWithPositions, + extractRawCandidates, + extractRawCandidatesWithPositions, + extractSourceCandidates, + extractSourceCandidatesWithPositions, + extractValidCandidates, + groupTokensByFile, + resolveProjectSourceFiles, +} from '@tailwindcss-mangle/engine/extraction/candidate-extractor' +export type { + ExtractCandidateOptions, + ExtractProjectCandidatesOptions, + ExtractSourceCandidate, + ExtractValidCandidatesOption, + ResolveProjectSourceFilesOptions, +} from '@tailwindcss-mangle/engine/extraction/candidate-extractor' diff --git a/packages/tailwindcss-patch/src/extraction/split-candidate-tokens.ts b/packages/tailwindcss-patch/src/extraction/split-candidate-tokens.ts index be97761c..457861c8 100644 --- a/packages/tailwindcss-patch/src/extraction/split-candidate-tokens.ts +++ b/packages/tailwindcss-patch/src/extraction/split-candidate-tokens.ts @@ -1,101 +1,5 @@ -// 参考链接:https://github.com/tailwindlabs/tailwindcss/blob/master/src/lib/regex.js -// eslint-disable-next-line regexp/no-obscure-range -export const validateCandidateTokenRE = /[\w\u00A0-\uFFFF%-?]/ - -export function isValidCandidateToken(token = ''): token is string { - return validateCandidateTokenRE.test(token) -} - -const SPLIT_CACHE_LIMIT = 8192 -const ESCAPED_WHITESPACE_RE = /\\[nrt]/g -const splitCache = new Map() - -function isSplitter(char: string, bracketDepth: number) { - return bracketDepth === 0 && (char === '"' || /\s/.test(char)) -} - -function hasClosingQuotedArbitraryValue(code: string, start: number, quote: string) { - for (let index = start; index < code.length; index++) { - if (code[index] === '\\') { - index++ - continue - } - if (code[index] === quote) { - return code.includes(']', index + 1) - } - } - - return false -} - -function splitBracketAware(code: string) { - const result: string[] = [] - let bracketDepth = 0 - let bracketQuote: string | undefined - let start = 0 - - for (let index = 0; index < code.length; index++) { - const char = code[index] - if (char === undefined) { - continue - } - if (bracketDepth > 0 && char === '\\') { - index++ - continue - } - - if (bracketDepth > 0 && (char === '"' || char === '\'')) { - if (bracketQuote === char) { - bracketQuote = undefined - } - else if (bracketQuote === undefined && hasClosingQuotedArbitraryValue(code, index + 1, char)) { - bracketQuote = char - } - } - - if (bracketQuote === undefined) { - if (char === '[' && code.includes(']', index + 1)) { - bracketDepth++ - } - else if (char === ']' && bracketDepth > 0) { - bracketDepth-- - } - } - - if (!isSplitter(char, bracketDepth)) { - continue - } - - const candidate = code.slice(start, index) - if (isValidCandidateToken(candidate)) { - result.push(candidate) - } - start = index + 1 - } - - const candidate = code.slice(start) - if (isValidCandidateToken(candidate)) { - result.push(candidate) - } - - return result -} - -export function splitCandidateTokens(code: string) { - const cached = splitCache.get(code) - if (cached) { - return cached - } - - // 把压缩产物中的转义空白字符(\n \r \t)先还原成空格,避免被粘连到类名上。 - const normalized = code.includes('\\') ? code.replace(ESCAPED_WHITESPACE_RE, ' ') : code - const result = splitBracketAware(normalized) - - // 防止缓存无限增长。 - if (splitCache.size >= SPLIT_CACHE_LIMIT) { - splitCache.clear() - } - splitCache.set(code, result) - - return result -} +export { + isValidCandidateToken, + splitCandidateTokens, + validateCandidateTokenRE, +} from '@tailwindcss-mangle/engine/extraction/split-candidate-tokens' diff --git a/packages/tailwindcss-patch/src/options/types.ts b/packages/tailwindcss-patch/src/options/types.ts index 936cc09d..f34844f8 100644 --- a/packages/tailwindcss-patch/src/options/types.ts +++ b/packages/tailwindcss-patch/src/options/types.ts @@ -1,7 +1,7 @@ +import type { TailwindV4CssSource } from '@tailwindcss-mangle/engine/v4/types' import type { SourceEntry } from '@tailwindcss/oxide' import type { PackageResolvingOptions } from 'local-pkg' import type { ILengthUnitsPatchOptions } from '../types' -import type { TailwindV4CssSource } from '../v4/types' export type CacheStrategy = 'merge' | 'overwrite' export type CacheDriver = 'file' | 'memory' | 'noop' diff --git a/packages/tailwindcss-patch/src/style-candidates.ts b/packages/tailwindcss-patch/src/style-candidates.ts index ba5dd5eb..c39f0c6f 100644 --- a/packages/tailwindcss-patch/src/style-candidates.ts +++ b/packages/tailwindcss-patch/src/style-candidates.ts @@ -1,35 +1,7 @@ -import type { BareArbitraryValueOptions } from './v4/bare-arbitrary-values' -import { extractSourceCandidates } from './extraction/candidate-extractor' - -export interface TailwindStyleSource { - content: string - extension?: string - file?: string -} - -export interface TailwindStyleCandidateOptions { - candidates?: Iterable - sources?: TailwindStyleSource[] - /** - * Enables UnoCSS-style bare arbitrary values such as `p-10%` and `p-2.5px`. - */ - bareArbitraryValues?: boolean | BareArbitraryValueOptions -} - -export async function collectTailwindStyleCandidates( - options: TailwindStyleCandidateOptions = {}, -): Promise> { - const candidates = new Set() - for (const candidate of options.candidates ?? []) { - candidates.add(candidate) - } - for (const source of options.sources ?? []) { - const sourceCandidates = await extractSourceCandidates(source.content, source.extension, { - bareArbitraryValues: options.bareArbitraryValues, - }) - for (const candidate of sourceCandidates) { - candidates.add(candidate) - } - } - return candidates -} +export { + collectTailwindStyleCandidates, +} from '@tailwindcss-mangle/engine/style-candidates' +export type { + TailwindStyleCandidateOptions, + TailwindStyleSource, +} from '@tailwindcss-mangle/engine/style-candidates' diff --git a/packages/tailwindcss-patch/src/style-generator.ts b/packages/tailwindcss-patch/src/style-generator.ts index c0729cda..a8d626e0 100644 --- a/packages/tailwindcss-patch/src/style-generator.ts +++ b/packages/tailwindcss-patch/src/style-generator.ts @@ -1,80 +1,11 @@ -import type { - TailwindStyleCandidateOptions, - TailwindStyleSource, -} from './style-candidates' -import type { - TailwindV3StyleGenerateOptions, - TailwindV3StyleGenerateResult, -} from './v3' -import type { - TailwindV4StyleGenerateOptions, - TailwindV4StyleGenerateResult, -} from './v4' -import { collectTailwindStyleCandidates } from './style-candidates' -import { generateTailwindV3Style } from './v3' -import { generateTailwindV4Style } from './v4' - -export interface CustomTailwindStyleGenerateContext { - tokens: Set - classSet: Set - sources: TailwindStyleSource[] -} - -export interface CustomTailwindStyleGenerateOptions extends TailwindStyleCandidateOptions { - generate: (context: CustomTailwindStyleGenerateContext) => string | Promise -} - -export interface CustomTailwindStyleGenerateResult { - version: 'custom' - css: string - tokens: Set - classSet: Set - sources: TailwindStyleSource[] -} - -export type TailwindStyleGenerateOptions - = | ({ version: 3 } & TailwindV3StyleGenerateOptions) - | ({ version: 4 } & TailwindV4StyleGenerateOptions) - | ({ version: 'custom' } & CustomTailwindStyleGenerateOptions) - -export type TailwindStyleGenerateResult - = | TailwindV3StyleGenerateResult - | (TailwindV4StyleGenerateResult & { version: 4 }) - | CustomTailwindStyleGenerateResult - -export async function generateCustomStyle( - options: CustomTailwindStyleGenerateOptions, -): Promise { - const tokens = await collectTailwindStyleCandidates(options) - const classSet = new Set(tokens) - const sources = options.sources ?? [] - const css = await options.generate({ - tokens, - classSet, - sources, - }) - - return { - version: 'custom', - css, - tokens, - classSet, - sources, - } -} - -export async function generateTailwindStyle( - options: TailwindStyleGenerateOptions, -): Promise { - if (options.version === 3) { - return generateTailwindV3Style(options) - } - if (options.version === 4) { - const result = await generateTailwindV4Style(options) - return { - ...result, - version: 4, - } - } - return generateCustomStyle(options) -} +export { + generateCustomStyle, + generateTailwindStyle, +} from '@tailwindcss-mangle/engine/style-generator' +export type { + CustomTailwindStyleGenerateContext, + CustomTailwindStyleGenerateOptions, + CustomTailwindStyleGenerateResult, + TailwindStyleGenerateOptions, + TailwindStyleGenerateResult, +} from '@tailwindcss-mangle/engine/style-generator' diff --git a/packages/tailwindcss-patch/src/types.ts b/packages/tailwindcss-patch/src/types.ts index ab7bc1b6..9797c5af 100644 --- a/packages/tailwindcss-patch/src/types.ts +++ b/packages/tailwindcss-patch/src/types.ts @@ -1,6 +1,3 @@ -import type { SourceEntry } from '@tailwindcss/oxide' -import type { Node, Rule } from 'postcss' -import type { Config } from 'tailwindcss' import type { ApplyOptions, CacheOptions, @@ -16,96 +13,19 @@ import type { TailwindV4Options, } from './options/types' -type TailwindcssClassCacheEntry = Rule | { - layer: string - options: Record - sort: Record -} - -export type TailwindcssClassCache = Map - -export interface TailwindcssRuntimeContext { - applyClassCache: Map - candidateRuleCache: Map< - string, - Set< - [ - { - arbitrary: any - index: any - layer: string - options: any[] - parallelIndex: any - parentLayer: string - variants: any - }, - Node, - ] - > - > - candidateRuleMap: Map - changedContent: any[] - classCache: TailwindcssClassCache - disposables: any[] - getClassList: (...args: any[]) => any - getClassOrder: (...args: any[]) => any - getVariants: (...args: any[]) => any - markInvalidUtilityCandidate: (...args: any[]) => any - markInvalidUtilityNode: (...args: any[]) => any - notClassCache: Set - offsets: { - layerPositions: object - offsets: object - reservedVariantBits: any - variantOffsets: Map - } - postCssNodeCache: Map - ruleCache: Set<[object, Node]> - stylesheetCache: Record> - tailwindConfig: Config - userConfigPath: string | null - variantMap: Map unknown]]> - variantOptions: Map -} - -export interface ExtractResult { - classList: string[] - classSet: Set - filename?: string -} - -export interface TailwindTokenLocation { - rawCandidate: string - file: string - relativeFile: string - extension: string - start: number - end: number - length: number - line: number - column: number - lineText: string -} - -export type TailwindTokenFileKey = 'relative' | 'absolute' - -export interface TailwindTokenReport { - entries: TailwindTokenLocation[] - filesScanned: number - sources: SourceEntry[] - skippedFiles: { - file: string - reason: string - }[] -} - -export type TailwindTokenByFileMap = Record - export interface TailwindPatchRuntime { options: NormalizedTailwindCssPatchOptions majorVersion: 2 | 3 | 4 } +export type { + CacheClearOptions, + CacheClearResult, + CacheClearScope, + CacheContextMetadata, + CacheReadMeta, +} from './cache/types' + export type { ApplyOptions, CacheOptions, @@ -151,9 +71,11 @@ export interface PatchStatusReport { } export type { - CacheClearOptions, - CacheClearResult, - CacheClearScope, - CacheContextMetadata, - CacheReadMeta, -} from './cache/types' + ExtractResult, + TailwindcssClassCache, + TailwindcssRuntimeContext, + TailwindTokenByFileMap, + TailwindTokenFileKey, + TailwindTokenLocation, + TailwindTokenReport, +} from '@tailwindcss-mangle/engine/types' diff --git a/packages/tailwindcss-patch/src/v3/index.ts b/packages/tailwindcss-patch/src/v3/index.ts index 83d42a2a..dcc9585c 100644 --- a/packages/tailwindcss-patch/src/v3/index.ts +++ b/packages/tailwindcss-patch/src/v3/index.ts @@ -1,11 +1,11 @@ export { generateTailwindV3RawStyle, generateTailwindV3Style, -} from './style-generator' +} from '@tailwindcss-mangle/engine/v3' export type { TailwindV3RawStyleGenerateOptions, TailwindV3RawStyleGenerateResult, TailwindV3StyleGenerateOptions, TailwindV3StyleGenerateResult, TailwindV3StyleLayer, -} from './style-generator' +} from '@tailwindcss-mangle/engine/v3' diff --git a/packages/tailwindcss-patch/src/v3/style-generator.ts b/packages/tailwindcss-patch/src/v3/style-generator.ts index f3485e3f..47c819fd 100644 --- a/packages/tailwindcss-patch/src/v3/style-generator.ts +++ b/packages/tailwindcss-patch/src/v3/style-generator.ts @@ -1,384 +1,11 @@ -import type { Node } from 'postcss' -import type { Config } from 'tailwindcss' -import type { TailwindStyleCandidateOptions, TailwindStyleSource } from '../style-candidates' -import type { TailwindcssRuntimeContext } from '../types' -import { createRequire } from 'node:module' -import process from 'node:process' -import path from 'pathe' -import postcss from 'postcss' -import { collectTailwindStyleCandidates } from '../style-candidates' - -type NodeRequire = ReturnType - -interface TailwindV3CreateContextModule { - createContext: ( - tailwindConfig: Config, - changedContent?: Array<{ content?: string, extension?: string }>, - root?: ReturnType, - ) => TailwindcssRuntimeContext -} - -interface TailwindV3GenerateRulesModule { - generateRules: ( - candidates: Set, - context: TailwindcssRuntimeContext, - ) => Array<[unknown, Node]> -} - -interface TailwindV3ProcessResult { - css: string - messages: Array> -} - -interface TailwindV3CollapseRulesModule { - default?: (context: TailwindcssRuntimeContext) => (root: postcss.Root, result: TailwindV3ProcessResult) => void -} - -interface TailwindV3ProcessTailwindFeaturesModule { - default?: ( - setupContext: () => (root: postcss.Root) => TailwindcssRuntimeContext, - ) => (root: postcss.Root, result: TailwindV3ProcessResult) => Promise -} - -interface TailwindV3ResolveDefaultsAtRulesModule { - default?: (context: TailwindcssRuntimeContext) => (root: postcss.Root, result: TailwindV3ProcessResult) => void -} - -interface TailwindV3ValidateConfigModule { - validateConfig: (config: unknown) => Config -} - -interface TailwindV3SharedStateModule { - NOT_ON_DEMAND?: string -} - -type ResolveConfig = (config: Config) => Config - -interface TailwindV3Offsets { - sort: (rules: Array<[unknown, T]>) => Array<[{ - layer: 'base' | 'components' | 'defaults' | 'utilities' | 'variants' - }, T]> -} - -export interface TailwindV3StyleGenerateOptions extends TailwindStyleCandidateOptions { - /** - * Tailwind v3 package name or alias. Defaults to `tailwindcss`. - */ - packageName?: string - /** - * `createRequire` base used to resolve the Tailwind v3 package. - */ - cwd?: string - /** - * Inline Tailwind v3 config. `content` is injected from collected candidates. - */ - config?: Partial - /** - * Generate all layers by default. Pass a subset to emit only selected layers. - */ - layers?: TailwindV3StyleLayer[] -} - -export type TailwindV3StyleLayer = 'base' | 'components' | 'utilities' | 'variants' - -export interface TailwindV3RawStyleGenerateOptions extends TailwindStyleCandidateOptions { - /** - * Tailwind v3 package name or alias. Defaults to `tailwindcss`. - */ - packageName?: string - /** - * `createRequire` base used to resolve the Tailwind v3 package. - */ - cwd?: string - /** - * Tailwind v3 entry CSS. Defaults to `@tailwind utilities;`. - */ - css?: string - /** - * Inline Tailwind v3 config. Candidate content is injected automatically. - */ - config?: Partial - /** - * Directly append generated utility rules when the CSS is exactly `@tailwind utilities;`. - * This mirrors Tailwind v3's internal fast path and keeps output order aligned. - */ - directUtilitiesOnly?: boolean | 'auto' -} - -export interface TailwindV3RawStyleGenerateResult { - version: 3 - css: string - tokens: Set - classSet: Set - context: TailwindcssRuntimeContext - dependencies: string[] - sources: TailwindStyleSource[] - config: Config -} - -export interface TailwindV3StyleGenerateResult { - version: 3 - css: string - tokens: Set - classSet: Set - sources: TailwindStyleSource[] - config: Config -} - -function createPackageRequire(cwd?: string): NodeRequire { - return createRequire(path.join(path.resolve(cwd ?? process.cwd()), 'package.json')) -} - -function createDefaultTailwindV3Config(tokens: Set): Config { - return { - content: [ - { - raw: [...tokens].join(' '), - extension: 'html', - }, - ], - theme: { - extend: {}, - }, - plugins: [], - } -} - -function getDefaultExport(module: { default?: T } | T): T { - if (module && typeof module === 'object' && 'default' in module) { - return module.default as T - } - return module as T -} - -function loadTailwindV3Modules(options: Pick) { - const packageName = options.packageName ?? 'tailwindcss' - const moduleRequire = createPackageRequire(options.cwd) - const resolveConfig = getDefaultExport( - moduleRequire(`${packageName}/lib/public/resolve-config`) as { default?: ResolveConfig } | ResolveConfig, - ) - const contextModule = moduleRequire(`${packageName}/lib/lib/setupContextUtils`) as TailwindV3CreateContextModule - const generateRulesModule = moduleRequire(`${packageName}/lib/lib/generateRules`) as TailwindV3GenerateRulesModule - const collapseAdjacentRulesModule = moduleRequire(`${packageName}/lib/lib/collapseAdjacentRules`) as TailwindV3CollapseRulesModule - const collapseDuplicateDeclarationsModule = moduleRequire(`${packageName}/lib/lib/collapseDuplicateDeclarations`) as TailwindV3CollapseRulesModule - const processTailwindFeaturesModule = moduleRequire(`${packageName}/lib/processTailwindFeatures`) as TailwindV3ProcessTailwindFeaturesModule - const resolveDefaultsAtRulesModule = moduleRequire(`${packageName}/lib/lib/resolveDefaultsAtRules`) as TailwindV3ResolveDefaultsAtRulesModule - const sharedStateModule = moduleRequire(`${packageName}/lib/lib/sharedState`) as TailwindV3SharedStateModule - const validateConfigModule = moduleRequire(`${packageName}/lib/util/validateConfig.js`) as TailwindV3ValidateConfigModule - return { - collapseAdjacentRules: getDefaultExport(collapseAdjacentRulesModule), - collapseDuplicateDeclarations: getDefaultExport(collapseDuplicateDeclarationsModule), - createContext: contextModule.createContext, - generateRules: generateRulesModule.generateRules, - notOnDemandCandidate: sharedStateModule.NOT_ON_DEMAND ?? '*', - processTailwindFeatures: getDefaultExport(processTailwindFeaturesModule), - resolveDefaultsAtRules: getDefaultExport(resolveDefaultsAtRulesModule), - resolveConfig, - validateConfig: validateConfigModule.validateConfig, - } -} - -function createRawContentEntries(candidates: Iterable, sources: TailwindStyleSource[]) { - const entries: Array<{ raw: string, extension: string }> = [] - const candidateContent = [...candidates].join(' ') - if (candidateContent.length > 0) { - entries.push({ - raw: candidateContent, - extension: 'html', - }) - } - for (const source of sources) { - entries.push({ - raw: source.content, - extension: source.extension ?? 'html', - }) - } - return entries -} - -function createChangedContentEntries(candidates: Iterable, sources: TailwindStyleSource[]) { - return createRawContentEntries(candidates, sources).map(entry => ({ - content: entry.raw, - extension: entry.extension, - })) -} - -function createTailwindConfigWithContent( - config: Partial | undefined, - tokens: Set, - sources: TailwindStyleSource[], -) { - const userContent = config?.content - return { - ...createDefaultTailwindV3Config(tokens), - ...(config ?? {}), - content: [ - ...(Array.isArray(userContent) ? userContent : []), - ...createRawContentEntries(tokens, sources), - ], - } as Config -} - -function isDirectUtilitiesOnlyCss(css: string) { - return css.replace(/\s+/g, '') === '@tailwindutilities;' -} - -function sortCandidates(candidates: Iterable) { - return [...candidates].sort((a, z) => { - if (a === z) { - return 0 - } - return a < z ? -1 : 1 - }) -} - -function appendUtilityRules( - root: postcss.Root, - context: TailwindcssRuntimeContext, - rules: Array<[unknown, Node]>, -) { - const sortedRules = (context.offsets as unknown as TailwindV3Offsets).sort(rules) - for (const [sort, rule] of sortedRules) { - const tailwindRaw = rule.raws.tailwind as { parentLayer?: string } | undefined - if (sort.layer === 'utilities' || (sort.layer === 'variants' && tailwindRaw?.parentLayer === 'utilities')) { - root.append(rule.clone()) - } - } -} - -function collectClassSet(context: TailwindcssRuntimeContext, notOnDemandCandidate: string) { - const classSet = new Set() - for (const candidate of context.classCache.keys()) { - if (String(candidate) !== String(notOnDemandCandidate)) { - classSet.add(candidate) - } - } - return classSet -} - -function collectDependencyMessages(result: TailwindV3ProcessResult) { - const dependencies = new Set() - for (const message of result.messages) { - const file = message.file - if (message.type === 'dependency' && typeof file === 'string') { - dependencies.add(file) - } - } - return [...dependencies] -} - -function buildStylesheetNodes( - rules: Array<[unknown, Node]>, - context: TailwindcssRuntimeContext, - layers: TailwindV3StyleLayer[], -) { - const sortedRules = (context.offsets as unknown as TailwindV3Offsets).sort(rules) - const nodes: Node[] = [] - const layerSet = new Set(layers) - - for (const [sort, rule] of sortedRules) { - const layer = sort.layer === 'defaults' ? 'base' : sort.layer - if (layerSet.has(layer)) { - nodes.push(rule.clone()) - } - } - return nodes -} - -function createRootFromNodes(nodes: Node[]) { - const root = postcss.root() - for (const node of nodes) { - root.append(node) - } - return root -} - -export async function generateTailwindV3Style( - options: TailwindV3StyleGenerateOptions = {}, -): Promise { - const tokens = await collectTailwindStyleCandidates(options) - const { createContext, generateRules, resolveConfig } = loadTailwindV3Modules(options) - const userContent = options.config?.content - const config = resolveConfig({ - ...createDefaultTailwindV3Config(tokens), - ...(options.config ?? {}), - content: [ - ...(Array.isArray(userContent) ? userContent : []), - { - raw: [...tokens].join(' '), - extension: 'html', - }, - ], - } as Config) - const root = postcss.root() - const context = createContext(config, [], root) - const rules = generateRules(tokens, context) - const nodes = buildStylesheetNodes(rules, context, options.layers ?? ['base', 'components', 'utilities', 'variants']) - const css = createRootFromNodes(nodes).toString() - - return { - version: 3, - css, - tokens, - classSet: new Set(context.classCache.keys()), - sources: options.sources ?? [], - config, - } -} - -export async function generateTailwindV3RawStyle( - options: TailwindV3RawStyleGenerateOptions = {}, -): Promise { - const tokens = await collectTailwindStyleCandidates(options) - const { - collapseAdjacentRules, - collapseDuplicateDeclarations, - createContext, - generateRules, - notOnDemandCandidate, - processTailwindFeatures, - resolveConfig, - resolveDefaultsAtRules, - validateConfig, - } = loadTailwindV3Modules(options) - const css = options.css ?? '@tailwind utilities;' - const config = validateConfig(resolveConfig(createTailwindConfigWithContent(options.config, tokens, options.sources ?? []))) - const root = postcss.parse(css, { - from: undefined, - }) - const result: TailwindV3ProcessResult = { - css: '', - messages: [], - } - const changedContent = createChangedContentEntries(tokens, options.sources ?? []) - const shouldUseDirectUtilities = options.directUtilitiesOnly === true - || (options.directUtilitiesOnly !== false && isDirectUtilitiesOnlyCss(css)) - let context: TailwindcssRuntimeContext - - if (shouldUseDirectUtilities) { - context = createContext(config, changedContent, root) - generateRules(new Set(sortCandidates([notOnDemandCandidate, ...tokens])), context) - root.removeAll() - appendUtilityRules(root, context, [...context.ruleCache]) - resolveDefaultsAtRules(context)(root, result) - collapseAdjacentRules(context)(root, result) - collapseDuplicateDeclarations(context)(root, result) - } - else { - const setupContext = () => { - return (currentRoot: postcss.Root) => createContext(config, changedContent, currentRoot) - } - context = await processTailwindFeatures(setupContext)(root, result) - } - - return { - version: 3, - css: root.toString(), - tokens, - classSet: collectClassSet(context, notOnDemandCandidate), - context, - dependencies: collectDependencyMessages(result), - sources: options.sources ?? [], - config, - } -} +export { + generateTailwindV3RawStyle, + generateTailwindV3Style, +} from '@tailwindcss-mangle/engine/v3/style-generator' +export type { + TailwindV3RawStyleGenerateOptions, + TailwindV3RawStyleGenerateResult, + TailwindV3StyleGenerateOptions, + TailwindV3StyleGenerateResult, + TailwindV3StyleLayer, +} from '@tailwindcss-mangle/engine/v3/style-generator' diff --git a/packages/tailwindcss-patch/src/v4/bare-arbitrary-values.ts b/packages/tailwindcss-patch/src/v4/bare-arbitrary-values.ts index 71720414..9fb24fb6 100644 --- a/packages/tailwindcss-patch/src/v4/bare-arbitrary-values.ts +++ b/packages/tailwindcss-patch/src/v4/bare-arbitrary-values.ts @@ -1,545 +1,12 @@ -export interface BareArbitraryValueOptions { - /** - * 允许作为无方括号任意值的单位列表。 - */ - units?: string[] -} - -export interface BareArbitraryValueResolveResult { - candidate: string - canonicalCandidate: string -} - -export interface BareArbitraryValueSourceCandidate { - rawCandidate: string - start: number - end: number -} - -const DEFAULT_BARE_ARBITRARY_VALUE_UNITS = [ - '%', - 'px', - 'rpx', - 'rem', - 'em', - 'vw', - 'vh', - 'vmin', - 'vmax', - 'dvw', - 'dvh', - 'svw', - 'svh', - 'lvw', - 'lvh', - 'ch', - 'ex', - 'lh', - 'rlh', - 'fr', - 'deg', - 'rad', - 'turn', - 's', - 'ms', -] - -const NUMBER_RE = /^-?(?:\d+|\d*\.\d+)$/ -const FUNCTION_VALUE_RE = /^[a-z_-][\w-]*\(/i -const HEX_ESCAPE_RE = /^[\da-f]$/i -const ASPECT_RATIO_RE = /^\d+\/\d+$/ -const ESCAPED_WHITESPACE_RE = /\\[nrt]/g - -function splitVariantPrefix(candidate: string) { - let depth = 0 - let quote: string | undefined - let lastSeparator = -1 - - for (let index = 0; index < candidate.length; index++) { - const character = candidate[index] - if (character === '\\') { - index++ - continue - } - - if (quote) { - if (character === quote) { - quote = undefined - } - continue - } - - if (character === '"' || character === '\'') { - quote = character - continue - } - - if (character === '[' || character === '(' || character === '{') { - depth++ - continue - } - - if (character === ']' || character === ')' || character === '}') { - depth = Math.max(0, depth - 1) - continue - } - - if (depth === 0 && character === ':') { - lastSeparator = index - } - } - - if (lastSeparator === -1) { - return { - prefix: '', - body: candidate, - } - } - - return { - prefix: candidate.slice(0, lastSeparator + 1), - body: candidate.slice(lastSeparator + 1), - } -} - -function isBalancedFunctionValue(value: string) { - let depth = 0 - let quote: string | undefined - - for (let index = 0; index < value.length; index++) { - const character = value[index] - - if (character === '\\') { - index++ - continue - } - - if (quote) { - if (character === quote) { - quote = undefined - } - continue - } - - if (character === '"' || character === '\'') { - quote = character - continue - } - - if (character === '(') { - depth++ - continue - } - - if (character === ')') { - depth-- - if (depth < 0) { - return false - } - } - } - - return depth === 0 && quote === undefined -} - -function isEscapedAt(value: string, index: number) { - let slashCount = 0 - for (let slashIndex = index - 1; slashIndex >= 0 && value[slashIndex] === '\\'; slashIndex--) { - slashCount++ - } - return slashCount % 2 === 1 -} - -function isBalancedBareArbitraryBody(value: string) { - let depth = 0 - let quote: string | undefined - - for (let index = 0; index < value.length; index++) { - const character = value[index] - - if (isEscapedAt(value, index)) { - continue - } - - if (quote) { - if (character === quote) { - quote = undefined - } - continue - } - - if (character === '"' || character === '\'') { - quote = character - continue - } - - if (character === '(' || character === '{') { - depth++ - continue - } - - if (character === ')' || character === '}') { - depth-- - if (depth < 0) { - return false - } - } - } - - return depth === 0 && quote === undefined -} - -function isHexColorValue(value: string) { - return /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6,8})$/i.test(value) -} - -function isQuotedValue(value: string) { - const quote = value[0] - if ((quote !== '"' && quote !== '\'') || value[value.length - 1] !== quote) { - return false - } - - let escaped = false - for (let index = 1; index < value.length - 1; index++) { - const character = value[index] - if (escaped) { - escaped = false - continue - } - if (character === '\\') { - escaped = true - } - } - - return !escaped -} - -function normalizeBareArbitraryValueOptions(options: boolean | BareArbitraryValueOptions | undefined) { - if (options === false || options === undefined || options === null) { - return - } - - const units = options === true ? DEFAULT_BARE_ARBITRARY_VALUE_UNITS : options.units ?? DEFAULT_BARE_ARBITRARY_VALUE_UNITS - const normalizedUnits = [...new Set(units.filter(unit => typeof unit === 'string' && unit.length > 0))] - if (normalizedUnits.length === 0) { - return - } - return { - units: normalizedUnits.sort((a, b) => b.length - a.length), - } -} - -export function isBareArbitraryValuesEnabled(options: boolean | BareArbitraryValueOptions | undefined) { - return normalizeBareArbitraryValueOptions(options) !== undefined -} - -function normalizeEscapedValue(value: string) { - let result = '' - for (let index = 0; index < value.length; index++) { - const character = value[index] - if (character !== '\\') { - result += character - continue - } - - const nextCharacter = value[index + 1] - if (nextCharacter === undefined) { - result += character - continue - } - - if (HEX_ESCAPE_RE.test(nextCharacter)) { - let hex = '' - let nextIndex = index + 1 - while (nextIndex < value.length && hex.length < 6) { - const hexCharacter = value[nextIndex] - if (hexCharacter === undefined || !HEX_ESCAPE_RE.test(hexCharacter)) { - break - } - hex += hexCharacter - nextIndex++ - } - if (/[\t\n\f\r ]/.test(value[nextIndex] ?? '')) { - nextIndex++ - } - - const decoded = String.fromCodePoint(Number.parseInt(hex, 16)) - result += decoded === '_' ? '\\_' : decoded - index = nextIndex - 1 - continue - } - - result += nextCharacter === '_' ? '\\_' : nextCharacter - index++ - } - return result -} - -function resolveValueWithUnit(body: string, units: string[]) { - const value = normalizeEscapedValue(body) - for (const unit of units) { - if (!value.endsWith(unit)) { - continue - } - const numberPart = value.slice(0, -unit.length) - if (NUMBER_RE.test(numberPart)) { - return `${numberPart}${unit}` - } - } -} - -function resolveArbitraryValue(utility: string, body: string, units: string[]) { - const value = normalizeEscapedValue(body) - const withUnit = resolveValueWithUnit(value, units) - if (withUnit) { - return withUnit - } - - if (utility === 'aspect' && ASPECT_RATIO_RE.test(value)) { - return value - } - - if (isHexColorValue(value)) { - return value - } - - if (isQuotedValue(value)) { - return value - } - - if (FUNCTION_VALUE_RE.test(value) && value.endsWith(')') && isBalancedFunctionValue(value)) { - if (utility === 'text' && /^var\(/i.test(value)) { - return `color:${value}` - } - return value - } -} - -function resolveUtilityAndValue(body: string, units: string[]) { - let depth = 0 - let quote: string | undefined - - for (let index = body.length - 1; index > 0; index--) { - const character = body[index] - - if (isEscapedAt(body, index)) { - continue - } - - if (quote) { - if (character === quote) { - quote = undefined - } - continue - } - - if (character === '"' || character === '\'') { - quote = character - continue - } - - if (character === ')' || character === '}') { - depth++ - continue - } - - if (character === '(' || character === '{') { - depth = Math.max(0, depth - 1) - continue - } - - if (depth > 0 || character !== '-') { - continue - } - - const utility = body.slice(0, index) - const rawValue = body.slice(index + 1) - if (!utility || !rawValue) { - continue - } - - const value = resolveArbitraryValue(utility, rawValue, units) - if (value) { - return { - utility, - value, - } - } - } -} - -export function resolveBareArbitraryValueCandidate( - candidate: string, - options?: boolean | BareArbitraryValueOptions, -): BareArbitraryValueResolveResult | undefined { - const normalizedOptions = normalizeBareArbitraryValueOptions(options) - if (!normalizedOptions || !candidate || candidate.includes('[') || candidate.includes(']')) { - return - } - - const { prefix, body } = splitVariantPrefix(candidate) - const important = body.startsWith('!') ? '!' : '' - let normalizedBody = important ? body.slice(1) : body - const negative = normalizedBody.startsWith('-') ? '-' : '' - if (negative) { - normalizedBody = normalizedBody.slice(1) - } - if (!isBalancedBareArbitraryBody(normalizedBody)) { - return - } - - const resolved = resolveUtilityAndValue(normalizedBody, normalizedOptions.units) - if (!resolved) { - return - } - - return { - candidate, - canonicalCandidate: `${prefix}${important}${negative}${resolved.utility}-[${resolved.value}]`, - } -} - -function isBareArbitrarySourceSplitter(char: string) { - return /\s/.test(char) -} - -function isQuoteBoundary(content: string, start: number, index: number) { - const tokenPrefix = content.slice(start, index) - return tokenPrefix.length === 0 || !tokenPrefix.endsWith('-') -} - -function trimBareArbitrarySourceToken(token: string, start: number) { - let nextToken = token - let nextStart = start - while (nextToken.length > 0 && /^[<{([]$/.test(nextToken[0]!)) { - nextToken = nextToken.slice(1) - nextStart++ - } - while (nextToken.length > 0 && /^[>\],;]$/.test(nextToken[nextToken.length - 1]!)) { - nextToken = nextToken.slice(0, -1) - } - return { - token: nextToken, - start: nextStart, - } -} - -function pushBareArbitrarySourceCandidate( - result: BareArbitraryValueSourceCandidate[], - token: string, - start: number, - options: boolean | BareArbitraryValueOptions | undefined, -) { - const trimmed = trimBareArbitrarySourceToken(token, start) - if (!trimmed.token || trimmed.token.includes('=') || trimmed.token.includes('[') || trimmed.token.includes(']')) { - return - } - if (!resolveBareArbitraryValueCandidate(trimmed.token, options)) { - return - } - result.push({ - rawCandidate: trimmed.token, - start: trimmed.start, - end: trimmed.start + trimmed.token.length, - }) -} - -export function extractBareArbitraryValueSourceCandidatesWithPositions( - content: string, - options?: boolean | BareArbitraryValueOptions, -): BareArbitraryValueSourceCandidate[] { - if (!isBareArbitraryValuesEnabled(options)) { - return [] - } - - const normalized = content.includes('\\') ? content.replace(ESCAPED_WHITESPACE_RE, ' ') : content - const result: BareArbitraryValueSourceCandidate[] = [] - let depth = 0 - let quote: string | undefined - let start = 0 - - for (let index = 0; index < normalized.length; index++) { - const char = normalized[index] - if (char === undefined) { - continue - } - if (char === '\\') { - index++ - continue - } - - if (quote) { - if (char === quote) { - quote = undefined - } - } - else if ((char === '"' || char === '\'' || char === '`') && !isQuoteBoundary(normalized, start, index)) { - quote = char - } - else if (char === '(' || char === '{' || char === '[') { - depth++ - } - else if (char === ')' || char === '}' || char === ']') { - depth = Math.max(0, depth - 1) - } - - if (!isBareArbitrarySourceSplitter(char) && !((char === '"' || char === '\'' || char === '`') && depth === 0 && isQuoteBoundary(normalized, start, index))) { - continue - } - - pushBareArbitrarySourceCandidate(result, normalized.slice(start, index), start, options) - start = index + 1 - } - - pushBareArbitrarySourceCandidate(result, normalized.slice(start), start, options) - return result -} - -export function extractBareArbitraryValueSourceCandidates( - content: string, - options?: boolean | BareArbitraryValueOptions, -) { - return [...new Set( - extractBareArbitraryValueSourceCandidatesWithPositions(content, options) - .map(candidate => candidate.rawCandidate), - )] -} - -// Based on the CSS.escape algorithm, scoped to class selector escaping. -export function escapeCssClassName(value: string) { - let result = '' - for (let index = 0; index < value.length; index++) { - const codeUnit = value.charCodeAt(index) - const character = value.charAt(index) - - if (codeUnit === 0x0000) { - result += '\uFFFD' - continue - } - - if ( - (codeUnit >= 0x0001 && codeUnit <= 0x001F) - || codeUnit === 0x007F - || (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) - || (index === 1 && codeUnit >= 0x0030 && codeUnit <= 0x0039 && value.charCodeAt(0) === 0x002D) - ) { - result += `\\${codeUnit.toString(16)} ` - continue - } - - if ( - codeUnit >= 0x0080 - || codeUnit === 0x002D - || codeUnit === 0x005F - || (codeUnit >= 0x0030 && codeUnit <= 0x0039) - || (codeUnit >= 0x0041 && codeUnit <= 0x005A) - || (codeUnit >= 0x0061 && codeUnit <= 0x007A) - ) { - result += character - continue - } - - result += `\\${character}` - } - return result -} +export { + escapeCssClassName, + extractBareArbitraryValueSourceCandidates, + extractBareArbitraryValueSourceCandidatesWithPositions, + isBareArbitraryValuesEnabled, + resolveBareArbitraryValueCandidate, +} from '@tailwindcss-mangle/engine/v4/bare-arbitrary-values' +export type { + BareArbitraryValueOptions, + BareArbitraryValueResolveResult, + BareArbitraryValueSourceCandidate, +} from '@tailwindcss-mangle/engine/v4/bare-arbitrary-values' diff --git a/packages/tailwindcss-patch/src/v4/candidates.ts b/packages/tailwindcss-patch/src/v4/candidates.ts index 3add7956..62fa6524 100644 --- a/packages/tailwindcss-patch/src/v4/candidates.ts +++ b/packages/tailwindcss-patch/src/v4/candidates.ts @@ -1,316 +1,6 @@ -import type { BareArbitraryValueOptions } from './bare-arbitrary-values' -import type { TailwindV4DesignSystem } from './types' -import postcss from 'postcss' -import { escapeCssClassName, resolveBareArbitraryValueCandidate } from './bare-arbitrary-values' - -export function resolveValidTailwindV4Candidates( - designSystem: TailwindV4DesignSystem, - candidates: Iterable, - options?: { - bareArbitraryValues?: boolean | BareArbitraryValueOptions - }, -): Set { - const validCandidates = new Set() - const parsedCandidates: string[] = [] - const originalCandidatesByCanonical = new Map>() - - for (const candidate of candidates) { - if (!candidate) { - continue - } - - const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options?.bareArbitraryValues) - const candidateToCheck = bareArbitrary?.canonicalCandidate ?? candidate - - if (bareArbitrary) { - const originalCandidates = originalCandidatesByCanonical.get(candidateToCheck) ?? new Set() - originalCandidates.add(candidate) - originalCandidatesByCanonical.set(candidateToCheck, originalCandidates) - } - - const alreadyParsed = parsedCandidates.includes(candidateToCheck) - if (alreadyParsed) { - continue - } - - if (designSystem.parseCandidate(candidateToCheck).length > 0) { - parsedCandidates.push(candidateToCheck) - } - } - - if (parsedCandidates.length === 0) { - return validCandidates - } - - const cssByCandidate = designSystem.candidatesToCss(parsedCandidates) - for (let index = 0; index < parsedCandidates.length; index++) { - const candidate = parsedCandidates[index] - const candidateCss = cssByCandidate[index] - if (candidate && typeof candidateCss === 'string' && candidateCss.trim().length > 0) { - const originalCandidates = originalCandidatesByCanonical.get(candidate) - if (originalCandidates) { - for (const originalCandidate of originalCandidates) { - validCandidates.add(originalCandidate) - } - continue - } - validCandidates.add(candidate) - } - } - - return validCandidates -} - -function createSelectorAliasMap( - candidates: Iterable, - options?: boolean | BareArbitraryValueOptions, -) { - const aliases = new Map>() - for (const candidate of candidates) { - const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options) - if (!bareArbitrary) { - continue - } - const canonicalSelector = escapeCssClassName(bareArbitrary.canonicalCandidate) - const bareSelectors = aliases.get(canonicalSelector) ?? new Set() - bareSelectors.add(escapeCssClassName(bareArbitrary.candidate)) - aliases.set(canonicalSelector, bareSelectors) - } - return aliases -} - -export function replaceBareArbitraryValueSelectors( - css: string, - candidates: Iterable, - options?: boolean | BareArbitraryValueOptions, -) { - const aliases = createSelectorAliasMap(candidates, options) - if (aliases.size === 0) { - return css - } - - if (Array.from(aliases.values()).every(bareSelectors => bareSelectors.size === 1)) { - let result = css - for (const [canonicalSelector, bareSelectors] of aliases) { - const bareSelector = Array.from(bareSelectors)[0] - if (bareSelector !== undefined) { - result = result.replaceAll(canonicalSelector, bareSelector) - } - } - return result - } - - const root = postcss.parse(css) - root.walkRules((rule) => { - let selectors = rule.selectors - for (const [canonicalSelector, bareSelectors] of aliases) { - selectors = selectors.flatMap((selector) => { - if (!selector.includes(canonicalSelector)) { - return selector - } - return Array.from(bareSelectors, bareSelector => selector.replaceAll(canonicalSelector, bareSelector)) - }) - } - rule.selectors = selectors - }) - return root.toString() -} - -export function canonicalizeBareArbitraryValueCandidates( - candidates: Iterable, - options?: boolean | BareArbitraryValueOptions, -) { - return Array.from(candidates, (candidate) => { - const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options) - return bareArbitrary?.canonicalCandidate ?? candidate - }) -} - -function splitTopLevel(value: string, separator: string, options?: { keepEmpty?: boolean }) { - const result: string[] = [] - let start = 0 - let depth = 0 - let quote: string | undefined - - for (let index = 0; index < value.length; index++) { - const character = value[index] - if (character === '\\') { - index++ - continue - } - - if (quote) { - if (character === quote) { - quote = undefined - } - continue - } - - if (character === '"' || character === '\'') { - quote = character - continue - } - - if (character === '(' || character === '[' || character === '{') { - depth++ - continue - } - - if (character === ')' || character === ']' || character === '}') { - depth = Math.max(0, depth - 1) - continue - } - - if (depth === 0 && character === separator) { - const item = value.slice(start, index).trim() - if (item || options?.keepEmpty) { - result.push(item) - } - start = index + 1 - } - } - - const item = value.slice(start).trim() - if (item || options?.keepEmpty) { - result.push(item) - } - return result -} - -const sequencePattern = /^(-?\d+)\.\.(-?\d+)(?:\.\.(-?\d+))?$/ - -function expandSequence(value: string) { - const match = value.match(sequencePattern) - if (!match) { - return [value] - } - - const [, startValue, endValue, stepValue] = match - if (startValue === undefined || endValue === undefined) { - return [value] - } - - const start = Number.parseInt(startValue, 10) - const end = Number.parseInt(endValue, 10) - let step = stepValue === undefined ? (start <= end ? 1 : -1) : Number.parseInt(stepValue, 10) - if (step === 0) { - throw new Error('Step cannot be zero in Tailwind CSS v4 inline source sequence.') - } - - const ascending = start < end - if (ascending && step < 0) { - step = -step - } - if (!ascending && step > 0) { - step = -step - } - - const result: string[] = [] - for (let current = start; ascending ? current <= end : current >= end; current += step) { - result.push(current.toString()) - } - return result -} - -function expandInlinePattern(pattern: string): string[] { - const openIndex = pattern.indexOf('{') - if (openIndex === -1) { - return [pattern] - } - - const prefix = pattern.slice(0, openIndex) - const rest = pattern.slice(openIndex) - let depth = 0 - let closeIndex = -1 - for (let index = 0; index < rest.length; index++) { - const character = rest[index] - if (character === '{') { - depth++ - } - else if (character === '}') { - depth-- - if (depth === 0) { - closeIndex = index - break - } - } - } - - if (closeIndex === -1) { - throw new Error(`The Tailwind CSS v4 inline source pattern "${pattern}" is not balanced.`) - } - - const body = rest.slice(1, closeIndex) - const suffix = rest.slice(closeIndex + 1) - const parts = sequencePattern.test(body) - ? expandSequence(body) - : splitTopLevel(body, ',', { keepEmpty: true }).flatMap(part => expandInlinePattern(part)) - const suffixes = expandInlinePattern(suffix) - - const result: string[] = [] - for (const part of parts) { - for (const expandedSuffix of suffixes) { - result.push(`${prefix}${part}${expandedSuffix}`) - } - } - return result -} - -function unquoteCssString(value: string) { - const quote = value[0] - if ((quote !== '"' && quote !== '\'') || value[value.length - 1] !== quote) { - return undefined - } - - let result = '' - for (let index = 1; index < value.length - 1; index++) { - const character = value[index] - if (character === '\\') { - index++ - result += value[index] ?? '' - continue - } - result += character - } - return result -} - -export function extractTailwindV4InlineSourceCandidates(css: string) { - const included = new Set() - const excluded = new Set() - - const root = postcss.parse(css) - root.walkAtRules('source', (rule) => { - let params = rule.params.trim() - if (!params) { - return - } - - let negated = false - if (params.startsWith('not ')) { - negated = true - params = params.slice(4).trim() - } - - if (!params.startsWith('inline(') || !params.endsWith(')')) { - return - } - - const inlineValue = unquoteCssString(params.slice(7, -1).trim()) - if (inlineValue === undefined) { - return - } - - const target = negated ? excluded : included - for (const part of splitTopLevel(inlineValue, ' ')) { - for (const candidate of expandInlinePattern(part)) { - target.add(candidate) - } - } - }) - - return { - included, - excluded, - } -} +export { + canonicalizeBareArbitraryValueCandidates, + extractTailwindV4InlineSourceCandidates, + replaceBareArbitraryValueSelectors, + resolveValidTailwindV4Candidates, +} from '@tailwindcss-mangle/engine/v4/candidates' diff --git a/packages/tailwindcss-patch/src/v4/engine.ts b/packages/tailwindcss-patch/src/v4/engine.ts index 9765d6cc..7c168d27 100644 --- a/packages/tailwindcss-patch/src/v4/engine.ts +++ b/packages/tailwindcss-patch/src/v4/engine.ts @@ -1,112 +1,3 @@ -import type { - TailwindV4Engine, - TailwindV4GenerateOptions, - TailwindV4GenerateResult, - TailwindV4ResolvedSource, - TailwindV4SourcePattern, -} from './types' -import { extractRawCandidates, extractRawCandidatesWithPositions } from '../extraction/candidate-extractor' -import { - canonicalizeBareArbitraryValueCandidates, - extractTailwindV4InlineSourceCandidates, - replaceBareArbitraryValueSelectors, - resolveValidTailwindV4Candidates, -} from './candidates' -import { compileTailwindV4Source, loadTailwindV4DesignSystem } from './node-adapter' -import { createTailwindV4CompiledSourceEntries } from './source-scan' - -function resolveScanSources( - options: TailwindV4GenerateOptions | undefined, - source: TailwindV4ResolvedSource, - compiledRoot: TailwindV4GenerateResult['root'], - compiledSources: TailwindV4SourcePattern[], -) { - if (Array.isArray(options?.scanSources)) { - return options.scanSources - } - if (options?.scanSources === true) { - return createTailwindV4CompiledSourceEntries(compiledRoot, compiledSources, source.base) - } - return [] -} - -async function collectRawCandidates( - source: TailwindV4ResolvedSource, - options: TailwindV4GenerateOptions | undefined, - compiledRoot: TailwindV4GenerateResult['root'], - compiledSources: TailwindV4SourcePattern[] = [], -) { - const rawCandidates = new Set() - const extractOptions = options?.bareArbitraryValues === undefined - ? undefined - : { bareArbitraryValues: options.bareArbitraryValues } - - for (const candidate of options?.candidates ?? []) { - rawCandidates.add(candidate) - } - - for (const candidateSource of options?.sources ?? []) { - const candidates = await extractRawCandidatesWithPositions(candidateSource.content, candidateSource.extension, extractOptions) - for (const candidate of candidates) { - rawCandidates.add(candidate.rawCandidate) - } - } - - const filesystemSources = resolveScanSources(options, source, compiledRoot, compiledSources) - if (filesystemSources.length > 0) { - for (const candidate of await extractRawCandidates(filesystemSources, extractOptions)) { - rawCandidates.add(candidate) - } - } - - const inlineSources = extractTailwindV4InlineSourceCandidates(source.css) - for (const candidate of inlineSources.included) { - rawCandidates.add(candidate) - } - for (const candidate of inlineSources.excluded) { - rawCandidates.delete(candidate) - } - - return rawCandidates -} - -export function createTailwindV4Engine(source: TailwindV4ResolvedSource): TailwindV4Engine { - return { - source, - loadDesignSystem() { - return loadTailwindV4DesignSystem(source) - }, - async validateCandidates(candidates) { - const designSystem = await loadTailwindV4DesignSystem(source) - return resolveValidTailwindV4Candidates(designSystem, candidates) - }, - async generate(options): Promise { - const { compiled, dependencies } = await compileTailwindV4Source(source) - const rawCandidates = await collectRawCandidates(source, options, compiled.root, compiled.sources) - const designSystem = await loadTailwindV4DesignSystem(source) - const classSet = resolveValidTailwindV4Candidates(designSystem, rawCandidates, { - ...(options?.bareArbitraryValues === undefined ? {} : { bareArbitraryValues: options.bareArbitraryValues }), - }) - const inlineSources = extractTailwindV4InlineSourceCandidates(source.css) - for (const candidate of inlineSources.excluded) { - classSet.delete(candidate) - } - - const buildCandidates = canonicalizeBareArbitraryValueCandidates(classSet, options?.bareArbitraryValues) - const css = replaceBareArbitraryValueSelectors( - compiled.build(buildCandidates), - classSet, - options?.bareArbitraryValues, - ) - - return { - css, - classSet, - rawCandidates, - dependencies: Array.from(dependencies), - sources: compiled.sources, - root: compiled.root, - } - }, - } -} +export { + createTailwindV4Engine, +} from '@tailwindcss-mangle/engine/v4/engine' diff --git a/packages/tailwindcss-patch/src/v4/node-adapter.ts b/packages/tailwindcss-patch/src/v4/node-adapter.ts index bda76d73..5648cc21 100644 --- a/packages/tailwindcss-patch/src/v4/node-adapter.ts +++ b/packages/tailwindcss-patch/src/v4/node-adapter.ts @@ -1,207 +1,6 @@ -import type { - TailwindV4CompiledSourceRoot, - TailwindV4DesignSystem, - TailwindV4ResolvedSource, - TailwindV4SourcePattern, -} from './types' -import { createRequire } from 'node:module' -import { pathToFileURL } from 'node:url' -import path from 'pathe' - -interface TailwindV4CompiledSource { - sources: TailwindV4SourcePattern[] - root: TailwindV4CompiledSourceRoot - build: (candidates: string[]) => string -} - -interface TailwindV4NodeModule { - compile: (css: string, options: { - base: string - onDependency: (dependency: string) => void - customCssResolver?: (id: string, base: string) => Promise - }) => Promise - __unstable__loadDesignSystem: (css: string, options: { base: string }) => Promise -} - -const nodeModulePromiseCache = new Map>() -const designSystemPromiseCache = new Map>() - -function unique(values: Iterable) { - return Array.from(new Set(Array.from(values).filter(Boolean).map(value => path.resolve(value)))) -} - -function createRequireBase(base: string) { - return path.join(base, 'package.json') -} - -function isRelativeSpecifier(id: string) { - return id.startsWith('./') || id.startsWith('../') || id === '.' || id === '..' -} - -function isAbsoluteSpecifier(id: string) { - return path.isAbsolute(id) -} - -function isCssSpecifier(id: string) { - return path.extname(id) === '.css' -} - -function createCssResolutionCandidates(id: string) { - if (isCssSpecifier(id)) { - return [id] - } - return [`${id}/index.css`, id] -} - -function createFallbackCssResolver(baseCandidates: string[]) { - const bases = unique(baseCandidates) - return async (id: string) => { - if (isRelativeSpecifier(id) || isAbsoluteSpecifier(id)) { - return undefined - } - - for (const base of bases) { - const requireFromBase = createRequire(createRequireBase(base)) - for (const candidate of createCssResolutionCandidates(id)) { - try { - return requireFromBase.resolve(candidate) - } - catch {} - } - } - return undefined - } -} - -async function importResolvedModule(resolved: string): Promise { - return import(pathToFileURL(resolved).href) as unknown as Promise -} - -async function importTailwindNodeFromBase(base: string): Promise { - try { - const resolved = createRequire(createRequireBase(base)).resolve('@tailwindcss/node') - return await importResolvedModule(resolved) - } - catch { - return undefined - } -} - -async function importFallbackTailwindNode(): Promise { - return import('@tailwindcss/node') as unknown as Promise -} - -export async function loadTailwindV4NodeModule(baseCandidates: string[]): Promise { - const bases = unique(baseCandidates) - const cacheKey = JSON.stringify(bases) - const cached = nodeModulePromiseCache.get(cacheKey) - if (cached) { - return cached - } - - const promise = (async () => { - for (const base of bases) { - const loaded = await importTailwindNodeFromBase(base) - if (loaded) { - return loaded - } - } - - return importFallbackTailwindNode() - })() - - nodeModulePromiseCache.set(cacheKey, promise) - promise.catch(() => { - if (nodeModulePromiseCache.get(cacheKey) === promise) { - nodeModulePromiseCache.delete(cacheKey) - } - }) - return promise -} - -function createDesignSystemCacheKey(css: string, bases: string[]) { - return JSON.stringify({ - css, - bases: unique(bases), - }) -} - -export function getTailwindV4DesignSystemCacheKey(source: Pick) { - return createDesignSystemCacheKey(source.css, [source.base, ...source.baseFallbacks]) -} - -export async function loadTailwindV4DesignSystem(source: TailwindV4ResolvedSource): Promise { - const bases = unique([source.base, ...source.baseFallbacks]) - if (bases.length === 0) { - throw new Error('No base directories provided for Tailwind CSS v4 design system.') - } - - const cacheKey = createDesignSystemCacheKey(source.css, bases) - const cached = designSystemPromiseCache.get(cacheKey) - if (cached) { - return cached - } - - const promise = (async () => { - const node = await loadTailwindV4NodeModule([source.projectRoot, ...bases]) - let lastError: unknown - - for (const base of bases) { - try { - return await node.__unstable__loadDesignSystem(source.css, { base }) - } - catch (error) { - lastError = error - } - } - - if (lastError instanceof Error) { - throw lastError - } - throw new Error('Failed to load Tailwind CSS v4 design system.') - })() - - designSystemPromiseCache.set(cacheKey, promise) - promise.catch(() => { - if (designSystemPromiseCache.get(cacheKey) === promise) { - designSystemPromiseCache.delete(cacheKey) - } - }) - return promise -} - -export async function compileTailwindV4Source(source: TailwindV4ResolvedSource) { - const bases = unique([source.base, ...source.baseFallbacks]) - if (bases.length === 0) { - throw new Error('No base directories provided for Tailwind CSS v4 compiler.') - } - - const node = await loadTailwindV4NodeModule([source.projectRoot, ...bases]) - let lastError: unknown - - for (const base of bases) { - const dependencies = new Set(source.dependencies) - try { - const compiled = await node.compile(source.css, { - base, - customCssResolver: createFallbackCssResolver([source.projectRoot, ...bases]), - onDependency(dependency) { - dependencies.add(path.resolve(dependency)) - }, - }) - - return { - compiled, - dependencies, - } - } - catch (error) { - lastError = error - } - } - - if (lastError instanceof Error) { - throw lastError - } - throw new Error('Failed to compile Tailwind CSS v4 source.') -} +export { + compileTailwindV4Source, + getTailwindV4DesignSystemCacheKey, + loadTailwindV4DesignSystem, + loadTailwindV4NodeModule, +} from '@tailwindcss-mangle/engine/v4/node-adapter' diff --git a/packages/tailwindcss-patch/src/v4/source-scan.ts b/packages/tailwindcss-patch/src/v4/source-scan.ts index 3064096b..3cdf11db 100644 --- a/packages/tailwindcss-patch/src/v4/source-scan.ts +++ b/packages/tailwindcss-patch/src/v4/source-scan.ts @@ -1,432 +1,24 @@ -import type { SourceEntry } from '@tailwindcss/oxide' -import type { TailwindV4CompiledSourceRoot, TailwindV4SourcePattern } from './types' -import { realpathSync } from 'node:fs' -import { stat } from 'node:fs/promises' -import process from 'node:process' -import micromatch from 'micromatch' -import path from 'pathe' - -export const TAILWIND_V4_IGNORED_CONTENT_DIRS = [ - '.git', - '.hg', - '.jj', - '.next', - '.parcel-cache', - '.pnpm-store', - '.svelte-kit', - '.svn', - '.turbo', - '.venv', - '.vercel', - '.yarn', - '__pycache__', - 'node_modules', - 'venv', -] - -export const TAILWIND_V4_IGNORED_EXTENSIONS = [ - 'less', - 'lock', - 'sass', - 'scss', - 'styl', - 'log', -] - -export const TAILWIND_V4_IGNORED_FILES = [ - 'package-lock.json', - 'pnpm-lock.yaml', - 'bun.lockb', - '.gitignore', - '.env', - '.env.*', -] - -export const TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN = '**/*' - -function uniqueResolvedPaths(values: Iterable) { - const result: string[] = [] - for (const value of values) { - if (!value) { - continue - } - const resolved = path.resolve(value) - if (!result.includes(resolved)) { - result.push(resolved) - } - } - return result -} - -export function toPosixPath(value: string) { - return value.replaceAll(path.sep, '/') -} - -export function resolveSourceScanPath(value: string) { - const resolved = path.resolve(value) - try { - return realpathSync.native(resolved) - } - catch { - return resolved - } -} - -export function normalizeGlobPattern(pattern: string) { - return pattern.startsWith('./') ? pattern.slice(2) : pattern -} - -function hasGlobMagic(value: string) { - return /[*?[\]{}()!+@]/.test(value) -} - -function splitStaticGlobPrefix(pattern: string) { - const normalized = normalizeGlobPattern(pattern) - const segments = normalized.split(/[\\/]+/) - const prefix: string[] = [] - const rest: string[] = [] - let reachedGlob = false - - for (const segment of segments) { - if (!reachedGlob && segment && !hasGlobMagic(segment)) { - prefix.push(segment) - continue - } - reachedGlob = true - rest.push(segment) - } - - return { - prefix, - rest, - } -} - -async function pathExistsAsDirectory(file: string) { - try { - return (await stat(file)).isDirectory() - } - catch { - return false - } -} - -export function createTailwindV4DefaultIgnoreSources(base: string): TailwindV4SourcePattern[] { - return [ - ...TAILWIND_V4_IGNORED_CONTENT_DIRS.map(pattern => ({ - base, - pattern: `**/${pattern}/**`, - negated: true, - })), - ...TAILWIND_V4_IGNORED_EXTENSIONS.map(extension => ({ - base, - pattern: `**/*.${extension}`, - negated: true, - })), - ...TAILWIND_V4_IGNORED_FILES.map(pattern => ({ - base, - pattern: `**/${pattern}`, - negated: true, - })), - ] -} - -export function createTailwindV4RootSources( - root: TailwindV4CompiledSourceRoot, - fallbackBase: string, -): TailwindV4SourcePattern[] { - if (root === 'none') { - return [] - } - if (root === null) { - return [{ base: fallbackBase, pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN, negated: false }] - } - return [{ ...root, negated: false }] -} - -export function createTailwindV4CompiledSourceEntries( - root: TailwindV4CompiledSourceRoot, - sources: TailwindV4SourcePattern[], - fallbackBase: string, -) { - return [ - ...createTailwindV4RootSources(root, fallbackBase), - ...sources, - ] -} - -export async function resolveTailwindV4SourceEntry( - sourcePath: string, - base: string, - negated: boolean, - defaultPattern = TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN, -): Promise { - const absoluteSource = path.isAbsolute(sourcePath) ? path.resolve(sourcePath) : path.resolve(base, sourcePath) - - if (await pathExistsAsDirectory(absoluteSource)) { - return { - base: absoluteSource, - negated, - pattern: normalizeGlobPattern(defaultPattern), - } - } - - if (path.isAbsolute(sourcePath)) { - return { - base: path.dirname(absoluteSource), - negated, - pattern: normalizeGlobPattern(path.basename(absoluteSource)), - } - } - - const { prefix, rest } = splitStaticGlobPrefix(sourcePath) - if (prefix.length > 0 && rest.length > 0) { - return { - base: path.resolve(base, ...prefix), - negated, - pattern: normalizeGlobPattern(rest.join('/')), - } - } - - return { - base, - negated, - pattern: normalizeGlobPattern(sourcePath), - } -} - -export async function normalizeTailwindV4SourceEntries( - sources: TailwindV4SourcePattern[], - options: { - cwd?: string - defaultPattern?: string - } = {}, -) { - const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd() - return Promise.all(sources.map(source => - resolveTailwindV4SourceEntry( - source.pattern, - source.base ? path.resolve(source.base) : cwd, - source.negated, - options.defaultPattern, - ))) -} - -function expandBracePattern(pattern: string): string[] { - const index = pattern.indexOf('{') - if (index === -1) { - return [pattern] - } - - const rest = pattern.slice(index) - let depth = 0 - let endIndex = -1 - for (let i = 0; i < rest.length; i++) { - const char = rest[i] - if (char === '\\') { - i += 1 - continue - } - if (char === '{') { - depth += 1 - continue - } - if (char === '}') { - depth -= 1 - if (depth === 0) { - endIndex = i - break - } - } - } - if (endIndex === -1) { - return [pattern] - } - - const prefix = pattern.slice(0, index) - const inner = rest.slice(1, endIndex) - const suffix = rest.slice(endIndex + 1) - const parts: string[] = [] - const stack: string[] = [] - let lastPos = 0 - for (let i = 0; i < inner.length; i++) { - const char = inner[i] - if (char === '\\') { - i += 1 - continue - } - if (char === '{') { - stack.push('}') - continue - } - if (char === '}' && stack[stack.length - 1] === '}') { - stack.pop() - continue - } - if (char === ',' && stack.length === 0) { - parts.push(inner.slice(lastPos, i)) - lastPos = i + 1 - } - } - parts.push(inner.slice(lastPos)) - - return parts.flatMap(part => - expandBracePattern(`${prefix}${part}${suffix}`)) -} - -export function expandTailwindV4SourceEntryBraces(sources: TailwindV4SourcePattern[]): TailwindV4SourcePattern[] { - return sources.flatMap((source) => { - const base = path.resolve(source.base) - return expandBracePattern(source.pattern).map(pattern => ({ - base, - pattern, - negated: source.negated, - })) - }) -} - -export function normalizeTailwindV4ScannerSources( - sources: TailwindV4SourcePattern[] | undefined, - cwd: string, - ignoredSources: TailwindV4SourcePattern[] = [], -): SourceEntry[] { - const baseSources = sources?.length - ? sources - : [ - { - base: cwd, - pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN, - negated: false, - }, - ] - - return expandTailwindV4SourceEntryBraces([...baseSources, ...ignoredSources]) -} - -function normalizeEntryPattern(entry: TailwindV4SourcePattern) { - return path.isAbsolute(entry.pattern) - ? toPosixPath(path.relative(resolveSourceScanPath(entry.base), entry.pattern)) - : normalizeGlobPattern(entry.pattern) -} - -function isFileMatchedByTailwindV4SourceEntry(file: string, entry: TailwindV4SourcePattern) { - const relative = toPosixPath(path.relative(resolveSourceScanPath(entry.base), file)) - return Boolean(relative) - && !relative.startsWith('../') - && !path.isAbsolute(relative) - && micromatch.isMatch(relative, normalizeEntryPattern(entry)) -} - -export function isFileExcludedByTailwindV4SourceEntries( - file: string, - entries: TailwindV4SourcePattern[] | undefined, -) { - if (!entries?.length) { - return false - } - const resolvedFile = resolveSourceScanPath(file) - return entries.some(entry => entry.negated && isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry)) -} - -export function isFileMatchedByTailwindV4SourceEntries( - file: string, - entries: TailwindV4SourcePattern[] | undefined, -) { - if (!entries?.length) { - return true - } - - const positiveEntries = entries.filter(entry => !entry.negated) - const negativeEntries = entries.filter(entry => entry.negated) - if (positiveEntries.length === 0) { - return false - } - - const resolvedFile = resolveSourceScanPath(file) - const matchesPositive = positiveEntries.some(entry => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry)) - if (!matchesPositive) { - return false - } - - return !negativeEntries.some(entry => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry)) -} - -export function createTailwindV4SourceEntryMatcher(entries: TailwindV4SourcePattern[] | undefined) { - if (!entries?.length) { - return undefined - } - return (file: string) => isFileMatchedByTailwindV4SourceEntries(file, entries) -} - -export function createTailwindV4SourceExclusionMatcher(entries: TailwindV4SourcePattern[] | undefined) { - if (!entries?.length) { - return undefined - } - return (file: string) => isFileExcludedByTailwindV4SourceEntries(file, entries) -} - -export function groupTailwindV4SourceEntriesByBase(entries: TailwindV4SourcePattern[]) { - const entriesByBase = new Map() - for (const entry of entries) { - const base = path.resolve(entry.base) - const group = entriesByBase.get(base) ?? [] - group.push({ - ...entry, - base, - pattern: normalizeGlobPattern(entry.pattern), - }) - entriesByBase.set(base, group) - } - return entriesByBase -} - -export async function expandTailwindV4SourceEntries( - entries: TailwindV4SourcePattern[], - resolveFiles: (options: { cwd: string, sources: TailwindV4SourcePattern[] }) => Promise, -) { - if (entries.length === 0) { - return [] - } - - const files = new Set() - await Promise.all([...groupTailwindV4SourceEntriesByBase(entries).entries()].map(async ([base, group]) => { - const matched = await resolveFiles({ - cwd: base, - sources: group, - }) - for (const file of matched) { - files.add(path.resolve(file)) - } - })) - - return [...files].filter(file => !isFileExcludedByTailwindV4SourceEntries(file, entries)) -} - -export function mergeTailwindV4SourceEntries(...entries: Array) { - const result: TailwindV4SourcePattern[] = [] - const seen = new Set() - for (const group of entries) { - for (const entry of group ?? []) { - const normalized = { - base: path.resolve(entry.base), - pattern: normalizeGlobPattern(entry.pattern), - negated: entry.negated, - } - const key = JSON.stringify(normalized) - if (seen.has(key)) { - continue - } - seen.add(key) - result.push(normalized) - } - } - return result -} - -export function resolveTailwindV4SourceBaseCandidates( - projectRoot: string, - base: string, - baseFallbacks: string[], -) { - return uniqueResolvedPaths([base, projectRoot, ...baseFallbacks]) -} +export { + createTailwindV4CompiledSourceEntries, + createTailwindV4DefaultIgnoreSources, + createTailwindV4RootSources, + createTailwindV4SourceEntryMatcher, + createTailwindV4SourceExclusionMatcher, + expandTailwindV4SourceEntries, + expandTailwindV4SourceEntryBraces, + groupTailwindV4SourceEntriesByBase, + isFileExcludedByTailwindV4SourceEntries, + isFileMatchedByTailwindV4SourceEntries, + mergeTailwindV4SourceEntries, + normalizeGlobPattern, + normalizeTailwindV4ScannerSources, + normalizeTailwindV4SourceEntries, + resolveSourceScanPath, + resolveTailwindV4SourceBaseCandidates, + resolveTailwindV4SourceEntry, + TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN, + TAILWIND_V4_IGNORED_CONTENT_DIRS, + TAILWIND_V4_IGNORED_EXTENSIONS, + TAILWIND_V4_IGNORED_FILES, + toPosixPath, +} from '@tailwindcss-mangle/engine/v4/source-scan' diff --git a/packages/tailwindcss-patch/src/v4/source.ts b/packages/tailwindcss-patch/src/v4/source.ts index c6d861de..0e6970d8 100644 --- a/packages/tailwindcss-patch/src/v4/source.ts +++ b/packages/tailwindcss-patch/src/v4/source.ts @@ -1,18 +1,9 @@ +import type { TailwindV4ResolvedSource, TailwindV4SourceOptions } from '@tailwindcss-mangle/engine/v4/types' import type { NormalizedTailwindCssPatchOptions, TailwindCssPatchOptions } from '../config' -import type { TailwindV4CssSource, TailwindV4ResolvedSource, TailwindV4SourceOptions } from './types' -import { promises as fs } from 'node:fs' -import process from 'node:process' +import { resolveTailwindV4Source } from '@tailwindcss-mangle/engine/v4/source' import path from 'pathe' import { normalizeOptions } from '../config' -function resolveBase(value: string | undefined, fallback: string) { - return value === undefined - ? fallback - : path.isAbsolute(value) - ? path.resolve(value) - : path.resolve(fallback, value) -} - function uniquePaths(values: Iterable) { const result: string[] = [] for (const value of values) { @@ -27,171 +18,6 @@ function uniquePaths(values: Iterable) { return result } -function toCssImportPath(value: string) { - return value.replaceAll('\\', '/') -} - -function quoteCssImport(value: string) { - return value.replaceAll('\\', '\\\\').replaceAll('"', '\\"') -} - -function isPostcssPluginSpecifier(packageName: string) { - return packageName === '@tailwindcss/postcss' - || /(?:^|[/\\])@tailwindcss[/\\]postcss(?:[/\\]|$)/.test(packageName) - || /(?:^|[/\\])postcss(?:[/\\]|$)/i.test(packageName) - || /postcss\.config\.[cm]?[jt]s$/i.test(packageName) -} - -function createDefaultCss(packageName: string | undefined) { - const cssPackageName = packageName && !isPostcssPluginSpecifier(packageName) - ? packageName - : 'tailwindcss' - return `@import "${quoteCssImport(toCssImportPath(cssPackageName))}";` -} - -async function pathExists(filePath: string) { - try { - await fs.access(filePath) - return true - } - catch { - return false - } -} - -async function resolveCssEntries(entries: string[], projectRoot: string, base: string | undefined) { - const resolvedEntries = entries.map(entry => ({ - original: entry, - absolute: path.isAbsolute(entry) ? path.resolve(entry) : path.resolve(projectRoot, entry), - })) - const resolvedBase = base ?? path.dirname(resolvedEntries[0]?.absolute ?? projectRoot) - const dependencies = resolvedEntries.map(entry => entry.absolute) - const cssParts: string[] = [] - - for (const entry of resolvedEntries) { - if (await pathExists(entry.absolute)) { - cssParts.push(await fs.readFile(entry.absolute, 'utf8')) - continue - } - - const importPath = path.isAbsolute(entry.original) - ? entry.absolute - : path.relative(resolvedBase, entry.absolute) - cssParts.push(`@import "${quoteCssImport(toCssImportPath(importPath))}";`) - } - - return { - base: resolvedBase, - css: cssParts.join('\n'), - dependencies, - } -} - -function resolveCssSources(sources: TailwindV4CssSource[], projectRoot: string, base: string | undefined) { - const resolvedSources = sources.map(source => ({ - ...source, - base: source.base === undefined ? undefined : resolveBase(source.base, projectRoot), - file: source.file === undefined - ? undefined - : path.isAbsolute(source.file) - ? path.resolve(source.file) - : path.resolve(projectRoot, source.file), - dependencies: source.dependencies?.map(dependency => - path.isAbsolute(dependency) ? path.resolve(dependency) : path.resolve(projectRoot, dependency), - ) ?? [], - })) - const firstSource = resolvedSources[0] - const resolvedBase = base - ?? firstSource?.base - ?? (firstSource?.file ? path.dirname(firstSource.file) : projectRoot) - const dependencies = resolvedSources.flatMap(source => [ - source.file, - ...source.dependencies, - ]).filter((dependency): dependency is string => Boolean(dependency)) - - return { - base: resolvedBase, - css: resolvedSources.map(source => source.css).join('\n'), - dependencies, - } -} - -function normalizeResolvedSource( - source: { - projectRoot: string - cwd: string - base: string - baseFallbacks: string[] - css: string - dependencies: string[] - }, -): TailwindV4ResolvedSource { - const baseFallbacks = uniquePaths([ - ...source.baseFallbacks, - source.projectRoot, - source.cwd, - ]).filter(base => base !== source.base) - - return { - projectRoot: source.projectRoot, - base: source.base, - baseFallbacks, - css: source.css, - dependencies: Array.from(new Set(source.dependencies.map(dependency => path.resolve(dependency)))), - } -} - -export async function resolveTailwindV4Source(options: TailwindV4SourceOptions = {}): Promise { - const projectRoot = resolveBase(options.projectRoot, process.cwd()) - const cwd = resolveBase(options.cwd, projectRoot) - const configuredBase = options.base === undefined ? undefined : resolveBase(options.base, projectRoot) - const baseFallbacks = uniquePaths(options.baseFallbacks?.map(base => resolveBase(base, projectRoot)) ?? []) - - if (options.css !== undefined) { - return normalizeResolvedSource({ - projectRoot, - cwd, - base: configuredBase ?? cwd, - baseFallbacks, - css: options.css, - dependencies: [], - }) - } - - if (options.cssEntries?.length || options.cssSources?.length) { - const entries = options.cssEntries?.length - ? await resolveCssEntries(options.cssEntries, projectRoot, configuredBase) - : undefined - const sources = options.cssSources?.length - ? resolveCssSources(options.cssSources, projectRoot, configuredBase) - : undefined - const css = [ - entries?.css, - sources?.css, - ].filter(Boolean).join('\n') - return normalizeResolvedSource({ - projectRoot, - cwd, - base: configuredBase ?? entries?.base ?? sources?.base ?? cwd, - baseFallbacks, - css, - dependencies: [ - ...(entries?.dependencies ?? []), - ...(sources?.dependencies ?? []), - ], - }) - } - - return normalizeResolvedSource({ - projectRoot, - cwd, - base: configuredBase ?? cwd, - baseFallbacks, - css: createDefaultCss(options.packageName), - dependencies: [], - }) -} - function resolveConfigDir(config: string | undefined, projectRoot: string) { if (!config) { return undefined @@ -224,6 +50,8 @@ function createSourceOptionsFromNormalizedPatchOptions( } } +export { resolveTailwindV4Source } + export function tailwindV4SourceOptionsFromPatchOptions(options: TailwindCssPatchOptions): TailwindV4SourceOptions { return createSourceOptionsFromNormalizedPatchOptions(normalizeOptions(options)) } diff --git a/packages/tailwindcss-patch/src/v4/style-generator.ts b/packages/tailwindcss-patch/src/v4/style-generator.ts index a863588e..bd0b3cb7 100644 --- a/packages/tailwindcss-patch/src/v4/style-generator.ts +++ b/packages/tailwindcss-patch/src/v4/style-generator.ts @@ -1,44 +1,4 @@ -import type { - TailwindV4SourceOptions, - TailwindV4StyleGenerateOptions, - TailwindV4StyleGenerateResult, -} from './types' -import { collectTailwindStyleCandidates } from '../style-candidates' -import { createTailwindV4Engine } from './engine' -import { resolveTailwindV4Source } from './source' - -function createSourceOptions(options: TailwindV4StyleGenerateOptions): TailwindV4SourceOptions { - return { - ...(options.projectRoot === undefined ? {} : { projectRoot: options.projectRoot }), - ...(options.cwd === undefined ? {} : { cwd: options.cwd }), - ...(options.base === undefined ? {} : { base: options.base }), - ...(options.baseFallbacks === undefined ? {} : { baseFallbacks: options.baseFallbacks }), - ...(options.css === undefined ? {} : { css: options.css }), - ...(options.cssSources === undefined ? {} : { cssSources: options.cssSources }), - ...(options.cssEntries === undefined ? {} : { cssEntries: options.cssEntries }), - ...(options.packageName === undefined ? {} : { packageName: options.packageName }), - } -} - -export async function collectTailwindV4StyleCandidates( - options: Pick, -): Promise> { - return collectTailwindStyleCandidates(options) -} - -export async function generateTailwindV4Style( - options: TailwindV4StyleGenerateOptions = {}, -): Promise { - const source = options.source ?? await resolveTailwindV4Source(createSourceOptions(options)) - const candidates = await collectTailwindV4StyleCandidates(options) - const result = await createTailwindV4Engine(source).generate({ - candidates, - ...(options.bareArbitraryValues === undefined ? {} : { bareArbitraryValues: options.bareArbitraryValues }), - ...(options.scanSources === undefined ? {} : { scanSources: options.scanSources }), - }) - return { - ...result, - tokens: result.rawCandidates, - source, - } -} +export { + collectTailwindV4StyleCandidates, + generateTailwindV4Style, +} from '@tailwindcss-mangle/engine/v4/style-generator' diff --git a/packages/tailwindcss-patch/src/v4/types.ts b/packages/tailwindcss-patch/src/v4/types.ts index 3440f0ce..6e97b546 100644 --- a/packages/tailwindcss-patch/src/v4/types.ts +++ b/packages/tailwindcss-patch/src/v4/types.ts @@ -1,103 +1,15 @@ -import type { TailwindStyleSource } from '../style-candidates' - -export interface TailwindV4SourceOptions { - projectRoot?: string - cwd?: string - base?: string - baseFallbacks?: string[] - css?: string - cssSources?: TailwindV4CssSource[] - cssEntries?: string[] - packageName?: string -} - -export interface TailwindV4CssSource { - css: string - base?: string - file?: string - dependencies?: string[] -} - -export interface TailwindV4ResolvedSource { - projectRoot: string - base: string - baseFallbacks: string[] - css: string - dependencies: string[] -} - -export interface TailwindV4CandidateSource { - content: string - extension?: string -} - -export interface TailwindV4StyleSource extends TailwindStyleSource {} - -export interface TailwindV4GenerateOptions { - candidates?: Iterable - sources?: TailwindV4CandidateSource[] - /** - * Enables UnoCSS-style bare arbitrary values such as `p-10%` and `p-2.5px`. - */ - bareArbitraryValues?: boolean | { - units?: string[] - } - /** - * 扫描文件系统 source entries 中的候选类名。 - * - * - `true`:使用 Tailwind v4 编译入口解析出的 `@source` 列表。 - * - `TailwindV4SourcePattern[]`:使用调用方显式传入的 source 列表。 - */ - scanSources?: boolean | TailwindV4SourcePattern[] -} - -export type TailwindV4CompiledSourceRoot = null | 'none' | { - base: string - pattern: string -} - -export interface TailwindV4SourcePattern { - base: string - pattern: string - negated: boolean -} - -export interface TailwindV4GenerateResult { - css: string - classSet: Set - rawCandidates: Set - dependencies: string[] - sources: TailwindV4SourcePattern[] - root: TailwindV4CompiledSourceRoot -} - -export interface TailwindV4StyleGenerateOptions extends TailwindV4SourceOptions { - source?: TailwindV4ResolvedSource - candidates?: Iterable - sources?: TailwindV4StyleSource[] - /** - * Enables UnoCSS-style bare arbitrary values such as `p-10%` and `p-2.5px`. - */ - bareArbitraryValues?: TailwindV4GenerateOptions['bareArbitraryValues'] - /** - * Scans the compiled Tailwind CSS v4 source entries in addition to in-memory sources. - */ - scanSources?: TailwindV4GenerateOptions['scanSources'] -} - -export interface TailwindV4StyleGenerateResult extends TailwindV4GenerateResult { - tokens: Set - source: TailwindV4ResolvedSource -} - -export interface TailwindV4DesignSystem { - parseCandidate: (candidate: string) => unknown[] - candidatesToCss: (candidates: string[]) => Array -} - -export interface TailwindV4Engine { - source: TailwindV4ResolvedSource - loadDesignSystem: () => Promise - validateCandidates: (candidates: Iterable) => Promise> - generate: (options?: TailwindV4GenerateOptions) => Promise -} +export type { + TailwindV4CandidateSource, + TailwindV4CompiledSourceRoot, + TailwindV4CssSource, + TailwindV4DesignSystem, + TailwindV4Engine, + TailwindV4GenerateOptions, + TailwindV4GenerateResult, + TailwindV4ResolvedSource, + TailwindV4SourceOptions, + TailwindV4SourcePattern, + TailwindV4StyleGenerateOptions, + TailwindV4StyleGenerateResult, + TailwindV4StyleSource, +} from '@tailwindcss-mangle/engine/v4/types' diff --git a/packages/tailwindcss-patch/test/packaged-runtime-dependency.test.ts b/packages/tailwindcss-patch/test/packaged-runtime-dependency.test.ts index dcdd0fac..c8516939 100644 --- a/packages/tailwindcss-patch/test/packaged-runtime-dependency.test.ts +++ b/packages/tailwindcss-patch/test/packaged-runtime-dependency.test.ts @@ -1,6 +1,7 @@ import { execFileSync } from 'node:child_process' import fsSync, { promises as fs } from 'node:fs' import { createRequire } from 'node:module' +import os from 'node:os' import path from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' @@ -8,6 +9,7 @@ const require = createRequire(import.meta.url) const packageDir = path.resolve(__dirname, '..') const repoRoot = path.resolve(packageDir, '../..') const configPackageDir = path.resolve(repoRoot, 'packages/config') +const enginePackageDir = path.resolve(repoRoot, 'packages/engine') let tempDir: string @@ -55,9 +57,11 @@ async function packTailwindcssPatch() { async function packConsumerInstallTarballs() { const configTarball = await packPackage(configPackageDir) + const engineTarball = await packPackage(enginePackageDir) const tailwindcssPatchTarball = await packTailwindcssPatch() return { config: configTarball, + engine: engineTarball, tailwindcssPatch: tailwindcssPatchTarball, } } @@ -79,23 +83,30 @@ async function createProject(name: string) { function installProject( projectDir: string, - tarballs: { config: string, tailwindcssPatch: string }, + tarballs: { config: string, engine: string, tailwindcssPatch: string }, tailwindVersion: string, ) { - const packageJsonPath = path.join(projectDir, 'package.json') - const packageJson = JSON.parse(fsSync.readFileSync(packageJsonPath, 'utf8')) - packageJson.pnpm = { - ...packageJson.pnpm, - overrides: { - ...packageJson.pnpm?.overrides, - '@tailwindcss-mangle/config': `file:${tarballs.config}`, - }, - } - fsSync.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, 'utf8') + fsSync.writeFileSync( + path.join(projectDir, 'pnpm-workspace.yaml'), + [ + 'packages:', + ' - .', + 'overrides:', + ` '@tailwindcss-mangle/config': 'file:${tarballs.config}'`, + ` '@tailwindcss-mangle/engine': 'file:${tarballs.engine}'`, + '', + ].join('\n'), + 'utf8', + ) + + runPnpm([ + 'add', + `@tailwindcss-mangle/config@file:${tarballs.config}`, + `@tailwindcss-mangle/engine@file:${tarballs.engine}`, + ], projectDir) runPnpm([ 'add', - '--ignore-workspace', tarballs.tailwindcssPatch, `tailwindcss@${tailwindVersion}`, ], projectDir) @@ -109,7 +120,7 @@ function runProjectScript(projectDir: string, source: string) { describe('packed tailwindcss-patch runtime dependencies', () => { beforeEach(async () => { - tempDir = await fs.mkdtemp(path.join(repoRoot, '.tmp-tw-patch-packaged-')) + tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'tw-patch-packaged-')) }) afterEach(async () => { @@ -150,7 +161,9 @@ describe('packed tailwindcss-patch runtime dependencies', () => { await fs.writeFile(path.join(cwd, 'page.html'), '
') const require = createRequire(import.meta.url) - const oxidePackageJson = require.resolve('@tailwindcss/oxide/package.json') + const patchEntry = require.resolve('tailwindcss-patch') + const patchRequire = createRequire(patchEntry) + const oxidePackageJson = patchRequire.resolve('@tailwindcss/oxide/package.json') const patcher = new TailwindcssPatcher({ projectRoot: cwd, cache: false, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8e854da1..58b7f79d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -851,6 +851,31 @@ importers: specifier: ^7.0.0 version: 7.0.0 + packages/engine: + dependencies: + '@tailwindcss/node': + specifier: ^4.3.1 + version: 4.3.1 + '@tailwindcss/oxide': + specifier: ^4.3.1 + version: 4.3.1 + micromatch: + specifier: ^4.0.8 + version: 4.0.8 + pathe: + specifier: ^2.0.3 + version: 2.0.3 + postcss: + specifier: ^8.5.15 + version: 8.5.15 + devDependencies: + tailwindcss: + specifier: ^4.3.1 + version: 4.3.1 + tailwindcss-3: + specifier: catalog:tailwindcss3 + version: tailwindcss@3.4.19(tsx@4.22.4)(yaml@2.9.0) + packages/shared: {} packages/tailwindcss-patch: @@ -870,6 +895,9 @@ importers: '@tailwindcss-mangle/config': specifier: workspace:* version: link:../config + '@tailwindcss-mangle/engine': + specifier: workspace:* + version: link:../engine '@tailwindcss/node': specifier: ^4.3.1 version: 4.3.1 @@ -3662,9 +3690,6 @@ packages: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jridgewell/gen-mapping@0.3.12': - resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} - '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -9519,11 +9544,6 @@ packages: browserify-zlib@0.1.4: resolution: {integrity: sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==} - browserslist@4.24.4: - resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - browserslist@4.28.1: resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -11046,9 +11066,6 @@ packages: electron-to-chromium@1.5.349: resolution: {integrity: sha512-QsWVGyRuY07Aqb234QytTfwd5d9AJlfNIQ5wIOl1L+PZDzI9d9+Fn0FRale/QYlFxt/bUnB0/nLd1jFPGxGK1A==} - electron-to-chromium@1.5.88: - resolution: {integrity: sha512-K3C2qf1o+bGzbilTDCTBhTQcMS9KW60yTAaTeeXsfvQuTDDwlokLam/AdqlqcSy9u4UainDgsHV23ksXAOgamw==} - emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -13643,9 +13660,6 @@ packages: lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - lodash@4.18.1: resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} @@ -14573,9 +14587,6 @@ packages: node-mock-http@1.0.4: resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} @@ -15826,10 +15837,6 @@ packages: peerDependencies: postcss: ^8.4.29 - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} - engines: {node: '>=4'} - postcss-selector-parser@6.1.4: resolution: {integrity: sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==} engines: {node: '>=4'} @@ -16466,11 +16473,6 @@ packages: resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} engines: {node: '>=10'} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} - hasBin: true - resolve@1.22.11: resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} @@ -16481,10 +16483,6 @@ packages: engines: {node: '>= 0.4'} hasBin: true - resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} - hasBin: true - resolve@2.0.0-next.7: resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} engines: {node: '>= 0.4'} @@ -18236,12 +18234,6 @@ packages: unwasm@0.5.3: resolution: {integrity: sha512-keBgTSfp3r6+s9ZcSma+0chwxQdmLbB5+dAD9vjtB21UTMYuKAxHXCU1K2CbCtnP09EaWeRvACnXk0EJtUx+hw==} - update-browserslist-db@1.1.2: - resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -19168,7 +19160,7 @@ snapshots: '@ampproject/remapping@2.3.0': dependencies: - '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 '@antfu/eslint-config@9.0.0(@eslint-react/eslint-plugin@5.8.18(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(@next/eslint-plugin-next@16.2.9)(@typescript-eslint/rule-tester@8.61.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(@typescript-eslint/typescript-estree@8.61.0(typescript@6.0.3))(@typescript-eslint/utils@8.61.0(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(@unocss/eslint-plugin@66.6.8(eslint@10.5.0(jiti@2.7.0))(typescript@6.0.3))(@vue/compiler-sfc@3.5.37)(eslint-plugin-format@2.0.1(eslint@10.5.0(jiti@2.7.0)))(eslint-plugin-jsx-a11y@6.10.2(eslint@10.5.0(jiti@2.7.0)))(eslint-plugin-react-refresh@0.5.2(eslint@10.5.0(jiti@2.7.0)))(eslint-plugin-vuejs-accessibility@2.5.0(eslint@10.5.0(jiti@2.7.0))(globals@17.6.0))(eslint@10.5.0(jiti@2.7.0))(ts-declaration-location@1.0.7(typescript@6.0.3))(typescript@6.0.3)(vitest@4.1.9)': @@ -19412,7 +19404,7 @@ snapshots: dependencies: '@babel/compat-data': 7.26.5 '@babel/helper-validator-option': 7.25.9 - browserslist: 4.24.4 + browserslist: 4.28.2 lru-cache: 5.1.1 semver: 6.3.1 @@ -22496,11 +22488,6 @@ snapshots: dependencies: '@sinclair/typebox': 0.27.10 - '@jridgewell/gen-mapping@0.3.12': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -27117,7 +27104,7 @@ snapshots: '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 - resolve: 1.22.10 + resolve: 1.22.12 optionalDependencies: rollup: 4.62.0 @@ -27587,7 +27574,7 @@ snapshots: html-tags: 3.3.1 is-color-stop: 1.1.0 is-glob: 4.0.3 - lodash: 4.17.21 + lodash: 4.18.1 lodash.topath: 4.5.2 modern-normalize: 1.1.0 node-emoji: 1.11.0 @@ -27598,13 +27585,13 @@ snapshots: postcss-js: 2.0.3 postcss-load-config: 3.1.4(postcss@7.0.39) postcss-nested: 4.2.3 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 6.1.4 postcss-value-parser: 4.2.0 pretty-hrtime: 1.0.3 purgecss: 4.1.3 quick-lru: 5.1.1 reduce-css-calc: 2.1.8 - resolve: 1.22.10 + resolve: 1.22.12 tmp: 0.2.3 transitivePeerDependencies: - ts-node @@ -28687,8 +28674,8 @@ snapshots: dependencies: '@mapbox/node-pre-gyp': 2.0.3(encoding@0.1.13) '@rollup/pluginutils': 5.4.0(rollup@4.62.0) - acorn: 8.16.0 - acorn-import-attributes: 1.9.5(acorn@8.16.0) + acorn: 8.17.0 + acorn-import-attributes: 1.9.5(acorn@8.17.0) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 @@ -29626,9 +29613,9 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-import-attributes@1.9.5(acorn@8.16.0): + acorn-import-attributes@1.9.5(acorn@8.17.0): dependencies: - acorn: 8.16.0 + acorn: 8.17.0 acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: @@ -30138,7 +30125,7 @@ snapshots: autoprefixer@9.8.8: dependencies: browserslist: 4.28.2 - caniuse-lite: 1.0.30001791 + caniuse-lite: 1.0.30001797 normalize-range: 0.1.2 num2fraction: 1.2.2 picocolors: 0.2.1 @@ -30406,13 +30393,6 @@ snapshots: dependencies: pako: 0.2.9 - browserslist@4.24.4: - dependencies: - caniuse-lite: 1.0.30001797 - electron-to-chromium: 1.5.88 - node-releases: 2.0.19 - update-browserslist-db: 1.1.2(browserslist@4.24.4) - browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.10.35 @@ -30582,7 +30562,7 @@ snapshots: caniuse-api@3.0.0: dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 caniuse-lite: 1.0.30001797 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 @@ -30953,11 +30933,11 @@ snapshots: core-js-compat@3.40.0: dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 core-js-compat@3.48.0: dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 core-js-compat@3.49.0: dependencies: @@ -30985,7 +30965,7 @@ snapshots: cosmiconfig@6.0.0: dependencies: '@types/parse-json': 4.0.2 - import-fresh: 3.3.0 + import-fresh: 3.3.1 parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.3 @@ -30993,14 +30973,14 @@ snapshots: cosmiconfig@7.1.0: dependencies: '@types/parse-json': 4.0.2 - import-fresh: 3.3.0 + import-fresh: 3.3.1 parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.3 cosmiconfig@8.3.6(typescript@6.0.3): dependencies: - import-fresh: 3.3.0 + import-fresh: 3.3.1 js-yaml: 4.2.0 parse-json: 5.2.0 path-type: 4.0.0 @@ -31843,8 +31823,6 @@ snapshots: electron-to-chromium@1.5.349: {} - electron-to-chromium@1.5.88: {} - emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} @@ -32028,7 +32006,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.3 es-shim-unscopables@1.1.0: dependencies: @@ -32052,7 +32030,7 @@ snapshots: esast-util-from-js@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 - acorn: 8.15.0 + acorn: 8.17.0 esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 @@ -32881,7 +32859,7 @@ snapshots: object.fromentries: 2.0.8 object.values: 1.2.1 prop-types: 15.8.1 - resolve: 2.0.0-next.5 + resolve: 2.0.0-next.7 semver: 6.3.1 string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 @@ -33520,7 +33498,7 @@ snapshots: fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.2.1 universalify: 2.0.1 fs-extra@11.3.0: @@ -33586,7 +33564,7 @@ snapshots: call-bound: 1.0.4 define-properties: 1.2.1 functions-have-names: 1.2.3 - hasown: 2.0.2 + hasown: 2.0.3 is-callable: 1.2.7 functions-have-names@1.2.3: {} @@ -34372,7 +34350,7 @@ snapshots: internal-slot@1.1.0: dependencies: es-errors: 1.3.0 - hasown: 2.0.2 + hasown: 2.0.3 side-channel: 1.1.0 internmap@1.0.1: {} @@ -34608,7 +34586,7 @@ snapshots: call-bound: 1.0.4 gopd: 1.2.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.3 is-set@2.0.3: {} @@ -35125,8 +35103,6 @@ snapshots: lodash.uniq@4.5.0: {} - lodash@4.17.21: {} - lodash@4.18.1: {} log-symbols@4.1.0: @@ -35899,8 +35875,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) micromark-extension-mdx-expression: 3.0.1 micromark-extension-mdx-jsx: 3.0.2 micromark-extension-mdx-md: 2.0.0 @@ -36657,7 +36633,7 @@ snapshots: node-emoji@1.11.0: dependencies: - lodash: 4.17.21 + lodash: 4.18.1 node-exports-info@1.6.0: dependencies: @@ -36702,8 +36678,6 @@ snapshots: node-mock-http@1.0.4: {} - node-releases@2.0.19: {} - node-releases@2.0.27: {} node-releases@2.0.38: {} @@ -36728,7 +36702,7 @@ snapshots: normalize-package-data@3.0.3: dependencies: hosted-git-info: 4.1.0 - is-core-module: 2.16.1 + is-core-module: 2.16.2 semver: 7.8.4 validate-npm-package-license: 3.0.4 @@ -37439,7 +37413,7 @@ snapshots: path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 - minipass: 7.1.2 + minipass: 7.1.3 path-scurry@2.0.1: dependencies: @@ -37579,7 +37553,7 @@ snapshots: postcss-colormin@5.3.1(postcss@8.5.15): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 caniuse-api: 3.0.0 colord: 2.9.3 postcss: 8.5.15 @@ -37603,7 +37577,7 @@ snapshots: postcss-convert-values@5.1.3(postcss@8.5.15): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 postcss: 8.5.15 postcss-value-parser: 4.2.0 @@ -37764,7 +37738,7 @@ snapshots: postcss-merge-rules@5.1.4(postcss@8.5.15): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 caniuse-api: 3.0.0 cssnano-utils: 3.1.0(postcss@8.5.15) postcss: 8.5.15 @@ -37824,7 +37798,7 @@ snapshots: postcss-minify-params@5.1.4(postcss@8.5.15): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 cssnano-utils: 3.1.0(postcss@8.5.15) postcss: 8.5.15 postcss-value-parser: 4.2.0 @@ -37898,7 +37872,7 @@ snapshots: postcss-nested@4.2.3: dependencies: postcss: 7.0.39 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 6.1.4 postcss-nested@6.2.0(postcss@8.5.15): dependencies: @@ -37999,7 +37973,7 @@ snapshots: postcss-normalize-unicode@5.1.1(postcss@8.5.15): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 postcss: 8.5.15 postcss-value-parser: 4.2.0 @@ -38066,7 +38040,7 @@ snapshots: postcss-reduce-initial@5.1.2(postcss@8.5.15): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 caniuse-api: 3.0.0 postcss: 8.5.15 @@ -38111,11 +38085,6 @@ snapshots: dependencies: postcss: 8.5.15 - postcss-selector-parser@6.1.2: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - postcss-selector-parser@6.1.4: dependencies: cssesc: 3.0.0 @@ -38346,7 +38315,7 @@ snapshots: commander: 8.3.0 glob: 7.2.3 postcss: 8.5.15 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 6.1.4 qified@0.10.1: dependencies: @@ -38861,12 +38830,6 @@ snapshots: resolve.exports@2.0.3: {} - resolve@1.22.10: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.11: dependencies: is-core-module: 2.16.1 @@ -38880,12 +38843,6 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - resolve@2.0.0-next.5: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@2.0.0-next.7: dependencies: es-errors: 1.3.0 @@ -39881,7 +39838,7 @@ snapshots: stylehacks@5.1.1(postcss@8.5.15): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 postcss: 8.5.15 postcss-selector-parser: 6.1.4 @@ -40464,7 +40421,7 @@ snapshots: ts-loader@9.5.4(typescript@6.0.3)(webpack@5.107.2(cssnano@5.1.15(postcss@8.5.15))(esbuild@0.28.0)(html-minifier-terser@7.2.0)(lightningcss@1.32.0)(postcss@8.5.15)): dependencies: chalk: 4.1.2 - enhanced-resolve: 5.19.0 + enhanced-resolve: 5.24.0 micromatch: 4.0.8 semver: 7.8.4 source-map: 0.7.6 @@ -41037,7 +40994,7 @@ snapshots: dependencies: citty: 0.1.6 defu: 6.1.7 - jiti: 2.5.1 + jiti: 2.7.0 knitwork: 1.2.0 scule: 1.3.0 @@ -41050,12 +41007,6 @@ snapshots: pathe: 2.0.3 pkg-types: 2.3.1 - update-browserslist-db@1.1.2(browserslist@4.24.4): - dependencies: - browserslist: 4.24.4 - escalade: 3.2.0 - picocolors: 1.1.1 - update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 diff --git a/scripts/check-package-boundaries.mjs b/scripts/check-package-boundaries.mjs index 2fef5932..543b2ef8 100644 --- a/scripts/check-package-boundaries.mjs +++ b/scripts/check-package-boundaries.mjs @@ -67,12 +67,16 @@ const RULES = { allowedInternal: ['@tailwindcss-mangle/config', '@tailwindcss-mangle/shared'], disallowedSpecifiers: ['tailwindcss-patch', 'tailwindcss-patch/'], }, + '@tailwindcss-mangle/engine': { + allowedInternal: [], + disallowedSpecifiers: ['tailwindcss-patch', 'tailwindcss-patch/', 'unplugin-tailwindcss-mangle', 'unplugin-tailwindcss-mangle/', '@tailwindcss-mangle/core', '@tailwindcss-mangle/core/'], + }, 'unplugin-tailwindcss-mangle': { allowedInternal: ['@tailwindcss-mangle/core', '@tailwindcss-mangle/config', '@tailwindcss-mangle/shared'], disallowedSpecifiers: ['tailwindcss-patch', 'tailwindcss-patch/'], }, 'tailwindcss-patch': { - allowedInternal: ['@tailwindcss-mangle/config', '@tailwindcss-mangle/shared'], + allowedInternal: ['@tailwindcss-mangle/config', '@tailwindcss-mangle/engine', '@tailwindcss-mangle/shared'], disallowedSpecifiers: ['unplugin-tailwindcss-mangle', 'unplugin-tailwindcss-mangle/', '@tailwindcss-mangle/core', '@tailwindcss-mangle/core/'], }, }