tailwindcss-patch 9.4.4 → 9.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/{cli-srv0kRlt.js → cli-CGyUnvFc.js} +3 -2
  2. package/dist/{cli-CLvyx3xl.mjs → cli-DRfALTSo.mjs} +1 -1
  3. package/dist/cli.js +2 -2
  4. package/dist/cli.mjs +2 -2
  5. package/dist/commands/cli-runtime.d.mts +1 -1
  6. package/dist/commands/cli-runtime.d.ts +1 -1
  7. package/dist/commands/cli-runtime.js +2 -2
  8. package/dist/commands/cli-runtime.mjs +2 -2
  9. package/dist/{dist-Dn7cMVhi.js → dist-DlC5vuI2.js} +1 -1
  10. package/dist/index.d.mts +7 -149
  11. package/dist/index.d.ts +8 -150
  12. package/dist/index.js +294 -521
  13. package/dist/index.mjs +6 -471
  14. package/dist/{validate-oAkURzUC.d.mts → validate-B5-08lrU.d.ts} +8 -252
  15. package/dist/{validate-BuqRodYI.d.ts → validate-CgrG4aAY.d.mts} +8 -252
  16. package/dist/{validate-CUNJFfHh.mjs → validate-Q00Ccqht.mjs} +5 -1402
  17. package/dist/{validate-RpdgpjgT.js → validate-XiYmTZcd.js} +79 -1705
  18. package/package.json +4 -6
  19. package/src/api/tailwindcss-patcher.ts +3 -2
  20. package/src/extraction/candidate-extractor.ts +17 -701
  21. package/src/extraction/split-candidate-tokens.ts +5 -101
  22. package/src/options/types.ts +1 -2
  23. package/src/style-candidates.ts +5 -35
  24. package/src/style-generator.ts +11 -80
  25. package/src/types.ts +21 -95
  26. package/src/v3/index.ts +2 -2
  27. package/src/v4/index.ts +104 -28
  28. package/src/v3/style-generator.ts +0 -384
  29. package/src/v4/bare-arbitrary-values.ts +0 -545
  30. package/src/v4/candidates.ts +0 -316
  31. package/src/v4/engine.ts +0 -112
  32. package/src/v4/node-adapter.ts +0 -207
  33. package/src/v4/source-scan.ts +0 -432
  34. package/src/v4/source.ts +0 -235
  35. package/src/v4/style-generator.ts +0 -44
  36. package/src/v4/types.ts +0 -103
@@ -1,316 +0,0 @@
1
- import type { BareArbitraryValueOptions } from './bare-arbitrary-values'
2
- import type { TailwindV4DesignSystem } from './types'
3
- import postcss from 'postcss'
4
- import { escapeCssClassName, resolveBareArbitraryValueCandidate } from './bare-arbitrary-values'
5
-
6
- export function resolveValidTailwindV4Candidates(
7
- designSystem: TailwindV4DesignSystem,
8
- candidates: Iterable<string>,
9
- options?: {
10
- bareArbitraryValues?: boolean | BareArbitraryValueOptions
11
- },
12
- ): Set<string> {
13
- const validCandidates = new Set<string>()
14
- const parsedCandidates: string[] = []
15
- const originalCandidatesByCanonical = new Map<string, Set<string>>()
16
-
17
- for (const candidate of candidates) {
18
- if (!candidate) {
19
- continue
20
- }
21
-
22
- const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options?.bareArbitraryValues)
23
- const candidateToCheck = bareArbitrary?.canonicalCandidate ?? candidate
24
-
25
- if (bareArbitrary) {
26
- const originalCandidates = originalCandidatesByCanonical.get(candidateToCheck) ?? new Set<string>()
27
- originalCandidates.add(candidate)
28
- originalCandidatesByCanonical.set(candidateToCheck, originalCandidates)
29
- }
30
-
31
- const alreadyParsed = parsedCandidates.includes(candidateToCheck)
32
- if (alreadyParsed) {
33
- continue
34
- }
35
-
36
- if (designSystem.parseCandidate(candidateToCheck).length > 0) {
37
- parsedCandidates.push(candidateToCheck)
38
- }
39
- }
40
-
41
- if (parsedCandidates.length === 0) {
42
- return validCandidates
43
- }
44
-
45
- const cssByCandidate = designSystem.candidatesToCss(parsedCandidates)
46
- for (let index = 0; index < parsedCandidates.length; index++) {
47
- const candidate = parsedCandidates[index]
48
- const candidateCss = cssByCandidate[index]
49
- if (candidate && typeof candidateCss === 'string' && candidateCss.trim().length > 0) {
50
- const originalCandidates = originalCandidatesByCanonical.get(candidate)
51
- if (originalCandidates) {
52
- for (const originalCandidate of originalCandidates) {
53
- validCandidates.add(originalCandidate)
54
- }
55
- continue
56
- }
57
- validCandidates.add(candidate)
58
- }
59
- }
60
-
61
- return validCandidates
62
- }
63
-
64
- function createSelectorAliasMap(
65
- candidates: Iterable<string>,
66
- options?: boolean | BareArbitraryValueOptions,
67
- ) {
68
- const aliases = new Map<string, Set<string>>()
69
- for (const candidate of candidates) {
70
- const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options)
71
- if (!bareArbitrary) {
72
- continue
73
- }
74
- const canonicalSelector = escapeCssClassName(bareArbitrary.canonicalCandidate)
75
- const bareSelectors = aliases.get(canonicalSelector) ?? new Set<string>()
76
- bareSelectors.add(escapeCssClassName(bareArbitrary.candidate))
77
- aliases.set(canonicalSelector, bareSelectors)
78
- }
79
- return aliases
80
- }
81
-
82
- export function replaceBareArbitraryValueSelectors(
83
- css: string,
84
- candidates: Iterable<string>,
85
- options?: boolean | BareArbitraryValueOptions,
86
- ) {
87
- const aliases = createSelectorAliasMap(candidates, options)
88
- if (aliases.size === 0) {
89
- return css
90
- }
91
-
92
- if (Array.from(aliases.values()).every(bareSelectors => bareSelectors.size === 1)) {
93
- let result = css
94
- for (const [canonicalSelector, bareSelectors] of aliases) {
95
- const bareSelector = Array.from(bareSelectors)[0]
96
- if (bareSelector !== undefined) {
97
- result = result.replaceAll(canonicalSelector, bareSelector)
98
- }
99
- }
100
- return result
101
- }
102
-
103
- const root = postcss.parse(css)
104
- root.walkRules((rule) => {
105
- let selectors = rule.selectors
106
- for (const [canonicalSelector, bareSelectors] of aliases) {
107
- selectors = selectors.flatMap((selector) => {
108
- if (!selector.includes(canonicalSelector)) {
109
- return selector
110
- }
111
- return Array.from(bareSelectors, bareSelector => selector.replaceAll(canonicalSelector, bareSelector))
112
- })
113
- }
114
- rule.selectors = selectors
115
- })
116
- return root.toString()
117
- }
118
-
119
- export function canonicalizeBareArbitraryValueCandidates(
120
- candidates: Iterable<string>,
121
- options?: boolean | BareArbitraryValueOptions,
122
- ) {
123
- return Array.from(candidates, (candidate) => {
124
- const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options)
125
- return bareArbitrary?.canonicalCandidate ?? candidate
126
- })
127
- }
128
-
129
- function splitTopLevel(value: string, separator: string, options?: { keepEmpty?: boolean }) {
130
- const result: string[] = []
131
- let start = 0
132
- let depth = 0
133
- let quote: string | undefined
134
-
135
- for (let index = 0; index < value.length; index++) {
136
- const character = value[index]
137
- if (character === '\\') {
138
- index++
139
- continue
140
- }
141
-
142
- if (quote) {
143
- if (character === quote) {
144
- quote = undefined
145
- }
146
- continue
147
- }
148
-
149
- if (character === '"' || character === '\'') {
150
- quote = character
151
- continue
152
- }
153
-
154
- if (character === '(' || character === '[' || character === '{') {
155
- depth++
156
- continue
157
- }
158
-
159
- if (character === ')' || character === ']' || character === '}') {
160
- depth = Math.max(0, depth - 1)
161
- continue
162
- }
163
-
164
- if (depth === 0 && character === separator) {
165
- const item = value.slice(start, index).trim()
166
- if (item || options?.keepEmpty) {
167
- result.push(item)
168
- }
169
- start = index + 1
170
- }
171
- }
172
-
173
- const item = value.slice(start).trim()
174
- if (item || options?.keepEmpty) {
175
- result.push(item)
176
- }
177
- return result
178
- }
179
-
180
- const sequencePattern = /^(-?\d+)\.\.(-?\d+)(?:\.\.(-?\d+))?$/
181
-
182
- function expandSequence(value: string) {
183
- const match = value.match(sequencePattern)
184
- if (!match) {
185
- return [value]
186
- }
187
-
188
- const [, startValue, endValue, stepValue] = match
189
- if (startValue === undefined || endValue === undefined) {
190
- return [value]
191
- }
192
-
193
- const start = Number.parseInt(startValue, 10)
194
- const end = Number.parseInt(endValue, 10)
195
- let step = stepValue === undefined ? (start <= end ? 1 : -1) : Number.parseInt(stepValue, 10)
196
- if (step === 0) {
197
- throw new Error('Step cannot be zero in Tailwind CSS v4 inline source sequence.')
198
- }
199
-
200
- const ascending = start < end
201
- if (ascending && step < 0) {
202
- step = -step
203
- }
204
- if (!ascending && step > 0) {
205
- step = -step
206
- }
207
-
208
- const result: string[] = []
209
- for (let current = start; ascending ? current <= end : current >= end; current += step) {
210
- result.push(current.toString())
211
- }
212
- return result
213
- }
214
-
215
- function expandInlinePattern(pattern: string): string[] {
216
- const openIndex = pattern.indexOf('{')
217
- if (openIndex === -1) {
218
- return [pattern]
219
- }
220
-
221
- const prefix = pattern.slice(0, openIndex)
222
- const rest = pattern.slice(openIndex)
223
- let depth = 0
224
- let closeIndex = -1
225
- for (let index = 0; index < rest.length; index++) {
226
- const character = rest[index]
227
- if (character === '{') {
228
- depth++
229
- }
230
- else if (character === '}') {
231
- depth--
232
- if (depth === 0) {
233
- closeIndex = index
234
- break
235
- }
236
- }
237
- }
238
-
239
- if (closeIndex === -1) {
240
- throw new Error(`The Tailwind CSS v4 inline source pattern "${pattern}" is not balanced.`)
241
- }
242
-
243
- const body = rest.slice(1, closeIndex)
244
- const suffix = rest.slice(closeIndex + 1)
245
- const parts = sequencePattern.test(body)
246
- ? expandSequence(body)
247
- : splitTopLevel(body, ',', { keepEmpty: true }).flatMap(part => expandInlinePattern(part))
248
- const suffixes = expandInlinePattern(suffix)
249
-
250
- const result: string[] = []
251
- for (const part of parts) {
252
- for (const expandedSuffix of suffixes) {
253
- result.push(`${prefix}${part}${expandedSuffix}`)
254
- }
255
- }
256
- return result
257
- }
258
-
259
- function unquoteCssString(value: string) {
260
- const quote = value[0]
261
- if ((quote !== '"' && quote !== '\'') || value[value.length - 1] !== quote) {
262
- return undefined
263
- }
264
-
265
- let result = ''
266
- for (let index = 1; index < value.length - 1; index++) {
267
- const character = value[index]
268
- if (character === '\\') {
269
- index++
270
- result += value[index] ?? ''
271
- continue
272
- }
273
- result += character
274
- }
275
- return result
276
- }
277
-
278
- export function extractTailwindV4InlineSourceCandidates(css: string) {
279
- const included = new Set<string>()
280
- const excluded = new Set<string>()
281
-
282
- const root = postcss.parse(css)
283
- root.walkAtRules('source', (rule) => {
284
- let params = rule.params.trim()
285
- if (!params) {
286
- return
287
- }
288
-
289
- let negated = false
290
- if (params.startsWith('not ')) {
291
- negated = true
292
- params = params.slice(4).trim()
293
- }
294
-
295
- if (!params.startsWith('inline(') || !params.endsWith(')')) {
296
- return
297
- }
298
-
299
- const inlineValue = unquoteCssString(params.slice(7, -1).trim())
300
- if (inlineValue === undefined) {
301
- return
302
- }
303
-
304
- const target = negated ? excluded : included
305
- for (const part of splitTopLevel(inlineValue, ' ')) {
306
- for (const candidate of expandInlinePattern(part)) {
307
- target.add(candidate)
308
- }
309
- }
310
- })
311
-
312
- return {
313
- included,
314
- excluded,
315
- }
316
- }
package/src/v4/engine.ts DELETED
@@ -1,112 +0,0 @@
1
- import type {
2
- TailwindV4Engine,
3
- TailwindV4GenerateOptions,
4
- TailwindV4GenerateResult,
5
- TailwindV4ResolvedSource,
6
- TailwindV4SourcePattern,
7
- } from './types'
8
- import { extractRawCandidates, extractRawCandidatesWithPositions } from '../extraction/candidate-extractor'
9
- import {
10
- canonicalizeBareArbitraryValueCandidates,
11
- extractTailwindV4InlineSourceCandidates,
12
- replaceBareArbitraryValueSelectors,
13
- resolveValidTailwindV4Candidates,
14
- } from './candidates'
15
- import { compileTailwindV4Source, loadTailwindV4DesignSystem } from './node-adapter'
16
- import { createTailwindV4CompiledSourceEntries } from './source-scan'
17
-
18
- function resolveScanSources(
19
- options: TailwindV4GenerateOptions | undefined,
20
- source: TailwindV4ResolvedSource,
21
- compiledRoot: TailwindV4GenerateResult['root'],
22
- compiledSources: TailwindV4SourcePattern[],
23
- ) {
24
- if (Array.isArray(options?.scanSources)) {
25
- return options.scanSources
26
- }
27
- if (options?.scanSources === true) {
28
- return createTailwindV4CompiledSourceEntries(compiledRoot, compiledSources, source.base)
29
- }
30
- return []
31
- }
32
-
33
- async function collectRawCandidates(
34
- source: TailwindV4ResolvedSource,
35
- options: TailwindV4GenerateOptions | undefined,
36
- compiledRoot: TailwindV4GenerateResult['root'],
37
- compiledSources: TailwindV4SourcePattern[] = [],
38
- ) {
39
- const rawCandidates = new Set<string>()
40
- const extractOptions = options?.bareArbitraryValues === undefined
41
- ? undefined
42
- : { bareArbitraryValues: options.bareArbitraryValues }
43
-
44
- for (const candidate of options?.candidates ?? []) {
45
- rawCandidates.add(candidate)
46
- }
47
-
48
- for (const candidateSource of options?.sources ?? []) {
49
- const candidates = await extractRawCandidatesWithPositions(candidateSource.content, candidateSource.extension, extractOptions)
50
- for (const candidate of candidates) {
51
- rawCandidates.add(candidate.rawCandidate)
52
- }
53
- }
54
-
55
- const filesystemSources = resolveScanSources(options, source, compiledRoot, compiledSources)
56
- if (filesystemSources.length > 0) {
57
- for (const candidate of await extractRawCandidates(filesystemSources, extractOptions)) {
58
- rawCandidates.add(candidate)
59
- }
60
- }
61
-
62
- const inlineSources = extractTailwindV4InlineSourceCandidates(source.css)
63
- for (const candidate of inlineSources.included) {
64
- rawCandidates.add(candidate)
65
- }
66
- for (const candidate of inlineSources.excluded) {
67
- rawCandidates.delete(candidate)
68
- }
69
-
70
- return rawCandidates
71
- }
72
-
73
- export function createTailwindV4Engine(source: TailwindV4ResolvedSource): TailwindV4Engine {
74
- return {
75
- source,
76
- loadDesignSystem() {
77
- return loadTailwindV4DesignSystem(source)
78
- },
79
- async validateCandidates(candidates) {
80
- const designSystem = await loadTailwindV4DesignSystem(source)
81
- return resolveValidTailwindV4Candidates(designSystem, candidates)
82
- },
83
- async generate(options): Promise<TailwindV4GenerateResult> {
84
- const { compiled, dependencies } = await compileTailwindV4Source(source)
85
- const rawCandidates = await collectRawCandidates(source, options, compiled.root, compiled.sources)
86
- const designSystem = await loadTailwindV4DesignSystem(source)
87
- const classSet = resolveValidTailwindV4Candidates(designSystem, rawCandidates, {
88
- ...(options?.bareArbitraryValues === undefined ? {} : { bareArbitraryValues: options.bareArbitraryValues }),
89
- })
90
- const inlineSources = extractTailwindV4InlineSourceCandidates(source.css)
91
- for (const candidate of inlineSources.excluded) {
92
- classSet.delete(candidate)
93
- }
94
-
95
- const buildCandidates = canonicalizeBareArbitraryValueCandidates(classSet, options?.bareArbitraryValues)
96
- const css = replaceBareArbitraryValueSelectors(
97
- compiled.build(buildCandidates),
98
- classSet,
99
- options?.bareArbitraryValues,
100
- )
101
-
102
- return {
103
- css,
104
- classSet,
105
- rawCandidates,
106
- dependencies: Array.from(dependencies),
107
- sources: compiled.sources,
108
- root: compiled.root,
109
- }
110
- },
111
- }
112
- }
@@ -1,207 +0,0 @@
1
- import type {
2
- TailwindV4CompiledSourceRoot,
3
- TailwindV4DesignSystem,
4
- TailwindV4ResolvedSource,
5
- TailwindV4SourcePattern,
6
- } from './types'
7
- import { createRequire } from 'node:module'
8
- import { pathToFileURL } from 'node:url'
9
- import path from 'pathe'
10
-
11
- interface TailwindV4CompiledSource {
12
- sources: TailwindV4SourcePattern[]
13
- root: TailwindV4CompiledSourceRoot
14
- build: (candidates: string[]) => string
15
- }
16
-
17
- interface TailwindV4NodeModule {
18
- compile: (css: string, options: {
19
- base: string
20
- onDependency: (dependency: string) => void
21
- customCssResolver?: (id: string, base: string) => Promise<string | false | undefined>
22
- }) => Promise<TailwindV4CompiledSource>
23
- __unstable__loadDesignSystem: (css: string, options: { base: string }) => Promise<TailwindV4DesignSystem>
24
- }
25
-
26
- const nodeModulePromiseCache = new Map<string, Promise<TailwindV4NodeModule>>()
27
- const designSystemPromiseCache = new Map<string, Promise<TailwindV4DesignSystem>>()
28
-
29
- function unique(values: Iterable<string>) {
30
- return Array.from(new Set(Array.from(values).filter(Boolean).map(value => path.resolve(value))))
31
- }
32
-
33
- function createRequireBase(base: string) {
34
- return path.join(base, 'package.json')
35
- }
36
-
37
- function isRelativeSpecifier(id: string) {
38
- return id.startsWith('./') || id.startsWith('../') || id === '.' || id === '..'
39
- }
40
-
41
- function isAbsoluteSpecifier(id: string) {
42
- return path.isAbsolute(id)
43
- }
44
-
45
- function isCssSpecifier(id: string) {
46
- return path.extname(id) === '.css'
47
- }
48
-
49
- function createCssResolutionCandidates(id: string) {
50
- if (isCssSpecifier(id)) {
51
- return [id]
52
- }
53
- return [`${id}/index.css`, id]
54
- }
55
-
56
- function createFallbackCssResolver(baseCandidates: string[]) {
57
- const bases = unique(baseCandidates)
58
- return async (id: string) => {
59
- if (isRelativeSpecifier(id) || isAbsoluteSpecifier(id)) {
60
- return undefined
61
- }
62
-
63
- for (const base of bases) {
64
- const requireFromBase = createRequire(createRequireBase(base))
65
- for (const candidate of createCssResolutionCandidates(id)) {
66
- try {
67
- return requireFromBase.resolve(candidate)
68
- }
69
- catch {}
70
- }
71
- }
72
- return undefined
73
- }
74
- }
75
-
76
- async function importResolvedModule(resolved: string): Promise<TailwindV4NodeModule> {
77
- return import(pathToFileURL(resolved).href) as unknown as Promise<TailwindV4NodeModule>
78
- }
79
-
80
- async function importTailwindNodeFromBase(base: string): Promise<TailwindV4NodeModule | undefined> {
81
- try {
82
- const resolved = createRequire(createRequireBase(base)).resolve('@tailwindcss/node')
83
- return await importResolvedModule(resolved)
84
- }
85
- catch {
86
- return undefined
87
- }
88
- }
89
-
90
- async function importFallbackTailwindNode(): Promise<TailwindV4NodeModule> {
91
- return import('@tailwindcss/node') as unknown as Promise<TailwindV4NodeModule>
92
- }
93
-
94
- export async function loadTailwindV4NodeModule(baseCandidates: string[]): Promise<TailwindV4NodeModule> {
95
- const bases = unique(baseCandidates)
96
- const cacheKey = JSON.stringify(bases)
97
- const cached = nodeModulePromiseCache.get(cacheKey)
98
- if (cached) {
99
- return cached
100
- }
101
-
102
- const promise = (async () => {
103
- for (const base of bases) {
104
- const loaded = await importTailwindNodeFromBase(base)
105
- if (loaded) {
106
- return loaded
107
- }
108
- }
109
-
110
- return importFallbackTailwindNode()
111
- })()
112
-
113
- nodeModulePromiseCache.set(cacheKey, promise)
114
- promise.catch(() => {
115
- if (nodeModulePromiseCache.get(cacheKey) === promise) {
116
- nodeModulePromiseCache.delete(cacheKey)
117
- }
118
- })
119
- return promise
120
- }
121
-
122
- function createDesignSystemCacheKey(css: string, bases: string[]) {
123
- return JSON.stringify({
124
- css,
125
- bases: unique(bases),
126
- })
127
- }
128
-
129
- export function getTailwindV4DesignSystemCacheKey(source: Pick<TailwindV4ResolvedSource, 'css' | 'base' | 'baseFallbacks'>) {
130
- return createDesignSystemCacheKey(source.css, [source.base, ...source.baseFallbacks])
131
- }
132
-
133
- export async function loadTailwindV4DesignSystem(source: TailwindV4ResolvedSource): Promise<TailwindV4DesignSystem> {
134
- const bases = unique([source.base, ...source.baseFallbacks])
135
- if (bases.length === 0) {
136
- throw new Error('No base directories provided for Tailwind CSS v4 design system.')
137
- }
138
-
139
- const cacheKey = createDesignSystemCacheKey(source.css, bases)
140
- const cached = designSystemPromiseCache.get(cacheKey)
141
- if (cached) {
142
- return cached
143
- }
144
-
145
- const promise = (async () => {
146
- const node = await loadTailwindV4NodeModule([source.projectRoot, ...bases])
147
- let lastError: unknown
148
-
149
- for (const base of bases) {
150
- try {
151
- return await node.__unstable__loadDesignSystem(source.css, { base })
152
- }
153
- catch (error) {
154
- lastError = error
155
- }
156
- }
157
-
158
- if (lastError instanceof Error) {
159
- throw lastError
160
- }
161
- throw new Error('Failed to load Tailwind CSS v4 design system.')
162
- })()
163
-
164
- designSystemPromiseCache.set(cacheKey, promise)
165
- promise.catch(() => {
166
- if (designSystemPromiseCache.get(cacheKey) === promise) {
167
- designSystemPromiseCache.delete(cacheKey)
168
- }
169
- })
170
- return promise
171
- }
172
-
173
- export async function compileTailwindV4Source(source: TailwindV4ResolvedSource) {
174
- const bases = unique([source.base, ...source.baseFallbacks])
175
- if (bases.length === 0) {
176
- throw new Error('No base directories provided for Tailwind CSS v4 compiler.')
177
- }
178
-
179
- const node = await loadTailwindV4NodeModule([source.projectRoot, ...bases])
180
- let lastError: unknown
181
-
182
- for (const base of bases) {
183
- const dependencies = new Set(source.dependencies)
184
- try {
185
- const compiled = await node.compile(source.css, {
186
- base,
187
- customCssResolver: createFallbackCssResolver([source.projectRoot, ...bases]),
188
- onDependency(dependency) {
189
- dependencies.add(path.resolve(dependency))
190
- },
191
- })
192
-
193
- return {
194
- compiled,
195
- dependencies,
196
- }
197
- }
198
- catch (error) {
199
- lastError = error
200
- }
201
- }
202
-
203
- if (lastError instanceof Error) {
204
- throw lastError
205
- }
206
- throw new Error('Failed to compile Tailwind CSS v4 source.')
207
- }