tailwindcss 0.0.0-insiders.ff2c25f → 0.0.0-internal.b2586d4e

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