tailwindcss 0.0.0-insiders.ea139f2 → 0.0.0-insiders.ea4e1cd

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 (236) hide show
  1. package/LICENSE +1 -2
  2. package/README.md +15 -7
  3. package/colors.d.ts +3 -0
  4. package/colors.js +2 -1
  5. package/defaultConfig.d.ts +3 -0
  6. package/defaultConfig.js +2 -1
  7. package/defaultTheme.d.ts +4 -0
  8. package/defaultTheme.js +2 -1
  9. package/lib/cli/build/deps.js +62 -0
  10. package/lib/cli/build/index.js +54 -0
  11. package/lib/cli/build/plugin.js +378 -0
  12. package/lib/cli/build/utils.js +88 -0
  13. package/lib/cli/build/watching.js +182 -0
  14. package/lib/cli/help/index.js +73 -0
  15. package/lib/cli/index.js +230 -0
  16. package/lib/cli/init/index.js +63 -0
  17. package/lib/cli-peer-dependencies.js +28 -7
  18. package/lib/cli.js +4 -703
  19. package/lib/corePluginList.js +12 -3
  20. package/lib/corePlugins.js +2373 -1863
  21. package/lib/css/preflight.css +10 -8
  22. package/lib/featureFlags.js +49 -26
  23. package/lib/index.js +1 -31
  24. package/lib/lib/cacheInvalidation.js +92 -0
  25. package/lib/lib/collapseAdjacentRules.js +30 -10
  26. package/lib/lib/collapseDuplicateDeclarations.js +60 -4
  27. package/lib/lib/content.js +181 -0
  28. package/lib/lib/defaultExtractor.js +243 -0
  29. package/lib/lib/detectNesting.js +21 -10
  30. package/lib/lib/evaluateTailwindFunctions.js +115 -50
  31. package/lib/lib/expandApplyAtRules.js +467 -161
  32. package/lib/lib/expandTailwindAtRules.js +160 -133
  33. package/lib/lib/findAtConfigPath.js +46 -0
  34. package/lib/lib/generateRules.js +553 -200
  35. package/lib/lib/getModuleDependencies.js +88 -37
  36. package/lib/lib/load-config.js +42 -0
  37. package/lib/lib/normalizeTailwindDirectives.js +46 -33
  38. package/lib/lib/offsets.js +306 -0
  39. package/lib/lib/partitionApplyAtRules.js +58 -0
  40. package/lib/lib/regex.js +74 -0
  41. package/lib/lib/remap-bitfield.js +89 -0
  42. package/lib/lib/resolveDefaultsAtRules.js +98 -58
  43. package/lib/lib/setupContextUtils.js +773 -321
  44. package/lib/lib/setupTrackingContext.js +70 -75
  45. package/lib/lib/sharedState.js +78 -10
  46. package/lib/lib/substituteScreenAtRules.js +14 -10
  47. package/lib/oxide/cli/build/deps.js +89 -0
  48. package/lib/oxide/cli/build/index.js +53 -0
  49. package/lib/oxide/cli/build/plugin.js +375 -0
  50. package/lib/oxide/cli/build/utils.js +87 -0
  51. package/lib/oxide/cli/build/watching.js +179 -0
  52. package/lib/oxide/cli/help/index.js +72 -0
  53. package/lib/oxide/cli/index.js +214 -0
  54. package/lib/oxide/cli/init/index.js +52 -0
  55. package/lib/oxide/cli.js +5 -0
  56. package/lib/oxide/postcss-plugin.js +2 -0
  57. package/lib/plugin.js +98 -0
  58. package/{nesting → lib/postcss-plugins/nesting}/README.md +2 -2
  59. package/lib/postcss-plugins/nesting/index.js +21 -0
  60. package/lib/postcss-plugins/nesting/plugin.js +89 -0
  61. package/lib/processTailwindFeatures.js +39 -26
  62. package/lib/public/colors.js +272 -246
  63. package/lib/public/create-plugin.js +9 -5
  64. package/lib/public/default-config.js +10 -6
  65. package/lib/public/default-theme.js +10 -6
  66. package/lib/public/load-config.js +12 -0
  67. package/lib/public/resolve-config.js +11 -6
  68. package/lib/util/applyImportantSelector.js +36 -0
  69. package/lib/util/bigSign.js +6 -1
  70. package/lib/util/buildMediaQuery.js +13 -6
  71. package/lib/util/cloneDeep.js +9 -6
  72. package/lib/util/cloneNodes.js +23 -3
  73. package/lib/util/color.js +70 -38
  74. package/lib/util/colorNames.js +752 -0
  75. package/lib/util/configurePlugins.js +7 -2
  76. package/lib/util/createPlugin.js +8 -6
  77. package/lib/util/createUtilityPlugin.js +16 -16
  78. package/lib/util/dataTypes.js +173 -108
  79. package/lib/util/defaults.js +14 -3
  80. package/lib/util/escapeClassName.js +13 -8
  81. package/lib/util/escapeCommas.js +7 -2
  82. package/lib/util/flattenColorPalette.js +11 -12
  83. package/lib/util/formatVariantSelector.js +228 -151
  84. package/lib/util/getAllConfigs.js +33 -12
  85. package/lib/util/hashConfig.js +9 -4
  86. package/lib/util/isKeyframeRule.js +7 -2
  87. package/lib/util/isPlainObject.js +7 -2
  88. package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +25 -15
  89. package/lib/util/log.js +27 -13
  90. package/lib/util/nameClass.js +27 -10
  91. package/lib/util/negateValue.js +25 -8
  92. package/lib/util/normalizeConfig.js +139 -65
  93. package/lib/util/normalizeScreens.js +131 -11
  94. package/lib/util/parseAnimationValue.js +44 -40
  95. package/lib/util/parseBoxShadowValue.js +34 -23
  96. package/lib/util/parseDependency.js +39 -55
  97. package/lib/util/parseGlob.js +36 -0
  98. package/lib/util/parseObjectStyles.js +15 -10
  99. package/lib/util/pluginUtils.js +159 -69
  100. package/lib/util/prefixSelector.js +30 -12
  101. package/lib/util/pseudoElements.js +229 -0
  102. package/lib/util/removeAlphaVariables.js +31 -0
  103. package/lib/util/resolveConfig.js +97 -75
  104. package/lib/util/resolveConfigPath.js +30 -12
  105. package/lib/util/responsive.js +11 -6
  106. package/lib/util/splitAtTopLevelOnly.js +51 -0
  107. package/lib/util/tap.js +6 -1
  108. package/lib/util/toColorValue.js +7 -3
  109. package/lib/util/toPath.js +26 -3
  110. package/lib/util/transformThemeValue.js +40 -30
  111. package/lib/util/validateConfig.js +37 -0
  112. package/lib/util/validateFormalSyntax.js +26 -0
  113. package/lib/util/withAlphaVariable.js +27 -15
  114. package/loadConfig.d.ts +4 -0
  115. package/loadConfig.js +2 -0
  116. package/nesting/index.js +2 -12
  117. package/package.json +66 -57
  118. package/peers/index.js +75964 -55560
  119. package/plugin.d.ts +11 -0
  120. package/plugin.js +2 -1
  121. package/resolveConfig.d.ts +12 -0
  122. package/resolveConfig.js +2 -1
  123. package/scripts/generate-types.js +105 -0
  124. package/scripts/release-channel.js +18 -0
  125. package/scripts/release-notes.js +21 -0
  126. package/scripts/swap-engines.js +40 -0
  127. package/scripts/type-utils.js +27 -0
  128. package/src/cli/build/deps.js +56 -0
  129. package/src/cli/build/index.js +49 -0
  130. package/src/cli/build/plugin.js +444 -0
  131. package/src/cli/build/utils.js +76 -0
  132. package/src/cli/build/watching.js +229 -0
  133. package/src/cli/help/index.js +70 -0
  134. package/src/cli/index.js +216 -0
  135. package/src/cli/init/index.js +79 -0
  136. package/src/cli-peer-dependencies.js +7 -1
  137. package/src/cli.js +4 -765
  138. package/src/corePluginList.js +1 -1
  139. package/src/corePlugins.js +786 -306
  140. package/src/css/preflight.css +10 -8
  141. package/src/featureFlags.js +21 -5
  142. package/src/index.js +1 -34
  143. package/src/lib/cacheInvalidation.js +52 -0
  144. package/src/lib/collapseAdjacentRules.js +21 -2
  145. package/src/lib/collapseDuplicateDeclarations.js +66 -1
  146. package/src/lib/content.js +208 -0
  147. package/src/lib/defaultExtractor.js +217 -0
  148. package/src/lib/detectNesting.js +9 -1
  149. package/src/lib/evaluateTailwindFunctions.js +79 -8
  150. package/src/lib/expandApplyAtRules.js +515 -153
  151. package/src/lib/expandTailwindAtRules.js +115 -86
  152. package/src/lib/findAtConfigPath.js +48 -0
  153. package/src/lib/generateRules.js +545 -147
  154. package/src/lib/getModuleDependencies.js +70 -30
  155. package/src/lib/load-config.ts +31 -0
  156. package/src/lib/normalizeTailwindDirectives.js +7 -1
  157. package/src/lib/offsets.js +373 -0
  158. package/src/lib/partitionApplyAtRules.js +52 -0
  159. package/src/lib/regex.js +74 -0
  160. package/src/lib/remap-bitfield.js +82 -0
  161. package/src/lib/resolveDefaultsAtRules.js +59 -17
  162. package/src/lib/setupContextUtils.js +701 -175
  163. package/src/lib/setupTrackingContext.js +51 -62
  164. package/src/lib/sharedState.js +58 -7
  165. package/src/oxide/cli/build/deps.ts +91 -0
  166. package/src/oxide/cli/build/index.ts +47 -0
  167. package/src/oxide/cli/build/plugin.ts +442 -0
  168. package/src/oxide/cli/build/utils.ts +74 -0
  169. package/src/oxide/cli/build/watching.ts +225 -0
  170. package/src/oxide/cli/help/index.ts +69 -0
  171. package/src/oxide/cli/index.ts +204 -0
  172. package/src/oxide/cli/init/index.ts +59 -0
  173. package/src/oxide/cli.ts +1 -0
  174. package/src/oxide/postcss-plugin.ts +1 -0
  175. package/src/plugin.js +107 -0
  176. package/src/postcss-plugins/nesting/README.md +42 -0
  177. package/src/postcss-plugins/nesting/index.js +13 -0
  178. package/src/postcss-plugins/nesting/plugin.js +80 -0
  179. package/src/processTailwindFeatures.js +12 -2
  180. package/src/public/colors.js +22 -0
  181. package/src/public/default-config.js +1 -1
  182. package/src/public/default-theme.js +2 -2
  183. package/src/public/load-config.js +2 -0
  184. package/src/util/applyImportantSelector.js +27 -0
  185. package/src/util/buildMediaQuery.js +5 -3
  186. package/src/util/cloneNodes.js +19 -2
  187. package/src/util/color.js +44 -12
  188. package/src/util/colorNames.js +150 -0
  189. package/src/util/dataTypes.js +51 -16
  190. package/src/util/defaults.js +6 -0
  191. package/src/util/formatVariantSelector.js +264 -144
  192. package/src/util/getAllConfigs.js +21 -2
  193. package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
  194. package/src/util/log.js +11 -7
  195. package/src/util/nameClass.js +4 -0
  196. package/src/util/negateValue.js +11 -3
  197. package/src/util/normalizeConfig.js +57 -5
  198. package/src/util/normalizeScreens.js +105 -7
  199. package/src/util/parseBoxShadowValue.js +4 -3
  200. package/src/util/parseDependency.js +37 -42
  201. package/src/util/parseGlob.js +24 -0
  202. package/src/util/pluginUtils.js +123 -24
  203. package/src/util/prefixSelector.js +30 -10
  204. package/src/util/pseudoElements.js +170 -0
  205. package/src/util/removeAlphaVariables.js +24 -0
  206. package/src/util/resolveConfig.js +74 -26
  207. package/src/util/resolveConfigPath.js +12 -1
  208. package/src/util/splitAtTopLevelOnly.js +52 -0
  209. package/src/util/toPath.js +23 -1
  210. package/src/util/transformThemeValue.js +13 -3
  211. package/src/util/validateConfig.js +26 -0
  212. package/src/util/validateFormalSyntax.js +34 -0
  213. package/src/util/withAlphaVariable.js +1 -1
  214. package/stubs/.gitignore +1 -0
  215. package/stubs/.prettierrc.json +6 -0
  216. package/stubs/{defaultConfig.stub.js → config.full.js} +206 -166
  217. package/stubs/postcss.config.js +6 -0
  218. package/stubs/tailwind.config.cjs +2 -0
  219. package/stubs/tailwind.config.js +2 -0
  220. package/stubs/tailwind.config.ts +3 -0
  221. package/types/config.d.ts +368 -0
  222. package/types/generated/.gitkeep +0 -0
  223. package/types/generated/colors.d.ts +298 -0
  224. package/types/generated/corePluginList.d.ts +1 -0
  225. package/types/generated/default-theme.d.ts +371 -0
  226. package/types/index.d.ts +7 -0
  227. package/CHANGELOG.md +0 -1843
  228. package/lib/constants.js +0 -37
  229. package/lib/lib/setupWatchingContext.js +0 -288
  230. package/nesting/plugin.js +0 -41
  231. package/scripts/install-integrations.js +0 -27
  232. package/scripts/rebuildFixtures.js +0 -68
  233. package/src/constants.js +0 -17
  234. package/src/lib/setupWatchingContext.js +0 -311
  235. /package/stubs/{simpleConfig.stub.js → config.simple.js} +0 -0
  236. /package/stubs/{defaultPostCssConfig.stub.js → postcss.config.cjs} +0 -0
@@ -1,35 +1,15 @@
1
- import LRU from 'quick-lru'
1
+ import fs from 'fs'
2
+ import LRU from '@alloc/quick-lru'
2
3
  import * as sharedState from './sharedState'
3
4
  import { generateRules } from './generateRules'
4
- import bigSign from '../util/bigSign'
5
+ import log from '../util/log'
5
6
  import cloneNodes from '../util/cloneNodes'
7
+ import { defaultExtractor } from './defaultExtractor'
6
8
 
7
9
  let env = sharedState.env
8
10
 
9
- const PATTERNS = [
10
- /([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif]
11
- /([^<>"'`\s]*\[\w*"[^"`\s]*"?\])/.source, // font-["some_font",sans-serif]
12
- /([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')]
13
- /([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
14
- /([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source, // bg-[url('...'),url('...')]
15
- /([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")]
16
- /([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
17
- /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
18
- /([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]`
19
- /([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']`
20
- /([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50`
21
- /([^<>"'`\s]*[^"'`\s:])/.source, // `px-1.5`, `uppercase` but not `uppercase:`
22
- ].join('|')
23
- const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g')
24
- const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g
25
-
26
11
  const builtInExtractors = {
27
- DEFAULT: (content) => {
28
- let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || []
29
- let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || []
30
-
31
- return [...broadMatches, ...innerMatches]
32
- },
12
+ DEFAULT: defaultExtractor,
33
13
  }
34
14
 
35
15
  const builtInTransformers = {
@@ -37,14 +17,14 @@ const builtInTransformers = {
37
17
  svelte: (content) => content.replace(/(?:^|\s)class:/g, ' '),
38
18
  }
39
19
 
40
- function getExtractor(tailwindConfig, fileExtension) {
41
- let extractors = tailwindConfig.content.extract
20
+ function getExtractor(context, fileExtension) {
21
+ let extractors = context.tailwindConfig.content.extract
42
22
 
43
23
  return (
44
24
  extractors[fileExtension] ||
45
25
  extractors.DEFAULT ||
46
26
  builtInExtractors[fileExtension] ||
47
- builtInExtractors.DEFAULT
27
+ builtInExtractors.DEFAULT(context)
48
28
  )
49
29
  }
50
30
 
@@ -94,51 +74,24 @@ function getClassCandidates(content, extractor, candidates, seen) {
94
74
  }
95
75
  }
96
76
 
77
+ /**
78
+ *
79
+ * @param {[import('./offsets.js').RuleOffset, import('postcss').Node][]} rules
80
+ * @param {*} context
81
+ */
97
82
  function buildStylesheet(rules, context) {
98
- let sortedRules = rules.sort(([a], [z]) => bigSign(a - z))
83
+ let sortedRules = context.offsets.sort(rules)
99
84
 
100
85
  let returnValue = {
101
86
  base: new Set(),
87
+ defaults: new Set(),
102
88
  components: new Set(),
103
89
  utilities: new Set(),
104
90
  variants: new Set(),
105
-
106
- // All the CSS that is not Tailwind related can be put in this bucket. This
107
- // will make it easier to later use this information when we want to
108
- // `@apply` for example. The main reason we do this here is because we
109
- // still need to make sure the order is correct. Last but not least, we
110
- // will make sure to always re-inject this section into the css, even if
111
- // certain rules were not used. This means that it will look like a no-op
112
- // from the user's perspective, but we gathered all the useful information
113
- // we need.
114
- user: new Set(),
115
91
  }
116
92
 
117
93
  for (let [sort, rule] of sortedRules) {
118
- if (sort >= context.minimumScreen) {
119
- returnValue.variants.add(rule)
120
- continue
121
- }
122
-
123
- if (sort & context.layerOrder.base) {
124
- returnValue.base.add(rule)
125
- continue
126
- }
127
-
128
- if (sort & context.layerOrder.components) {
129
- returnValue.components.add(rule)
130
- continue
131
- }
132
-
133
- if (sort & context.layerOrder.utilities) {
134
- returnValue.utilities.add(rule)
135
- continue
136
- }
137
-
138
- if (sort & context.layerOrder.user) {
139
- returnValue.user.add(rule)
140
- continue
141
- }
94
+ returnValue[sort.layer].add(rule)
142
95
  }
143
96
 
144
97
  return returnValue
@@ -153,13 +106,15 @@ export default function expandTailwindAtRules(context) {
153
106
  variants: null,
154
107
  }
155
108
 
156
- // Make sure this file contains Tailwind directives. If not, we can save
157
- // a lot of work and bail early. Also we don't have to register our touch
158
- // file as a dependency since the output of this CSS does not depend on
159
- // the source of any templates. Think Vue <style> blocks for example.
160
- root.walkAtRules('tailwind', (rule) => {
161
- if (Object.keys(layerNodes).includes(rule.params)) {
162
- layerNodes[rule.params] = rule
109
+ root.walkAtRules((rule) => {
110
+ // Make sure this file contains Tailwind directives. If not, we can save
111
+ // a lot of work and bail early. Also we don't have to register our touch
112
+ // file as a dependency since the output of this CSS does not depend on
113
+ // the source of any templates. Think Vue <style> blocks for example.
114
+ if (rule.name === 'tailwind') {
115
+ if (Object.keys(layerNodes).includes(rule.params)) {
116
+ layerNodes[rule.params] = rule
117
+ }
163
118
  }
164
119
  })
165
120
 
@@ -170,38 +125,65 @@ export default function expandTailwindAtRules(context) {
170
125
  // ---
171
126
 
172
127
  // Find potential rules in changed files
173
- let candidates = new Set(['*'])
128
+ let candidates = new Set([...(context.candidates ?? []), sharedState.NOT_ON_DEMAND])
174
129
  let seen = new Set()
175
130
 
176
131
  env.DEBUG && console.time('Reading changed files')
177
132
 
178
- for (let { content, extension } of context.changedContent) {
179
- let transformer = getTransformer(context.tailwindConfig, extension)
180
- let extractor = getExtractor(context.tailwindConfig, extension)
181
- getClassCandidates(transformer(content), extractor, candidates, seen)
133
+ if (__OXIDE__) {
134
+ // TODO: Pass through or implement `extractor`
135
+ for (let candidate of require('@tailwindcss/oxide').parseCandidateStringsFromFiles(
136
+ context.changedContent
137
+ // Object.assign({}, builtInTransformers, context.tailwindConfig.content.transform)
138
+ )) {
139
+ candidates.add(candidate)
140
+ }
141
+
142
+ // for (let { file, content, extension } of context.changedContent) {
143
+ // let transformer = getTransformer(context.tailwindConfig, extension)
144
+ // let extractor = getExtractor(context, extension)
145
+ // getClassCandidatesOxide(file, transformer(content), extractor, candidates, seen)
146
+ // }
147
+ } else {
148
+ for (let { file, content, extension } of context.changedContent) {
149
+ let transformer = getTransformer(context.tailwindConfig, extension)
150
+ let extractor = getExtractor(context, extension)
151
+ content = file ? fs.readFileSync(file, 'utf8') : content
152
+ getClassCandidates(transformer(content), extractor, candidates, seen)
153
+ }
182
154
  }
183
155
 
156
+ env.DEBUG && console.timeEnd('Reading changed files')
157
+
184
158
  // ---
185
159
 
186
160
  // Generate the actual CSS
187
161
  let classCacheCount = context.classCache.size
188
162
 
189
163
  env.DEBUG && console.time('Generate rules')
190
- let rules = generateRules(candidates, context)
164
+ env.DEBUG && console.time('Sorting candidates')
165
+ let sortedCandidates = __OXIDE__
166
+ ? candidates
167
+ : new Set(
168
+ [...candidates].sort((a, z) => {
169
+ if (a === z) return 0
170
+ if (a < z) return -1
171
+ return 1
172
+ })
173
+ )
174
+ env.DEBUG && console.timeEnd('Sorting candidates')
175
+ generateRules(sortedCandidates, context)
191
176
  env.DEBUG && console.timeEnd('Generate rules')
192
177
 
193
178
  // We only ever add to the classCache, so if it didn't grow, there is nothing new.
194
179
  env.DEBUG && console.time('Build stylesheet')
195
180
  if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
196
- for (let rule of rules) {
197
- context.ruleCache.add(rule)
198
- }
199
-
200
181
  context.stylesheetCache = buildStylesheet([...context.ruleCache], context)
201
182
  }
202
183
  env.DEBUG && console.timeEnd('Build stylesheet')
203
184
 
204
185
  let {
186
+ defaults: defaultNodes,
205
187
  base: baseNodes,
206
188
  components: componentNodes,
207
189
  utilities: utilityNodes,
@@ -213,25 +195,72 @@ export default function expandTailwindAtRules(context) {
213
195
  // Replace any Tailwind directives with generated CSS
214
196
 
215
197
  if (layerNodes.base) {
216
- layerNodes.base.before(cloneNodes([...baseNodes], layerNodes.base.source))
198
+ layerNodes.base.before(
199
+ cloneNodes([...baseNodes, ...defaultNodes], layerNodes.base.source, {
200
+ layer: 'base',
201
+ })
202
+ )
217
203
  layerNodes.base.remove()
218
204
  }
219
205
 
220
206
  if (layerNodes.components) {
221
- layerNodes.components.before(cloneNodes([...componentNodes], layerNodes.components.source))
207
+ layerNodes.components.before(
208
+ cloneNodes([...componentNodes], layerNodes.components.source, {
209
+ layer: 'components',
210
+ })
211
+ )
222
212
  layerNodes.components.remove()
223
213
  }
224
214
 
225
215
  if (layerNodes.utilities) {
226
- layerNodes.utilities.before(cloneNodes([...utilityNodes], layerNodes.utilities.source))
216
+ layerNodes.utilities.before(
217
+ cloneNodes([...utilityNodes], layerNodes.utilities.source, {
218
+ layer: 'utilities',
219
+ })
220
+ )
227
221
  layerNodes.utilities.remove()
228
222
  }
229
223
 
224
+ // We do post-filtering to not alter the emitted order of the variants
225
+ const variantNodes = Array.from(screenNodes).filter((node) => {
226
+ const parentLayer = node.raws.tailwind?.parentLayer
227
+
228
+ if (parentLayer === 'components') {
229
+ return layerNodes.components !== null
230
+ }
231
+
232
+ if (parentLayer === 'utilities') {
233
+ return layerNodes.utilities !== null
234
+ }
235
+
236
+ return true
237
+ })
238
+
230
239
  if (layerNodes.variants) {
231
- layerNodes.variants.before(cloneNodes([...screenNodes], layerNodes.variants.source))
240
+ layerNodes.variants.before(
241
+ cloneNodes(variantNodes, layerNodes.variants.source, {
242
+ layer: 'variants',
243
+ })
244
+ )
232
245
  layerNodes.variants.remove()
233
- } else {
234
- root.append(cloneNodes([...screenNodes], root.source))
246
+ } else if (variantNodes.length > 0) {
247
+ root.append(
248
+ cloneNodes(variantNodes, root.source, {
249
+ layer: 'variants',
250
+ })
251
+ )
252
+ }
253
+
254
+ // If we've got a utility layer and no utilities are generated there's likely something wrong
255
+ const hasUtilityVariants = variantNodes.some(
256
+ (node) => node.raws.tailwind?.parentLayer === 'utilities'
257
+ )
258
+
259
+ if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
260
+ log.warn('content-problems', [
261
+ 'No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.',
262
+ 'https://tailwindcss.com/docs/content-configuration',
263
+ ])
235
264
  }
236
265
 
237
266
  // ---
@@ -0,0 +1,48 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+
4
+ /**
5
+ * Find the @config at-rule in the given CSS AST and return the relative path to the config file
6
+ *
7
+ * @param {import('postcss').Root} root
8
+ * @param {import('postcss').Result} result
9
+ */
10
+ export function findAtConfigPath(root, result) {
11
+ let configPath = null
12
+ let relativeTo = null
13
+
14
+ root.walkAtRules('config', (rule) => {
15
+ relativeTo = rule.source?.input.file ?? result.opts.from ?? null
16
+
17
+ if (relativeTo === null) {
18
+ throw rule.error(
19
+ 'The `@config` directive cannot be used without setting `from` in your PostCSS config.'
20
+ )
21
+ }
22
+
23
+ if (configPath) {
24
+ throw rule.error('Only one `@config` directive is allowed per file.')
25
+ }
26
+
27
+ let matches = rule.params.match(/(['"])(.*?)\1/)
28
+ if (!matches) {
29
+ throw rule.error('A path is required when using the `@config` directive.')
30
+ }
31
+
32
+ let inputPath = matches[2]
33
+ if (path.isAbsolute(inputPath)) {
34
+ throw rule.error('The `@config` directive cannot be used with an absolute path.')
35
+ }
36
+
37
+ configPath = path.resolve(path.dirname(relativeTo), inputPath)
38
+ if (!fs.existsSync(configPath)) {
39
+ throw rule.error(
40
+ `The config file at "${inputPath}" does not exist. Make sure the path is correct and the file exists.`
41
+ )
42
+ }
43
+
44
+ rule.remove()
45
+ })
46
+
47
+ return configPath ? configPath : null
48
+ }