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
|
@@ -9,13 +9,78 @@ import parseObjectStyles from '../util/parseObjectStyles'
|
|
|
9
9
|
import prefixSelector from '../util/prefixSelector'
|
|
10
10
|
import isPlainObject from '../util/isPlainObject'
|
|
11
11
|
import escapeClassName from '../util/escapeClassName'
|
|
12
|
-
import nameClass from '../util/nameClass'
|
|
12
|
+
import nameClass, { formatClass } from '../util/nameClass'
|
|
13
13
|
import { coerceValue } from '../util/pluginUtils'
|
|
14
|
-
import
|
|
15
|
-
import * as corePlugins from '../corePlugins'
|
|
14
|
+
import { variantPlugins, corePlugins } from '../corePlugins'
|
|
16
15
|
import * as sharedState from './sharedState'
|
|
17
16
|
import { env } from './sharedState'
|
|
18
17
|
import { toPath } from '../util/toPath'
|
|
18
|
+
import log from '../util/log'
|
|
19
|
+
import negateValue from '../util/negateValue'
|
|
20
|
+
import isSyntacticallyValidPropertyValue from '../util/isSyntacticallyValidPropertyValue'
|
|
21
|
+
import { generateRules, getClassNameFromSelector } from './generateRules'
|
|
22
|
+
import { hasContentChanged } from './cacheInvalidation.js'
|
|
23
|
+
import { Offsets } from './offsets.js'
|
|
24
|
+
import { flagEnabled } from '../featureFlags.js'
|
|
25
|
+
import { finalizeSelector, formatVariantSelector } from '../util/formatVariantSelector'
|
|
26
|
+
|
|
27
|
+
const VARIANT_TYPES = {
|
|
28
|
+
AddVariant: Symbol.for('ADD_VARIANT'),
|
|
29
|
+
MatchVariant: Symbol.for('MATCH_VARIANT'),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const VARIANT_INFO = {
|
|
33
|
+
Base: 1 << 0,
|
|
34
|
+
Dynamic: 1 << 1,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function prefix(context, selector) {
|
|
38
|
+
let prefix = context.tailwindConfig.prefix
|
|
39
|
+
return typeof prefix === 'function' ? prefix(selector) : prefix + selector
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function normalizeOptionTypes({ type = 'any', ...options }) {
|
|
43
|
+
let types = [].concat(type)
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
...options,
|
|
47
|
+
types: types.map((type) => {
|
|
48
|
+
if (Array.isArray(type)) {
|
|
49
|
+
return { type: type[0], ...type[1] }
|
|
50
|
+
}
|
|
51
|
+
return { type, preferOnConflict: false }
|
|
52
|
+
}),
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function parseVariantFormatString(input) {
|
|
57
|
+
if (input.includes('{')) {
|
|
58
|
+
if (!isBalanced(input)) throw new Error(`Your { and } are unbalanced.`)
|
|
59
|
+
|
|
60
|
+
return input
|
|
61
|
+
.split(/{(.*)}/gim)
|
|
62
|
+
.flatMap((line) => parseVariantFormatString(line))
|
|
63
|
+
.filter(Boolean)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return [input.trim()]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isBalanced(input) {
|
|
70
|
+
let count = 0
|
|
71
|
+
|
|
72
|
+
for (let char of input) {
|
|
73
|
+
if (char === '{') {
|
|
74
|
+
count++
|
|
75
|
+
} else if (char === '}') {
|
|
76
|
+
if (--count < 0) {
|
|
77
|
+
return false // unbalanced
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return count === 0
|
|
83
|
+
}
|
|
19
84
|
|
|
20
85
|
function insertInto(list, value, { before = [] } = {}) {
|
|
21
86
|
before = [].concat(before)
|
|
@@ -46,39 +111,82 @@ function parseStyles(styles) {
|
|
|
46
111
|
})
|
|
47
112
|
}
|
|
48
113
|
|
|
49
|
-
function getClasses(selector) {
|
|
114
|
+
function getClasses(selector, mutate) {
|
|
50
115
|
let parser = selectorParser((selectors) => {
|
|
51
116
|
let allClasses = []
|
|
117
|
+
|
|
118
|
+
if (mutate) {
|
|
119
|
+
mutate(selectors)
|
|
120
|
+
}
|
|
121
|
+
|
|
52
122
|
selectors.walkClasses((classNode) => {
|
|
53
123
|
allClasses.push(classNode.value)
|
|
54
124
|
})
|
|
125
|
+
|
|
55
126
|
return allClasses
|
|
56
127
|
})
|
|
57
128
|
return parser.transformSync(selector)
|
|
58
129
|
}
|
|
59
130
|
|
|
60
|
-
function extractCandidates(node) {
|
|
61
|
-
let classes =
|
|
131
|
+
function extractCandidates(node, state = { containsNonOnDemandable: false }, depth = 0) {
|
|
132
|
+
let classes = []
|
|
133
|
+
|
|
134
|
+
// Handle normal rules
|
|
135
|
+
if (node.type === 'rule') {
|
|
136
|
+
// Ignore everything inside a :not(...). This allows you to write code like
|
|
137
|
+
// `div:not(.foo)`. If `.foo` is never found in your code, then we used to
|
|
138
|
+
// not generated it. But now we will ignore everything inside a `:not`, so
|
|
139
|
+
// that it still gets generated.
|
|
140
|
+
function ignoreNot(selectors) {
|
|
141
|
+
selectors.walkPseudos((pseudo) => {
|
|
142
|
+
if (pseudo.value === ':not') {
|
|
143
|
+
pseudo.remove()
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
}
|
|
62
147
|
|
|
63
|
-
|
|
148
|
+
for (let selector of node.selectors) {
|
|
149
|
+
let classCandidates = getClasses(selector, ignoreNot)
|
|
150
|
+
// At least one of the selectors contains non-"on-demandable" candidates.
|
|
151
|
+
if (classCandidates.length === 0) {
|
|
152
|
+
state.containsNonOnDemandable = true
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for (let classCandidate of classCandidates) {
|
|
156
|
+
classes.push(classCandidate)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Handle at-rules (which contains nested rules)
|
|
162
|
+
else if (node.type === 'atrule') {
|
|
64
163
|
node.walkRules((rule) => {
|
|
65
|
-
|
|
164
|
+
for (let classCandidate of rule.selectors.flatMap((selector) => getClasses(selector))) {
|
|
165
|
+
classes.push(classCandidate)
|
|
166
|
+
}
|
|
66
167
|
})
|
|
67
168
|
}
|
|
68
169
|
|
|
170
|
+
if (depth === 0) {
|
|
171
|
+
return [state.containsNonOnDemandable || classes.length === 0, classes]
|
|
172
|
+
}
|
|
173
|
+
|
|
69
174
|
return classes
|
|
70
175
|
}
|
|
71
176
|
|
|
72
177
|
function withIdentifiers(styles) {
|
|
73
178
|
return parseStyles(styles).flatMap((node) => {
|
|
74
179
|
let nodeMap = new Map()
|
|
75
|
-
let candidates = extractCandidates(node)
|
|
180
|
+
let [containsNonOnDemandableSelectors, candidates] = extractCandidates(node)
|
|
76
181
|
|
|
77
|
-
// If this isn't "on-demandable", assign it a universal candidate.
|
|
78
|
-
if (
|
|
79
|
-
|
|
182
|
+
// If this isn't "on-demandable", assign it a universal candidate to always include it.
|
|
183
|
+
if (containsNonOnDemandableSelectors) {
|
|
184
|
+
candidates.unshift(sharedState.NOT_ON_DEMAND)
|
|
80
185
|
}
|
|
81
186
|
|
|
187
|
+
// However, it could be that it also contains "on-demandable" candidates.
|
|
188
|
+
// E.g.: `span, .foo {}`, in that case it should still be possible to use
|
|
189
|
+
// `@apply foo` for example.
|
|
82
190
|
return candidates.map((c) => {
|
|
83
191
|
if (!nodeMap.has(node)) {
|
|
84
192
|
nodeMap.set(node, node)
|
|
@@ -88,65 +196,42 @@ function withIdentifiers(styles) {
|
|
|
88
196
|
})
|
|
89
197
|
}
|
|
90
198
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
['(', ')'],
|
|
95
|
-
])
|
|
96
|
-
let inverseMatchingBrackets = new Map(
|
|
97
|
-
Array.from(matchingBrackets.entries()).map(([k, v]) => [v, k])
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
let quotes = new Set(['"', "'", '`'])
|
|
101
|
-
|
|
102
|
-
// Arbitrary values must contain balanced brackets (), [] and {}. Escaped
|
|
103
|
-
// values don't count, and brackets inside quotes also don't count.
|
|
104
|
-
//
|
|
105
|
-
// E.g.: w-[this-is]w-[weird-and-invalid]
|
|
106
|
-
// E.g.: w-[this-is\\]w-\\[weird-but-valid]
|
|
107
|
-
// E.g.: content-['this-is-also-valid]-weirdly-enough']
|
|
108
|
-
function isValidArbitraryValue(value) {
|
|
109
|
-
let stack = []
|
|
110
|
-
let inQuotes = false
|
|
111
|
-
|
|
112
|
-
for (let i = 0; i < value.length; i++) {
|
|
113
|
-
let char = value[i]
|
|
114
|
-
|
|
115
|
-
// Non-escaped quotes allow us to "allow" anything in between
|
|
116
|
-
if (quotes.has(char) && value[i - 1] !== '\\') {
|
|
117
|
-
inQuotes = !inQuotes
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (inQuotes) continue
|
|
121
|
-
if (value[i - 1] === '\\') continue // Escaped
|
|
199
|
+
export function isValidVariantFormatString(format) {
|
|
200
|
+
return format.startsWith('@') || format.includes('&')
|
|
201
|
+
}
|
|
122
202
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
203
|
+
export function parseVariant(variant) {
|
|
204
|
+
variant = variant
|
|
205
|
+
.replace(/\n+/g, '')
|
|
206
|
+
.replace(/\s{1,}/g, ' ')
|
|
207
|
+
.trim()
|
|
127
208
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
209
|
+
let fns = parseVariantFormatString(variant)
|
|
210
|
+
.map((str) => {
|
|
211
|
+
if (!str.startsWith('@')) {
|
|
212
|
+
return ({ format }) => format(str)
|
|
131
213
|
}
|
|
132
214
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
}
|
|
215
|
+
let [, name, params] = /@(.*?)( .+|[({].*)/g.exec(str)
|
|
216
|
+
return ({ wrap }) => wrap(postcss.atRule({ name, params: params.trim() }))
|
|
217
|
+
})
|
|
218
|
+
.reverse()
|
|
139
219
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
220
|
+
return (api) => {
|
|
221
|
+
for (let fn of fns) {
|
|
222
|
+
fn(api)
|
|
223
|
+
}
|
|
143
224
|
}
|
|
144
|
-
|
|
145
|
-
// All good, totally balanced!
|
|
146
|
-
return true
|
|
147
225
|
}
|
|
148
226
|
|
|
149
|
-
|
|
227
|
+
/**
|
|
228
|
+
*
|
|
229
|
+
* @param {any} tailwindConfig
|
|
230
|
+
* @param {any} context
|
|
231
|
+
* @param {object} param2
|
|
232
|
+
* @param {Offsets} param2.offsets
|
|
233
|
+
*/
|
|
234
|
+
function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offsets, classList }) {
|
|
150
235
|
function getConfigValue(path, defaultValue) {
|
|
151
236
|
return path ? dlv(tailwindConfig, path, defaultValue) : tailwindConfig
|
|
152
237
|
}
|
|
@@ -156,37 +241,30 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
156
241
|
}
|
|
157
242
|
|
|
158
243
|
function prefixIdentifier(identifier, options) {
|
|
159
|
-
if (identifier ===
|
|
160
|
-
return
|
|
244
|
+
if (identifier === sharedState.NOT_ON_DEMAND) {
|
|
245
|
+
return sharedState.NOT_ON_DEMAND
|
|
161
246
|
}
|
|
162
247
|
|
|
163
248
|
if (!options.respectPrefix) {
|
|
164
249
|
return identifier
|
|
165
250
|
}
|
|
166
251
|
|
|
167
|
-
if (typeof context.tailwindConfig.prefix === 'function') {
|
|
168
|
-
return prefixSelector(context.tailwindConfig.prefix, `.${identifier}`).substr(1)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
252
|
return context.tailwindConfig.prefix + identifier
|
|
172
253
|
}
|
|
173
254
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
255
|
+
function resolveThemeValue(path, defaultValue, opts = {}) {
|
|
256
|
+
let parts = toPath(path)
|
|
257
|
+
let value = getConfigValue(['theme', ...parts], defaultValue)
|
|
258
|
+
return transformThemeValue(parts[0])(value, opts)
|
|
259
|
+
}
|
|
177
260
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
},
|
|
261
|
+
let variantIdentifier = 0
|
|
262
|
+
let api = {
|
|
181
263
|
postcss,
|
|
182
264
|
prefix: applyConfiguredPrefix,
|
|
183
265
|
e: escapeClassName,
|
|
184
266
|
config: getConfigValue,
|
|
185
|
-
theme
|
|
186
|
-
const [pathRoot, ...subPaths] = toPath(path)
|
|
187
|
-
const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
|
|
188
|
-
return transformThemeValue(pathRoot)(value)
|
|
189
|
-
},
|
|
267
|
+
theme: resolveThemeValue,
|
|
190
268
|
corePlugins: (path) => {
|
|
191
269
|
if (Array.isArray(tailwindConfig.corePlugins)) {
|
|
192
270
|
return tailwindConfig.corePlugins.includes(path)
|
|
@@ -198,21 +276,31 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
198
276
|
// Preserved for backwards compatibility but not used in v3.0+
|
|
199
277
|
return []
|
|
200
278
|
},
|
|
201
|
-
|
|
202
|
-
for (let [identifier, rule] of withIdentifiers(
|
|
203
|
-
let
|
|
279
|
+
addBase(base) {
|
|
280
|
+
for (let [identifier, rule] of withIdentifiers(base)) {
|
|
281
|
+
let prefixedIdentifier = prefixIdentifier(identifier, {})
|
|
282
|
+
let offset = offsets.create('base')
|
|
204
283
|
|
|
205
|
-
if (!context.candidateRuleMap.has(
|
|
206
|
-
context.candidateRuleMap.set(
|
|
284
|
+
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
|
|
285
|
+
context.candidateRuleMap.set(prefixedIdentifier, [])
|
|
207
286
|
}
|
|
208
287
|
|
|
209
|
-
context.candidateRuleMap
|
|
288
|
+
context.candidateRuleMap
|
|
289
|
+
.get(prefixedIdentifier)
|
|
290
|
+
.push([{ sort: offset, layer: 'base' }, rule])
|
|
210
291
|
}
|
|
211
292
|
},
|
|
212
|
-
|
|
213
|
-
|
|
293
|
+
/**
|
|
294
|
+
* @param {string} group
|
|
295
|
+
* @param {Record<string, string | string[]>} declarations
|
|
296
|
+
*/
|
|
297
|
+
addDefaults(group, declarations) {
|
|
298
|
+
const groups = {
|
|
299
|
+
[`@defaults ${group}`]: declarations,
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for (let [identifier, rule] of withIdentifiers(groups)) {
|
|
214
303
|
let prefixedIdentifier = prefixIdentifier(identifier, {})
|
|
215
|
-
let offset = offsets.base++
|
|
216
304
|
|
|
217
305
|
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
|
|
218
306
|
context.candidateRuleMap.set(prefixedIdentifier, [])
|
|
@@ -220,26 +308,22 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
220
308
|
|
|
221
309
|
context.candidateRuleMap
|
|
222
310
|
.get(prefixedIdentifier)
|
|
223
|
-
.push([{ sort:
|
|
311
|
+
.push([{ sort: offsets.create('defaults'), layer: 'defaults' }, rule])
|
|
224
312
|
}
|
|
225
313
|
},
|
|
226
314
|
addComponents(components, options) {
|
|
227
315
|
let defaultOptions = {
|
|
228
|
-
|
|
316
|
+
preserveSource: false,
|
|
229
317
|
respectPrefix: true,
|
|
230
318
|
respectImportant: false,
|
|
231
|
-
respectVariants: true,
|
|
232
319
|
}
|
|
233
320
|
|
|
234
|
-
options = Object.assign(
|
|
235
|
-
{},
|
|
236
|
-
defaultOptions,
|
|
237
|
-
Array.isArray(options) ? { variants: options } : options
|
|
238
|
-
)
|
|
321
|
+
options = Object.assign({}, defaultOptions, Array.isArray(options) ? {} : options)
|
|
239
322
|
|
|
240
323
|
for (let [identifier, rule] of withIdentifiers(components)) {
|
|
241
324
|
let prefixedIdentifier = prefixIdentifier(identifier, options)
|
|
242
|
-
|
|
325
|
+
|
|
326
|
+
classList.add(prefixedIdentifier)
|
|
243
327
|
|
|
244
328
|
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
|
|
245
329
|
context.candidateRuleMap.set(prefixedIdentifier, [])
|
|
@@ -247,26 +331,22 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
247
331
|
|
|
248
332
|
context.candidateRuleMap
|
|
249
333
|
.get(prefixedIdentifier)
|
|
250
|
-
.push([{ sort:
|
|
334
|
+
.push([{ sort: offsets.create('components'), layer: 'components', options }, rule])
|
|
251
335
|
}
|
|
252
336
|
},
|
|
253
337
|
addUtilities(utilities, options) {
|
|
254
338
|
let defaultOptions = {
|
|
255
|
-
|
|
339
|
+
preserveSource: false,
|
|
256
340
|
respectPrefix: true,
|
|
257
341
|
respectImportant: true,
|
|
258
|
-
respectVariants: true,
|
|
259
342
|
}
|
|
260
343
|
|
|
261
|
-
options = Object.assign(
|
|
262
|
-
{},
|
|
263
|
-
defaultOptions,
|
|
264
|
-
Array.isArray(options) ? { variants: options } : options
|
|
265
|
-
)
|
|
344
|
+
options = Object.assign({}, defaultOptions, Array.isArray(options) ? {} : options)
|
|
266
345
|
|
|
267
346
|
for (let [identifier, rule] of withIdentifiers(utilities)) {
|
|
268
347
|
let prefixedIdentifier = prefixIdentifier(identifier, options)
|
|
269
|
-
|
|
348
|
+
|
|
349
|
+
classList.add(prefixedIdentifier)
|
|
270
350
|
|
|
271
351
|
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
|
|
272
352
|
context.candidateRuleMap.set(prefixedIdentifier, [])
|
|
@@ -274,53 +354,78 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
274
354
|
|
|
275
355
|
context.candidateRuleMap
|
|
276
356
|
.get(prefixedIdentifier)
|
|
277
|
-
.push([{ sort:
|
|
357
|
+
.push([{ sort: offsets.create('utilities'), layer: 'utilities', options }, rule])
|
|
278
358
|
}
|
|
279
359
|
},
|
|
280
360
|
matchUtilities: function (utilities, options) {
|
|
281
361
|
let defaultOptions = {
|
|
282
|
-
variants: [],
|
|
283
362
|
respectPrefix: true,
|
|
284
363
|
respectImportant: true,
|
|
285
|
-
|
|
364
|
+
modifiers: false,
|
|
286
365
|
}
|
|
287
366
|
|
|
288
|
-
options = { ...defaultOptions, ...options }
|
|
367
|
+
options = normalizeOptionTypes({ ...defaultOptions, ...options })
|
|
289
368
|
|
|
290
|
-
let offset = offsets.utilities
|
|
369
|
+
let offset = offsets.create('utilities')
|
|
291
370
|
|
|
292
371
|
for (let identifier in utilities) {
|
|
293
372
|
let prefixedIdentifier = prefixIdentifier(identifier, options)
|
|
294
373
|
let rule = utilities[identifier]
|
|
295
374
|
|
|
296
|
-
|
|
297
|
-
let { type = 'any' } = options
|
|
298
|
-
type = [].concat(type)
|
|
299
|
-
let [value, coercedType] = coerceValue(type, modifier, options.values, tailwindConfig)
|
|
375
|
+
classList.add([prefixedIdentifier, options])
|
|
300
376
|
|
|
301
|
-
|
|
377
|
+
function wrapped(modifier, { isOnlyPlugin }) {
|
|
378
|
+
let [value, coercedType, utilityModifier] = coerceValue(
|
|
379
|
+
options.types,
|
|
380
|
+
modifier,
|
|
381
|
+
options,
|
|
382
|
+
tailwindConfig
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
if (value === undefined) {
|
|
302
386
|
return []
|
|
303
387
|
}
|
|
304
388
|
|
|
305
|
-
if (!
|
|
389
|
+
if (!options.types.some(({ type }) => type === coercedType)) {
|
|
390
|
+
if (isOnlyPlugin) {
|
|
391
|
+
log.warn([
|
|
392
|
+
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
|
|
393
|
+
`You can safely update it to \`${identifier}-${modifier.replace(
|
|
394
|
+
coercedType + ':',
|
|
395
|
+
''
|
|
396
|
+
)}\`.`,
|
|
397
|
+
])
|
|
398
|
+
} else {
|
|
399
|
+
return []
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (!isSyntacticallyValidPropertyValue(value)) {
|
|
306
404
|
return []
|
|
307
405
|
}
|
|
308
406
|
|
|
309
|
-
let
|
|
407
|
+
let extras = {
|
|
408
|
+
get modifier() {
|
|
409
|
+
if (!options.modifiers) {
|
|
410
|
+
log.warn(`modifier-used-without-options-for-${identifier}`, [
|
|
411
|
+
'Your plugin must set `modifiers: true` in its options to support modifiers.',
|
|
412
|
+
])
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return utilityModifier
|
|
416
|
+
},
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
|
|
420
|
+
|
|
310
421
|
let ruleSets = []
|
|
311
|
-
.concat(
|
|
312
|
-
rule(value, {
|
|
313
|
-
includeRules(rules) {
|
|
314
|
-
includedRules.push(...rules)
|
|
315
|
-
},
|
|
316
|
-
})
|
|
317
|
-
)
|
|
422
|
+
.concat(modifiersEnabled ? rule(value, extras) : rule(value))
|
|
318
423
|
.filter(Boolean)
|
|
319
424
|
.map((declaration) => ({
|
|
320
425
|
[nameClass(identifier, modifier)]: declaration,
|
|
321
426
|
}))
|
|
322
427
|
|
|
323
|
-
return
|
|
428
|
+
return ruleSets
|
|
324
429
|
}
|
|
325
430
|
|
|
326
431
|
let withOffsets = [{ sort: offset, layer: 'utilities', options }, wrapped]
|
|
@@ -332,7 +437,189 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
|
|
|
332
437
|
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
|
|
333
438
|
}
|
|
334
439
|
},
|
|
440
|
+
matchComponents: function (components, options) {
|
|
441
|
+
let defaultOptions = {
|
|
442
|
+
respectPrefix: true,
|
|
443
|
+
respectImportant: false,
|
|
444
|
+
modifiers: false,
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
options = normalizeOptionTypes({ ...defaultOptions, ...options })
|
|
448
|
+
|
|
449
|
+
let offset = offsets.create('components')
|
|
450
|
+
|
|
451
|
+
for (let identifier in components) {
|
|
452
|
+
let prefixedIdentifier = prefixIdentifier(identifier, options)
|
|
453
|
+
let rule = components[identifier]
|
|
454
|
+
|
|
455
|
+
classList.add([prefixedIdentifier, options])
|
|
456
|
+
|
|
457
|
+
function wrapped(modifier, { isOnlyPlugin }) {
|
|
458
|
+
let [value, coercedType, utilityModifier] = coerceValue(
|
|
459
|
+
options.types,
|
|
460
|
+
modifier,
|
|
461
|
+
options,
|
|
462
|
+
tailwindConfig
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
if (value === undefined) {
|
|
466
|
+
return []
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (!options.types.some(({ type }) => type === coercedType)) {
|
|
470
|
+
if (isOnlyPlugin) {
|
|
471
|
+
log.warn([
|
|
472
|
+
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
|
|
473
|
+
`You can safely update it to \`${identifier}-${modifier.replace(
|
|
474
|
+
coercedType + ':',
|
|
475
|
+
''
|
|
476
|
+
)}\`.`,
|
|
477
|
+
])
|
|
478
|
+
} else {
|
|
479
|
+
return []
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (!isSyntacticallyValidPropertyValue(value)) {
|
|
484
|
+
return []
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
let extras = {
|
|
488
|
+
get modifier() {
|
|
489
|
+
if (!options.modifiers) {
|
|
490
|
+
log.warn(`modifier-used-without-options-for-${identifier}`, [
|
|
491
|
+
'Your plugin must set `modifiers: true` in its options to support modifiers.',
|
|
492
|
+
])
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return utilityModifier
|
|
496
|
+
},
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
|
|
500
|
+
|
|
501
|
+
let ruleSets = []
|
|
502
|
+
.concat(modifiersEnabled ? rule(value, extras) : rule(value))
|
|
503
|
+
.filter(Boolean)
|
|
504
|
+
.map((declaration) => ({
|
|
505
|
+
[nameClass(identifier, modifier)]: declaration,
|
|
506
|
+
}))
|
|
507
|
+
|
|
508
|
+
return ruleSets
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
let withOffsets = [{ sort: offset, layer: 'components', options }, wrapped]
|
|
512
|
+
|
|
513
|
+
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
|
|
514
|
+
context.candidateRuleMap.set(prefixedIdentifier, [])
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
addVariant(variantName, variantFunctions, options = {}) {
|
|
521
|
+
variantFunctions = [].concat(variantFunctions).map((variantFunction) => {
|
|
522
|
+
if (typeof variantFunction !== 'string') {
|
|
523
|
+
// Safelist public API functions
|
|
524
|
+
return (api = {}) => {
|
|
525
|
+
let { args, modifySelectors, container, separator, wrap, format } = api
|
|
526
|
+
let result = variantFunction(
|
|
527
|
+
Object.assign(
|
|
528
|
+
{ modifySelectors, container, separator },
|
|
529
|
+
options.type === VARIANT_TYPES.MatchVariant && { args, wrap, format }
|
|
530
|
+
)
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
if (typeof result === 'string' && !isValidVariantFormatString(result)) {
|
|
534
|
+
throw new Error(
|
|
535
|
+
`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`
|
|
536
|
+
)
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (Array.isArray(result)) {
|
|
540
|
+
return result
|
|
541
|
+
.filter((variant) => typeof variant === 'string')
|
|
542
|
+
.map((variant) => parseVariant(variant))
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// result may be undefined with legacy variants that use APIs like `modifySelectors`
|
|
546
|
+
// result may also be a postcss node if someone was returning the result from `modifySelectors`
|
|
547
|
+
return result && typeof result === 'string' && parseVariant(result)(api)
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (!isValidVariantFormatString(variantFunction)) {
|
|
552
|
+
throw new Error(
|
|
553
|
+
`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`
|
|
554
|
+
)
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
return parseVariant(variantFunction)
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
insertInto(variantList, variantName, options)
|
|
561
|
+
variantMap.set(variantName, variantFunctions)
|
|
562
|
+
context.variantOptions.set(variantName, options)
|
|
563
|
+
},
|
|
564
|
+
matchVariant(variant, variantFn, options) {
|
|
565
|
+
// A unique identifier that "groups" these variants together.
|
|
566
|
+
// This is for internal use only which is why it is not present in the types
|
|
567
|
+
let id = options?.id ?? ++variantIdentifier
|
|
568
|
+
let isSpecial = variant === '@'
|
|
569
|
+
|
|
570
|
+
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
|
|
571
|
+
|
|
572
|
+
for (let [key, value] of Object.entries(options?.values ?? {})) {
|
|
573
|
+
if (key === 'DEFAULT') continue
|
|
574
|
+
|
|
575
|
+
api.addVariant(
|
|
576
|
+
isSpecial ? `${variant}${key}` : `${variant}-${key}`,
|
|
577
|
+
({ args, container }) => {
|
|
578
|
+
return variantFn(
|
|
579
|
+
value,
|
|
580
|
+
modifiersEnabled ? { modifier: args?.modifier, container } : { container }
|
|
581
|
+
)
|
|
582
|
+
},
|
|
583
|
+
|
|
584
|
+
{
|
|
585
|
+
...options,
|
|
586
|
+
value,
|
|
587
|
+
id,
|
|
588
|
+
type: VARIANT_TYPES.MatchVariant,
|
|
589
|
+
variantInfo: VARIANT_INFO.Base,
|
|
590
|
+
}
|
|
591
|
+
)
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
let hasDefault = 'DEFAULT' in (options?.values ?? {})
|
|
595
|
+
|
|
596
|
+
api.addVariant(
|
|
597
|
+
variant,
|
|
598
|
+
({ args, container }) => {
|
|
599
|
+
if (args?.value === sharedState.NONE && !hasDefault) {
|
|
600
|
+
return null
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
return variantFn(
|
|
604
|
+
args?.value === sharedState.NONE
|
|
605
|
+
? options.values.DEFAULT
|
|
606
|
+
: // Falling back to args if it is a string, otherwise '' for older intellisense
|
|
607
|
+
// (JetBrains) plugins.
|
|
608
|
+
args?.value ?? (typeof args === 'string' ? args : ''),
|
|
609
|
+
modifiersEnabled ? { modifier: args?.modifier, container } : { container }
|
|
610
|
+
)
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
...options,
|
|
614
|
+
id,
|
|
615
|
+
type: VARIANT_TYPES.MatchVariant,
|
|
616
|
+
variantInfo: VARIANT_INFO.Dynamic,
|
|
617
|
+
}
|
|
618
|
+
)
|
|
619
|
+
},
|
|
335
620
|
}
|
|
621
|
+
|
|
622
|
+
return api
|
|
336
623
|
}
|
|
337
624
|
|
|
338
625
|
let fileModifiedMapCache = new WeakMap()
|
|
@@ -352,7 +639,14 @@ function trackModified(files, fileModifiedMap) {
|
|
|
352
639
|
let parsed = url.parse(file)
|
|
353
640
|
let pathname = parsed.hash ? parsed.href.replace(parsed.hash, '') : parsed.href
|
|
354
641
|
pathname = parsed.search ? pathname.replace(parsed.search, '') : pathname
|
|
355
|
-
let newModified = fs.statSync(decodeURIComponent(pathname))
|
|
642
|
+
let newModified = fs.statSync(decodeURIComponent(pathname), { throwIfNoEntry: false })?.mtimeMs
|
|
643
|
+
if (!newModified) {
|
|
644
|
+
// It could happen that a file is passed in that doesn't exist. E.g.:
|
|
645
|
+
// postcss-cli will provide you a fake path when reading from stdin. This
|
|
646
|
+
// path then looks like /path-to-your-project/stdin In that case we just
|
|
647
|
+
// want to ignore it and don't track changes at all.
|
|
648
|
+
continue
|
|
649
|
+
}
|
|
356
650
|
|
|
357
651
|
if (!fileModifiedMap.has(file) || newModified > fileModifiedMap.get(file)) {
|
|
358
652
|
changed = true
|
|
@@ -398,34 +692,25 @@ function collectLayerPlugins(root) {
|
|
|
398
692
|
} else if (layerRule.params === 'components') {
|
|
399
693
|
for (let node of layerRule.nodes) {
|
|
400
694
|
layerPlugins.push(function ({ addComponents }) {
|
|
401
|
-
addComponents(node, { respectPrefix: false })
|
|
695
|
+
addComponents(node, { respectPrefix: false, preserveSource: true })
|
|
402
696
|
})
|
|
403
697
|
}
|
|
404
698
|
layerRule.remove()
|
|
405
699
|
} else if (layerRule.params === 'utilities') {
|
|
406
700
|
for (let node of layerRule.nodes) {
|
|
407
701
|
layerPlugins.push(function ({ addUtilities }) {
|
|
408
|
-
addUtilities(node, { respectPrefix: false })
|
|
702
|
+
addUtilities(node, { respectPrefix: false, preserveSource: true })
|
|
409
703
|
})
|
|
410
704
|
}
|
|
411
705
|
layerRule.remove()
|
|
412
706
|
}
|
|
413
707
|
})
|
|
414
708
|
|
|
415
|
-
root.walkRules((rule) => {
|
|
416
|
-
// At this point it is safe to include all the left-over css from the
|
|
417
|
-
// user's css file. This is because the `@tailwind` and `@layer` directives
|
|
418
|
-
// will already be handled and will be removed from the css tree.
|
|
419
|
-
layerPlugins.push(function ({ addUserCss }) {
|
|
420
|
-
addUserCss(rule, { respectPrefix: false })
|
|
421
|
-
})
|
|
422
|
-
})
|
|
423
|
-
|
|
424
709
|
return layerPlugins
|
|
425
710
|
}
|
|
426
711
|
|
|
427
|
-
function resolvePlugins(context,
|
|
428
|
-
let corePluginList = Object.entries(corePlugins)
|
|
712
|
+
function resolvePlugins(context, root) {
|
|
713
|
+
let corePluginList = Object.entries({ ...variantPlugins, ...corePlugins })
|
|
429
714
|
.map(([name, plugin]) => {
|
|
430
715
|
if (!context.tailwindConfig.corePlugins.includes(name)) {
|
|
431
716
|
return null
|
|
@@ -443,16 +728,25 @@ function resolvePlugins(context, tailwindDirectives, root) {
|
|
|
443
728
|
return typeof plugin === 'function' ? plugin : plugin.handler
|
|
444
729
|
})
|
|
445
730
|
|
|
446
|
-
let layerPlugins = collectLayerPlugins(root
|
|
731
|
+
let layerPlugins = collectLayerPlugins(root)
|
|
447
732
|
|
|
448
733
|
// TODO: This is a workaround for backwards compatibility, since custom variants
|
|
449
734
|
// were historically sorted before screen/stackable variants.
|
|
450
|
-
let beforeVariants = [
|
|
735
|
+
let beforeVariants = [
|
|
736
|
+
variantPlugins['pseudoElementVariants'],
|
|
737
|
+
variantPlugins['pseudoClassVariants'],
|
|
738
|
+
variantPlugins['ariaVariants'],
|
|
739
|
+
variantPlugins['dataVariants'],
|
|
740
|
+
]
|
|
451
741
|
let afterVariants = [
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
742
|
+
variantPlugins['supportsVariants'],
|
|
743
|
+
variantPlugins['directionVariants'],
|
|
744
|
+
variantPlugins['reducedMotionVariants'],
|
|
745
|
+
variantPlugins['prefersContrastVariants'],
|
|
746
|
+
variantPlugins['darkVariants'],
|
|
747
|
+
variantPlugins['printVariant'],
|
|
748
|
+
variantPlugins['screenVariants'],
|
|
749
|
+
variantPlugins['orientationVariants'],
|
|
456
750
|
]
|
|
457
751
|
|
|
458
752
|
return [...corePluginList, ...beforeVariants, ...userPlugins, ...afterVariants, ...layerPlugins]
|
|
@@ -461,17 +755,18 @@ function resolvePlugins(context, tailwindDirectives, root) {
|
|
|
461
755
|
function registerPlugins(plugins, context) {
|
|
462
756
|
let variantList = []
|
|
463
757
|
let variantMap = new Map()
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
758
|
+
context.variantMap = variantMap
|
|
759
|
+
|
|
760
|
+
let offsets = new Offsets()
|
|
761
|
+
context.offsets = offsets
|
|
762
|
+
|
|
763
|
+
let classList = new Set()
|
|
470
764
|
|
|
471
765
|
let pluginApi = buildPluginApi(context.tailwindConfig, context, {
|
|
472
766
|
variantList,
|
|
473
767
|
variantMap,
|
|
474
768
|
offsets,
|
|
769
|
+
classList,
|
|
475
770
|
})
|
|
476
771
|
|
|
477
772
|
for (let plugin of plugins) {
|
|
@@ -484,68 +779,400 @@ function registerPlugins(plugins, context) {
|
|
|
484
779
|
}
|
|
485
780
|
}
|
|
486
781
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
offsets.components,
|
|
490
|
-
offsets.utilities,
|
|
491
|
-
offsets.user,
|
|
492
|
-
])
|
|
493
|
-
let reservedBits = BigInt(highestOffset.toString(2).length)
|
|
494
|
-
|
|
495
|
-
context.layerOrder = {
|
|
496
|
-
base: (1n << reservedBits) << 0n,
|
|
497
|
-
components: (1n << reservedBits) << 1n,
|
|
498
|
-
utilities: (1n << reservedBits) << 2n,
|
|
499
|
-
user: (1n << reservedBits) << 3n,
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
reservedBits += 4n
|
|
503
|
-
|
|
504
|
-
let offset = 0
|
|
505
|
-
context.variantOrder = new Map(
|
|
506
|
-
variantList
|
|
507
|
-
.map((variant, i) => {
|
|
508
|
-
let variantFunctions = variantMap.get(variant).length
|
|
509
|
-
let bits = (1n << BigInt(i + offset)) << reservedBits
|
|
510
|
-
offset += variantFunctions - 1
|
|
511
|
-
return [variant, bits]
|
|
512
|
-
})
|
|
513
|
-
.sort(([, a], [, z]) => bigSign(a - z))
|
|
514
|
-
)
|
|
515
|
-
|
|
516
|
-
context.minimumScreen = [...context.variantOrder.values()].shift()
|
|
782
|
+
// Make sure to record bit masks for every variant
|
|
783
|
+
offsets.recordVariants(variantList, (variant) => variantMap.get(variant).length)
|
|
517
784
|
|
|
518
785
|
// Build variantMap
|
|
519
786
|
for (let [variantName, variantFunctions] of variantMap.entries()) {
|
|
520
|
-
let sort = context.variantOrder.get(variantName)
|
|
521
787
|
context.variantMap.set(
|
|
522
788
|
variantName,
|
|
523
|
-
variantFunctions.map((variantFunction, idx) => [
|
|
789
|
+
variantFunctions.map((variantFunction, idx) => [
|
|
790
|
+
offsets.forVariant(variantName, idx),
|
|
791
|
+
variantFunction,
|
|
792
|
+
])
|
|
524
793
|
)
|
|
525
794
|
}
|
|
795
|
+
|
|
796
|
+
let safelist = (context.tailwindConfig.safelist ?? []).filter(Boolean)
|
|
797
|
+
if (safelist.length > 0) {
|
|
798
|
+
let checks = []
|
|
799
|
+
|
|
800
|
+
for (let value of safelist) {
|
|
801
|
+
if (typeof value === 'string') {
|
|
802
|
+
context.changedContent.push({ content: value, extension: 'html' })
|
|
803
|
+
continue
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (value instanceof RegExp) {
|
|
807
|
+
log.warn('root-regex', [
|
|
808
|
+
'Regular expressions in `safelist` work differently in Tailwind CSS v3.0.',
|
|
809
|
+
'Update your `safelist` configuration to eliminate this warning.',
|
|
810
|
+
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
|
|
811
|
+
])
|
|
812
|
+
continue
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
checks.push(value)
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
if (checks.length > 0) {
|
|
819
|
+
let patternMatchingCount = new Map()
|
|
820
|
+
let prefixLength = context.tailwindConfig.prefix.length
|
|
821
|
+
let checkImportantUtils = checks.some((check) => check.pattern.source.includes('!'))
|
|
822
|
+
|
|
823
|
+
for (let util of classList) {
|
|
824
|
+
let utils = Array.isArray(util)
|
|
825
|
+
? (() => {
|
|
826
|
+
let [utilName, options] = util
|
|
827
|
+
let values = Object.keys(options?.values ?? {})
|
|
828
|
+
let classes = values.map((value) => formatClass(utilName, value))
|
|
829
|
+
|
|
830
|
+
if (options?.supportsNegativeValues) {
|
|
831
|
+
// This is the normal negated version
|
|
832
|
+
// e.g. `-inset-1` or `-tw-inset-1`
|
|
833
|
+
classes = [...classes, ...classes.map((cls) => '-' + cls)]
|
|
834
|
+
|
|
835
|
+
// This is the negated version *after* the prefix
|
|
836
|
+
// e.g. `tw--inset-1`
|
|
837
|
+
// The prefix is already attached to util name
|
|
838
|
+
// So we add the negative after the prefix
|
|
839
|
+
classes = [
|
|
840
|
+
...classes,
|
|
841
|
+
...classes.map(
|
|
842
|
+
(cls) => cls.slice(0, prefixLength) + '-' + cls.slice(prefixLength)
|
|
843
|
+
),
|
|
844
|
+
]
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (options.types.some(({ type }) => type === 'color')) {
|
|
848
|
+
classes = [
|
|
849
|
+
...classes,
|
|
850
|
+
...classes.flatMap((cls) =>
|
|
851
|
+
Object.keys(context.tailwindConfig.theme.opacity).map(
|
|
852
|
+
(opacity) => `${cls}/${opacity}`
|
|
853
|
+
)
|
|
854
|
+
),
|
|
855
|
+
]
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
if (checkImportantUtils && options?.respectImportant) {
|
|
859
|
+
classes = [...classes, ...classes.map((cls) => '!' + cls)]
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return classes
|
|
863
|
+
})()
|
|
864
|
+
: [util]
|
|
865
|
+
|
|
866
|
+
for (let util of utils) {
|
|
867
|
+
for (let { pattern, variants = [] } of checks) {
|
|
868
|
+
// RegExp with the /g flag are stateful, so let's reset the last
|
|
869
|
+
// index pointer to reset the state.
|
|
870
|
+
pattern.lastIndex = 0
|
|
871
|
+
|
|
872
|
+
if (!patternMatchingCount.has(pattern)) {
|
|
873
|
+
patternMatchingCount.set(pattern, 0)
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
if (!pattern.test(util)) continue
|
|
877
|
+
|
|
878
|
+
patternMatchingCount.set(pattern, patternMatchingCount.get(pattern) + 1)
|
|
879
|
+
|
|
880
|
+
context.changedContent.push({ content: util, extension: 'html' })
|
|
881
|
+
for (let variant of variants) {
|
|
882
|
+
context.changedContent.push({
|
|
883
|
+
content: variant + context.tailwindConfig.separator + util,
|
|
884
|
+
extension: 'html',
|
|
885
|
+
})
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
for (let [regex, count] of patternMatchingCount.entries()) {
|
|
892
|
+
if (count !== 0) continue
|
|
893
|
+
|
|
894
|
+
log.warn([
|
|
895
|
+
`The safelist pattern \`${regex}\` doesn't match any Tailwind CSS classes.`,
|
|
896
|
+
'Fix this pattern or remove it from your `safelist` configuration.',
|
|
897
|
+
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
|
|
898
|
+
])
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
let darkClassName = [].concat(context.tailwindConfig.darkMode ?? 'media')[1] ?? 'dark'
|
|
904
|
+
|
|
905
|
+
// A list of utilities that are used by certain Tailwind CSS utilities but
|
|
906
|
+
// that don't exist on their own. This will result in them "not existing" and
|
|
907
|
+
// sorting could be weird since you still require them in order to make the
|
|
908
|
+
// host utilities work properly. (Thanks Biology)
|
|
909
|
+
let parasiteUtilities = [
|
|
910
|
+
prefix(context, darkClassName),
|
|
911
|
+
prefix(context, 'group'),
|
|
912
|
+
prefix(context, 'peer'),
|
|
913
|
+
]
|
|
914
|
+
context.getClassOrder = function getClassOrder(classes) {
|
|
915
|
+
// Non-util classes won't be generated, so we default them to null
|
|
916
|
+
let sortedClassNames = new Map(classes.map((className) => [className, null]))
|
|
917
|
+
|
|
918
|
+
// Sort all classes in order
|
|
919
|
+
// Non-tailwind classes won't be generated and will be left as `null`
|
|
920
|
+
let rules = generateRules(new Set(classes), context)
|
|
921
|
+
rules = context.offsets.sort(rules)
|
|
922
|
+
|
|
923
|
+
let idx = BigInt(parasiteUtilities.length)
|
|
924
|
+
|
|
925
|
+
for (const [, rule] of rules) {
|
|
926
|
+
sortedClassNames.set(rule.raws.tailwind.candidate, idx++)
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
return classes.map((className) => {
|
|
930
|
+
let order = sortedClassNames.get(className) ?? null
|
|
931
|
+
let parasiteIndex = parasiteUtilities.indexOf(className)
|
|
932
|
+
|
|
933
|
+
if (order === null && parasiteIndex !== -1) {
|
|
934
|
+
// This will make sure that it is at the very beginning of the
|
|
935
|
+
// `components` layer which technically means 'before any
|
|
936
|
+
// components'.
|
|
937
|
+
order = BigInt(parasiteIndex)
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
return [className, order]
|
|
941
|
+
})
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// Generate a list of strings for autocompletion purposes, e.g.
|
|
945
|
+
// ['uppercase', 'lowercase', ...]
|
|
946
|
+
context.getClassList = function getClassList() {
|
|
947
|
+
let output = []
|
|
948
|
+
|
|
949
|
+
for (let util of classList) {
|
|
950
|
+
if (Array.isArray(util)) {
|
|
951
|
+
let [utilName, options] = util
|
|
952
|
+
let negativeClasses = []
|
|
953
|
+
|
|
954
|
+
for (let [key, value] of Object.entries(options?.values ?? {})) {
|
|
955
|
+
// Ignore undefined and null values
|
|
956
|
+
if (value == null) {
|
|
957
|
+
continue
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
output.push(formatClass(utilName, key))
|
|
961
|
+
if (options?.supportsNegativeValues && negateValue(value)) {
|
|
962
|
+
negativeClasses.push(formatClass(utilName, `-${key}`))
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
output.push(...negativeClasses)
|
|
967
|
+
} else {
|
|
968
|
+
output.push(util)
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
return output
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// Generate a list of available variants with meta information of the type of variant.
|
|
976
|
+
context.getVariants = function getVariants() {
|
|
977
|
+
let result = []
|
|
978
|
+
for (let [name, options] of context.variantOptions.entries()) {
|
|
979
|
+
if (options.variantInfo === VARIANT_INFO.Base) continue
|
|
980
|
+
|
|
981
|
+
result.push({
|
|
982
|
+
name,
|
|
983
|
+
isArbitrary: options.type === Symbol.for('MATCH_VARIANT'),
|
|
984
|
+
values: Object.keys(options.values ?? {}),
|
|
985
|
+
hasDash: name !== '@',
|
|
986
|
+
selectors({ modifier, value } = {}) {
|
|
987
|
+
let candidate = '__TAILWIND_PLACEHOLDER__'
|
|
988
|
+
|
|
989
|
+
let rule = postcss.rule({ selector: `.${candidate}` })
|
|
990
|
+
let container = postcss.root({ nodes: [rule.clone()] })
|
|
991
|
+
|
|
992
|
+
let before = container.toString()
|
|
993
|
+
|
|
994
|
+
let fns = (context.variantMap.get(name) ?? []).flatMap(([_, fn]) => fn)
|
|
995
|
+
let formatStrings = []
|
|
996
|
+
for (let fn of fns) {
|
|
997
|
+
let localFormatStrings = []
|
|
998
|
+
|
|
999
|
+
let api = {
|
|
1000
|
+
args: { modifier, value: options.values?.[value] ?? value },
|
|
1001
|
+
separator: context.tailwindConfig.separator,
|
|
1002
|
+
modifySelectors(modifierFunction) {
|
|
1003
|
+
// Run the modifierFunction over each rule
|
|
1004
|
+
container.each((rule) => {
|
|
1005
|
+
if (rule.type !== 'rule') {
|
|
1006
|
+
return
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
rule.selectors = rule.selectors.map((selector) => {
|
|
1010
|
+
return modifierFunction({
|
|
1011
|
+
get className() {
|
|
1012
|
+
return getClassNameFromSelector(selector)
|
|
1013
|
+
},
|
|
1014
|
+
selector,
|
|
1015
|
+
})
|
|
1016
|
+
})
|
|
1017
|
+
})
|
|
1018
|
+
|
|
1019
|
+
return container
|
|
1020
|
+
},
|
|
1021
|
+
format(str) {
|
|
1022
|
+
localFormatStrings.push(str)
|
|
1023
|
+
},
|
|
1024
|
+
wrap(wrapper) {
|
|
1025
|
+
localFormatStrings.push(`@${wrapper.name} ${wrapper.params} { & }`)
|
|
1026
|
+
},
|
|
1027
|
+
container,
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
let ruleWithVariant = fn(api)
|
|
1031
|
+
if (localFormatStrings.length > 0) {
|
|
1032
|
+
formatStrings.push(localFormatStrings)
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
if (Array.isArray(ruleWithVariant)) {
|
|
1036
|
+
for (let variantFunction of ruleWithVariant) {
|
|
1037
|
+
localFormatStrings = []
|
|
1038
|
+
variantFunction(api)
|
|
1039
|
+
formatStrings.push(localFormatStrings)
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// Reverse engineer the result of the `container`
|
|
1045
|
+
let manualFormatStrings = []
|
|
1046
|
+
let after = container.toString()
|
|
1047
|
+
|
|
1048
|
+
if (before !== after) {
|
|
1049
|
+
// Figure out all selectors
|
|
1050
|
+
container.walkRules((rule) => {
|
|
1051
|
+
let modified = rule.selector
|
|
1052
|
+
|
|
1053
|
+
// Rebuild the base selector, this is what plugin authors would do
|
|
1054
|
+
// as well. E.g.: `${variant}${separator}${className}`.
|
|
1055
|
+
// However, plugin authors probably also prepend or append certain
|
|
1056
|
+
// classes, pseudos, ids, ...
|
|
1057
|
+
let rebuiltBase = selectorParser((selectors) => {
|
|
1058
|
+
selectors.walkClasses((classNode) => {
|
|
1059
|
+
classNode.value = `${name}${context.tailwindConfig.separator}${classNode.value}`
|
|
1060
|
+
})
|
|
1061
|
+
}).processSync(modified)
|
|
1062
|
+
|
|
1063
|
+
// Now that we know the original selector, the new selector, and
|
|
1064
|
+
// the rebuild part in between, we can replace the part that plugin
|
|
1065
|
+
// authors need to rebuild with `&`, and eventually store it in the
|
|
1066
|
+
// collectedFormats. Similar to what `format('...')` would do.
|
|
1067
|
+
//
|
|
1068
|
+
// E.g.:
|
|
1069
|
+
// variant: foo
|
|
1070
|
+
// selector: .markdown > p
|
|
1071
|
+
// modified (by plugin): .foo .foo\\:markdown > p
|
|
1072
|
+
// rebuiltBase (internal): .foo\\:markdown > p
|
|
1073
|
+
// format: .foo &
|
|
1074
|
+
manualFormatStrings.push(modified.replace(rebuiltBase, '&').replace(candidate, '&'))
|
|
1075
|
+
})
|
|
1076
|
+
|
|
1077
|
+
// Figure out all atrules
|
|
1078
|
+
container.walkAtRules((atrule) => {
|
|
1079
|
+
manualFormatStrings.push(`@${atrule.name} (${atrule.params}) { & }`)
|
|
1080
|
+
})
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
let result = formatStrings.map((formatString) =>
|
|
1084
|
+
finalizeSelector(formatVariantSelector('&', ...formatString), {
|
|
1085
|
+
selector: `.${candidate}`,
|
|
1086
|
+
candidate,
|
|
1087
|
+
context,
|
|
1088
|
+
isArbitraryVariant: !(value in (options.values ?? {})),
|
|
1089
|
+
})
|
|
1090
|
+
.replace(`.${candidate}`, '&')
|
|
1091
|
+
.replace('{ & }', '')
|
|
1092
|
+
.trim()
|
|
1093
|
+
)
|
|
1094
|
+
|
|
1095
|
+
if (manualFormatStrings.length > 0) {
|
|
1096
|
+
result.push(formatVariantSelector('&', ...manualFormatStrings))
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
return result
|
|
1100
|
+
},
|
|
1101
|
+
})
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
return result
|
|
1105
|
+
}
|
|
526
1106
|
}
|
|
527
1107
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
1108
|
+
/**
|
|
1109
|
+
* Mark as class as retroactively invalid
|
|
1110
|
+
*
|
|
1111
|
+
*
|
|
1112
|
+
* @param {string} candidate
|
|
1113
|
+
*/
|
|
1114
|
+
function markInvalidUtilityCandidate(context, candidate) {
|
|
1115
|
+
if (!context.classCache.has(candidate)) {
|
|
1116
|
+
return
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// Mark this as not being a real utility
|
|
1120
|
+
context.notClassCache.add(candidate)
|
|
1121
|
+
|
|
1122
|
+
// Remove it from any candidate-specific caches
|
|
1123
|
+
context.classCache.delete(candidate)
|
|
1124
|
+
context.applyClassCache.delete(candidate)
|
|
1125
|
+
context.candidateRuleMap.delete(candidate)
|
|
1126
|
+
context.candidateRuleCache.delete(candidate)
|
|
1127
|
+
|
|
1128
|
+
// Ensure the stylesheet gets rebuilt
|
|
1129
|
+
context.stylesheetCache = null
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
/**
|
|
1133
|
+
* Mark as class as retroactively invalid
|
|
1134
|
+
*
|
|
1135
|
+
* @param {import('postcss').Node} node
|
|
1136
|
+
*/
|
|
1137
|
+
function markInvalidUtilityNode(context, node) {
|
|
1138
|
+
let candidate = node.raws.tailwind.candidate
|
|
1139
|
+
|
|
1140
|
+
if (!candidate) {
|
|
1141
|
+
return
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
for (const entry of context.ruleCache) {
|
|
1145
|
+
if (entry[1].raws.tailwind.candidate === candidate) {
|
|
1146
|
+
context.ruleCache.delete(entry)
|
|
1147
|
+
// context.postCssNodeCache.delete(node)
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
markInvalidUtilityCandidate(context, candidate)
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
export function createContext(tailwindConfig, changedContent = [], root = postcss.root()) {
|
|
534
1155
|
let context = {
|
|
535
1156
|
disposables: [],
|
|
536
1157
|
ruleCache: new Set(),
|
|
1158
|
+
candidateRuleCache: new Map(),
|
|
537
1159
|
classCache: new Map(),
|
|
538
1160
|
applyClassCache: new Map(),
|
|
539
|
-
|
|
1161
|
+
// Seed the not class cache with the blocklist (which is only strings)
|
|
1162
|
+
notClassCache: new Set(tailwindConfig.blocklist ?? []),
|
|
540
1163
|
postCssNodeCache: new Map(),
|
|
541
1164
|
candidateRuleMap: new Map(),
|
|
542
1165
|
tailwindConfig,
|
|
543
1166
|
changedContent: changedContent,
|
|
544
1167
|
variantMap: new Map(),
|
|
545
1168
|
stylesheetCache: null,
|
|
1169
|
+
variantOptions: new Map(),
|
|
1170
|
+
|
|
1171
|
+
markInvalidUtilityCandidate: (candidate) => markInvalidUtilityCandidate(context, candidate),
|
|
1172
|
+
markInvalidUtilityNode: (node) => markInvalidUtilityNode(context, node),
|
|
546
1173
|
}
|
|
547
1174
|
|
|
548
|
-
let resolvedPlugins = resolvePlugins(context,
|
|
1175
|
+
let resolvedPlugins = resolvePlugins(context, root)
|
|
549
1176
|
registerPlugins(resolvedPlugins, context)
|
|
550
1177
|
|
|
551
1178
|
return context
|
|
@@ -556,7 +1183,6 @@ let configContextMap = sharedState.configContextMap
|
|
|
556
1183
|
let contextSourcesMap = sharedState.contextSourcesMap
|
|
557
1184
|
|
|
558
1185
|
export function getContext(
|
|
559
|
-
tailwindDirectives,
|
|
560
1186
|
root,
|
|
561
1187
|
result,
|
|
562
1188
|
tailwindConfig,
|
|
@@ -581,6 +1207,8 @@ export function getContext(
|
|
|
581
1207
|
existingContext = context
|
|
582
1208
|
}
|
|
583
1209
|
|
|
1210
|
+
let cssDidChange = hasContentChanged(sourcePath, root)
|
|
1211
|
+
|
|
584
1212
|
// If there's already a context in the cache and we don't need to
|
|
585
1213
|
// reset the context, return the cached context.
|
|
586
1214
|
if (existingContext) {
|
|
@@ -588,7 +1216,7 @@ export function getContext(
|
|
|
588
1216
|
[...contextDependencies],
|
|
589
1217
|
getFileModifiedMap(existingContext)
|
|
590
1218
|
)
|
|
591
|
-
if (!contextDependenciesChanged) {
|
|
1219
|
+
if (!contextDependenciesChanged && !cssDidChange) {
|
|
592
1220
|
return [existingContext, false]
|
|
593
1221
|
}
|
|
594
1222
|
}
|
|
@@ -618,7 +1246,11 @@ export function getContext(
|
|
|
618
1246
|
|
|
619
1247
|
env.DEBUG && console.log('Setting up new context...')
|
|
620
1248
|
|
|
621
|
-
let context = createContext(tailwindConfig, [],
|
|
1249
|
+
let context = createContext(tailwindConfig, [], root)
|
|
1250
|
+
|
|
1251
|
+
Object.assign(context, {
|
|
1252
|
+
userConfigPath,
|
|
1253
|
+
})
|
|
622
1254
|
|
|
623
1255
|
trackModified([...contextDependencies], getFileModifiedMap(context))
|
|
624
1256
|
|