summaryrefslogtreecommitdiff
path: root/node_modules/tailwindcss/src/postcss-plugins/nesting/plugin.js
diff options
context:
space:
mode:
authorPhilipp Tanlak <philipp.tanlak@gmail.com>2025-11-24 20:54:57 +0100
committerPhilipp Tanlak <philipp.tanlak@gmail.com>2025-11-24 20:57:48 +0100
commitb1e2c8fd5cb5dfa46bc440a12eafaf56cd844b1c (patch)
tree49d360fd6cbc6a2754efe93524ac47ff0fbe0f7d /node_modules/tailwindcss/src/postcss-plugins/nesting/plugin.js
Docs
Diffstat (limited to 'node_modules/tailwindcss/src/postcss-plugins/nesting/plugin.js')
-rw-r--r--node_modules/tailwindcss/src/postcss-plugins/nesting/plugin.js80
1 files changed, 80 insertions, 0 deletions
diff --git a/node_modules/tailwindcss/src/postcss-plugins/nesting/plugin.js b/node_modules/tailwindcss/src/postcss-plugins/nesting/plugin.js
new file mode 100644
index 0000000..a13cfd4
--- /dev/null
+++ b/node_modules/tailwindcss/src/postcss-plugins/nesting/plugin.js
@@ -0,0 +1,80 @@
+import postcss from 'postcss'
+import postcssNested from 'postcss-nested'
+
+export function nesting(opts = postcssNested) {
+ return (root, result) => {
+ root.walkAtRules('screen', (rule) => {
+ rule.name = 'media'
+ rule.params = `screen(${rule.params})`
+ })
+
+ root.walkAtRules('apply', (rule) => {
+ rule.before(postcss.decl({ prop: '__apply', value: rule.params, source: rule.source }))
+ rule.remove()
+ })
+
+ let plugin = (() => {
+ if (
+ typeof opts === 'function' ||
+ (typeof opts === 'object' && opts?.hasOwnProperty?.('postcssPlugin'))
+ ) {
+ return opts
+ }
+
+ if (typeof opts === 'string') {
+ return require(opts)
+ }
+
+ if (Object.keys(opts).length <= 0) {
+ return postcssNested
+ }
+
+ throw new Error('tailwindcss/nesting should be loaded with a nesting plugin.')
+ })()
+
+ postcss([plugin]).process(root, result.opts).sync()
+
+ root.walkDecls('__apply', (decl) => {
+ decl.before(postcss.atRule({ name: 'apply', params: decl.value, source: decl.source }))
+ decl.remove()
+ })
+
+ /**
+ * Use a private PostCSS API to remove the "clean" flag from the entire AST.
+ * This is done because running process() on the AST will set the "clean"
+ * flag on all nodes, which we don't want.
+ *
+ * This causes downstream plugins using the visitor API to be skipped.
+ *
+ * This is guarded because the PostCSS API is not public
+ * and may change in future versions of PostCSS.
+ *
+ * See https://github.com/postcss/postcss/issues/1712 for more details
+ *
+ * @param {import('postcss').Node} node
+ */
+ function markDirty(node) {
+ if (!('markDirty' in node)) {
+ return
+ }
+
+ // Traverse the tree down to the leaf nodes
+ if (node.nodes) {
+ node.nodes.forEach((n) => markDirty(n))
+ }
+
+ // If it's a leaf node mark it as dirty
+ // We do this here because marking a node as dirty
+ // will walk up the tree and mark all parents as dirty
+ // resulting in a lot of unnecessary work if we did this
+ // for every single node
+ if (!node.nodes) {
+ node.markDirty()
+ }
+ }
+
+ markDirty(root)
+
+ return root
+ }
+}