tailwindcss 0.0.0-insiders.fda68f7 → 0.0.0-oxide.6bf5e56
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/CHANGELOG.md +603 -2
- package/LICENSE +1 -2
- package/README.md +14 -6
- package/colors.d.ts +3 -0
- package/colors.js +2 -304
- package/defaultConfig.d.ts +3 -0
- package/defaultConfig.js +2 -4
- package/defaultTheme.d.ts +4 -0
- package/defaultTheme.js +2 -4
- package/lib/cli/build/deps.js +54 -0
- package/lib/cli/build/index.js +48 -0
- package/lib/cli/build/plugin.js +367 -0
- package/lib/cli/build/utils.js +78 -0
- package/lib/cli/build/watching.js +178 -0
- package/lib/cli/help/index.js +71 -0
- package/lib/cli/index.js +18 -0
- package/lib/cli/init/index.js +46 -0
- package/lib/cli/shared.js +13 -0
- package/lib/cli-peer-dependencies.js +22 -14
- package/lib/cli.js +217 -743
- package/lib/constants.js +41 -34
- package/lib/corePluginList.js +178 -5
- package/lib/corePlugins.js +3879 -2941
- package/lib/css/preflight.css +22 -9
- package/lib/featureFlags.js +61 -50
- package/lib/index.js +45 -28
- package/lib/lib/cacheInvalidation.js +90 -0
- package/lib/lib/collapseAdjacentRules.js +52 -36
- package/lib/lib/collapseDuplicateDeclarations.js +83 -0
- package/lib/lib/content.js +176 -0
- package/lib/lib/defaultExtractor.js +236 -0
- package/lib/lib/detectNesting.js +37 -0
- package/lib/lib/evaluateTailwindFunctions.js +203 -161
- package/lib/lib/expandApplyAtRules.js +502 -221
- package/lib/lib/expandTailwindAtRules.js +258 -243
- package/lib/lib/findAtConfigPath.js +44 -0
- package/lib/lib/generateRules.js +775 -320
- package/lib/lib/getModuleDependencies.js +44 -46
- package/lib/lib/normalizeTailwindDirectives.js +79 -60
- package/lib/lib/offsets.js +217 -0
- package/lib/lib/partitionApplyAtRules.js +56 -0
- package/lib/lib/regex.js +60 -0
- package/lib/lib/resolveDefaultsAtRules.js +150 -94
- package/lib/lib/setupContextUtils.js +1146 -599
- package/lib/lib/setupTrackingContext.js +129 -177
- package/lib/lib/sharedState.js +53 -21
- package/lib/lib/substituteScreenAtRules.js +26 -28
- package/{nesting → lib/postcss-plugins/nesting}/README.md +2 -2
- package/lib/postcss-plugins/nesting/index.js +19 -0
- package/lib/postcss-plugins/nesting/plugin.js +87 -0
- package/lib/processTailwindFeatures.js +58 -53
- package/lib/public/colors.js +331 -0
- package/lib/public/create-plugin.js +15 -0
- package/lib/public/default-config.js +16 -0
- package/lib/public/default-theme.js +16 -0
- package/lib/public/resolve-config.js +22 -0
- package/lib/util/bigSign.js +7 -6
- package/lib/util/buildMediaQuery.js +21 -32
- package/lib/util/cloneDeep.js +16 -14
- package/lib/util/cloneNodes.js +29 -15
- package/lib/util/color.js +90 -66
- package/lib/util/configurePlugins.js +17 -15
- package/lib/util/createPlugin.js +23 -26
- package/lib/util/createUtilityPlugin.js +46 -46
- package/lib/util/dataTypes.js +242 -0
- package/lib/util/defaults.js +20 -15
- package/lib/util/escapeClassName.js +18 -17
- package/lib/util/escapeCommas.js +7 -6
- package/lib/util/flattenColorPalette.js +13 -12
- package/lib/util/formatVariantSelector.js +285 -0
- package/lib/util/getAllConfigs.js +44 -18
- package/lib/util/hashConfig.js +15 -12
- package/lib/util/isKeyframeRule.js +7 -6
- package/lib/util/isPlainObject.js +11 -11
- package/lib/util/isSyntacticallyValidPropertyValue.js +72 -0
- package/lib/util/log.js +52 -33
- package/lib/util/nameClass.js +37 -26
- package/lib/util/negateValue.js +31 -17
- package/lib/util/normalizeConfig.js +281 -0
- package/lib/util/normalizeScreens.js +170 -0
- package/lib/util/parseAnimationValue.js +85 -54
- package/lib/util/parseBoxShadowValue.js +84 -0
- package/lib/util/parseDependency.js +41 -70
- package/lib/util/parseGlob.js +34 -0
- package/lib/util/parseObjectStyles.js +30 -24
- package/lib/util/pluginUtils.js +252 -287
- package/lib/util/prefixSelector.js +20 -20
- package/lib/util/removeAlphaVariables.js +29 -0
- package/lib/util/resolveConfig.js +221 -256
- package/lib/util/resolveConfigPath.js +43 -48
- package/lib/util/responsive.js +18 -14
- package/lib/util/splitAtTopLevelOnly.js +43 -0
- package/lib/util/tap.js +8 -7
- package/lib/util/toColorValue.js +7 -6
- package/lib/util/toPath.js +27 -8
- package/lib/util/transformThemeValue.js +67 -28
- package/lib/util/validateConfig.js +24 -0
- package/lib/util/validateFormalSyntax.js +24 -0
- package/lib/util/withAlphaVariable.js +67 -57
- package/nesting/index.js +2 -12
- package/package.json +60 -65
- package/peers/index.js +76445 -84221
- package/plugin.d.ts +11 -0
- package/plugin.js +1 -2
- package/resolveConfig.d.ts +12 -0
- package/resolveConfig.js +2 -7
- package/scripts/create-plugin-list.js +2 -2
- package/scripts/generate-types.js +105 -0
- package/scripts/release-channel.js +18 -0
- package/scripts/release-notes.js +21 -0
- package/scripts/type-utils.js +27 -0
- package/src/cli/build/deps.js +56 -0
- package/src/cli/build/index.js +49 -0
- package/src/cli/build/plugin.js +439 -0
- package/src/cli/build/utils.js +76 -0
- package/src/cli/build/watching.js +227 -0
- package/src/cli/help/index.js +70 -0
- package/src/cli/index.js +3 -0
- package/src/cli/init/index.js +50 -0
- package/src/cli/shared.js +6 -0
- package/src/cli-peer-dependencies.js +7 -1
- package/src/cli.js +50 -575
- package/src/corePluginList.js +1 -1
- package/src/corePlugins.js +2405 -1948
- package/src/css/preflight.css +22 -9
- package/src/featureFlags.js +26 -10
- package/src/index.js +19 -6
- package/src/lib/cacheInvalidation.js +52 -0
- package/src/lib/collapseAdjacentRules.js +21 -2
- package/src/lib/collapseDuplicateDeclarations.js +93 -0
- package/src/lib/content.js +212 -0
- package/src/lib/defaultExtractor.js +211 -0
- package/src/lib/detectNesting.js +39 -0
- package/src/lib/evaluateTailwindFunctions.js +84 -10
- package/src/lib/expandApplyAtRules.js +508 -153
- package/src/lib/expandTailwindAtRules.js +130 -104
- package/src/lib/findAtConfigPath.js +48 -0
- package/src/lib/generateRules.js +596 -70
- package/src/lib/normalizeTailwindDirectives.js +10 -3
- package/src/lib/offsets.js +270 -0
- package/src/lib/partitionApplyAtRules.js +52 -0
- package/src/lib/regex.js +74 -0
- package/src/lib/resolveDefaultsAtRules.js +105 -47
- package/src/lib/setupContextUtils.js +828 -196
- package/src/lib/setupTrackingContext.js +19 -54
- package/src/lib/sharedState.js +45 -7
- package/src/lib/substituteScreenAtRules.js +6 -3
- package/src/postcss-plugins/nesting/README.md +42 -0
- package/src/postcss-plugins/nesting/index.js +13 -0
- package/src/postcss-plugins/nesting/plugin.js +80 -0
- package/src/processTailwindFeatures.js +19 -2
- package/src/public/colors.js +300 -0
- package/src/public/create-plugin.js +2 -0
- package/src/public/default-config.js +4 -0
- package/src/public/default-theme.js +4 -0
- package/src/public/resolve-config.js +7 -0
- package/src/util/buildMediaQuery.js +14 -16
- package/src/util/cloneNodes.js +19 -2
- package/src/util/color.js +31 -14
- package/src/util/createUtilityPlugin.js +2 -11
- package/src/util/dataTypes.js +256 -0
- package/src/util/defaults.js +6 -0
- package/src/util/formatVariantSelector.js +319 -0
- package/src/util/getAllConfigs.js +19 -0
- package/src/util/isSyntacticallyValidPropertyValue.js +61 -0
- package/src/util/log.js +23 -22
- package/src/util/nameClass.js +14 -6
- package/src/util/negateValue.js +15 -5
- package/src/util/normalizeConfig.js +300 -0
- package/src/util/normalizeScreens.js +140 -0
- package/src/util/parseAnimationValue.js +7 -1
- package/src/util/parseBoxShadowValue.js +72 -0
- package/src/util/parseDependency.js +37 -38
- package/src/util/parseGlob.js +24 -0
- package/src/util/pluginUtils.js +216 -197
- package/src/util/prefixSelector.js +7 -8
- package/src/util/removeAlphaVariables.js +24 -0
- package/src/util/resolveConfig.js +86 -91
- package/src/util/splitAtTopLevelOnly.js +45 -0
- package/src/util/toPath.js +23 -1
- package/src/util/transformThemeValue.js +33 -8
- package/src/util/validateConfig.js +13 -0
- package/src/util/validateFormalSyntax.js +34 -0
- package/src/util/withAlphaVariable.js +14 -9
- package/stubs/defaultConfig.stub.js +186 -117
- package/stubs/simpleConfig.stub.js +1 -1
- package/types/config.d.ts +362 -0
- package/types/generated/.gitkeep +0 -0
- package/types/generated/colors.d.ts +276 -0
- package/types/generated/corePluginList.d.ts +1 -0
- package/types/generated/default-theme.d.ts +342 -0
- package/types/index.d.ts +7 -0
- package/lib/lib/setupWatchingContext.js +0 -331
- package/nesting/plugin.js +0 -41
- package/src/lib/setupWatchingContext.js +0 -306
package/src/lib/generateRules.js
CHANGED
|
@@ -3,13 +3,22 @@ import selectorParser from 'postcss-selector-parser'
|
|
|
3
3
|
import parseObjectStyles from '../util/parseObjectStyles'
|
|
4
4
|
import isPlainObject from '../util/isPlainObject'
|
|
5
5
|
import prefixSelector from '../util/prefixSelector'
|
|
6
|
-
import { updateAllClasses } from '../util/pluginUtils'
|
|
6
|
+
import { updateAllClasses, filterSelectorsForClass, getMatchingTypes } from '../util/pluginUtils'
|
|
7
|
+
import log from '../util/log'
|
|
8
|
+
import * as sharedState from './sharedState'
|
|
9
|
+
import { formatVariantSelector, finalizeSelector } from '../util/formatVariantSelector'
|
|
10
|
+
import { asClass } from '../util/nameClass'
|
|
11
|
+
import { normalize } from '../util/dataTypes'
|
|
12
|
+
import { isValidVariantFormatString, parseVariant } from './setupContextUtils'
|
|
13
|
+
import isValidArbitraryValue from '../util/isSyntacticallyValidPropertyValue'
|
|
14
|
+
import { splitAtTopLevelOnly } from '../util/splitAtTopLevelOnly.js'
|
|
15
|
+
import { flagEnabled } from '../featureFlags'
|
|
7
16
|
|
|
8
17
|
let classNameParser = selectorParser((selectors) => {
|
|
9
18
|
return selectors.first.filter(({ type }) => type === 'class').pop().value
|
|
10
19
|
})
|
|
11
20
|
|
|
12
|
-
function getClassNameFromSelector(selector) {
|
|
21
|
+
export function getClassNameFromSelector(selector) {
|
|
13
22
|
return classNameParser.transformSync(selector)
|
|
14
23
|
}
|
|
15
24
|
|
|
@@ -20,33 +29,49 @@ function getClassNameFromSelector(selector) {
|
|
|
20
29
|
// Example with dynamic classes:
|
|
21
30
|
// ['grid-cols', '[[linename],1fr,auto]']
|
|
22
31
|
// ['grid', 'cols-[[linename],1fr,auto]']
|
|
23
|
-
function* candidatePermutations(candidate
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
function* candidatePermutations(candidate) {
|
|
33
|
+
let lastIndex = Infinity
|
|
34
|
+
|
|
35
|
+
while (lastIndex >= 0) {
|
|
36
|
+
let dashIdx
|
|
37
|
+
let wasSlash = false
|
|
38
|
+
|
|
39
|
+
if (lastIndex === Infinity && candidate.endsWith(']')) {
|
|
40
|
+
let bracketIdx = candidate.indexOf('[')
|
|
41
|
+
|
|
42
|
+
// If character before `[` isn't a dash or a slash, this isn't a dynamic class
|
|
43
|
+
// eg. string[]
|
|
44
|
+
if (candidate[bracketIdx - 1] === '-') {
|
|
45
|
+
dashIdx = bracketIdx - 1
|
|
46
|
+
} else if (candidate[bracketIdx - 1] === '/') {
|
|
47
|
+
dashIdx = bracketIdx - 1
|
|
48
|
+
wasSlash = true
|
|
49
|
+
} else {
|
|
50
|
+
dashIdx = -1
|
|
51
|
+
}
|
|
52
|
+
} else if (lastIndex === Infinity && candidate.includes('/')) {
|
|
53
|
+
dashIdx = candidate.lastIndexOf('/')
|
|
54
|
+
wasSlash = true
|
|
55
|
+
} else {
|
|
56
|
+
dashIdx = candidate.lastIndexOf('-', lastIndex)
|
|
57
|
+
}
|
|
32
58
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} else {
|
|
37
|
-
dashIdx = candidate.lastIndexOf('-', lastIndex)
|
|
38
|
-
}
|
|
59
|
+
if (dashIdx < 0) {
|
|
60
|
+
break
|
|
61
|
+
}
|
|
39
62
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
63
|
+
let prefix = candidate.slice(0, dashIdx)
|
|
64
|
+
let modifier = candidate.slice(wasSlash ? dashIdx : dashIdx + 1)
|
|
43
65
|
|
|
44
|
-
|
|
45
|
-
let modifier = candidate.slice(dashIdx + 1)
|
|
66
|
+
lastIndex = dashIdx - 1
|
|
46
67
|
|
|
47
|
-
|
|
68
|
+
// TODO: This feels a bit hacky
|
|
69
|
+
if (prefix === '' || modifier === '/') {
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
48
72
|
|
|
49
|
-
|
|
73
|
+
yield [prefix, modifier]
|
|
74
|
+
}
|
|
50
75
|
}
|
|
51
76
|
|
|
52
77
|
function applyPrefix(matches, context) {
|
|
@@ -58,9 +83,23 @@ function applyPrefix(matches, context) {
|
|
|
58
83
|
let [meta] = match
|
|
59
84
|
if (meta.options.respectPrefix) {
|
|
60
85
|
let container = postcss.root({ nodes: [match[1].clone()] })
|
|
86
|
+
let classCandidate = match[1].raws.tailwind.classCandidate
|
|
87
|
+
|
|
61
88
|
container.walkRules((r) => {
|
|
62
|
-
|
|
89
|
+
// If this is a negative utility with a dash *before* the prefix we
|
|
90
|
+
// have to ensure that the generated selector matches the candidate
|
|
91
|
+
|
|
92
|
+
// Not doing this will cause `-tw-top-1` to generate the class `.tw--top-1`
|
|
93
|
+
// The disconnect between candidate <-> class can cause @apply to hard crash.
|
|
94
|
+
let shouldPrependNegative = classCandidate.startsWith('-')
|
|
95
|
+
|
|
96
|
+
r.selector = prefixSelector(
|
|
97
|
+
context.tailwindConfig.prefix,
|
|
98
|
+
r.selector,
|
|
99
|
+
shouldPrependNegative
|
|
100
|
+
)
|
|
63
101
|
})
|
|
102
|
+
|
|
64
103
|
match[1] = container.nodes[0]
|
|
65
104
|
}
|
|
66
105
|
}
|
|
@@ -68,7 +107,7 @@ function applyPrefix(matches, context) {
|
|
|
68
107
|
return matches
|
|
69
108
|
}
|
|
70
109
|
|
|
71
|
-
function applyImportant(matches) {
|
|
110
|
+
function applyImportant(matches, classCandidate) {
|
|
72
111
|
if (matches.length === 0) {
|
|
73
112
|
return matches
|
|
74
113
|
}
|
|
@@ -77,9 +116,15 @@ function applyImportant(matches) {
|
|
|
77
116
|
for (let [meta, rule] of matches) {
|
|
78
117
|
let container = postcss.root({ nodes: [rule.clone()] })
|
|
79
118
|
container.walkRules((r) => {
|
|
80
|
-
r.selector = updateAllClasses(
|
|
81
|
-
|
|
82
|
-
|
|
119
|
+
r.selector = updateAllClasses(
|
|
120
|
+
filterSelectorsForClass(r.selector, classCandidate),
|
|
121
|
+
(className) => {
|
|
122
|
+
if (className === classCandidate) {
|
|
123
|
+
return `!${className}`
|
|
124
|
+
}
|
|
125
|
+
return className
|
|
126
|
+
}
|
|
127
|
+
)
|
|
83
128
|
r.walkDecls((d) => (d.important = true))
|
|
84
129
|
})
|
|
85
130
|
result.push([{ ...meta, important: true }, container.nodes[0]])
|
|
@@ -102,21 +147,86 @@ function applyVariant(variant, matches, context) {
|
|
|
102
147
|
return matches
|
|
103
148
|
}
|
|
104
149
|
|
|
150
|
+
/** @type {{modifier: string | null, value: string | null}} */
|
|
151
|
+
let args = { modifier: null, value: sharedState.NONE }
|
|
152
|
+
|
|
153
|
+
// Retrieve "modifier"
|
|
154
|
+
{
|
|
155
|
+
let match = /(.*)\/(.*)$/g.exec(variant)
|
|
156
|
+
if (match) {
|
|
157
|
+
variant = match[1]
|
|
158
|
+
args.modifier = match[2]
|
|
159
|
+
|
|
160
|
+
if (!flagEnabled(context.tailwindConfig, 'generalizedModifiers')) {
|
|
161
|
+
return []
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Retrieve "arbitrary value"
|
|
167
|
+
if (variant.endsWith(']') && !variant.startsWith('[')) {
|
|
168
|
+
// We either have:
|
|
169
|
+
// @[200px]
|
|
170
|
+
// group-[:hover]
|
|
171
|
+
//
|
|
172
|
+
// But we don't want:
|
|
173
|
+
// @-[200px] (`-` is incorrect)
|
|
174
|
+
// group[:hover] (`-` is missing)
|
|
175
|
+
let match = /(.)(-?)\[(.*)\]/g.exec(variant)
|
|
176
|
+
if (match) {
|
|
177
|
+
let [, char, seperator, value] = match
|
|
178
|
+
// @-[200px] case
|
|
179
|
+
if (char === '@' && seperator === '-') return []
|
|
180
|
+
// group[:hover] case
|
|
181
|
+
if (char !== '@' && seperator === '') return []
|
|
182
|
+
|
|
183
|
+
variant = variant.replace(`${seperator}[${value}]`, '')
|
|
184
|
+
args.value = value
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Register arbitrary variants
|
|
189
|
+
if (isArbitraryValue(variant) && !context.variantMap.has(variant)) {
|
|
190
|
+
let selector = normalize(variant.slice(1, -1))
|
|
191
|
+
|
|
192
|
+
if (!isValidVariantFormatString(selector)) {
|
|
193
|
+
return []
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let fn = parseVariant(selector)
|
|
197
|
+
|
|
198
|
+
let sort = context.offsets.recordVariant(variant)
|
|
199
|
+
|
|
200
|
+
context.variantMap.set(variant, [[sort, fn]])
|
|
201
|
+
}
|
|
202
|
+
|
|
105
203
|
if (context.variantMap.has(variant)) {
|
|
106
|
-
let variantFunctionTuples = context.variantMap.get(variant)
|
|
204
|
+
let variantFunctionTuples = context.variantMap.get(variant).slice()
|
|
107
205
|
let result = []
|
|
108
206
|
|
|
109
207
|
for (let [meta, rule] of matches) {
|
|
110
|
-
|
|
111
|
-
|
|
208
|
+
// Don't generate variants for user css
|
|
209
|
+
if (meta.layer === 'user') {
|
|
112
210
|
continue
|
|
113
211
|
}
|
|
114
212
|
|
|
115
213
|
let container = postcss.root({ nodes: [rule.clone()] })
|
|
116
214
|
|
|
117
|
-
for (let [variantSort, variantFunction] of variantFunctionTuples) {
|
|
118
|
-
let clone = container.clone()
|
|
215
|
+
for (let [variantSort, variantFunction, containerFromArray] of variantFunctionTuples) {
|
|
216
|
+
let clone = (containerFromArray ?? container).clone()
|
|
217
|
+
let collectedFormats = []
|
|
218
|
+
|
|
219
|
+
function prepareBackup() {
|
|
220
|
+
// Already prepared, chicken out
|
|
221
|
+
if (clone.raws.neededBackup) {
|
|
222
|
+
return
|
|
223
|
+
}
|
|
224
|
+
clone.raws.neededBackup = true
|
|
225
|
+
clone.walkRules((rule) => (rule.raws.originalSelector = rule.selector))
|
|
226
|
+
}
|
|
227
|
+
|
|
119
228
|
function modifySelectors(modifierFunction) {
|
|
229
|
+
prepareBackup()
|
|
120
230
|
clone.each((rule) => {
|
|
121
231
|
if (rule.type !== 'rule') {
|
|
122
232
|
return
|
|
@@ -131,20 +241,118 @@ function applyVariant(variant, matches, context) {
|
|
|
131
241
|
})
|
|
132
242
|
})
|
|
133
243
|
})
|
|
244
|
+
|
|
134
245
|
return clone
|
|
135
246
|
}
|
|
136
247
|
|
|
137
248
|
let ruleWithVariant = variantFunction({
|
|
138
|
-
|
|
249
|
+
// Public API
|
|
250
|
+
get container() {
|
|
251
|
+
prepareBackup()
|
|
252
|
+
return clone
|
|
253
|
+
},
|
|
139
254
|
separator: context.tailwindConfig.separator,
|
|
140
255
|
modifySelectors,
|
|
256
|
+
|
|
257
|
+
// Private API for now
|
|
258
|
+
wrap(wrapper) {
|
|
259
|
+
let nodes = clone.nodes
|
|
260
|
+
clone.removeAll()
|
|
261
|
+
wrapper.append(nodes)
|
|
262
|
+
clone.append(wrapper)
|
|
263
|
+
},
|
|
264
|
+
format(selectorFormat) {
|
|
265
|
+
collectedFormats.push(selectorFormat)
|
|
266
|
+
},
|
|
267
|
+
args,
|
|
141
268
|
})
|
|
142
269
|
|
|
270
|
+
// It can happen that a list of format strings is returned from within the function. In that
|
|
271
|
+
// case, we have to process them as well. We can use the existing `variantSort`.
|
|
272
|
+
if (Array.isArray(ruleWithVariant)) {
|
|
273
|
+
for (let [idx, variantFunction] of ruleWithVariant.entries()) {
|
|
274
|
+
// This is a little bit scary since we are pushing to an array of items that we are
|
|
275
|
+
// currently looping over. However, you can also think of it like a processing queue
|
|
276
|
+
// where you keep handling jobs until everything is done and each job can queue more
|
|
277
|
+
// jobs if needed.
|
|
278
|
+
variantFunctionTuples.push([
|
|
279
|
+
context.offsets.applyParallelOffset(variantSort, idx),
|
|
280
|
+
variantFunction,
|
|
281
|
+
|
|
282
|
+
// If the clone has been modified we have to pass that back
|
|
283
|
+
// though so each rule can use the modified container
|
|
284
|
+
clone.clone(),
|
|
285
|
+
])
|
|
286
|
+
}
|
|
287
|
+
continue
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (typeof ruleWithVariant === 'string') {
|
|
291
|
+
collectedFormats.push(ruleWithVariant)
|
|
292
|
+
}
|
|
293
|
+
|
|
143
294
|
if (ruleWithVariant === null) {
|
|
144
295
|
continue
|
|
145
296
|
}
|
|
146
297
|
|
|
147
|
-
|
|
298
|
+
// We had to backup selectors, therefore we assume that somebody touched
|
|
299
|
+
// `container` or `modifySelectors`. Let's see if they did, so that we
|
|
300
|
+
// can restore the selectors, and collect the format strings.
|
|
301
|
+
if (clone.raws.neededBackup) {
|
|
302
|
+
delete clone.raws.neededBackup
|
|
303
|
+
clone.walkRules((rule) => {
|
|
304
|
+
let before = rule.raws.originalSelector
|
|
305
|
+
if (!before) return
|
|
306
|
+
delete rule.raws.originalSelector
|
|
307
|
+
if (before === rule.selector) return // No mutation happened
|
|
308
|
+
|
|
309
|
+
let modified = rule.selector
|
|
310
|
+
|
|
311
|
+
// Rebuild the base selector, this is what plugin authors would do
|
|
312
|
+
// as well. E.g.: `${variant}${separator}${className}`.
|
|
313
|
+
// However, plugin authors probably also prepend or append certain
|
|
314
|
+
// classes, pseudos, ids, ...
|
|
315
|
+
let rebuiltBase = selectorParser((selectors) => {
|
|
316
|
+
selectors.walkClasses((classNode) => {
|
|
317
|
+
classNode.value = `${variant}${context.tailwindConfig.separator}${classNode.value}`
|
|
318
|
+
})
|
|
319
|
+
}).processSync(before)
|
|
320
|
+
|
|
321
|
+
// Now that we know the original selector, the new selector, and
|
|
322
|
+
// the rebuild part in between, we can replace the part that plugin
|
|
323
|
+
// authors need to rebuild with `&`, and eventually store it in the
|
|
324
|
+
// collectedFormats. Similar to what `format('...')` would do.
|
|
325
|
+
//
|
|
326
|
+
// E.g.:
|
|
327
|
+
// variant: foo
|
|
328
|
+
// selector: .markdown > p
|
|
329
|
+
// modified (by plugin): .foo .foo\\:markdown > p
|
|
330
|
+
// rebuiltBase (internal): .foo\\:markdown > p
|
|
331
|
+
// format: .foo &
|
|
332
|
+
collectedFormats.push(modified.replace(rebuiltBase, '&'))
|
|
333
|
+
rule.selector = before
|
|
334
|
+
})
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// This tracks the originating layer for the variant
|
|
338
|
+
// For example:
|
|
339
|
+
// .sm:underline {} is a variant of something in the utilities layer
|
|
340
|
+
// .sm:container {} is a variant of the container component
|
|
341
|
+
clone.nodes[0].raws.tailwind = { ...clone.nodes[0].raws.tailwind, parentLayer: meta.layer }
|
|
342
|
+
|
|
343
|
+
let withOffset = [
|
|
344
|
+
{
|
|
345
|
+
...meta,
|
|
346
|
+
sort: context.offsets.applyVariantOffset(
|
|
347
|
+
meta.sort,
|
|
348
|
+
variantSort,
|
|
349
|
+
Object.assign(args, context.variantOptions.get(variant))
|
|
350
|
+
),
|
|
351
|
+
collectedFormats: (meta.collectedFormats ?? []).concat(collectedFormats),
|
|
352
|
+
isArbitraryVariant: isArbitraryValue(variant),
|
|
353
|
+
},
|
|
354
|
+
clone.nodes[0],
|
|
355
|
+
]
|
|
148
356
|
result.push(withOffset)
|
|
149
357
|
}
|
|
150
358
|
}
|
|
@@ -174,34 +382,154 @@ function parseRules(rule, cache, options = {}) {
|
|
|
174
382
|
return [cache.get(rule), options]
|
|
175
383
|
}
|
|
176
384
|
|
|
385
|
+
const IS_VALID_PROPERTY_NAME = /^[a-z_-]/
|
|
386
|
+
|
|
387
|
+
function isValidPropName(name) {
|
|
388
|
+
return IS_VALID_PROPERTY_NAME.test(name)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* @param {string} declaration
|
|
393
|
+
* @returns {boolean}
|
|
394
|
+
*/
|
|
395
|
+
function looksLikeUri(declaration) {
|
|
396
|
+
// Quick bailout for obvious non-urls
|
|
397
|
+
// This doesn't support schemes that don't use a leading // but that's unlikely to be a problem
|
|
398
|
+
if (!declaration.includes('://')) {
|
|
399
|
+
return false
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
try {
|
|
403
|
+
const url = new URL(declaration)
|
|
404
|
+
return url.scheme !== '' && url.host !== ''
|
|
405
|
+
} catch (err) {
|
|
406
|
+
// Definitely not a valid url
|
|
407
|
+
return false
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function isParsableNode(node) {
|
|
412
|
+
let isParsable = true
|
|
413
|
+
|
|
414
|
+
node.walkDecls((decl) => {
|
|
415
|
+
if (!isParsableCssValue(decl.name, decl.value)) {
|
|
416
|
+
isParsable = false
|
|
417
|
+
return false
|
|
418
|
+
}
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
return isParsable
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function isParsableCssValue(property, value) {
|
|
425
|
+
// We don't want to to treat [https://example.com] as a custom property
|
|
426
|
+
// Even though, according to the CSS grammar, it's a totally valid CSS declaration
|
|
427
|
+
// So we short-circuit here by checking if the custom property looks like a url
|
|
428
|
+
if (looksLikeUri(`${property}:${value}`)) {
|
|
429
|
+
return false
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
try {
|
|
433
|
+
postcss.parse(`a{${property}:${value}}`).toResult()
|
|
434
|
+
return true
|
|
435
|
+
} catch (err) {
|
|
436
|
+
return false
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function extractArbitraryProperty(classCandidate, context) {
|
|
441
|
+
let [, property, value] = classCandidate.match(/^\[([a-zA-Z0-9-_]+):(\S+)\]$/) ?? []
|
|
442
|
+
|
|
443
|
+
if (value === undefined) {
|
|
444
|
+
return null
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (!isValidPropName(property)) {
|
|
448
|
+
return null
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (!isValidArbitraryValue(value)) {
|
|
452
|
+
return null
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
let normalized = normalize(value)
|
|
456
|
+
|
|
457
|
+
if (!isParsableCssValue(property, normalized)) {
|
|
458
|
+
return null
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
let sort = context.offsets.arbitraryProperty()
|
|
462
|
+
|
|
463
|
+
return [
|
|
464
|
+
[
|
|
465
|
+
{ sort, layer: 'utilities' },
|
|
466
|
+
() => ({
|
|
467
|
+
[asClass(classCandidate)]: {
|
|
468
|
+
[property]: normalized,
|
|
469
|
+
},
|
|
470
|
+
}),
|
|
471
|
+
],
|
|
472
|
+
]
|
|
473
|
+
}
|
|
474
|
+
|
|
177
475
|
function* resolveMatchedPlugins(classCandidate, context) {
|
|
178
476
|
if (context.candidateRuleMap.has(classCandidate)) {
|
|
179
477
|
yield [context.candidateRuleMap.get(classCandidate), 'DEFAULT']
|
|
180
478
|
}
|
|
181
479
|
|
|
480
|
+
yield* (function* (arbitraryPropertyRule) {
|
|
481
|
+
if (arbitraryPropertyRule !== null) {
|
|
482
|
+
yield [arbitraryPropertyRule, 'DEFAULT']
|
|
483
|
+
}
|
|
484
|
+
})(extractArbitraryProperty(classCandidate, context))
|
|
485
|
+
|
|
182
486
|
let candidatePrefix = classCandidate
|
|
183
487
|
let negative = false
|
|
184
488
|
|
|
185
|
-
const twConfigPrefix = context.tailwindConfig.prefix
|
|
489
|
+
const twConfigPrefix = context.tailwindConfig.prefix
|
|
490
|
+
|
|
186
491
|
const twConfigPrefixLen = twConfigPrefix.length
|
|
187
|
-
|
|
492
|
+
|
|
493
|
+
const hasMatchingPrefix =
|
|
494
|
+
candidatePrefix.startsWith(twConfigPrefix) || candidatePrefix.startsWith(`-${twConfigPrefix}`)
|
|
495
|
+
|
|
496
|
+
if (candidatePrefix[twConfigPrefixLen] === '-' && hasMatchingPrefix) {
|
|
188
497
|
negative = true
|
|
189
498
|
candidatePrefix = twConfigPrefix + candidatePrefix.slice(twConfigPrefixLen + 1)
|
|
190
499
|
}
|
|
191
500
|
|
|
501
|
+
if (negative && context.candidateRuleMap.has(candidatePrefix)) {
|
|
502
|
+
yield [context.candidateRuleMap.get(candidatePrefix), '-DEFAULT']
|
|
503
|
+
}
|
|
504
|
+
|
|
192
505
|
for (let [prefix, modifier] of candidatePermutations(candidatePrefix)) {
|
|
193
506
|
if (context.candidateRuleMap.has(prefix)) {
|
|
194
507
|
yield [context.candidateRuleMap.get(prefix), negative ? `-${modifier}` : modifier]
|
|
195
|
-
return
|
|
196
508
|
}
|
|
197
509
|
}
|
|
198
510
|
}
|
|
199
511
|
|
|
200
512
|
function splitWithSeparator(input, separator) {
|
|
201
|
-
|
|
513
|
+
if (input === sharedState.NOT_ON_DEMAND) {
|
|
514
|
+
return [sharedState.NOT_ON_DEMAND]
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return splitAtTopLevelOnly(input, separator)
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function* recordCandidates(matches, classCandidate) {
|
|
521
|
+
for (const match of matches) {
|
|
522
|
+
match[1].raws.tailwind = {
|
|
523
|
+
...match[1].raws.tailwind,
|
|
524
|
+
classCandidate,
|
|
525
|
+
preserveSource: match[0].options?.preserveSource ?? false,
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
yield match
|
|
529
|
+
}
|
|
202
530
|
}
|
|
203
531
|
|
|
204
|
-
function* resolveMatches(candidate, context) {
|
|
532
|
+
function* resolveMatches(candidate, context, original = candidate) {
|
|
205
533
|
let separator = context.tailwindConfig.separator
|
|
206
534
|
let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse()
|
|
207
535
|
let important = false
|
|
@@ -211,6 +539,15 @@ function* resolveMatches(candidate, context) {
|
|
|
211
539
|
classCandidate = classCandidate.slice(1)
|
|
212
540
|
}
|
|
213
541
|
|
|
542
|
+
if (flagEnabled(context.tailwindConfig, 'variantGrouping')) {
|
|
543
|
+
if (classCandidate.startsWith('(') && classCandidate.endsWith(')')) {
|
|
544
|
+
let base = variants.slice().reverse().join(separator)
|
|
545
|
+
for (let part of splitAtTopLevelOnly(classCandidate.slice(1, -1), ',')) {
|
|
546
|
+
yield* resolveMatches(base + separator + part, context, original)
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
214
551
|
// TODO: Reintroduce this in ways that doesn't break on false positives
|
|
215
552
|
// function sortAgainst(toSort, against) {
|
|
216
553
|
// return toSort.slice().sort((a, z) => {
|
|
@@ -225,31 +562,170 @@ function* resolveMatches(candidate, context) {
|
|
|
225
562
|
|
|
226
563
|
for (let matchedPlugins of resolveMatchedPlugins(classCandidate, context)) {
|
|
227
564
|
let matches = []
|
|
565
|
+
let typesByMatches = new Map()
|
|
566
|
+
|
|
228
567
|
let [plugins, modifier] = matchedPlugins
|
|
568
|
+
let isOnlyPlugin = plugins.length === 1
|
|
229
569
|
|
|
230
570
|
for (let [sort, plugin] of plugins) {
|
|
571
|
+
let matchesPerPlugin = []
|
|
572
|
+
|
|
231
573
|
if (typeof plugin === 'function') {
|
|
232
|
-
for (let ruleSet of [].concat(plugin(modifier))) {
|
|
574
|
+
for (let ruleSet of [].concat(plugin(modifier, { isOnlyPlugin }))) {
|
|
233
575
|
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache)
|
|
234
576
|
for (let rule of rules) {
|
|
235
|
-
|
|
577
|
+
matchesPerPlugin.push([{ ...sort, options: { ...sort.options, ...options } }, rule])
|
|
236
578
|
}
|
|
237
579
|
}
|
|
238
580
|
}
|
|
239
581
|
// Only process static plugins on exact matches
|
|
240
|
-
else if (modifier === 'DEFAULT') {
|
|
582
|
+
else if (modifier === 'DEFAULT' || modifier === '-DEFAULT') {
|
|
241
583
|
let ruleSet = plugin
|
|
242
584
|
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache)
|
|
243
585
|
for (let rule of rules) {
|
|
244
|
-
|
|
586
|
+
matchesPerPlugin.push([{ ...sort, options: { ...sort.options, ...options } }, rule])
|
|
245
587
|
}
|
|
246
588
|
}
|
|
589
|
+
|
|
590
|
+
if (matchesPerPlugin.length > 0) {
|
|
591
|
+
let matchingTypes = Array.from(
|
|
592
|
+
getMatchingTypes(
|
|
593
|
+
sort.options?.types ?? [],
|
|
594
|
+
modifier,
|
|
595
|
+
sort.options ?? {},
|
|
596
|
+
context.tailwindConfig
|
|
597
|
+
)
|
|
598
|
+
).map(([_, type]) => type)
|
|
599
|
+
|
|
600
|
+
if (matchingTypes.length > 0) {
|
|
601
|
+
typesByMatches.set(matchesPerPlugin, matchingTypes)
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
matches.push(matchesPerPlugin)
|
|
605
|
+
}
|
|
247
606
|
}
|
|
248
607
|
|
|
608
|
+
if (isArbitraryValue(modifier)) {
|
|
609
|
+
if (matches.length > 1) {
|
|
610
|
+
// Partition plugins in 2 categories so that we can start searching in the plugins that
|
|
611
|
+
// don't have `any` as a type first.
|
|
612
|
+
let [withAny, withoutAny] = matches.reduce(
|
|
613
|
+
(group, plugin) => {
|
|
614
|
+
let hasAnyType = plugin.some(([{ options }]) =>
|
|
615
|
+
options.types.some(({ type }) => type === 'any')
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
if (hasAnyType) {
|
|
619
|
+
group[0].push(plugin)
|
|
620
|
+
} else {
|
|
621
|
+
group[1].push(plugin)
|
|
622
|
+
}
|
|
623
|
+
return group
|
|
624
|
+
},
|
|
625
|
+
[[], []]
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
function findFallback(matches) {
|
|
629
|
+
// If only a single plugin matches, let's take that one
|
|
630
|
+
if (matches.length === 1) {
|
|
631
|
+
return matches[0]
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Otherwise, find the plugin that creates a valid rule given the arbitrary value, and
|
|
635
|
+
// also has the correct type which preferOnConflicts the plugin in case of clashes.
|
|
636
|
+
return matches.find((rules) => {
|
|
637
|
+
let matchingTypes = typesByMatches.get(rules)
|
|
638
|
+
return rules.some(([{ options }, rule]) => {
|
|
639
|
+
if (!isParsableNode(rule)) {
|
|
640
|
+
return false
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return options.types.some(
|
|
644
|
+
({ type, preferOnConflict }) => matchingTypes.includes(type) && preferOnConflict
|
|
645
|
+
)
|
|
646
|
+
})
|
|
647
|
+
})
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// Try to find a fallback plugin, because we already know that multiple plugins matched for
|
|
651
|
+
// the given arbitrary value.
|
|
652
|
+
let fallback = findFallback(withoutAny) ?? findFallback(withAny)
|
|
653
|
+
if (fallback) {
|
|
654
|
+
matches = [fallback]
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// We couldn't find a fallback plugin which means that there are now multiple plugins that
|
|
658
|
+
// generated css for the current candidate. This means that the result is ambiguous and this
|
|
659
|
+
// should not happen. We won't generate anything right now, so let's report this to the user
|
|
660
|
+
// by logging some options about what they can do.
|
|
661
|
+
else {
|
|
662
|
+
let typesPerPlugin = matches.map(
|
|
663
|
+
(match) => new Set([...(typesByMatches.get(match) ?? [])])
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
// Remove duplicates, so that we can detect proper unique types for each plugin.
|
|
667
|
+
for (let pluginTypes of typesPerPlugin) {
|
|
668
|
+
for (let type of pluginTypes) {
|
|
669
|
+
let removeFromOwnGroup = false
|
|
670
|
+
|
|
671
|
+
for (let otherGroup of typesPerPlugin) {
|
|
672
|
+
if (pluginTypes === otherGroup) continue
|
|
673
|
+
|
|
674
|
+
if (otherGroup.has(type)) {
|
|
675
|
+
otherGroup.delete(type)
|
|
676
|
+
removeFromOwnGroup = true
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
if (removeFromOwnGroup) pluginTypes.delete(type)
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
let messages = []
|
|
685
|
+
|
|
686
|
+
for (let [idx, group] of typesPerPlugin.entries()) {
|
|
687
|
+
for (let type of group) {
|
|
688
|
+
let rules = matches[idx]
|
|
689
|
+
.map(([, rule]) => rule)
|
|
690
|
+
.flat()
|
|
691
|
+
.map((rule) =>
|
|
692
|
+
rule
|
|
693
|
+
.toString()
|
|
694
|
+
.split('\n')
|
|
695
|
+
.slice(1, -1) // Remove selector and closing '}'
|
|
696
|
+
.map((line) => line.trim())
|
|
697
|
+
.map((x) => ` ${x}`) // Re-indent
|
|
698
|
+
.join('\n')
|
|
699
|
+
)
|
|
700
|
+
.join('\n\n')
|
|
701
|
+
|
|
702
|
+
messages.push(
|
|
703
|
+
` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\``
|
|
704
|
+
)
|
|
705
|
+
break
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
log.warn([
|
|
710
|
+
`The class \`${candidate}\` is ambiguous and matches multiple utilities.`,
|
|
711
|
+
...messages,
|
|
712
|
+
`If this is content and not a class, replace it with \`${candidate
|
|
713
|
+
.replace('[', '[')
|
|
714
|
+
.replace(']', ']')}\` to silence this warning.`,
|
|
715
|
+
])
|
|
716
|
+
continue
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
matches = matches.map((list) => list.filter((match) => isParsableNode(match[1])))
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
matches = matches.flat()
|
|
724
|
+
matches = Array.from(recordCandidates(matches, classCandidate))
|
|
249
725
|
matches = applyPrefix(matches, context)
|
|
250
726
|
|
|
251
727
|
if (important) {
|
|
252
|
-
matches = applyImportant(matches,
|
|
728
|
+
matches = applyImportant(matches, classCandidate)
|
|
253
729
|
}
|
|
254
730
|
|
|
255
731
|
for (let variant of variants) {
|
|
@@ -257,6 +733,29 @@ function* resolveMatches(candidate, context) {
|
|
|
257
733
|
}
|
|
258
734
|
|
|
259
735
|
for (let match of matches) {
|
|
736
|
+
match[1].raws.tailwind = { ...match[1].raws.tailwind, candidate }
|
|
737
|
+
|
|
738
|
+
// Apply final format selector
|
|
739
|
+
if (match[0].collectedFormats) {
|
|
740
|
+
let finalFormat = formatVariantSelector('&', ...match[0].collectedFormats)
|
|
741
|
+
let container = postcss.root({ nodes: [match[1].clone()] })
|
|
742
|
+
container.walkRules((rule) => {
|
|
743
|
+
if (inKeyframes(rule)) return
|
|
744
|
+
|
|
745
|
+
rule.selector = finalizeSelector(finalFormat, {
|
|
746
|
+
selector: rule.selector,
|
|
747
|
+
candidate: original,
|
|
748
|
+
base: candidate
|
|
749
|
+
.split(new RegExp(`\\${context?.tailwindConfig?.separator ?? ':'}(?![^[]*\\])`))
|
|
750
|
+
.pop(),
|
|
751
|
+
isArbitraryVariant: match[0].isArbitraryVariant,
|
|
752
|
+
|
|
753
|
+
context,
|
|
754
|
+
})
|
|
755
|
+
})
|
|
756
|
+
match[1] = container.nodes[0]
|
|
757
|
+
}
|
|
758
|
+
|
|
260
759
|
yield match
|
|
261
760
|
}
|
|
262
761
|
}
|
|
@@ -266,16 +765,45 @@ function inKeyframes(rule) {
|
|
|
266
765
|
return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === 'keyframes'
|
|
267
766
|
}
|
|
268
767
|
|
|
768
|
+
function getImportantStrategy(important) {
|
|
769
|
+
if (important === true) {
|
|
770
|
+
return (rule) => {
|
|
771
|
+
if (inKeyframes(rule)) {
|
|
772
|
+
return
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
rule.walkDecls((d) => {
|
|
776
|
+
if (d.parent.type === 'rule' && !inKeyframes(d.parent)) {
|
|
777
|
+
d.important = true
|
|
778
|
+
}
|
|
779
|
+
})
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
if (typeof important === 'string') {
|
|
784
|
+
return (rule) => {
|
|
785
|
+
if (inKeyframes(rule)) {
|
|
786
|
+
return
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
rule.selectors = rule.selectors.map((selector) => {
|
|
790
|
+
return `${important} ${selector}`
|
|
791
|
+
})
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
269
796
|
function generateRules(candidates, context) {
|
|
270
797
|
let allRules = []
|
|
798
|
+
let strategy = getImportantStrategy(context.tailwindConfig.important)
|
|
271
799
|
|
|
272
800
|
for (let candidate of candidates) {
|
|
273
801
|
if (context.notClassCache.has(candidate)) {
|
|
274
802
|
continue
|
|
275
803
|
}
|
|
276
804
|
|
|
277
|
-
if (context.
|
|
278
|
-
allRules.
|
|
805
|
+
if (context.candidateRuleCache.has(candidate)) {
|
|
806
|
+
allRules = allRules.concat(Array.from(context.candidateRuleCache.get(candidate)))
|
|
279
807
|
continue
|
|
280
808
|
}
|
|
281
809
|
|
|
@@ -287,33 +815,31 @@ function generateRules(candidates, context) {
|
|
|
287
815
|
}
|
|
288
816
|
|
|
289
817
|
context.classCache.set(candidate, matches)
|
|
290
|
-
allRules.push(matches)
|
|
291
|
-
}
|
|
292
818
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (context.tailwindConfig.important === true) {
|
|
296
|
-
rule.walkDecls((d) => {
|
|
297
|
-
if (d.parent.type === 'rule' && !inKeyframes(d.parent)) {
|
|
298
|
-
d.important = true
|
|
299
|
-
}
|
|
300
|
-
})
|
|
301
|
-
} else if (typeof context.tailwindConfig.important === 'string') {
|
|
302
|
-
let container = postcss.root({ nodes: [rule.clone()] })
|
|
303
|
-
container.walkRules((r) => {
|
|
304
|
-
if (inKeyframes(r)) {
|
|
305
|
-
return
|
|
306
|
-
}
|
|
819
|
+
let rules = context.candidateRuleCache.get(candidate) ?? new Set()
|
|
820
|
+
context.candidateRuleCache.set(candidate, rules)
|
|
307
821
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
822
|
+
for (const match of matches) {
|
|
823
|
+
let [{ sort, options }, rule] = match
|
|
824
|
+
|
|
825
|
+
if (options.respectImportant && strategy) {
|
|
826
|
+
let container = postcss.root({ nodes: [rule.clone()] })
|
|
827
|
+
container.walkRules(strategy)
|
|
312
828
|
rule = container.nodes[0]
|
|
313
829
|
}
|
|
830
|
+
|
|
831
|
+
let newEntry = [sort, rule]
|
|
832
|
+
rules.add(newEntry)
|
|
833
|
+
context.ruleCache.add(newEntry)
|
|
834
|
+
allRules.push(newEntry)
|
|
314
835
|
}
|
|
315
|
-
|
|
316
|
-
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
return allRules
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function isArbitraryValue(input) {
|
|
842
|
+
return input.startsWith('[') && input.endsWith(']')
|
|
317
843
|
}
|
|
318
844
|
|
|
319
845
|
export { resolveMatches, generateRules }
|