tailwindcss-patch 9.3.1 → 9.3.3
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.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 +1 -1
- package/dist/commands/cli-runtime.mjs +1 -1
- package/dist/{index.bundle-Y1jzXpYx.js → index.bundle-BdxyJef9.js} +25 -6
- package/dist/{index.bundle-BKRsKEHP.mjs → index.bundle-C39laqrA.mjs} +25 -6
- package/dist/index.d.mts +2 -67
- package/dist/index.d.ts +2 -67
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{validate-Bd1fbQsd.js → validate-DABvQ44V.js} +147 -31
- package/dist/{validate-Bqych-z9.d.ts → validate-DDJnolx2.d.mts} +79 -5
- package/dist/{validate-CVInpab6.mjs → validate-cMWKFUKS.mjs} +147 -31
- package/dist/{validate-C8-qsOWo.d.mts → validate-rPPCy1cl.d.ts} +80 -4
- package/package.json +1 -1
- package/src/index.bundle.ts +1 -0
- package/src/index.ts +1 -0
- package/src/options/normalize.ts +14 -0
- package/src/options/types.ts +4 -0
- package/src/runtime/class-collector.ts +33 -13
- package/src/v4/bare-arbitrary-values.ts +110 -16
- package/src/v4/candidates.ts +48 -20
- package/src/v4/index.ts +1 -0
- package/src/v4/source.ts +48 -6
- package/src/v4/types.ts +8 -0
|
@@ -39,7 +39,8 @@ const DEFAULT_BARE_ARBITRARY_VALUE_UNITS = [
|
|
|
39
39
|
]
|
|
40
40
|
|
|
41
41
|
const NUMBER_RE = /^-?(?:\d+|\d*\.\d+)$/
|
|
42
|
-
const FUNCTION_VALUE_RE = /^[a-
|
|
42
|
+
const FUNCTION_VALUE_RE = /^[a-z_-][\w-]*\(/i
|
|
43
|
+
const HEX_ESCAPE_RE = /^[\da-f]$/i
|
|
43
44
|
|
|
44
45
|
function splitVariantPrefix(candidate: string) {
|
|
45
46
|
let depth = 0
|
|
@@ -133,8 +134,55 @@ function isBalancedFunctionValue(value: string) {
|
|
|
133
134
|
return depth === 0 && quote === undefined
|
|
134
135
|
}
|
|
135
136
|
|
|
137
|
+
function isEscapedAt(value: string, index: number) {
|
|
138
|
+
let slashCount = 0
|
|
139
|
+
for (let slashIndex = index - 1; slashIndex >= 0 && value[slashIndex] === '\\'; slashIndex--) {
|
|
140
|
+
slashCount++
|
|
141
|
+
}
|
|
142
|
+
return slashCount % 2 === 1
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function isBalancedBareArbitraryBody(value: string) {
|
|
146
|
+
let depth = 0
|
|
147
|
+
let quote: string | undefined
|
|
148
|
+
|
|
149
|
+
for (let index = 0; index < value.length; index++) {
|
|
150
|
+
const character = value[index]
|
|
151
|
+
|
|
152
|
+
if (isEscapedAt(value, index)) {
|
|
153
|
+
continue
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (quote) {
|
|
157
|
+
if (character === quote) {
|
|
158
|
+
quote = undefined
|
|
159
|
+
}
|
|
160
|
+
continue
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (character === '"' || character === '\'') {
|
|
164
|
+
quote = character
|
|
165
|
+
continue
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (character === '(' || character === '{') {
|
|
169
|
+
depth++
|
|
170
|
+
continue
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (character === ')' || character === '}') {
|
|
174
|
+
depth--
|
|
175
|
+
if (depth < 0) {
|
|
176
|
+
return false
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return depth === 0 && quote === undefined
|
|
182
|
+
}
|
|
183
|
+
|
|
136
184
|
function isHexColorValue(value: string) {
|
|
137
|
-
return /^#(?:[0-9a-
|
|
185
|
+
return /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6,8})$/i.test(value)
|
|
138
186
|
}
|
|
139
187
|
|
|
140
188
|
function isQuotedValue(value: string) {
|
|
@@ -173,12 +221,55 @@ function normalizeBareArbitraryValueOptions(options: boolean | BareArbitraryValu
|
|
|
173
221
|
}
|
|
174
222
|
}
|
|
175
223
|
|
|
224
|
+
function normalizeEscapedValue(value: string) {
|
|
225
|
+
let result = ''
|
|
226
|
+
for (let index = 0; index < value.length; index++) {
|
|
227
|
+
const character = value[index]
|
|
228
|
+
if (character !== '\\') {
|
|
229
|
+
result += character
|
|
230
|
+
continue
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const nextCharacter = value[index + 1]
|
|
234
|
+
if (nextCharacter === undefined) {
|
|
235
|
+
result += character
|
|
236
|
+
continue
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (HEX_ESCAPE_RE.test(nextCharacter)) {
|
|
240
|
+
let hex = ''
|
|
241
|
+
let nextIndex = index + 1
|
|
242
|
+
while (nextIndex < value.length && hex.length < 6) {
|
|
243
|
+
const hexCharacter = value[nextIndex]
|
|
244
|
+
if (hexCharacter === undefined || !HEX_ESCAPE_RE.test(hexCharacter)) {
|
|
245
|
+
break
|
|
246
|
+
}
|
|
247
|
+
hex += hexCharacter
|
|
248
|
+
nextIndex++
|
|
249
|
+
}
|
|
250
|
+
if (/[\t\n\f\r ]/.test(value[nextIndex] ?? '')) {
|
|
251
|
+
nextIndex++
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const decoded = String.fromCodePoint(Number.parseInt(hex, 16))
|
|
255
|
+
result += decoded === '_' ? '\\_' : decoded
|
|
256
|
+
index = nextIndex - 1
|
|
257
|
+
continue
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
result += nextCharacter === '_' ? '\\_' : nextCharacter
|
|
261
|
+
index++
|
|
262
|
+
}
|
|
263
|
+
return result
|
|
264
|
+
}
|
|
265
|
+
|
|
176
266
|
function resolveValueWithUnit(body: string, units: string[]) {
|
|
267
|
+
const value = normalizeEscapedValue(body)
|
|
177
268
|
for (const unit of units) {
|
|
178
|
-
if (!
|
|
269
|
+
if (!value.endsWith(unit)) {
|
|
179
270
|
continue
|
|
180
271
|
}
|
|
181
|
-
const numberPart =
|
|
272
|
+
const numberPart = value.slice(0, -unit.length)
|
|
182
273
|
if (NUMBER_RE.test(numberPart)) {
|
|
183
274
|
return `${numberPart}${unit}`
|
|
184
275
|
}
|
|
@@ -186,21 +277,22 @@ function resolveValueWithUnit(body: string, units: string[]) {
|
|
|
186
277
|
}
|
|
187
278
|
|
|
188
279
|
function resolveArbitraryValue(body: string, units: string[]) {
|
|
189
|
-
const
|
|
280
|
+
const value = normalizeEscapedValue(body)
|
|
281
|
+
const withUnit = resolveValueWithUnit(value, units)
|
|
190
282
|
if (withUnit) {
|
|
191
283
|
return withUnit
|
|
192
284
|
}
|
|
193
285
|
|
|
194
|
-
if (isHexColorValue(
|
|
195
|
-
return
|
|
286
|
+
if (isHexColorValue(value)) {
|
|
287
|
+
return value
|
|
196
288
|
}
|
|
197
289
|
|
|
198
|
-
if (isQuotedValue(
|
|
199
|
-
return
|
|
290
|
+
if (isQuotedValue(value)) {
|
|
291
|
+
return value
|
|
200
292
|
}
|
|
201
293
|
|
|
202
|
-
if (FUNCTION_VALUE_RE.test(
|
|
203
|
-
return
|
|
294
|
+
if (FUNCTION_VALUE_RE.test(value) && value.endsWith(')') && isBalancedFunctionValue(value)) {
|
|
295
|
+
return value
|
|
204
296
|
}
|
|
205
297
|
}
|
|
206
298
|
|
|
@@ -208,11 +300,10 @@ function resolveUtilityAndValue(body: string, units: string[]) {
|
|
|
208
300
|
let depth = 0
|
|
209
301
|
let quote: string | undefined
|
|
210
302
|
|
|
211
|
-
for (let index = 1; index
|
|
303
|
+
for (let index = body.length - 1; index > 0; index--) {
|
|
212
304
|
const character = body[index]
|
|
213
305
|
|
|
214
|
-
if (
|
|
215
|
-
index++
|
|
306
|
+
if (isEscapedAt(body, index)) {
|
|
216
307
|
continue
|
|
217
308
|
}
|
|
218
309
|
|
|
@@ -228,12 +319,12 @@ function resolveUtilityAndValue(body: string, units: string[]) {
|
|
|
228
319
|
continue
|
|
229
320
|
}
|
|
230
321
|
|
|
231
|
-
if (character === '
|
|
322
|
+
if (character === ')' || character === '}') {
|
|
232
323
|
depth++
|
|
233
324
|
continue
|
|
234
325
|
}
|
|
235
326
|
|
|
236
|
-
if (character === '
|
|
327
|
+
if (character === '(' || character === '{') {
|
|
237
328
|
depth = Math.max(0, depth - 1)
|
|
238
329
|
continue
|
|
239
330
|
}
|
|
@@ -274,6 +365,9 @@ export function resolveBareArbitraryValueCandidate(
|
|
|
274
365
|
if (negative) {
|
|
275
366
|
normalizedBody = normalizedBody.slice(1)
|
|
276
367
|
}
|
|
368
|
+
if (!isBalancedBareArbitraryBody(normalizedBody)) {
|
|
369
|
+
return
|
|
370
|
+
}
|
|
277
371
|
|
|
278
372
|
const resolved = resolveUtilityAndValue(normalizedBody, normalizedOptions.units)
|
|
279
373
|
if (!resolved) {
|
package/src/v4/candidates.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
+
import type { BareArbitraryValueOptions } from './bare-arbitrary-values'
|
|
1
2
|
import type { TailwindV4DesignSystem } from './types'
|
|
2
3
|
import postcss from 'postcss'
|
|
3
|
-
import {
|
|
4
|
-
escapeCssClassName,
|
|
5
|
-
type BareArbitraryValueOptions,
|
|
6
|
-
resolveBareArbitraryValueCandidate,
|
|
7
|
-
} from './bare-arbitrary-values'
|
|
4
|
+
import { escapeCssClassName, resolveBareArbitraryValueCandidate } from './bare-arbitrary-values'
|
|
8
5
|
|
|
9
6
|
export function resolveValidTailwindV4Candidates(
|
|
10
7
|
designSystem: TailwindV4DesignSystem,
|
|
@@ -15,7 +12,7 @@ export function resolveValidTailwindV4Candidates(
|
|
|
15
12
|
): Set<string> {
|
|
16
13
|
const validCandidates = new Set<string>()
|
|
17
14
|
const parsedCandidates: string[] = []
|
|
18
|
-
const
|
|
15
|
+
const originalCandidatesByCanonical = new Map<string, Set<string>>()
|
|
19
16
|
|
|
20
17
|
for (const candidate of candidates) {
|
|
21
18
|
if (!candidate) {
|
|
@@ -25,15 +22,19 @@ export function resolveValidTailwindV4Candidates(
|
|
|
25
22
|
const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options?.bareArbitraryValues)
|
|
26
23
|
const candidateToCheck = bareArbitrary?.canonicalCandidate ?? candidate
|
|
27
24
|
|
|
28
|
-
if (
|
|
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) {
|
|
29
33
|
continue
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
if (designSystem.parseCandidate(candidateToCheck).length > 0) {
|
|
33
37
|
parsedCandidates.push(candidateToCheck)
|
|
34
|
-
if (bareArbitrary) {
|
|
35
|
-
originalCandidateByCanonical.set(candidateToCheck, candidate)
|
|
36
|
-
}
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -46,7 +47,14 @@ export function resolveValidTailwindV4Candidates(
|
|
|
46
47
|
const candidate = parsedCandidates[index]
|
|
47
48
|
const candidateCss = cssByCandidate[index]
|
|
48
49
|
if (candidate && typeof candidateCss === 'string' && candidateCss.trim().length > 0) {
|
|
49
|
-
|
|
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)
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
60
|
|
|
@@ -57,16 +65,16 @@ function createSelectorAliasMap(
|
|
|
57
65
|
candidates: Iterable<string>,
|
|
58
66
|
options?: boolean | BareArbitraryValueOptions,
|
|
59
67
|
) {
|
|
60
|
-
const aliases = new Map<string, string
|
|
68
|
+
const aliases = new Map<string, Set<string>>()
|
|
61
69
|
for (const candidate of candidates) {
|
|
62
70
|
const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options)
|
|
63
71
|
if (!bareArbitrary) {
|
|
64
72
|
continue
|
|
65
73
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
)
|
|
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)
|
|
70
78
|
}
|
|
71
79
|
return aliases
|
|
72
80
|
}
|
|
@@ -81,11 +89,31 @@ export function replaceBareArbitraryValueSelectors(
|
|
|
81
89
|
return css
|
|
82
90
|
}
|
|
83
91
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
87
101
|
}
|
|
88
|
-
|
|
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()
|
|
89
117
|
}
|
|
90
118
|
|
|
91
119
|
export function canonicalizeBareArbitraryValueCandidates(
|
package/src/v4/index.ts
CHANGED
package/src/v4/source.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { NormalizedTailwindCssPatchOptions, TailwindCssPatchOptions } from '../config'
|
|
2
|
-
import type { TailwindV4ResolvedSource, TailwindV4SourceOptions } from './types'
|
|
2
|
+
import type { TailwindV4CssSource, TailwindV4ResolvedSource, TailwindV4SourceOptions } from './types'
|
|
3
3
|
import { promises as fs } from 'node:fs'
|
|
4
4
|
import process from 'node:process'
|
|
5
5
|
import path from 'pathe'
|
|
@@ -87,6 +87,35 @@ async function resolveCssEntries(entries: string[], projectRoot: string, base: s
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
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
|
+
|
|
90
119
|
function normalizeResolvedSource(
|
|
91
120
|
source: {
|
|
92
121
|
projectRoot: string
|
|
@@ -129,15 +158,27 @@ export async function resolveTailwindV4Source(options: TailwindV4SourceOptions =
|
|
|
129
158
|
})
|
|
130
159
|
}
|
|
131
160
|
|
|
132
|
-
if (options.cssEntries?.length) {
|
|
133
|
-
const entries =
|
|
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')
|
|
134
172
|
return normalizeResolvedSource({
|
|
135
173
|
projectRoot,
|
|
136
174
|
cwd,
|
|
137
|
-
base: entries
|
|
175
|
+
base: configuredBase ?? entries?.base ?? sources?.base ?? cwd,
|
|
138
176
|
baseFallbacks,
|
|
139
|
-
css
|
|
140
|
-
dependencies:
|
|
177
|
+
css,
|
|
178
|
+
dependencies: [
|
|
179
|
+
...(entries?.dependencies ?? []),
|
|
180
|
+
...(sources?.dependencies ?? []),
|
|
181
|
+
],
|
|
141
182
|
})
|
|
142
183
|
}
|
|
143
184
|
|
|
@@ -177,6 +218,7 @@ function createSourceOptionsFromNormalizedPatchOptions(
|
|
|
177
218
|
...(v4?.configuredBase === undefined ? {} : { base: v4.configuredBase }),
|
|
178
219
|
baseFallbacks,
|
|
179
220
|
...(v4?.css === undefined ? {} : { css: v4.css }),
|
|
221
|
+
...(v4?.cssSources === undefined ? {} : { cssSources: v4.cssSources }),
|
|
180
222
|
...(v4?.cssEntries === undefined ? {} : { cssEntries: v4.cssEntries }),
|
|
181
223
|
packageName: options.tailwind.packageName,
|
|
182
224
|
}
|
package/src/v4/types.ts
CHANGED
|
@@ -4,10 +4,18 @@ export interface TailwindV4SourceOptions {
|
|
|
4
4
|
base?: string
|
|
5
5
|
baseFallbacks?: string[]
|
|
6
6
|
css?: string
|
|
7
|
+
cssSources?: TailwindV4CssSource[]
|
|
7
8
|
cssEntries?: string[]
|
|
8
9
|
packageName?: string
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
export interface TailwindV4CssSource {
|
|
13
|
+
css: string
|
|
14
|
+
base?: string
|
|
15
|
+
file?: string
|
|
16
|
+
dependencies?: string[]
|
|
17
|
+
}
|
|
18
|
+
|
|
11
19
|
export interface TailwindV4ResolvedSource {
|
|
12
20
|
projectRoot: string
|
|
13
21
|
base: string
|