tailwindcss 3.0.21 → 3.0.24

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 (89) hide show
  1. package/CHANGELOG.md +45 -2
  2. package/lib/cli-peer-dependencies.js +3 -3
  3. package/lib/cli.js +183 -161
  4. package/lib/constants.js +8 -8
  5. package/lib/corePlugins.js +1597 -1518
  6. package/lib/featureFlags.js +9 -9
  7. package/lib/index.js +19 -6
  8. package/lib/lib/cacheInvalidation.js +69 -0
  9. package/lib/lib/collapseAdjacentRules.js +26 -13
  10. package/lib/lib/collapseDuplicateDeclarations.js +1 -1
  11. package/lib/lib/defaultExtractor.js +8 -6
  12. package/lib/lib/detectNesting.js +9 -9
  13. package/lib/lib/evaluateTailwindFunctions.js +16 -16
  14. package/lib/lib/expandApplyAtRules.js +180 -27
  15. package/lib/lib/expandTailwindAtRules.js +132 -122
  16. package/lib/lib/generateRules.js +117 -72
  17. package/lib/lib/getModuleDependencies.js +14 -14
  18. package/lib/lib/normalizeTailwindDirectives.js +35 -35
  19. package/lib/lib/partitionApplyAtRules.js +7 -7
  20. package/lib/lib/resolveDefaultsAtRules.js +81 -77
  21. package/lib/lib/setupContextUtils.js +83 -98
  22. package/lib/lib/setupTrackingContext.js +57 -57
  23. package/lib/lib/sharedState.js +11 -7
  24. package/lib/lib/substituteScreenAtRules.js +2 -2
  25. package/lib/postcss-plugins/nesting/README.md +2 -2
  26. package/lib/postcss-plugins/nesting/index.js +1 -1
  27. package/lib/postcss-plugins/nesting/plugin.js +41 -9
  28. package/lib/processTailwindFeatures.js +7 -7
  29. package/lib/public/colors.js +241 -241
  30. package/lib/public/resolve-config.js +5 -5
  31. package/lib/util/buildMediaQuery.js +2 -2
  32. package/lib/util/cloneDeep.js +1 -1
  33. package/lib/util/cloneNodes.js +12 -1
  34. package/lib/util/color.js +21 -20
  35. package/lib/util/createUtilityPlugin.js +6 -6
  36. package/lib/util/dataTypes.js +77 -75
  37. package/lib/util/escapeClassName.js +5 -5
  38. package/lib/util/escapeCommas.js +1 -1
  39. package/lib/util/flattenColorPalette.js +2 -2
  40. package/lib/util/formatVariantSelector.js +19 -19
  41. package/lib/util/getAllConfigs.js +5 -5
  42. package/lib/util/hashConfig.js +5 -5
  43. package/lib/util/isKeyframeRule.js +1 -1
  44. package/lib/util/isPlainObject.js +1 -1
  45. package/lib/util/isValidArbitraryValue.js +27 -27
  46. package/lib/util/log.js +8 -8
  47. package/lib/util/nameClass.js +7 -7
  48. package/lib/util/negateValue.js +4 -4
  49. package/lib/util/normalizeConfig.js +39 -39
  50. package/lib/util/normalizeScreens.js +4 -4
  51. package/lib/util/parseAnimationValue.js +56 -56
  52. package/lib/util/parseBoxShadowValue.js +60 -20
  53. package/lib/util/parseDependency.js +32 -32
  54. package/lib/util/parseObjectStyles.js +6 -6
  55. package/lib/util/pluginUtils.js +9 -9
  56. package/lib/util/prefixSelector.js +1 -1
  57. package/lib/util/resolveConfig.js +28 -28
  58. package/lib/util/resolveConfigPath.js +16 -16
  59. package/lib/util/responsive.js +6 -6
  60. package/lib/util/toColorValue.js +1 -1
  61. package/lib/util/toPath.js +2 -2
  62. package/lib/util/transformThemeValue.js +27 -27
  63. package/lib/util/withAlphaVariable.js +19 -19
  64. package/package.json +26 -25
  65. package/peers/index.js +4803 -4857
  66. package/scripts/generate-types.js +52 -0
  67. package/src/cli.js +41 -11
  68. package/src/corePlugins.js +104 -9
  69. package/src/featureFlags.js +2 -2
  70. package/src/index.js +17 -1
  71. package/src/lib/cacheInvalidation.js +52 -0
  72. package/src/lib/collapseAdjacentRules.js +16 -1
  73. package/src/lib/defaultExtractor.js +6 -4
  74. package/src/lib/expandApplyAtRules.js +179 -6
  75. package/src/lib/expandTailwindAtRules.js +26 -6
  76. package/src/lib/generateRules.js +73 -46
  77. package/src/lib/resolveDefaultsAtRules.js +6 -2
  78. package/src/lib/setupContextUtils.js +39 -48
  79. package/src/lib/setupTrackingContext.js +3 -3
  80. package/src/lib/sharedState.js +2 -0
  81. package/src/postcss-plugins/nesting/README.md +2 -2
  82. package/src/postcss-plugins/nesting/plugin.js +36 -0
  83. package/src/util/cloneNodes.js +14 -1
  84. package/src/util/color.js +7 -5
  85. package/src/util/dataTypes.js +3 -1
  86. package/src/util/log.js +7 -7
  87. package/src/util/parseBoxShadowValue.js +50 -2
  88. package/src/util/resolveConfig.js +32 -0
  89. package/stubs/defaultConfig.stub.js +5 -0
@@ -8,12 +8,20 @@ var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-pa
8
8
  var _generateRules = require("./generateRules");
9
9
  var _bigSign = _interopRequireDefault(require("../util/bigSign"));
10
10
  var _escapeClassName = _interopRequireDefault(require("../util/escapeClassName"));
11
+ function expandApplyAtRules(context) {
12
+ return (root)=>{
13
+ // Build a cache of the user's CSS so we can use it to resolve classes used by @apply
14
+ let localCache = lazyCache(()=>buildLocalApplyCache(root, context)
15
+ );
16
+ processApply(root, context, localCache);
17
+ };
18
+ }
11
19
  function _interopRequireDefault(obj) {
12
20
  return obj && obj.__esModule ? obj : {
13
21
  default: obj
14
22
  };
15
23
  }
16
- function extractClasses(node) {
24
+ /** @typedef {Map<string, [any, import('postcss').Rule[]]>} ApplyCache */ function extractClasses(node) {
17
25
  let classes = new Set();
18
26
  let container = _postcss.default.root({
19
27
  nodes: [
@@ -38,9 +46,116 @@ function extractBaseCandidates(candidates, separator) {
38
46
  }
39
47
  function prefix(context, selector) {
40
48
  let prefix1 = context.tailwindConfig.prefix;
41
- return typeof prefix1 === 'function' ? prefix1(selector) : prefix1 + selector;
49
+ return typeof prefix1 === "function" ? prefix1(selector) : prefix1 + selector;
50
+ }
51
+ function* pathToRoot(node) {
52
+ yield node;
53
+ while(node.parent){
54
+ yield node.parent;
55
+ node = node.parent;
56
+ }
57
+ }
58
+ /**
59
+ * Only clone the node itself and not its children
60
+ *
61
+ * @param {*} node
62
+ * @param {*} overrides
63
+ * @returns
64
+ */ function shallowClone(node, overrides = {}) {
65
+ let children = node.nodes;
66
+ node.nodes = [];
67
+ let tmp = node.clone(overrides);
68
+ node.nodes = children;
69
+ return tmp;
42
70
  }
43
- function buildApplyCache(applyCandidates, context) {
71
+ /**
72
+ * Clone just the nodes all the way to the top that are required to represent
73
+ * this singular rule in the tree.
74
+ *
75
+ * For example, if we have CSS like this:
76
+ * ```css
77
+ * @media (min-width: 768px) {
78
+ * @supports (display: grid) {
79
+ * .foo {
80
+ * display: grid;
81
+ * grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
82
+ * }
83
+ * }
84
+ *
85
+ * @supports (backdrop-filter: blur(1px)) {
86
+ * .bar {
87
+ * backdrop-filter: blur(1px);
88
+ * }
89
+ * }
90
+ *
91
+ * .baz {
92
+ * color: orange;
93
+ * }
94
+ * }
95
+ * ```
96
+ *
97
+ * And we're cloning `.bar` it'll return a cloned version of what's required for just that single node:
98
+ *
99
+ * ```css
100
+ * @media (min-width: 768px) {
101
+ * @supports (backdrop-filter: blur(1px)) {
102
+ * .bar {
103
+ * backdrop-filter: blur(1px);
104
+ * }
105
+ * }
106
+ * }
107
+ * ```
108
+ *
109
+ * @param {import('postcss').Node} node
110
+ */ function nestedClone(node) {
111
+ for (let parent of pathToRoot(node)){
112
+ if (node === parent) {
113
+ continue;
114
+ }
115
+ if (parent.type === "root") {
116
+ break;
117
+ }
118
+ node = shallowClone(parent, {
119
+ nodes: [
120
+ node
121
+ ]
122
+ });
123
+ }
124
+ return node;
125
+ }
126
+ /**
127
+ * @param {import('postcss').Root} root
128
+ */ function buildLocalApplyCache(root, context) {
129
+ /** @type {ApplyCache} */ let cache = new Map();
130
+ let highestOffset = context.layerOrder.user >> 4n;
131
+ root.walkRules((rule, idx)=>{
132
+ // Ignore rules generated by Tailwind
133
+ for (let node of pathToRoot(rule)){
134
+ var ref;
135
+ if (((ref = node.raws.tailwind) === null || ref === void 0 ? void 0 : ref.layer) !== undefined) {
136
+ return;
137
+ }
138
+ }
139
+ // Clone what's required to represent this singular rule in the tree
140
+ let container = nestedClone(rule);
141
+ for (let className of extractClasses(rule)){
142
+ let list = cache.get(className) || [];
143
+ cache.set(className, list);
144
+ list.push([
145
+ {
146
+ layer: "user",
147
+ sort: BigInt(idx) + highestOffset,
148
+ important: false
149
+ },
150
+ container,
151
+ ]);
152
+ }
153
+ });
154
+ return cache;
155
+ }
156
+ /**
157
+ * @returns {ApplyCache}
158
+ */ function buildApplyCache(applyCandidates, context) {
44
159
  for (let candidate of applyCandidates){
45
160
  if (context.notClassCache.has(candidate) || context.applyClassCache.has(candidate)) {
46
161
  continue;
@@ -62,9 +177,42 @@ function buildApplyCache(applyCandidates, context) {
62
177
  }
63
178
  return context.applyClassCache;
64
179
  }
180
+ /**
181
+ * Build a cache only when it's first used
182
+ *
183
+ * @param {() => ApplyCache} buildCacheFn
184
+ * @returns {ApplyCache}
185
+ */ function lazyCache(buildCacheFn) {
186
+ let cache = null;
187
+ return {
188
+ get: (name)=>{
189
+ cache = cache || buildCacheFn();
190
+ return cache.get(name);
191
+ },
192
+ has: (name)=>{
193
+ cache = cache || buildCacheFn();
194
+ return cache.has(name);
195
+ }
196
+ };
197
+ }
198
+ /**
199
+ * Take a series of multiple caches and merge
200
+ * them so they act like one large cache
201
+ *
202
+ * @param {ApplyCache[]} caches
203
+ * @returns {ApplyCache}
204
+ */ function combineCaches(caches) {
205
+ return {
206
+ get: (name)=>caches.flatMap((cache)=>cache.get(name) || []
207
+ )
208
+ ,
209
+ has: (name)=>caches.some((cache)=>cache.has(name)
210
+ )
211
+ };
212
+ }
65
213
  function extractApplyCandidates(params) {
66
214
  let candidates = params.split(/[\s\t\n]+/g);
67
- if (candidates[candidates.length - 1] === '!important') {
215
+ if (candidates[candidates.length - 1] === "!important") {
68
216
  return [
69
217
  candidates.slice(0, -1),
70
218
  true
@@ -75,11 +223,11 @@ function extractApplyCandidates(params) {
75
223
  false
76
224
  ];
77
225
  }
78
- function processApply(root, context) {
226
+ function processApply(root, context, localCache) {
79
227
  let applyCandidates = new Set();
80
228
  // Collect all @apply rules and candidates
81
229
  let applies = [];
82
- root.walkAtRules('apply', (rule)=>{
230
+ root.walkAtRules("apply", (rule)=>{
83
231
  let [candidates] = extractApplyCandidates(rule.params);
84
232
  for (let util of candidates){
85
233
  applyCandidates.add(util);
@@ -89,7 +237,10 @@ function processApply(root, context) {
89
237
  // Start the @apply process if we have rules with @apply in them
90
238
  if (applies.length > 0) {
91
239
  // Fill up some caches!
92
- let applyClassCache = buildApplyCache(applyCandidates, context);
240
+ let applyClassCache = combineCaches([
241
+ localCache,
242
+ buildApplyCache(applyCandidates, context)
243
+ ]);
93
244
  /**
94
245
  * When we have an apply like this:
95
246
  *
@@ -122,27 +273,30 @@ function processApply(root, context) {
122
273
  }
123
274
  replaced.push(replacedSelector);
124
275
  }
125
- return replaced.join(', ');
126
- }).join(', ');
276
+ return replaced.join(", ");
277
+ }).join(", ");
127
278
  }
128
279
  let perParentApplies = new Map();
129
280
  // Collect all apply candidates and their rules
130
281
  for (let apply of applies){
131
282
  let candidates = perParentApplies.get(apply.parent) || [];
132
- perParentApplies.set(apply.parent, candidates);
283
+ perParentApplies.set(apply.parent, [
284
+ candidates,
285
+ apply.source
286
+ ]);
133
287
  let [applyCandidates, important] = extractApplyCandidates(apply.params);
134
- if (apply.parent.type === 'atrule') {
135
- if (apply.parent.name === 'screen') {
288
+ if (apply.parent.type === "atrule") {
289
+ if (apply.parent.name === "screen") {
136
290
  const screenType = apply.parent.params;
137
291
  throw apply.error(`@apply is not supported within nested at-rules like @screen. We suggest you write this as @apply ${applyCandidates.map((c)=>`${screenType}:${c}`
138
- ).join(' ')} instead.`);
292
+ ).join(" ")} instead.`);
139
293
  }
140
294
  throw apply.error(`@apply is not supported within nested at-rules like @${apply.parent.name}. You can fix this by un-nesting @${apply.parent.name}.`);
141
295
  }
142
296
  for (let applyCandidate of applyCandidates){
143
297
  if ([
144
- prefix(context, 'group'),
145
- prefix(context, 'peer')
298
+ prefix(context, "group"),
299
+ prefix(context, "peer")
146
300
  ].includes(applyCandidate)) {
147
301
  // TODO: Link to specific documentation page with error code.
148
302
  throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`);
@@ -158,12 +312,12 @@ function processApply(root, context) {
158
312
  ]);
159
313
  }
160
314
  }
161
- for (const [parent, candidates] of perParentApplies){
315
+ for (const [parent, [candidates, atApplySource]] of perParentApplies){
162
316
  let siblings = [];
163
317
  for (let [applyCandidate, important, rules] of candidates){
164
- for (let [meta, node] of rules){
318
+ for (let [meta, node1] of rules){
165
319
  let parentClasses = extractClasses(parent);
166
- let nodeClasses = extractClasses(node);
320
+ let nodeClasses = extractClasses(node1);
167
321
  // Add base utility classes from the @apply node to the list of
168
322
  // classes to check whether it intersects and therefore results in a
169
323
  // circular dependency or not.
@@ -190,14 +344,18 @@ function processApply(root, context) {
190
344
  let intersects = parentClasses.some((selector)=>nodeClasses.includes(selector)
191
345
  );
192
346
  if (intersects) {
193
- throw node.error(`You cannot \`@apply\` the \`${applyCandidate}\` utility here because it creates a circular dependency.`);
347
+ throw node1.error(`You cannot \`@apply\` the \`${applyCandidate}\` utility here because it creates a circular dependency.`);
194
348
  }
195
349
  let root = _postcss.default.root({
196
350
  nodes: [
197
- node.clone()
351
+ node1.clone()
198
352
  ]
199
353
  });
200
- let canRewriteSelector = node.type !== 'atrule' || node.type === 'atrule' && node.name !== 'keyframes';
354
+ // Make sure every node in the entire tree points back at the @apply rule that generated it
355
+ root.walk((node)=>{
356
+ node.source = atApplySource;
357
+ });
358
+ let canRewriteSelector = node1.type !== "atrule" || node1.type === "atrule" && node1.name !== "keyframes";
201
359
  if (canRewriteSelector) {
202
360
  root.walkRules((rule)=>{
203
361
  // Let's imagine you have the following structure:
@@ -270,11 +428,6 @@ function processApply(root, context) {
270
428
  }
271
429
  }
272
430
  // Do it again, in case we have other `@apply` rules
273
- processApply(root, context);
431
+ processApply(root, context, localCache);
274
432
  }
275
433
  }
276
- function expandApplyAtRules(context) {
277
- return (root)=>{
278
- processApply(root, context);
279
- };
280
- }
@@ -10,6 +10,135 @@ var _bigSign = _interopRequireDefault(require("../util/bigSign"));
10
10
  var _log = _interopRequireDefault(require("../util/log"));
11
11
  var _cloneNodes = _interopRequireDefault(require("../util/cloneNodes"));
12
12
  var _defaultExtractor = require("./defaultExtractor");
13
+ function expandTailwindAtRules(context) {
14
+ return (root)=>{
15
+ let layerNodes = {
16
+ base: null,
17
+ components: null,
18
+ utilities: null,
19
+ variants: null
20
+ };
21
+ root.walkAtRules((rule)=>{
22
+ // Make sure this file contains Tailwind directives. If not, we can save
23
+ // a lot of work and bail early. Also we don't have to register our touch
24
+ // file as a dependency since the output of this CSS does not depend on
25
+ // the source of any templates. Think Vue <style> blocks for example.
26
+ if (rule.name === "tailwind") {
27
+ if (Object.keys(layerNodes).includes(rule.params)) {
28
+ layerNodes[rule.params] = rule;
29
+ }
30
+ }
31
+ });
32
+ if (Object.values(layerNodes).every((n)=>n === null
33
+ )) {
34
+ return root;
35
+ }
36
+ // ---
37
+ // Find potential rules in changed files
38
+ let candidates = new Set([
39
+ sharedState.NOT_ON_DEMAND
40
+ ]);
41
+ let seen = new Set();
42
+ env.DEBUG && console.time("Reading changed files");
43
+ for (let { content , extension } of context.changedContent){
44
+ let transformer = getTransformer(context.tailwindConfig, extension);
45
+ let extractor = getExtractor(context.tailwindConfig, extension);
46
+ getClassCandidates(transformer(content), extractor, candidates, seen);
47
+ }
48
+ env.DEBUG && console.timeEnd("Reading changed files");
49
+ // ---
50
+ // Generate the actual CSS
51
+ let classCacheCount = context.classCache.size;
52
+ env.DEBUG && console.time("Generate rules");
53
+ let rules = (0, _generateRules).generateRules(candidates, context);
54
+ env.DEBUG && console.timeEnd("Generate rules");
55
+ // We only ever add to the classCache, so if it didn't grow, there is nothing new.
56
+ env.DEBUG && console.time("Build stylesheet");
57
+ if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
58
+ for (let rule of rules){
59
+ context.ruleCache.add(rule);
60
+ }
61
+ context.stylesheetCache = buildStylesheet([
62
+ ...context.ruleCache
63
+ ], context);
64
+ }
65
+ env.DEBUG && console.timeEnd("Build stylesheet");
66
+ let { defaults: defaultNodes , base: baseNodes , components: componentNodes , utilities: utilityNodes , variants: screenNodes , } = context.stylesheetCache;
67
+ // ---
68
+ // Replace any Tailwind directives with generated CSS
69
+ if (layerNodes.base) {
70
+ layerNodes.base.before((0, _cloneNodes).default([
71
+ ...baseNodes,
72
+ ...defaultNodes
73
+ ], layerNodes.base.source, {
74
+ layer: "base"
75
+ }));
76
+ layerNodes.base.remove();
77
+ }
78
+ if (layerNodes.components) {
79
+ layerNodes.components.before((0, _cloneNodes).default([
80
+ ...componentNodes
81
+ ], layerNodes.components.source, {
82
+ layer: "components"
83
+ }));
84
+ layerNodes.components.remove();
85
+ }
86
+ if (layerNodes.utilities) {
87
+ layerNodes.utilities.before((0, _cloneNodes).default([
88
+ ...utilityNodes
89
+ ], layerNodes.utilities.source, {
90
+ layer: "utilities"
91
+ }));
92
+ layerNodes.utilities.remove();
93
+ }
94
+ // We do post-filtering to not alter the emitted order of the variants
95
+ const variantNodes = Array.from(screenNodes).filter((node)=>{
96
+ var ref;
97
+ const parentLayer = (ref = node.raws.tailwind) === null || ref === void 0 ? void 0 : ref.parentLayer;
98
+ if (parentLayer === "components") {
99
+ return layerNodes.components !== null;
100
+ }
101
+ if (parentLayer === "utilities") {
102
+ return layerNodes.utilities !== null;
103
+ }
104
+ return true;
105
+ });
106
+ if (layerNodes.variants) {
107
+ layerNodes.variants.before((0, _cloneNodes).default(variantNodes, layerNodes.variants.source, {
108
+ layer: "variants"
109
+ }));
110
+ layerNodes.variants.remove();
111
+ } else if (variantNodes.length > 0) {
112
+ root.append((0, _cloneNodes).default(variantNodes, root.source, {
113
+ layer: "variants"
114
+ }));
115
+ }
116
+ // If we've got a utility layer and no utilities are generated there's likely something wrong
117
+ const hasUtilityVariants = variantNodes.some((node)=>{
118
+ var ref;
119
+ return ((ref = node.raws.tailwind) === null || ref === void 0 ? void 0 : ref.parentLayer) === "utilities";
120
+ });
121
+ if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
122
+ _log.default.warn("content-problems", [
123
+ "No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.",
124
+ "https://tailwindcss.com/docs/content-configuration",
125
+ ]);
126
+ }
127
+ // ---
128
+ if (env.DEBUG) {
129
+ console.log("Potential classes: ", candidates.size);
130
+ console.log("Active contexts: ", sharedState.contextSourcesMap.size);
131
+ }
132
+ // Clear the cache for the changed files
133
+ context.changedContent = [];
134
+ // Cleanup any leftover @layer atrules
135
+ root.walkAtRules("layer", (rule)=>{
136
+ if (Object.keys(layerNodes).includes(rule.params)) {
137
+ rule.remove();
138
+ }
139
+ });
140
+ };
141
+ }
13
142
  function _interopRequireDefault(obj) {
14
143
  return obj && obj.__esModule ? obj : {
15
144
  default: obj
@@ -43,7 +172,7 @@ const builtInExtractors = {
43
172
  const builtInTransformers = {
44
173
  DEFAULT: (content)=>content
45
174
  ,
46
- svelte: (content)=>content.replace(/(?:^|\s)class:/g, ' ')
175
+ svelte: (content)=>content.replace(/(?:^|\s)class:/g, " ")
47
176
  };
48
177
  function getExtractor(tailwindConfig, fileExtension) {
49
178
  let extractors = tailwindConfig.content.extract;
@@ -63,7 +192,7 @@ function getClassCandidates(content, extractor, candidates, seen) {
63
192
  maxSize: 25000
64
193
  }));
65
194
  }
66
- for (let line of content.split('\n')){
195
+ for (let line of content.split("\n")){
67
196
  line = line.trim();
68
197
  if (seen.has(line)) {
69
198
  continue;
@@ -74,7 +203,7 @@ function getClassCandidates(content, extractor, candidates, seen) {
74
203
  candidates.add(match);
75
204
  }
76
205
  } else {
77
- let extractorMatches = extractor(line).filter((s)=>s !== '!*'
206
+ let extractorMatches = extractor(line).filter((s)=>s !== "!*"
78
207
  );
79
208
  let lineMatchesSet = new Set(extractorMatches);
80
209
  for (let match of lineMatchesSet){
@@ -131,122 +260,3 @@ function buildStylesheet(rules, context) {
131
260
  }
132
261
  return returnValue;
133
262
  }
134
- function expandTailwindAtRules(context) {
135
- return (root)=>{
136
- let layerNodes = {
137
- base: null,
138
- components: null,
139
- utilities: null,
140
- variants: null
141
- };
142
- root.walkAtRules((rule)=>{
143
- // Make sure this file contains Tailwind directives. If not, we can save
144
- // a lot of work and bail early. Also we don't have to register our touch
145
- // file as a dependency since the output of this CSS does not depend on
146
- // the source of any templates. Think Vue <style> blocks for example.
147
- if (rule.name === 'tailwind') {
148
- if (Object.keys(layerNodes).includes(rule.params)) {
149
- layerNodes[rule.params] = rule;
150
- }
151
- }
152
- });
153
- if (Object.values(layerNodes).every((n)=>n === null
154
- )) {
155
- return root;
156
- }
157
- // ---
158
- // Find potential rules in changed files
159
- let candidates = new Set([
160
- '*'
161
- ]);
162
- let seen = new Set();
163
- env.DEBUG && console.time('Reading changed files');
164
- for (let { content , extension } of context.changedContent){
165
- let transformer = getTransformer(context.tailwindConfig, extension);
166
- let extractor = getExtractor(context.tailwindConfig, extension);
167
- getClassCandidates(transformer(content), extractor, candidates, seen);
168
- }
169
- env.DEBUG && console.timeEnd('Reading changed files');
170
- // ---
171
- // Generate the actual CSS
172
- let classCacheCount = context.classCache.size;
173
- env.DEBUG && console.time('Generate rules');
174
- let rules = (0, _generateRules).generateRules(candidates, context);
175
- env.DEBUG && console.timeEnd('Generate rules');
176
- // We only ever add to the classCache, so if it didn't grow, there is nothing new.
177
- env.DEBUG && console.time('Build stylesheet');
178
- if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
179
- for (let rule of rules){
180
- context.ruleCache.add(rule);
181
- }
182
- context.stylesheetCache = buildStylesheet([
183
- ...context.ruleCache
184
- ], context);
185
- }
186
- env.DEBUG && console.timeEnd('Build stylesheet');
187
- let { defaults: defaultNodes , base: baseNodes , components: componentNodes , utilities: utilityNodes , variants: screenNodes , } = context.stylesheetCache;
188
- // ---
189
- // Replace any Tailwind directives with generated CSS
190
- if (layerNodes.base) {
191
- layerNodes.base.before((0, _cloneNodes).default([
192
- ...baseNodes,
193
- ...defaultNodes
194
- ], layerNodes.base.source));
195
- layerNodes.base.remove();
196
- }
197
- if (layerNodes.components) {
198
- layerNodes.components.before((0, _cloneNodes).default([
199
- ...componentNodes
200
- ], layerNodes.components.source));
201
- layerNodes.components.remove();
202
- }
203
- if (layerNodes.utilities) {
204
- layerNodes.utilities.before((0, _cloneNodes).default([
205
- ...utilityNodes
206
- ], layerNodes.utilities.source));
207
- layerNodes.utilities.remove();
208
- }
209
- // We do post-filtering to not alter the emitted order of the variants
210
- const variantNodes = Array.from(screenNodes).filter((node)=>{
211
- var ref;
212
- const parentLayer = (ref = node.raws.tailwind) === null || ref === void 0 ? void 0 : ref.parentLayer;
213
- if (parentLayer === 'components') {
214
- return layerNodes.components !== null;
215
- }
216
- if (parentLayer === 'utilities') {
217
- return layerNodes.utilities !== null;
218
- }
219
- return true;
220
- });
221
- if (layerNodes.variants) {
222
- layerNodes.variants.before((0, _cloneNodes).default(variantNodes, layerNodes.variants.source));
223
- layerNodes.variants.remove();
224
- } else if (variantNodes.length > 0) {
225
- root.append((0, _cloneNodes).default(variantNodes, root.source));
226
- }
227
- // If we've got a utility layer and no utilities are generated there's likely something wrong
228
- const hasUtilityVariants = variantNodes.some((node)=>{
229
- var ref;
230
- return ((ref = node.raws.tailwind) === null || ref === void 0 ? void 0 : ref.parentLayer) === 'utilities';
231
- });
232
- if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
233
- _log.default.warn('content-problems', [
234
- 'No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.',
235
- 'https://tailwindcss.com/docs/content-configuration',
236
- ]);
237
- }
238
- // ---
239
- if (env.DEBUG) {
240
- console.log('Potential classes: ', candidates.size);
241
- console.log('Active contexts: ', sharedState.contextSourcesMap.size);
242
- }
243
- // Clear the cache for the changed files
244
- context.changedContent = [];
245
- // Cleanup any leftover @layer atrules
246
- root.walkAtRules('layer', (rule)=>{
247
- if (Object.keys(layerNodes).includes(rule.params)) {
248
- rule.remove();
249
- }
250
- });
251
- };
252
- }