tailwindcss 0.0.0-insiders.ca1dfd6 → 0.0.0-insiders.cb6e45a

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 (190) hide show
  1. package/CHANGELOG.md +526 -2
  2. package/LICENSE +1 -2
  3. package/README.md +13 -6
  4. package/colors.d.ts +3 -0
  5. package/colors.js +2 -1
  6. package/defaultConfig.d.ts +3 -0
  7. package/defaultConfig.js +2 -1
  8. package/defaultTheme.d.ts +4 -0
  9. package/defaultTheme.js +2 -1
  10. package/lib/cli/build/deps.js +54 -0
  11. package/lib/cli/build/index.js +44 -0
  12. package/lib/cli/build/plugin.js +335 -0
  13. package/lib/cli/build/utils.js +78 -0
  14. package/lib/cli/build/watching.js +113 -0
  15. package/lib/cli/help/index.js +71 -0
  16. package/lib/cli/index.js +18 -0
  17. package/lib/cli/init/index.js +46 -0
  18. package/lib/cli/shared.js +12 -0
  19. package/lib/cli-peer-dependencies.js +20 -7
  20. package/lib/cli.js +91 -569
  21. package/lib/constants.js +27 -20
  22. package/lib/corePluginList.js +16 -4
  23. package/lib/corePlugins.js +2247 -1873
  24. package/lib/css/preflight.css +20 -9
  25. package/lib/featureFlags.js +37 -23
  26. package/lib/index.js +28 -12
  27. package/lib/lib/cacheInvalidation.js +90 -0
  28. package/lib/lib/collapseAdjacentRules.js +27 -9
  29. package/lib/lib/collapseDuplicateDeclarations.js +83 -0
  30. package/lib/lib/content.js +167 -0
  31. package/lib/lib/defaultExtractor.js +236 -0
  32. package/lib/lib/detectNesting.js +21 -3
  33. package/lib/lib/evaluateTailwindFunctions.js +117 -50
  34. package/lib/lib/expandApplyAtRules.js +439 -160
  35. package/lib/lib/expandTailwindAtRules.js +141 -151
  36. package/lib/lib/findAtConfigPath.js +44 -0
  37. package/lib/lib/generateRules.js +572 -105
  38. package/lib/lib/getModuleDependencies.js +11 -8
  39. package/lib/lib/normalizeTailwindDirectives.js +45 -33
  40. package/lib/lib/offsets.js +217 -0
  41. package/lib/lib/partitionApplyAtRules.js +56 -0
  42. package/lib/lib/regex.js +60 -0
  43. package/lib/lib/resolveDefaultsAtRules.js +114 -81
  44. package/lib/lib/setupContextUtils.js +777 -385
  45. package/lib/lib/setupTrackingContext.js +43 -71
  46. package/lib/lib/sharedState.js +49 -18
  47. package/lib/lib/substituteScreenAtRules.js +13 -8
  48. package/{nesting → lib/postcss-plugins/nesting}/README.md +2 -2
  49. package/lib/postcss-plugins/nesting/index.js +19 -0
  50. package/lib/postcss-plugins/nesting/plugin.js +87 -0
  51. package/lib/processTailwindFeatures.js +36 -21
  52. package/lib/public/colors.js +250 -252
  53. package/lib/public/create-plugin.js +6 -4
  54. package/lib/public/default-config.js +7 -5
  55. package/lib/public/default-theme.js +7 -5
  56. package/lib/public/resolve-config.js +8 -5
  57. package/lib/util/bigSign.js +4 -1
  58. package/lib/util/buildMediaQuery.js +18 -24
  59. package/lib/util/cloneDeep.js +7 -6
  60. package/lib/util/cloneNodes.js +21 -3
  61. package/lib/util/color.js +54 -40
  62. package/lib/util/configurePlugins.js +5 -2
  63. package/lib/util/createPlugin.js +6 -6
  64. package/lib/util/createUtilityPlugin.js +11 -13
  65. package/lib/util/dataTypes.js +137 -100
  66. package/lib/util/defaults.js +10 -1
  67. package/lib/util/escapeClassName.js +7 -4
  68. package/lib/util/escapeCommas.js +5 -2
  69. package/lib/util/flattenColorPalette.js +9 -12
  70. package/lib/util/formatVariantSelector.js +285 -0
  71. package/lib/util/getAllConfigs.js +27 -8
  72. package/lib/util/hashConfig.js +6 -3
  73. package/lib/util/isKeyframeRule.js +5 -2
  74. package/lib/util/isPlainObject.js +5 -2
  75. package/lib/util/isValidArbitraryValue.js +72 -0
  76. package/lib/util/log.js +44 -22
  77. package/lib/util/nameClass.js +20 -8
  78. package/lib/util/negateValue.js +23 -6
  79. package/lib/util/normalizeConfig.js +267 -0
  80. package/lib/util/normalizeScreens.js +170 -0
  81. package/lib/util/parseAnimationValue.js +42 -40
  82. package/lib/util/parseBoxShadowValue.js +84 -0
  83. package/lib/util/parseDependency.js +38 -56
  84. package/lib/util/parseGlob.js +34 -0
  85. package/lib/util/parseObjectStyles.js +11 -8
  86. package/lib/util/pluginUtils.js +171 -189
  87. package/lib/util/prefixSelector.js +10 -10
  88. package/lib/util/removeAlphaVariables.js +29 -0
  89. package/lib/util/resolveConfig.js +92 -126
  90. package/lib/util/resolveConfigPath.js +11 -9
  91. package/lib/util/responsive.js +8 -5
  92. package/lib/util/splitAtTopLevelOnly.js +43 -0
  93. package/lib/util/tap.js +4 -1
  94. package/lib/util/toColorValue.js +5 -3
  95. package/lib/util/toPath.js +24 -3
  96. package/lib/util/transformThemeValue.js +49 -31
  97. package/lib/util/validateConfig.js +24 -0
  98. package/lib/util/validateFormalSyntax.js +24 -0
  99. package/lib/util/withAlphaVariable.js +23 -15
  100. package/nesting/index.js +2 -12
  101. package/package.json +48 -46
  102. package/peers/index.js +14817 -12471
  103. package/plugin.d.ts +11 -0
  104. package/plugin.js +2 -1
  105. package/resolveConfig.d.ts +3 -0
  106. package/resolveConfig.js +2 -1
  107. package/scripts/create-plugin-list.js +2 -2
  108. package/scripts/generate-types.js +105 -0
  109. package/scripts/release-channel.js +18 -0
  110. package/scripts/release-notes.js +21 -0
  111. package/scripts/type-utils.js +27 -0
  112. package/src/cli/build/deps.js +56 -0
  113. package/src/cli/build/index.js +45 -0
  114. package/src/cli/build/plugin.js +397 -0
  115. package/src/cli/build/utils.js +76 -0
  116. package/src/cli/build/watching.js +134 -0
  117. package/src/cli/help/index.js +70 -0
  118. package/src/cli/index.js +3 -0
  119. package/src/cli/init/index.js +50 -0
  120. package/src/cli/shared.js +5 -0
  121. package/src/cli-peer-dependencies.js +7 -1
  122. package/src/cli.js +26 -565
  123. package/src/corePluginList.js +1 -1
  124. package/src/corePlugins.js +905 -615
  125. package/src/css/preflight.css +20 -9
  126. package/src/featureFlags.js +26 -10
  127. package/src/index.js +19 -6
  128. package/src/lib/cacheInvalidation.js +52 -0
  129. package/src/lib/collapseAdjacentRules.js +21 -2
  130. package/src/lib/collapseDuplicateDeclarations.js +93 -0
  131. package/src/lib/content.js +205 -0
  132. package/src/lib/defaultExtractor.js +211 -0
  133. package/src/lib/detectNesting.js +22 -3
  134. package/src/lib/evaluateTailwindFunctions.js +84 -10
  135. package/src/lib/expandApplyAtRules.js +488 -153
  136. package/src/lib/expandTailwindAtRules.js +94 -106
  137. package/src/lib/findAtConfigPath.js +50 -0
  138. package/src/lib/generateRules.js +589 -67
  139. package/src/lib/normalizeTailwindDirectives.js +10 -3
  140. package/src/lib/offsets.js +270 -0
  141. package/src/lib/partitionApplyAtRules.js +52 -0
  142. package/src/lib/regex.js +74 -0
  143. package/src/lib/resolveDefaultsAtRules.js +98 -60
  144. package/src/lib/setupContextUtils.js +737 -246
  145. package/src/lib/setupTrackingContext.js +16 -54
  146. package/src/lib/sharedState.js +44 -7
  147. package/src/lib/substituteScreenAtRules.js +6 -3
  148. package/src/postcss-plugins/nesting/README.md +42 -0
  149. package/src/postcss-plugins/nesting/index.js +13 -0
  150. package/src/postcss-plugins/nesting/plugin.js +80 -0
  151. package/src/processTailwindFeatures.js +17 -2
  152. package/src/public/colors.js +4 -9
  153. package/src/util/buildMediaQuery.js +14 -16
  154. package/src/util/cloneNodes.js +19 -2
  155. package/src/util/color.js +31 -14
  156. package/src/util/createUtilityPlugin.js +2 -2
  157. package/src/util/dataTypes.js +57 -21
  158. package/src/util/defaults.js +6 -0
  159. package/src/util/formatVariantSelector.js +319 -0
  160. package/src/util/getAllConfigs.js +19 -0
  161. package/src/util/isValidArbitraryValue.js +61 -0
  162. package/src/util/log.js +23 -22
  163. package/src/util/nameClass.js +6 -2
  164. package/src/util/negateValue.js +14 -4
  165. package/src/util/normalizeConfig.js +282 -0
  166. package/src/util/normalizeScreens.js +140 -0
  167. package/src/util/parseBoxShadowValue.js +72 -0
  168. package/src/util/parseDependency.js +37 -42
  169. package/src/util/parseGlob.js +24 -0
  170. package/src/util/pluginUtils.js +144 -152
  171. package/src/util/prefixSelector.js +7 -8
  172. package/src/util/removeAlphaVariables.js +24 -0
  173. package/src/util/resolveConfig.js +82 -81
  174. package/src/util/splitAtTopLevelOnly.js +45 -0
  175. package/src/util/toPath.js +23 -1
  176. package/src/util/transformThemeValue.js +33 -8
  177. package/src/util/validateConfig.js +13 -0
  178. package/src/util/validateFormalSyntax.js +34 -0
  179. package/src/util/withAlphaVariable.js +1 -1
  180. package/stubs/defaultConfig.stub.js +173 -93
  181. package/stubs/simpleConfig.stub.js +1 -1
  182. package/types/config.d.ts +361 -0
  183. package/types/generated/.gitkeep +0 -0
  184. package/types/generated/colors.d.ts +276 -0
  185. package/types/generated/corePluginList.d.ts +1 -0
  186. package/types/generated/default-theme.d.ts +342 -0
  187. package/types/index.d.ts +7 -0
  188. package/lib/lib/setupWatchingContext.js +0 -284
  189. package/nesting/plugin.js +0 -41
  190. package/src/lib/setupWatchingContext.js +0 -306
@@ -1,31 +1,14 @@
1
+ import LRU from 'quick-lru'
1
2
  import * as sharedState from './sharedState'
2
3
  import { generateRules } from './generateRules'
3
- import bigSign from '../util/bigSign'
4
+ import log from '../util/log'
4
5
  import cloneNodes from '../util/cloneNodes'
6
+ import { defaultExtractor } from './defaultExtractor'
5
7
 
6
8
  let env = sharedState.env
7
- let contentMatchCache = sharedState.contentMatchCache
8
-
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]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
15
- /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
16
- /([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50`
17
- /([^<>"'`\s]*[^"'`\s:])/.source, // `px-1.5`, `uppercase` but not `uppercase:`].join('|')
18
- ].join('|')
19
- const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g')
20
- const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g
21
9
 
22
10
  const builtInExtractors = {
23
- DEFAULT: (content) => {
24
- let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || []
25
- let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || []
26
-
27
- return [...broadMatches, ...innerMatches]
28
- },
11
+ DEFAULT: defaultExtractor,
29
12
  }
30
13
 
31
14
  const builtInTransformers = {
@@ -33,41 +16,20 @@ const builtInTransformers = {
33
16
  svelte: (content) => content.replace(/(?:^|\s)class:/g, ' '),
34
17
  }
35
18
 
36
- function getExtractor(tailwindConfig, fileExtension) {
37
- let extractors = tailwindConfig.content.extract
38
- let contentOptions = tailwindConfig.content.options
39
-
40
- if (typeof extractors === 'function') {
41
- extractors = {
42
- DEFAULT: extractors,
43
- }
44
- }
45
- if (contentOptions.defaultExtractor) {
46
- extractors.DEFAULT = contentOptions.defaultExtractor
47
- }
48
- for (let { extensions, extractor } of contentOptions.extractors || []) {
49
- for (let extension of extensions) {
50
- extractors[extension] = extractor
51
- }
52
- }
19
+ function getExtractor(context, fileExtension) {
20
+ let extractors = context.tailwindConfig.content.extract
53
21
 
54
22
  return (
55
23
  extractors[fileExtension] ||
56
24
  extractors.DEFAULT ||
57
25
  builtInExtractors[fileExtension] ||
58
- builtInExtractors.DEFAULT
26
+ builtInExtractors.DEFAULT(context)
59
27
  )
60
28
  }
61
29
 
62
30
  function getTransformer(tailwindConfig, fileExtension) {
63
31
  let transformers = tailwindConfig.content.transform
64
32
 
65
- if (typeof transformers === 'function') {
66
- transformers = {
67
- DEFAULT: transformers,
68
- }
69
- }
70
-
71
33
  return (
72
34
  transformers[fileExtension] ||
73
35
  transformers.DEFAULT ||
@@ -76,10 +38,16 @@ function getTransformer(tailwindConfig, fileExtension) {
76
38
  )
77
39
  }
78
40
 
41
+ let extractorCache = new WeakMap()
42
+
79
43
  // Scans template contents for possible classes. This is a hot path on initial build but
80
44
  // not too important for subsequent builds. The faster the better though — if we can speed
81
45
  // up these regexes by 50% that could cut initial build time by like 20%.
82
- function getClassCandidates(content, extractor, contentMatchCache, candidates, seen) {
46
+ function getClassCandidates(content, extractor, candidates, seen) {
47
+ if (!extractorCache.has(extractor)) {
48
+ extractorCache.set(extractor, new LRU({ maxSize: 25000 }))
49
+ }
50
+
83
51
  for (let line of content.split('\n')) {
84
52
  line = line.trim()
85
53
 
@@ -88,8 +56,8 @@ function getClassCandidates(content, extractor, contentMatchCache, candidates, s
88
56
  }
89
57
  seen.add(line)
90
58
 
91
- if (contentMatchCache.has(line)) {
92
- for (let match of contentMatchCache.get(line)) {
59
+ if (extractorCache.get(extractor).has(line)) {
60
+ for (let match of extractorCache.get(extractor).get(line)) {
93
61
  candidates.add(match)
94
62
  }
95
63
  } else {
@@ -100,56 +68,29 @@ function getClassCandidates(content, extractor, contentMatchCache, candidates, s
100
68
  candidates.add(match)
101
69
  }
102
70
 
103
- contentMatchCache.set(line, lineMatchesSet)
71
+ extractorCache.get(extractor).set(line, lineMatchesSet)
104
72
  }
105
73
  }
106
74
  }
107
75
 
76
+ /**
77
+ *
78
+ * @param {[import('./offsets.js').RuleOffset, import('postcss').Node][]} rules
79
+ * @param {*} context
80
+ */
108
81
  function buildStylesheet(rules, context) {
109
- let sortedRules = rules.sort(([a], [z]) => bigSign(a - z))
82
+ let sortedRules = context.offsets.sort(rules)
110
83
 
111
84
  let returnValue = {
112
85
  base: new Set(),
86
+ defaults: new Set(),
113
87
  components: new Set(),
114
88
  utilities: new Set(),
115
89
  variants: new Set(),
116
-
117
- // All the CSS that is not Tailwind related can be put in this bucket. This
118
- // will make it easier to later use this information when we want to
119
- // `@apply` for example. The main reason we do this here is because we
120
- // still need to make sure the order is correct. Last but not least, we
121
- // will make sure to always re-inject this section into the css, even if
122
- // certain rules were not used. This means that it will look like a no-op
123
- // from the user's perspective, but we gathered all the useful information
124
- // we need.
125
- user: new Set(),
126
90
  }
127
91
 
128
92
  for (let [sort, rule] of sortedRules) {
129
- if (sort >= context.minimumScreen) {
130
- returnValue.variants.add(rule)
131
- continue
132
- }
133
-
134
- if (sort & context.layerOrder.base) {
135
- returnValue.base.add(rule)
136
- continue
137
- }
138
-
139
- if (sort & context.layerOrder.components) {
140
- returnValue.components.add(rule)
141
- continue
142
- }
143
-
144
- if (sort & context.layerOrder.utilities) {
145
- returnValue.utilities.add(rule)
146
- continue
147
- }
148
-
149
- if (sort & context.layerOrder.user) {
150
- returnValue.user.add(rule)
151
- continue
152
- }
93
+ returnValue[sort.layer].add(rule)
153
94
  }
154
95
 
155
96
  return returnValue
@@ -164,13 +105,15 @@ export default function expandTailwindAtRules(context) {
164
105
  variants: null,
165
106
  }
166
107
 
167
- // Make sure this file contains Tailwind directives. If not, we can save
168
- // a lot of work and bail early. Also we don't have to register our touch
169
- // file as a dependency since the output of this CSS does not depend on
170
- // the source of any templates. Think Vue <style> blocks for example.
171
- root.walkAtRules('tailwind', (rule) => {
172
- if (Object.keys(layerNodes).includes(rule.params)) {
173
- layerNodes[rule.params] = rule
108
+ root.walkAtRules((rule) => {
109
+ // Make sure this file contains Tailwind directives. If not, we can save
110
+ // a lot of work and bail early. Also we don't have to register our touch
111
+ // file as a dependency since the output of this CSS does not depend on
112
+ // the source of any templates. Think Vue <style> blocks for example.
113
+ if (rule.name === 'tailwind') {
114
+ if (Object.keys(layerNodes).includes(rule.params)) {
115
+ layerNodes[rule.params] = rule
116
+ }
174
117
  }
175
118
  })
176
119
 
@@ -181,38 +124,37 @@ export default function expandTailwindAtRules(context) {
181
124
  // ---
182
125
 
183
126
  // Find potential rules in changed files
184
- let candidates = new Set(['*'])
127
+ let candidates = new Set([sharedState.NOT_ON_DEMAND])
185
128
  let seen = new Set()
186
129
 
187
130
  env.DEBUG && console.time('Reading changed files')
188
131
 
189
132
  for (let { content, extension } of context.changedContent) {
190
133
  let transformer = getTransformer(context.tailwindConfig, extension)
191
- let extractor = getExtractor(context.tailwindConfig, extension)
192
- getClassCandidates(transformer(content), extractor, contentMatchCache, candidates, seen)
134
+ let extractor = getExtractor(context, extension)
135
+ getClassCandidates(transformer(content), extractor, candidates, seen)
193
136
  }
194
137
 
138
+ env.DEBUG && console.timeEnd('Reading changed files')
139
+
195
140
  // ---
196
141
 
197
142
  // Generate the actual CSS
198
143
  let classCacheCount = context.classCache.size
199
144
 
200
145
  env.DEBUG && console.time('Generate rules')
201
- let rules = generateRules(candidates, context)
146
+ generateRules(candidates, context)
202
147
  env.DEBUG && console.timeEnd('Generate rules')
203
148
 
204
149
  // We only ever add to the classCache, so if it didn't grow, there is nothing new.
205
150
  env.DEBUG && console.time('Build stylesheet')
206
151
  if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
207
- for (let rule of rules) {
208
- context.ruleCache.add(rule)
209
- }
210
-
211
152
  context.stylesheetCache = buildStylesheet([...context.ruleCache], context)
212
153
  }
213
154
  env.DEBUG && console.timeEnd('Build stylesheet')
214
155
 
215
156
  let {
157
+ defaults: defaultNodes,
216
158
  base: baseNodes,
217
159
  components: componentNodes,
218
160
  utilities: utilityNodes,
@@ -224,25 +166,72 @@ export default function expandTailwindAtRules(context) {
224
166
  // Replace any Tailwind directives with generated CSS
225
167
 
226
168
  if (layerNodes.base) {
227
- layerNodes.base.before(cloneNodes([...baseNodes], layerNodes.base.source))
169
+ layerNodes.base.before(
170
+ cloneNodes([...baseNodes, ...defaultNodes], layerNodes.base.source, {
171
+ layer: 'base',
172
+ })
173
+ )
228
174
  layerNodes.base.remove()
229
175
  }
230
176
 
231
177
  if (layerNodes.components) {
232
- layerNodes.components.before(cloneNodes([...componentNodes], layerNodes.components.source))
178
+ layerNodes.components.before(
179
+ cloneNodes([...componentNodes], layerNodes.components.source, {
180
+ layer: 'components',
181
+ })
182
+ )
233
183
  layerNodes.components.remove()
234
184
  }
235
185
 
236
186
  if (layerNodes.utilities) {
237
- layerNodes.utilities.before(cloneNodes([...utilityNodes], layerNodes.utilities.source))
187
+ layerNodes.utilities.before(
188
+ cloneNodes([...utilityNodes], layerNodes.utilities.source, {
189
+ layer: 'utilities',
190
+ })
191
+ )
238
192
  layerNodes.utilities.remove()
239
193
  }
240
194
 
195
+ // We do post-filtering to not alter the emitted order of the variants
196
+ const variantNodes = Array.from(screenNodes).filter((node) => {
197
+ const parentLayer = node.raws.tailwind?.parentLayer
198
+
199
+ if (parentLayer === 'components') {
200
+ return layerNodes.components !== null
201
+ }
202
+
203
+ if (parentLayer === 'utilities') {
204
+ return layerNodes.utilities !== null
205
+ }
206
+
207
+ return true
208
+ })
209
+
241
210
  if (layerNodes.variants) {
242
- layerNodes.variants.before(cloneNodes([...screenNodes], layerNodes.variants.source))
211
+ layerNodes.variants.before(
212
+ cloneNodes(variantNodes, layerNodes.variants.source, {
213
+ layer: 'variants',
214
+ })
215
+ )
243
216
  layerNodes.variants.remove()
244
- } else {
245
- root.append(cloneNodes([...screenNodes], root.source))
217
+ } else if (variantNodes.length > 0) {
218
+ root.append(
219
+ cloneNodes(variantNodes, root.source, {
220
+ layer: 'variants',
221
+ })
222
+ )
223
+ }
224
+
225
+ // If we've got a utility layer and no utilities are generated there's likely something wrong
226
+ const hasUtilityVariants = variantNodes.some(
227
+ (node) => node.raws.tailwind?.parentLayer === 'utilities'
228
+ )
229
+
230
+ if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
231
+ log.warn('content-problems', [
232
+ 'No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.',
233
+ 'https://tailwindcss.com/docs/content-configuration',
234
+ ])
246
235
  }
247
236
 
248
237
  // ---
@@ -250,7 +239,6 @@ export default function expandTailwindAtRules(context) {
250
239
  if (env.DEBUG) {
251
240
  console.log('Potential classes: ', candidates.size)
252
241
  console.log('Active contexts: ', sharedState.contextSourcesMap.size)
253
- console.log('Content match entries', contentMatchCache.size)
254
242
  }
255
243
 
256
244
  // Clear the cache for the changed files
@@ -0,0 +1,50 @@
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` at-rule cannot be used without a `from` option being set on the PostCSS config.'
20
+ )
21
+ }
22
+
23
+ if (configPath) {
24
+ throw rule.error('Only `@config` at-rule is allowed per file.')
25
+ }
26
+
27
+ let matches = rule.params.match(/(['"])(.*?)\1/)
28
+ if (!matches) {
29
+ throw rule.error(
30
+ 'The `@config` at-rule must be followed by a string containing the path to the config file.'
31
+ )
32
+ }
33
+
34
+ let inputPath = matches[2]
35
+ if (path.isAbsolute(inputPath)) {
36
+ throw rule.error('The `@config` at-rule cannot be used with an absolute path.')
37
+ }
38
+
39
+ configPath = path.resolve(path.dirname(relativeTo), inputPath)
40
+ if (!fs.existsSync(configPath)) {
41
+ throw rule.error(
42
+ `The config file at "${inputPath}" does not exist. Make sure the path is correct and the file exists.`
43
+ )
44
+ }
45
+
46
+ rule.remove()
47
+ })
48
+
49
+ return configPath ? configPath : null
50
+ }