tailwindcss 0.0.0-insiders.bd4dddd → 0.0.0-insiders.bda8421

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 (224) hide show
  1. package/LICENSE +1 -2
  2. package/README.md +13 -10
  3. package/colors.d.ts +3 -0
  4. package/defaultConfig.d.ts +3 -0
  5. package/defaultTheme.d.ts +4 -0
  6. package/lib/cli/build/deps.js +62 -0
  7. package/lib/cli/build/index.js +54 -0
  8. package/lib/cli/build/plugin.js +371 -0
  9. package/lib/cli/build/utils.js +88 -0
  10. package/lib/cli/build/watching.js +182 -0
  11. package/lib/cli/help/index.js +73 -0
  12. package/lib/cli/index.js +230 -0
  13. package/lib/cli/init/index.js +63 -0
  14. package/lib/cli-peer-dependencies.js +28 -7
  15. package/lib/cli.js +1 -741
  16. package/lib/corePluginList.js +17 -4
  17. package/lib/corePlugins.js +2503 -1839
  18. package/lib/css/preflight.css +32 -13
  19. package/lib/featureFlags.js +45 -28
  20. package/lib/index.js +1 -29
  21. package/lib/lib/cacheInvalidation.js +92 -0
  22. package/lib/lib/collapseAdjacentRules.js +30 -10
  23. package/lib/lib/collapseDuplicateDeclarations.js +13 -8
  24. package/lib/lib/content.js +214 -0
  25. package/lib/lib/defaultExtractor.js +240 -31
  26. package/lib/lib/evaluateTailwindFunctions.js +117 -50
  27. package/lib/lib/expandApplyAtRules.js +466 -230
  28. package/lib/lib/expandTailwindAtRules.js +156 -135
  29. package/lib/lib/findAtConfigPath.js +46 -0
  30. package/lib/lib/generateRules.js +554 -200
  31. package/lib/lib/getModuleDependencies.js +88 -37
  32. package/lib/lib/load-config.js +57 -0
  33. package/lib/lib/normalizeTailwindDirectives.js +39 -33
  34. package/lib/lib/offsets.js +355 -0
  35. package/lib/lib/partitionApplyAtRules.js +58 -0
  36. package/lib/lib/regex.js +74 -0
  37. package/lib/lib/remap-bitfield.js +89 -0
  38. package/lib/lib/resolveDefaultsAtRules.js +97 -69
  39. package/lib/lib/setupContextUtils.js +796 -341
  40. package/lib/lib/setupTrackingContext.js +66 -71
  41. package/lib/lib/sharedState.js +45 -14
  42. package/lib/lib/substituteScreenAtRules.js +14 -10
  43. package/lib/plugin.js +48 -0
  44. package/{nesting → lib/postcss-plugins/nesting}/README.md +2 -2
  45. package/lib/postcss-plugins/nesting/index.js +21 -0
  46. package/lib/postcss-plugins/nesting/plugin.js +89 -0
  47. package/lib/processTailwindFeatures.js +37 -27
  48. package/lib/public/colors.js +272 -246
  49. package/lib/public/create-plugin.js +9 -5
  50. package/lib/public/default-config.js +10 -6
  51. package/lib/public/default-theme.js +10 -6
  52. package/lib/public/load-config.js +12 -0
  53. package/lib/public/resolve-config.js +11 -6
  54. package/lib/util/applyImportantSelector.js +36 -0
  55. package/lib/util/bigSign.js +6 -1
  56. package/lib/util/buildMediaQuery.js +13 -6
  57. package/lib/util/cloneDeep.js +9 -6
  58. package/lib/util/cloneNodes.js +44 -4
  59. package/lib/util/color.js +70 -53
  60. package/lib/util/colorNames.js +752 -0
  61. package/lib/util/configurePlugins.js +7 -2
  62. package/lib/util/createPlugin.js +8 -6
  63. package/lib/util/createUtilityPlugin.js +16 -16
  64. package/lib/util/dataTypes.js +295 -113
  65. package/lib/util/defaults.js +12 -7
  66. package/lib/util/escapeClassName.js +13 -8
  67. package/lib/util/escapeCommas.js +7 -2
  68. package/lib/util/flattenColorPalette.js +11 -12
  69. package/lib/util/formatVariantSelector.js +235 -151
  70. package/lib/util/getAllConfigs.js +33 -12
  71. package/lib/util/hashConfig.js +9 -4
  72. package/lib/util/isKeyframeRule.js +7 -2
  73. package/lib/util/isPlainObject.js +8 -3
  74. package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +25 -15
  75. package/lib/util/log.js +25 -15
  76. package/lib/util/nameClass.js +27 -10
  77. package/lib/util/negateValue.js +25 -8
  78. package/lib/util/normalizeConfig.js +127 -82
  79. package/lib/util/normalizeScreens.js +128 -11
  80. package/lib/util/parseAnimationValue.js +44 -40
  81. package/lib/util/parseBoxShadowValue.js +34 -23
  82. package/lib/util/parseDependency.js +39 -55
  83. package/lib/util/parseGlob.js +36 -0
  84. package/lib/util/parseObjectStyles.js +15 -10
  85. package/lib/util/pluginUtils.js +172 -69
  86. package/lib/util/prefixSelector.js +30 -12
  87. package/lib/util/pseudoElements.js +212 -0
  88. package/lib/util/removeAlphaVariables.js +31 -0
  89. package/lib/util/resolveConfig.js +101 -87
  90. package/lib/util/resolveConfigPath.js +30 -12
  91. package/lib/util/responsive.js +11 -6
  92. package/lib/util/splitAtTopLevelOnly.js +51 -0
  93. package/lib/util/tap.js +6 -1
  94. package/lib/util/toColorValue.js +7 -3
  95. package/lib/util/toPath.js +22 -4
  96. package/lib/util/transformThemeValue.js +40 -30
  97. package/lib/util/validateConfig.js +37 -0
  98. package/lib/util/validateFormalSyntax.js +26 -0
  99. package/lib/util/withAlphaVariable.js +27 -15
  100. package/lib/value-parser/LICENSE +22 -0
  101. package/lib/value-parser/README.md +3 -0
  102. package/lib/value-parser/index.d.js +2 -0
  103. package/lib/value-parser/index.js +22 -0
  104. package/lib/value-parser/parse.js +259 -0
  105. package/lib/value-parser/stringify.js +38 -0
  106. package/lib/value-parser/unit.js +86 -0
  107. package/lib/value-parser/walk.js +16 -0
  108. package/loadConfig.d.ts +4 -0
  109. package/loadConfig.js +2 -0
  110. package/nesting/index.d.ts +4 -0
  111. package/nesting/index.js +2 -12
  112. package/package.json +60 -55
  113. package/peers/index.js +75503 -55095
  114. package/plugin.d.ts +11 -0
  115. package/resolveConfig.d.ts +31 -0
  116. package/scripts/generate-types.js +104 -0
  117. package/scripts/release-channel.js +18 -0
  118. package/scripts/release-notes.js +21 -0
  119. package/scripts/type-utils.js +27 -0
  120. package/src/cli/build/deps.js +56 -0
  121. package/src/cli/build/index.js +49 -0
  122. package/src/cli/build/plugin.js +437 -0
  123. package/src/cli/build/utils.js +76 -0
  124. package/src/cli/build/watching.js +229 -0
  125. package/src/cli/help/index.js +70 -0
  126. package/src/cli/index.js +216 -0
  127. package/src/cli/init/index.js +79 -0
  128. package/src/cli-peer-dependencies.js +7 -1
  129. package/src/cli.js +1 -811
  130. package/src/corePluginList.js +1 -1
  131. package/src/corePlugins.js +849 -243
  132. package/src/css/preflight.css +32 -13
  133. package/src/featureFlags.js +13 -9
  134. package/src/index.js +1 -28
  135. package/src/lib/cacheInvalidation.js +52 -0
  136. package/src/lib/collapseAdjacentRules.js +21 -2
  137. package/src/lib/content.js +249 -0
  138. package/src/lib/defaultExtractor.js +215 -33
  139. package/src/lib/evaluateTailwindFunctions.js +82 -8
  140. package/src/lib/expandApplyAtRules.js +512 -224
  141. package/src/lib/expandTailwindAtRules.js +102 -87
  142. package/src/lib/findAtConfigPath.js +48 -0
  143. package/src/lib/generateRules.js +541 -146
  144. package/src/lib/getModuleDependencies.js +70 -30
  145. package/src/lib/load-config.ts +44 -0
  146. package/src/lib/normalizeTailwindDirectives.js +1 -0
  147. package/src/lib/offsets.js +432 -0
  148. package/src/lib/partitionApplyAtRules.js +52 -0
  149. package/src/lib/regex.js +74 -0
  150. package/src/lib/remap-bitfield.js +82 -0
  151. package/src/lib/resolveDefaultsAtRules.js +55 -30
  152. package/src/lib/setupContextUtils.js +720 -190
  153. package/src/lib/setupTrackingContext.js +47 -61
  154. package/src/lib/sharedState.js +15 -4
  155. package/src/plugin.js +47 -0
  156. package/src/postcss-plugins/nesting/README.md +42 -0
  157. package/src/postcss-plugins/nesting/index.js +13 -0
  158. package/src/postcss-plugins/nesting/plugin.js +80 -0
  159. package/src/processTailwindFeatures.js +11 -4
  160. package/src/public/colors.js +22 -0
  161. package/src/public/default-config.js +1 -1
  162. package/src/public/default-theme.js +2 -2
  163. package/src/public/load-config.js +2 -0
  164. package/src/util/applyImportantSelector.js +27 -0
  165. package/src/util/buildMediaQuery.js +5 -3
  166. package/src/util/cloneNodes.js +40 -2
  167. package/src/util/color.js +39 -20
  168. package/src/util/colorNames.js +150 -0
  169. package/src/util/dataTypes.js +184 -26
  170. package/src/util/formatVariantSelector.js +272 -144
  171. package/src/util/getAllConfigs.js +21 -2
  172. package/src/util/isPlainObject.js +1 -1
  173. package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
  174. package/src/util/log.js +8 -8
  175. package/src/util/nameClass.js +4 -0
  176. package/src/util/negateValue.js +11 -3
  177. package/src/util/normalizeConfig.js +45 -6
  178. package/src/util/normalizeScreens.js +99 -4
  179. package/src/util/parseBoxShadowValue.js +4 -3
  180. package/src/util/parseDependency.js +37 -42
  181. package/src/util/parseGlob.js +24 -0
  182. package/src/util/pluginUtils.js +139 -24
  183. package/src/util/prefixSelector.js +31 -10
  184. package/src/util/pseudoElements.js +171 -0
  185. package/src/util/removeAlphaVariables.js +24 -0
  186. package/src/util/resolveConfig.js +70 -32
  187. package/src/util/resolveConfigPath.js +12 -1
  188. package/src/util/splitAtTopLevelOnly.js +52 -0
  189. package/src/util/toPath.js +1 -1
  190. package/src/util/transformThemeValue.js +13 -3
  191. package/src/util/validateConfig.js +26 -0
  192. package/src/util/validateFormalSyntax.js +34 -0
  193. package/src/util/withAlphaVariable.js +1 -1
  194. package/src/value-parser/LICENSE +22 -0
  195. package/src/value-parser/README.md +3 -0
  196. package/src/value-parser/index.d.ts +177 -0
  197. package/src/value-parser/index.js +28 -0
  198. package/src/value-parser/parse.js +303 -0
  199. package/src/value-parser/stringify.js +41 -0
  200. package/src/value-parser/unit.js +118 -0
  201. package/src/value-parser/walk.js +18 -0
  202. package/stubs/.gitignore +1 -0
  203. package/stubs/.prettierrc.json +6 -0
  204. package/stubs/{defaultConfig.stub.js → config.full.js} +290 -178
  205. package/stubs/postcss.config.js +6 -0
  206. package/stubs/tailwind.config.cjs +2 -0
  207. package/stubs/tailwind.config.js +2 -0
  208. package/stubs/tailwind.config.ts +3 -0
  209. package/types/config.d.ts +376 -0
  210. package/types/generated/.gitkeep +0 -0
  211. package/types/generated/colors.d.ts +298 -0
  212. package/types/generated/corePluginList.d.ts +1 -0
  213. package/types/generated/default-theme.d.ts +397 -0
  214. package/types/index.d.ts +11 -0
  215. package/CHANGELOG.md +0 -1959
  216. package/lib/constants.js +0 -37
  217. package/lib/lib/detectNesting.js +0 -34
  218. package/nesting/plugin.js +0 -41
  219. package/scripts/install-integrations.js +0 -27
  220. package/scripts/rebuildFixtures.js +0 -68
  221. package/src/constants.js +0 -17
  222. package/src/lib/detectNesting.js +0 -39
  223. /package/stubs/{simpleConfig.stub.js → config.simple.js} +0 -0
  224. /package/stubs/{defaultPostCssConfig.stub.js → postcss.config.cjs} +0 -0
@@ -1,7 +1,8 @@
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'
6
7
  import { defaultExtractor } from './defaultExtractor'
7
8
 
@@ -16,14 +17,14 @@ const builtInTransformers = {
16
17
  svelte: (content) => content.replace(/(?:^|\s)class:/g, ' '),
17
18
  }
18
19
 
19
- function getExtractor(tailwindConfig, fileExtension) {
20
- let extractors = tailwindConfig.content.extract
20
+ function getExtractor(context, fileExtension) {
21
+ let extractors = context.tailwindConfig.content.extract
21
22
 
22
23
  return (
23
24
  extractors[fileExtension] ||
24
25
  extractors.DEFAULT ||
25
26
  builtInExtractors[fileExtension] ||
26
- builtInExtractors.DEFAULT
27
+ builtInExtractors.DEFAULT(context)
27
28
  )
28
29
  }
29
30
 
@@ -73,8 +74,13 @@ function getClassCandidates(content, extractor, candidates, seen) {
73
74
  }
74
75
  }
75
76
 
77
+ /**
78
+ *
79
+ * @param {[import('./offsets.js').RuleOffset, import('postcss').Node][]} rules
80
+ * @param {*} context
81
+ */
76
82
  function buildStylesheet(rules, context) {
77
- let sortedRules = rules.sort(([a], [z]) => bigSign(a - z))
83
+ let sortedRules = context.offsets.sort(rules)
78
84
 
79
85
  let returnValue = {
80
86
  base: new Set(),
@@ -82,57 +88,17 @@ function buildStylesheet(rules, context) {
82
88
  components: new Set(),
83
89
  utilities: new Set(),
84
90
  variants: new Set(),
85
-
86
- // All the CSS that is not Tailwind related can be put in this bucket. This
87
- // will make it easier to later use this information when we want to
88
- // `@apply` for example. The main reason we do this here is because we
89
- // still need to make sure the order is correct. Last but not least, we
90
- // will make sure to always re-inject this section into the css, even if
91
- // certain rules were not used. This means that it will look like a no-op
92
- // from the user's perspective, but we gathered all the useful information
93
- // we need.
94
- user: new Set(),
95
91
  }
96
92
 
97
93
  for (let [sort, rule] of sortedRules) {
98
- if (sort >= context.minimumScreen) {
99
- returnValue.variants.add(rule)
100
- continue
101
- }
102
-
103
- if (sort & context.layerOrder.base) {
104
- returnValue.base.add(rule)
105
- continue
106
- }
107
-
108
- if (sort & context.layerOrder.defaults) {
109
- returnValue.defaults.add(rule)
110
- continue
111
- }
112
-
113
- if (sort & context.layerOrder.components) {
114
- returnValue.components.add(rule)
115
- continue
116
- }
117
-
118
- if (sort & context.layerOrder.utilities) {
119
- returnValue.utilities.add(rule)
120
- continue
121
- }
122
-
123
- if (sort & context.layerOrder.user) {
124
- returnValue.user.add(rule)
125
- continue
126
- }
94
+ returnValue[sort.layer].add(rule)
127
95
  }
128
96
 
129
97
  return returnValue
130
98
  }
131
99
 
132
- export const DEFAULTS_LAYER = Symbol('defaults-layer')
133
-
134
100
  export default function expandTailwindAtRules(context) {
135
- return (root) => {
101
+ return async (root) => {
136
102
  let layerNodes = {
137
103
  base: null,
138
104
  components: null,
@@ -140,8 +106,6 @@ export default function expandTailwindAtRules(context) {
140
106
  variants: null,
141
107
  }
142
108
 
143
- // let hasApply = false
144
-
145
109
  root.walkAtRules((rule) => {
146
110
  // Make sure this file contains Tailwind directives. If not, we can save
147
111
  // a lot of work and bail early. Also we don't have to register our touch
@@ -152,13 +116,6 @@ export default function expandTailwindAtRules(context) {
152
116
  layerNodes[rule.params] = rule
153
117
  }
154
118
  }
155
-
156
- // We also want to check for @apply because the user can
157
- // apply classes in an isolated environment like CSS
158
- // modules and we still need to inject defaults
159
- // if (rule.name === 'apply') {
160
- // hasApply = true
161
- // }
162
119
  })
163
120
 
164
121
  if (Object.values(layerNodes).every((n) => n === null)) {
@@ -168,33 +125,55 @@ export default function expandTailwindAtRules(context) {
168
125
  // ---
169
126
 
170
127
  // Find potential rules in changed files
171
- let candidates = new Set(['*'])
128
+ let candidates = new Set([...(context.candidates ?? []), sharedState.NOT_ON_DEMAND])
172
129
  let seen = new Set()
173
130
 
174
131
  env.DEBUG && console.time('Reading changed files')
175
132
 
176
- for (let { content, extension } of context.changedContent) {
177
- let transformer = getTransformer(context.tailwindConfig, extension)
178
- let extractor = getExtractor(context.tailwindConfig, extension)
179
- getClassCandidates(transformer(content), extractor, candidates, seen)
133
+ /** @type {[item: {file?: string, content?: string}, meta: {transformer: any, extractor: any}][]} */
134
+ let regexParserContent = []
135
+
136
+ for (let item of context.changedContent) {
137
+ let transformer = getTransformer(context.tailwindConfig, item.extension)
138
+ let extractor = getExtractor(context, item.extension)
139
+ regexParserContent.push([item, { transformer, extractor }])
140
+ }
141
+
142
+ const BATCH_SIZE = 500
143
+
144
+ for (let i = 0; i < regexParserContent.length; i += BATCH_SIZE) {
145
+ let batch = regexParserContent.slice(i, i + BATCH_SIZE)
146
+ await Promise.all(
147
+ batch.map(async ([{ file, content }, { transformer, extractor }]) => {
148
+ content = file ? await fs.promises.readFile(file, 'utf8') : content
149
+ getClassCandidates(transformer(content), extractor, candidates, seen)
150
+ })
151
+ )
180
152
  }
181
153
 
154
+ env.DEBUG && console.timeEnd('Reading changed files')
155
+
182
156
  // ---
183
157
 
184
158
  // Generate the actual CSS
185
159
  let classCacheCount = context.classCache.size
186
160
 
187
161
  env.DEBUG && console.time('Generate rules')
188
- let rules = generateRules(candidates, context)
162
+ env.DEBUG && console.time('Sorting candidates')
163
+ let sortedCandidates = new Set(
164
+ [...candidates].sort((a, z) => {
165
+ if (a === z) return 0
166
+ if (a < z) return -1
167
+ return 1
168
+ })
169
+ )
170
+ env.DEBUG && console.timeEnd('Sorting candidates')
171
+ generateRules(sortedCandidates, context)
189
172
  env.DEBUG && console.timeEnd('Generate rules')
190
173
 
191
174
  // We only ever add to the classCache, so if it didn't grow, there is nothing new.
192
175
  env.DEBUG && console.time('Build stylesheet')
193
176
  if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
194
- for (let rule of rules) {
195
- context.ruleCache.add(rule)
196
- }
197
-
198
177
  context.stylesheetCache = buildStylesheet([...context.ruleCache], context)
199
178
  }
200
179
  env.DEBUG && console.timeEnd('Build stylesheet')
@@ -212,39 +191,75 @@ export default function expandTailwindAtRules(context) {
212
191
  // Replace any Tailwind directives with generated CSS
213
192
 
214
193
  if (layerNodes.base) {
215
- layerNodes.base.before(cloneNodes([...baseNodes], layerNodes.base.source))
216
- }
217
-
218
- // @defaults rules are unconditionally added first to ensure that
219
- // using any utility that relies on defaults will work even when
220
- // compiled in an isolated environment like CSS modules
221
- if (context.tailwindConfig[DEFAULTS_LAYER] !== false) {
222
- if (layerNodes.base) {
223
- layerNodes.base.after(cloneNodes([...defaultNodes], root.source))
224
- } else {
225
- root.prepend(cloneNodes([...defaultNodes], root.source))
226
- }
227
- }
228
-
229
- if (layerNodes.base) {
194
+ layerNodes.base.before(
195
+ cloneNodes([...baseNodes, ...defaultNodes], layerNodes.base.source, {
196
+ layer: 'base',
197
+ })
198
+ )
230
199
  layerNodes.base.remove()
231
200
  }
232
201
 
233
202
  if (layerNodes.components) {
234
- layerNodes.components.before(cloneNodes([...componentNodes], layerNodes.components.source))
203
+ layerNodes.components.before(
204
+ cloneNodes([...componentNodes], layerNodes.components.source, {
205
+ layer: 'components',
206
+ })
207
+ )
235
208
  layerNodes.components.remove()
236
209
  }
237
210
 
238
211
  if (layerNodes.utilities) {
239
- layerNodes.utilities.before(cloneNodes([...utilityNodes], layerNodes.utilities.source))
212
+ layerNodes.utilities.before(
213
+ cloneNodes([...utilityNodes], layerNodes.utilities.source, {
214
+ layer: 'utilities',
215
+ })
216
+ )
240
217
  layerNodes.utilities.remove()
241
218
  }
242
219
 
220
+ // We do post-filtering to not alter the emitted order of the variants
221
+ const variantNodes = Array.from(screenNodes).filter((node) => {
222
+ const parentLayer = node.raws.tailwind?.parentLayer
223
+
224
+ if (parentLayer === 'components') {
225
+ return layerNodes.components !== null
226
+ }
227
+
228
+ if (parentLayer === 'utilities') {
229
+ return layerNodes.utilities !== null
230
+ }
231
+
232
+ return true
233
+ })
234
+
243
235
  if (layerNodes.variants) {
244
- layerNodes.variants.before(cloneNodes([...screenNodes], layerNodes.variants.source))
236
+ layerNodes.variants.before(
237
+ cloneNodes(variantNodes, layerNodes.variants.source, {
238
+ layer: 'variants',
239
+ })
240
+ )
245
241
  layerNodes.variants.remove()
246
- } else {
247
- root.append(cloneNodes([...screenNodes], root.source))
242
+ } else if (variantNodes.length > 0) {
243
+ root.append(
244
+ cloneNodes(variantNodes, root.source, {
245
+ layer: 'variants',
246
+ })
247
+ )
248
+ }
249
+
250
+ // TODO: Why is the root node having no source location for `end` possible?
251
+ root.source.end = root.source.end ?? root.source.start
252
+
253
+ // If we've got a utility layer and no utilities are generated there's likely something wrong
254
+ const hasUtilityVariants = variantNodes.some(
255
+ (node) => node.raws.tailwind?.parentLayer === 'utilities'
256
+ )
257
+
258
+ if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
259
+ log.warn('content-problems', [
260
+ 'No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.',
261
+ 'https://tailwindcss.com/docs/content-configuration',
262
+ ])
248
263
  }
249
264
 
250
265
  // ---
@@ -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
+ }