tailwindcss-patch 9.4.3 → 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.
- package/dist/{cli-BztQHMRp.js → cli-CGyUnvFc.js} +3 -2
- package/dist/{cli-D0jXMGXf.mjs → cli-DRfALTSo.mjs} +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/commands/cli-runtime.d.mts +1 -1
- package/dist/commands/cli-runtime.d.ts +1 -1
- package/dist/commands/cli-runtime.js +2 -2
- package/dist/commands/cli-runtime.mjs +2 -2
- package/dist/{dist-DDcbvOwe.js → dist-DlC5vuI2.js} +1 -1
- package/dist/index.d.mts +7 -149
- package/dist/index.d.ts +8 -150
- package/dist/index.js +294 -521
- package/dist/index.mjs +6 -471
- package/dist/{validate-BuqRodYI.d.ts → validate-B5-08lrU.d.ts} +7 -251
- package/dist/{validate-oAkURzUC.d.mts → validate-CgrG4aAY.d.mts} +7 -251
- package/dist/{validate-Bug_WYcU.mjs → validate-Q00Ccqht.mjs} +8 -1405
- package/dist/{validate-DbuKewV-.js → validate-XiYmTZcd.js} +82 -1708
- package/package.json +8 -10
- package/src/api/tailwindcss-patcher.ts +8 -5
- package/src/extraction/candidate-extractor.ts +17 -701
- package/src/extraction/split-candidate-tokens.ts +5 -101
- package/src/options/types.ts +1 -2
- package/src/style-candidates.ts +5 -35
- package/src/style-generator.ts +11 -80
- package/src/types.ts +21 -95
- package/src/v3/index.ts +2 -2
- package/src/v4/index.ts +104 -28
- package/src/v3/style-generator.ts +0 -384
- package/src/v4/bare-arbitrary-values.ts +0 -545
- package/src/v4/candidates.ts +0 -316
- package/src/v4/engine.ts +0 -112
- package/src/v4/node-adapter.ts +0 -207
- package/src/v4/source-scan.ts +0 -432
- package/src/v4/source.ts +0 -235
- package/src/v4/style-generator.ts +0 -44
- package/src/v4/types.ts +0 -103
package/src/v4/source-scan.ts
DELETED
|
@@ -1,432 +0,0 @@
|
|
|
1
|
-
import type { SourceEntry } from '@tailwindcss/oxide'
|
|
2
|
-
import type { TailwindV4CompiledSourceRoot, TailwindV4SourcePattern } from './types'
|
|
3
|
-
import { realpathSync } from 'node:fs'
|
|
4
|
-
import { stat } from 'node:fs/promises'
|
|
5
|
-
import process from 'node:process'
|
|
6
|
-
import micromatch from 'micromatch'
|
|
7
|
-
import path from 'pathe'
|
|
8
|
-
|
|
9
|
-
export const TAILWIND_V4_IGNORED_CONTENT_DIRS = [
|
|
10
|
-
'.git',
|
|
11
|
-
'.hg',
|
|
12
|
-
'.jj',
|
|
13
|
-
'.next',
|
|
14
|
-
'.parcel-cache',
|
|
15
|
-
'.pnpm-store',
|
|
16
|
-
'.svelte-kit',
|
|
17
|
-
'.svn',
|
|
18
|
-
'.turbo',
|
|
19
|
-
'.venv',
|
|
20
|
-
'.vercel',
|
|
21
|
-
'.yarn',
|
|
22
|
-
'__pycache__',
|
|
23
|
-
'node_modules',
|
|
24
|
-
'venv',
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
export const TAILWIND_V4_IGNORED_EXTENSIONS = [
|
|
28
|
-
'less',
|
|
29
|
-
'lock',
|
|
30
|
-
'sass',
|
|
31
|
-
'scss',
|
|
32
|
-
'styl',
|
|
33
|
-
'log',
|
|
34
|
-
]
|
|
35
|
-
|
|
36
|
-
export const TAILWIND_V4_IGNORED_FILES = [
|
|
37
|
-
'package-lock.json',
|
|
38
|
-
'pnpm-lock.yaml',
|
|
39
|
-
'bun.lockb',
|
|
40
|
-
'.gitignore',
|
|
41
|
-
'.env',
|
|
42
|
-
'.env.*',
|
|
43
|
-
]
|
|
44
|
-
|
|
45
|
-
export const TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN = '**/*'
|
|
46
|
-
|
|
47
|
-
function uniqueResolvedPaths(values: Iterable<string | undefined>) {
|
|
48
|
-
const result: string[] = []
|
|
49
|
-
for (const value of values) {
|
|
50
|
-
if (!value) {
|
|
51
|
-
continue
|
|
52
|
-
}
|
|
53
|
-
const resolved = path.resolve(value)
|
|
54
|
-
if (!result.includes(resolved)) {
|
|
55
|
-
result.push(resolved)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return result
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function toPosixPath(value: string) {
|
|
62
|
-
return value.replaceAll(path.sep, '/')
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function resolveSourceScanPath(value: string) {
|
|
66
|
-
const resolved = path.resolve(value)
|
|
67
|
-
try {
|
|
68
|
-
return realpathSync.native(resolved)
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
return resolved
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function normalizeGlobPattern(pattern: string) {
|
|
76
|
-
return pattern.startsWith('./') ? pattern.slice(2) : pattern
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function hasGlobMagic(value: string) {
|
|
80
|
-
return /[*?[\]{}()!+@]/.test(value)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function splitStaticGlobPrefix(pattern: string) {
|
|
84
|
-
const normalized = normalizeGlobPattern(pattern)
|
|
85
|
-
const segments = normalized.split(/[\\/]+/)
|
|
86
|
-
const prefix: string[] = []
|
|
87
|
-
const rest: string[] = []
|
|
88
|
-
let reachedGlob = false
|
|
89
|
-
|
|
90
|
-
for (const segment of segments) {
|
|
91
|
-
if (!reachedGlob && segment && !hasGlobMagic(segment)) {
|
|
92
|
-
prefix.push(segment)
|
|
93
|
-
continue
|
|
94
|
-
}
|
|
95
|
-
reachedGlob = true
|
|
96
|
-
rest.push(segment)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return {
|
|
100
|
-
prefix,
|
|
101
|
-
rest,
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async function pathExistsAsDirectory(file: string) {
|
|
106
|
-
try {
|
|
107
|
-
return (await stat(file)).isDirectory()
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
return false
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function createTailwindV4DefaultIgnoreSources(base: string): TailwindV4SourcePattern[] {
|
|
115
|
-
return [
|
|
116
|
-
...TAILWIND_V4_IGNORED_CONTENT_DIRS.map(pattern => ({
|
|
117
|
-
base,
|
|
118
|
-
pattern: `**/${pattern}/**`,
|
|
119
|
-
negated: true,
|
|
120
|
-
})),
|
|
121
|
-
...TAILWIND_V4_IGNORED_EXTENSIONS.map(extension => ({
|
|
122
|
-
base,
|
|
123
|
-
pattern: `**/*.${extension}`,
|
|
124
|
-
negated: true,
|
|
125
|
-
})),
|
|
126
|
-
...TAILWIND_V4_IGNORED_FILES.map(pattern => ({
|
|
127
|
-
base,
|
|
128
|
-
pattern: `**/${pattern}`,
|
|
129
|
-
negated: true,
|
|
130
|
-
})),
|
|
131
|
-
]
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function createTailwindV4RootSources(
|
|
135
|
-
root: TailwindV4CompiledSourceRoot,
|
|
136
|
-
fallbackBase: string,
|
|
137
|
-
): TailwindV4SourcePattern[] {
|
|
138
|
-
if (root === 'none') {
|
|
139
|
-
return []
|
|
140
|
-
}
|
|
141
|
-
if (root === null) {
|
|
142
|
-
return [{ base: fallbackBase, pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN, negated: false }]
|
|
143
|
-
}
|
|
144
|
-
return [{ ...root, negated: false }]
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function createTailwindV4CompiledSourceEntries(
|
|
148
|
-
root: TailwindV4CompiledSourceRoot,
|
|
149
|
-
sources: TailwindV4SourcePattern[],
|
|
150
|
-
fallbackBase: string,
|
|
151
|
-
) {
|
|
152
|
-
return [
|
|
153
|
-
...createTailwindV4RootSources(root, fallbackBase),
|
|
154
|
-
...sources,
|
|
155
|
-
]
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export async function resolveTailwindV4SourceEntry(
|
|
159
|
-
sourcePath: string,
|
|
160
|
-
base: string,
|
|
161
|
-
negated: boolean,
|
|
162
|
-
defaultPattern = TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN,
|
|
163
|
-
): Promise<TailwindV4SourcePattern> {
|
|
164
|
-
const absoluteSource = path.isAbsolute(sourcePath) ? path.resolve(sourcePath) : path.resolve(base, sourcePath)
|
|
165
|
-
|
|
166
|
-
if (await pathExistsAsDirectory(absoluteSource)) {
|
|
167
|
-
return {
|
|
168
|
-
base: absoluteSource,
|
|
169
|
-
negated,
|
|
170
|
-
pattern: normalizeGlobPattern(defaultPattern),
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (path.isAbsolute(sourcePath)) {
|
|
175
|
-
return {
|
|
176
|
-
base: path.dirname(absoluteSource),
|
|
177
|
-
negated,
|
|
178
|
-
pattern: normalizeGlobPattern(path.basename(absoluteSource)),
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const { prefix, rest } = splitStaticGlobPrefix(sourcePath)
|
|
183
|
-
if (prefix.length > 0 && rest.length > 0) {
|
|
184
|
-
return {
|
|
185
|
-
base: path.resolve(base, ...prefix),
|
|
186
|
-
negated,
|
|
187
|
-
pattern: normalizeGlobPattern(rest.join('/')),
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return {
|
|
192
|
-
base,
|
|
193
|
-
negated,
|
|
194
|
-
pattern: normalizeGlobPattern(sourcePath),
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export async function normalizeTailwindV4SourceEntries(
|
|
199
|
-
sources: TailwindV4SourcePattern[],
|
|
200
|
-
options: {
|
|
201
|
-
cwd?: string
|
|
202
|
-
defaultPattern?: string
|
|
203
|
-
} = {},
|
|
204
|
-
) {
|
|
205
|
-
const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd()
|
|
206
|
-
return Promise.all(sources.map(source =>
|
|
207
|
-
resolveTailwindV4SourceEntry(
|
|
208
|
-
source.pattern,
|
|
209
|
-
source.base ? path.resolve(source.base) : cwd,
|
|
210
|
-
source.negated,
|
|
211
|
-
options.defaultPattern,
|
|
212
|
-
)))
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function expandBracePattern(pattern: string): string[] {
|
|
216
|
-
const index = pattern.indexOf('{')
|
|
217
|
-
if (index === -1) {
|
|
218
|
-
return [pattern]
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const rest = pattern.slice(index)
|
|
222
|
-
let depth = 0
|
|
223
|
-
let endIndex = -1
|
|
224
|
-
for (let i = 0; i < rest.length; i++) {
|
|
225
|
-
const char = rest[i]
|
|
226
|
-
if (char === '\\') {
|
|
227
|
-
i += 1
|
|
228
|
-
continue
|
|
229
|
-
}
|
|
230
|
-
if (char === '{') {
|
|
231
|
-
depth += 1
|
|
232
|
-
continue
|
|
233
|
-
}
|
|
234
|
-
if (char === '}') {
|
|
235
|
-
depth -= 1
|
|
236
|
-
if (depth === 0) {
|
|
237
|
-
endIndex = i
|
|
238
|
-
break
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
if (endIndex === -1) {
|
|
243
|
-
return [pattern]
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const prefix = pattern.slice(0, index)
|
|
247
|
-
const inner = rest.slice(1, endIndex)
|
|
248
|
-
const suffix = rest.slice(endIndex + 1)
|
|
249
|
-
const parts: string[] = []
|
|
250
|
-
const stack: string[] = []
|
|
251
|
-
let lastPos = 0
|
|
252
|
-
for (let i = 0; i < inner.length; i++) {
|
|
253
|
-
const char = inner[i]
|
|
254
|
-
if (char === '\\') {
|
|
255
|
-
i += 1
|
|
256
|
-
continue
|
|
257
|
-
}
|
|
258
|
-
if (char === '{') {
|
|
259
|
-
stack.push('}')
|
|
260
|
-
continue
|
|
261
|
-
}
|
|
262
|
-
if (char === '}' && stack[stack.length - 1] === '}') {
|
|
263
|
-
stack.pop()
|
|
264
|
-
continue
|
|
265
|
-
}
|
|
266
|
-
if (char === ',' && stack.length === 0) {
|
|
267
|
-
parts.push(inner.slice(lastPos, i))
|
|
268
|
-
lastPos = i + 1
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
parts.push(inner.slice(lastPos))
|
|
272
|
-
|
|
273
|
-
return parts.flatMap(part =>
|
|
274
|
-
expandBracePattern(`${prefix}${part}${suffix}`))
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
export function expandTailwindV4SourceEntryBraces(sources: TailwindV4SourcePattern[]): TailwindV4SourcePattern[] {
|
|
278
|
-
return sources.flatMap((source) => {
|
|
279
|
-
const base = path.resolve(source.base)
|
|
280
|
-
return expandBracePattern(source.pattern).map(pattern => ({
|
|
281
|
-
base,
|
|
282
|
-
pattern,
|
|
283
|
-
negated: source.negated,
|
|
284
|
-
}))
|
|
285
|
-
})
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
export function normalizeTailwindV4ScannerSources(
|
|
289
|
-
sources: TailwindV4SourcePattern[] | undefined,
|
|
290
|
-
cwd: string,
|
|
291
|
-
ignoredSources: TailwindV4SourcePattern[] = [],
|
|
292
|
-
): SourceEntry[] {
|
|
293
|
-
const baseSources = sources?.length
|
|
294
|
-
? sources
|
|
295
|
-
: [
|
|
296
|
-
{
|
|
297
|
-
base: cwd,
|
|
298
|
-
pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN,
|
|
299
|
-
negated: false,
|
|
300
|
-
},
|
|
301
|
-
]
|
|
302
|
-
|
|
303
|
-
return expandTailwindV4SourceEntryBraces([...baseSources, ...ignoredSources])
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function normalizeEntryPattern(entry: TailwindV4SourcePattern) {
|
|
307
|
-
return path.isAbsolute(entry.pattern)
|
|
308
|
-
? toPosixPath(path.relative(resolveSourceScanPath(entry.base), entry.pattern))
|
|
309
|
-
: normalizeGlobPattern(entry.pattern)
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function isFileMatchedByTailwindV4SourceEntry(file: string, entry: TailwindV4SourcePattern) {
|
|
313
|
-
const relative = toPosixPath(path.relative(resolveSourceScanPath(entry.base), file))
|
|
314
|
-
return Boolean(relative)
|
|
315
|
-
&& !relative.startsWith('../')
|
|
316
|
-
&& !path.isAbsolute(relative)
|
|
317
|
-
&& micromatch.isMatch(relative, normalizeEntryPattern(entry))
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
export function isFileExcludedByTailwindV4SourceEntries(
|
|
321
|
-
file: string,
|
|
322
|
-
entries: TailwindV4SourcePattern[] | undefined,
|
|
323
|
-
) {
|
|
324
|
-
if (!entries?.length) {
|
|
325
|
-
return false
|
|
326
|
-
}
|
|
327
|
-
const resolvedFile = resolveSourceScanPath(file)
|
|
328
|
-
return entries.some(entry => entry.negated && isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry))
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
export function isFileMatchedByTailwindV4SourceEntries(
|
|
332
|
-
file: string,
|
|
333
|
-
entries: TailwindV4SourcePattern[] | undefined,
|
|
334
|
-
) {
|
|
335
|
-
if (!entries?.length) {
|
|
336
|
-
return true
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const positiveEntries = entries.filter(entry => !entry.negated)
|
|
340
|
-
const negativeEntries = entries.filter(entry => entry.negated)
|
|
341
|
-
if (positiveEntries.length === 0) {
|
|
342
|
-
return false
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
const resolvedFile = resolveSourceScanPath(file)
|
|
346
|
-
const matchesPositive = positiveEntries.some(entry => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry))
|
|
347
|
-
if (!matchesPositive) {
|
|
348
|
-
return false
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
return !negativeEntries.some(entry => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry))
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
export function createTailwindV4SourceEntryMatcher(entries: TailwindV4SourcePattern[] | undefined) {
|
|
355
|
-
if (!entries?.length) {
|
|
356
|
-
return undefined
|
|
357
|
-
}
|
|
358
|
-
return (file: string) => isFileMatchedByTailwindV4SourceEntries(file, entries)
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
export function createTailwindV4SourceExclusionMatcher(entries: TailwindV4SourcePattern[] | undefined) {
|
|
362
|
-
if (!entries?.length) {
|
|
363
|
-
return undefined
|
|
364
|
-
}
|
|
365
|
-
return (file: string) => isFileExcludedByTailwindV4SourceEntries(file, entries)
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
export function groupTailwindV4SourceEntriesByBase(entries: TailwindV4SourcePattern[]) {
|
|
369
|
-
const entriesByBase = new Map<string, TailwindV4SourcePattern[]>()
|
|
370
|
-
for (const entry of entries) {
|
|
371
|
-
const base = path.resolve(entry.base)
|
|
372
|
-
const group = entriesByBase.get(base) ?? []
|
|
373
|
-
group.push({
|
|
374
|
-
...entry,
|
|
375
|
-
base,
|
|
376
|
-
pattern: normalizeGlobPattern(entry.pattern),
|
|
377
|
-
})
|
|
378
|
-
entriesByBase.set(base, group)
|
|
379
|
-
}
|
|
380
|
-
return entriesByBase
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
export async function expandTailwindV4SourceEntries(
|
|
384
|
-
entries: TailwindV4SourcePattern[],
|
|
385
|
-
resolveFiles: (options: { cwd: string, sources: TailwindV4SourcePattern[] }) => Promise<string[]>,
|
|
386
|
-
) {
|
|
387
|
-
if (entries.length === 0) {
|
|
388
|
-
return []
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
const files = new Set<string>()
|
|
392
|
-
await Promise.all([...groupTailwindV4SourceEntriesByBase(entries).entries()].map(async ([base, group]) => {
|
|
393
|
-
const matched = await resolveFiles({
|
|
394
|
-
cwd: base,
|
|
395
|
-
sources: group,
|
|
396
|
-
})
|
|
397
|
-
for (const file of matched) {
|
|
398
|
-
files.add(path.resolve(file))
|
|
399
|
-
}
|
|
400
|
-
}))
|
|
401
|
-
|
|
402
|
-
return [...files].filter(file => !isFileExcludedByTailwindV4SourceEntries(file, entries))
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
export function mergeTailwindV4SourceEntries(...entries: Array<TailwindV4SourcePattern[] | undefined>) {
|
|
406
|
-
const result: TailwindV4SourcePattern[] = []
|
|
407
|
-
const seen = new Set<string>()
|
|
408
|
-
for (const group of entries) {
|
|
409
|
-
for (const entry of group ?? []) {
|
|
410
|
-
const normalized = {
|
|
411
|
-
base: path.resolve(entry.base),
|
|
412
|
-
pattern: normalizeGlobPattern(entry.pattern),
|
|
413
|
-
negated: entry.negated,
|
|
414
|
-
}
|
|
415
|
-
const key = JSON.stringify(normalized)
|
|
416
|
-
if (seen.has(key)) {
|
|
417
|
-
continue
|
|
418
|
-
}
|
|
419
|
-
seen.add(key)
|
|
420
|
-
result.push(normalized)
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
return result
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
export function resolveTailwindV4SourceBaseCandidates(
|
|
427
|
-
projectRoot: string,
|
|
428
|
-
base: string,
|
|
429
|
-
baseFallbacks: string[],
|
|
430
|
-
) {
|
|
431
|
-
return uniqueResolvedPaths([base, projectRoot, ...baseFallbacks])
|
|
432
|
-
}
|
package/src/v4/source.ts
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import type { NormalizedTailwindCssPatchOptions, TailwindCssPatchOptions } from '../config'
|
|
2
|
-
import type { TailwindV4CssSource, TailwindV4ResolvedSource, TailwindV4SourceOptions } from './types'
|
|
3
|
-
import { promises as fs } from 'node:fs'
|
|
4
|
-
import process from 'node:process'
|
|
5
|
-
import path from 'pathe'
|
|
6
|
-
import { normalizeOptions } from '../config'
|
|
7
|
-
|
|
8
|
-
function resolveBase(value: string | undefined, fallback: string) {
|
|
9
|
-
return value === undefined
|
|
10
|
-
? fallback
|
|
11
|
-
: path.isAbsolute(value)
|
|
12
|
-
? path.resolve(value)
|
|
13
|
-
: path.resolve(fallback, value)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function uniquePaths(values: Iterable<string | undefined>) {
|
|
17
|
-
const result: string[] = []
|
|
18
|
-
for (const value of values) {
|
|
19
|
-
if (!value) {
|
|
20
|
-
continue
|
|
21
|
-
}
|
|
22
|
-
const resolved = path.resolve(value)
|
|
23
|
-
if (!result.includes(resolved)) {
|
|
24
|
-
result.push(resolved)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return result
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function toCssImportPath(value: string) {
|
|
31
|
-
return value.replaceAll('\\', '/')
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function quoteCssImport(value: string) {
|
|
35
|
-
return value.replaceAll('\\', '\\\\').replaceAll('"', '\\"')
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function isPostcssPluginSpecifier(packageName: string) {
|
|
39
|
-
return packageName === '@tailwindcss/postcss'
|
|
40
|
-
|| /(?:^|[/\\])@tailwindcss[/\\]postcss(?:[/\\]|$)/.test(packageName)
|
|
41
|
-
|| /(?:^|[/\\])postcss(?:[/\\]|$)/i.test(packageName)
|
|
42
|
-
|| /postcss\.config\.[cm]?[jt]s$/i.test(packageName)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function createDefaultCss(packageName: string | undefined) {
|
|
46
|
-
const cssPackageName = packageName && !isPostcssPluginSpecifier(packageName)
|
|
47
|
-
? packageName
|
|
48
|
-
: 'tailwindcss'
|
|
49
|
-
return `@import "${quoteCssImport(toCssImportPath(cssPackageName))}";`
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async function pathExists(filePath: string) {
|
|
53
|
-
try {
|
|
54
|
-
await fs.access(filePath)
|
|
55
|
-
return true
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
return false
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async function resolveCssEntries(entries: string[], projectRoot: string, base: string | undefined) {
|
|
63
|
-
const resolvedEntries = entries.map(entry => ({
|
|
64
|
-
original: entry,
|
|
65
|
-
absolute: path.isAbsolute(entry) ? path.resolve(entry) : path.resolve(projectRoot, entry),
|
|
66
|
-
}))
|
|
67
|
-
const resolvedBase = base ?? path.dirname(resolvedEntries[0]?.absolute ?? projectRoot)
|
|
68
|
-
const dependencies = resolvedEntries.map(entry => entry.absolute)
|
|
69
|
-
const cssParts: string[] = []
|
|
70
|
-
|
|
71
|
-
for (const entry of resolvedEntries) {
|
|
72
|
-
if (await pathExists(entry.absolute)) {
|
|
73
|
-
cssParts.push(await fs.readFile(entry.absolute, 'utf8'))
|
|
74
|
-
continue
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const importPath = path.isAbsolute(entry.original)
|
|
78
|
-
? entry.absolute
|
|
79
|
-
: path.relative(resolvedBase, entry.absolute)
|
|
80
|
-
cssParts.push(`@import "${quoteCssImport(toCssImportPath(importPath))}";`)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return {
|
|
84
|
-
base: resolvedBase,
|
|
85
|
-
css: cssParts.join('\n'),
|
|
86
|
-
dependencies,
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function resolveCssSources(sources: TailwindV4CssSource[], projectRoot: string, base: string | undefined) {
|
|
91
|
-
const resolvedSources = sources.map(source => ({
|
|
92
|
-
...source,
|
|
93
|
-
base: source.base === undefined ? undefined : resolveBase(source.base, projectRoot),
|
|
94
|
-
file: source.file === undefined
|
|
95
|
-
? undefined
|
|
96
|
-
: path.isAbsolute(source.file)
|
|
97
|
-
? path.resolve(source.file)
|
|
98
|
-
: path.resolve(projectRoot, source.file),
|
|
99
|
-
dependencies: source.dependencies?.map(dependency =>
|
|
100
|
-
path.isAbsolute(dependency) ? path.resolve(dependency) : path.resolve(projectRoot, dependency),
|
|
101
|
-
) ?? [],
|
|
102
|
-
}))
|
|
103
|
-
const firstSource = resolvedSources[0]
|
|
104
|
-
const resolvedBase = base
|
|
105
|
-
?? firstSource?.base
|
|
106
|
-
?? (firstSource?.file ? path.dirname(firstSource.file) : projectRoot)
|
|
107
|
-
const dependencies = resolvedSources.flatMap(source => [
|
|
108
|
-
source.file,
|
|
109
|
-
...source.dependencies,
|
|
110
|
-
]).filter((dependency): dependency is string => Boolean(dependency))
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
base: resolvedBase,
|
|
114
|
-
css: resolvedSources.map(source => source.css).join('\n'),
|
|
115
|
-
dependencies,
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function normalizeResolvedSource(
|
|
120
|
-
source: {
|
|
121
|
-
projectRoot: string
|
|
122
|
-
cwd: string
|
|
123
|
-
base: string
|
|
124
|
-
baseFallbacks: string[]
|
|
125
|
-
css: string
|
|
126
|
-
dependencies: string[]
|
|
127
|
-
},
|
|
128
|
-
): TailwindV4ResolvedSource {
|
|
129
|
-
const baseFallbacks = uniquePaths([
|
|
130
|
-
...source.baseFallbacks,
|
|
131
|
-
source.projectRoot,
|
|
132
|
-
source.cwd,
|
|
133
|
-
]).filter(base => base !== source.base)
|
|
134
|
-
|
|
135
|
-
return {
|
|
136
|
-
projectRoot: source.projectRoot,
|
|
137
|
-
base: source.base,
|
|
138
|
-
baseFallbacks,
|
|
139
|
-
css: source.css,
|
|
140
|
-
dependencies: Array.from(new Set(source.dependencies.map(dependency => path.resolve(dependency)))),
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export async function resolveTailwindV4Source(options: TailwindV4SourceOptions = {}): Promise<TailwindV4ResolvedSource> {
|
|
145
|
-
const projectRoot = resolveBase(options.projectRoot, process.cwd())
|
|
146
|
-
const cwd = resolveBase(options.cwd, projectRoot)
|
|
147
|
-
const configuredBase = options.base === undefined ? undefined : resolveBase(options.base, projectRoot)
|
|
148
|
-
const baseFallbacks = uniquePaths(options.baseFallbacks?.map(base => resolveBase(base, projectRoot)) ?? [])
|
|
149
|
-
|
|
150
|
-
if (options.css !== undefined) {
|
|
151
|
-
return normalizeResolvedSource({
|
|
152
|
-
projectRoot,
|
|
153
|
-
cwd,
|
|
154
|
-
base: configuredBase ?? cwd,
|
|
155
|
-
baseFallbacks,
|
|
156
|
-
css: options.css,
|
|
157
|
-
dependencies: [],
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (options.cssEntries?.length || options.cssSources?.length) {
|
|
162
|
-
const entries = options.cssEntries?.length
|
|
163
|
-
? await resolveCssEntries(options.cssEntries, projectRoot, configuredBase)
|
|
164
|
-
: undefined
|
|
165
|
-
const sources = options.cssSources?.length
|
|
166
|
-
? resolveCssSources(options.cssSources, projectRoot, configuredBase)
|
|
167
|
-
: undefined
|
|
168
|
-
const css = [
|
|
169
|
-
entries?.css,
|
|
170
|
-
sources?.css,
|
|
171
|
-
].filter(Boolean).join('\n')
|
|
172
|
-
return normalizeResolvedSource({
|
|
173
|
-
projectRoot,
|
|
174
|
-
cwd,
|
|
175
|
-
base: configuredBase ?? entries?.base ?? sources?.base ?? cwd,
|
|
176
|
-
baseFallbacks,
|
|
177
|
-
css,
|
|
178
|
-
dependencies: [
|
|
179
|
-
...(entries?.dependencies ?? []),
|
|
180
|
-
...(sources?.dependencies ?? []),
|
|
181
|
-
],
|
|
182
|
-
})
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return normalizeResolvedSource({
|
|
186
|
-
projectRoot,
|
|
187
|
-
cwd,
|
|
188
|
-
base: configuredBase ?? cwd,
|
|
189
|
-
baseFallbacks,
|
|
190
|
-
css: createDefaultCss(options.packageName),
|
|
191
|
-
dependencies: [],
|
|
192
|
-
})
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function resolveConfigDir(config: string | undefined, projectRoot: string) {
|
|
196
|
-
if (!config) {
|
|
197
|
-
return undefined
|
|
198
|
-
}
|
|
199
|
-
const configPath = path.isAbsolute(config) ? config : path.resolve(projectRoot, config)
|
|
200
|
-
return path.dirname(configPath)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function createSourceOptionsFromNormalizedPatchOptions(
|
|
204
|
-
options: NormalizedTailwindCssPatchOptions,
|
|
205
|
-
): TailwindV4SourceOptions {
|
|
206
|
-
const v4 = options.tailwind.v4
|
|
207
|
-
const configDir = resolveConfigDir(options.tailwind.config, options.projectRoot)
|
|
208
|
-
const baseFallbacks = uniquePaths([
|
|
209
|
-
v4?.configuredBase,
|
|
210
|
-
options.tailwind.cwd,
|
|
211
|
-
options.projectRoot,
|
|
212
|
-
configDir,
|
|
213
|
-
])
|
|
214
|
-
|
|
215
|
-
return {
|
|
216
|
-
projectRoot: options.projectRoot,
|
|
217
|
-
...(options.tailwind.cwd === undefined ? {} : { cwd: options.tailwind.cwd }),
|
|
218
|
-
...(v4?.configuredBase === undefined ? {} : { base: v4.configuredBase }),
|
|
219
|
-
baseFallbacks,
|
|
220
|
-
...(v4?.css === undefined ? {} : { css: v4.css }),
|
|
221
|
-
...(v4?.cssSources === undefined ? {} : { cssSources: v4.cssSources }),
|
|
222
|
-
...(v4?.cssEntries === undefined ? {} : { cssEntries: v4.cssEntries }),
|
|
223
|
-
packageName: options.tailwind.packageName,
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export function tailwindV4SourceOptionsFromPatchOptions(options: TailwindCssPatchOptions): TailwindV4SourceOptions {
|
|
228
|
-
return createSourceOptionsFromNormalizedPatchOptions(normalizeOptions(options))
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
export async function resolveTailwindV4SourceFromPatchOptions(
|
|
232
|
-
options: TailwindCssPatchOptions,
|
|
233
|
-
): Promise<TailwindV4ResolvedSource> {
|
|
234
|
-
return resolveTailwindV4Source(tailwindV4SourceOptionsFromPatchOptions(options))
|
|
235
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
TailwindV4SourceOptions,
|
|
3
|
-
TailwindV4StyleGenerateOptions,
|
|
4
|
-
TailwindV4StyleGenerateResult,
|
|
5
|
-
} from './types'
|
|
6
|
-
import { collectTailwindStyleCandidates } from '../style-candidates'
|
|
7
|
-
import { createTailwindV4Engine } from './engine'
|
|
8
|
-
import { resolveTailwindV4Source } from './source'
|
|
9
|
-
|
|
10
|
-
function createSourceOptions(options: TailwindV4StyleGenerateOptions): TailwindV4SourceOptions {
|
|
11
|
-
return {
|
|
12
|
-
...(options.projectRoot === undefined ? {} : { projectRoot: options.projectRoot }),
|
|
13
|
-
...(options.cwd === undefined ? {} : { cwd: options.cwd }),
|
|
14
|
-
...(options.base === undefined ? {} : { base: options.base }),
|
|
15
|
-
...(options.baseFallbacks === undefined ? {} : { baseFallbacks: options.baseFallbacks }),
|
|
16
|
-
...(options.css === undefined ? {} : { css: options.css }),
|
|
17
|
-
...(options.cssSources === undefined ? {} : { cssSources: options.cssSources }),
|
|
18
|
-
...(options.cssEntries === undefined ? {} : { cssEntries: options.cssEntries }),
|
|
19
|
-
...(options.packageName === undefined ? {} : { packageName: options.packageName }),
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function collectTailwindV4StyleCandidates(
|
|
24
|
-
options: Pick<TailwindV4StyleGenerateOptions, 'bareArbitraryValues' | 'candidates' | 'sources'>,
|
|
25
|
-
): Promise<Set<string>> {
|
|
26
|
-
return collectTailwindStyleCandidates(options)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export async function generateTailwindV4Style(
|
|
30
|
-
options: TailwindV4StyleGenerateOptions = {},
|
|
31
|
-
): Promise<TailwindV4StyleGenerateResult> {
|
|
32
|
-
const source = options.source ?? await resolveTailwindV4Source(createSourceOptions(options))
|
|
33
|
-
const candidates = await collectTailwindV4StyleCandidates(options)
|
|
34
|
-
const result = await createTailwindV4Engine(source).generate({
|
|
35
|
-
candidates,
|
|
36
|
-
...(options.bareArbitraryValues === undefined ? {} : { bareArbitraryValues: options.bareArbitraryValues }),
|
|
37
|
-
...(options.scanSources === undefined ? {} : { scanSources: options.scanSources }),
|
|
38
|
-
})
|
|
39
|
-
return {
|
|
40
|
-
...result,
|
|
41
|
-
tokens: result.rawCandidates,
|
|
42
|
-
source,
|
|
43
|
-
}
|
|
44
|
-
}
|