blob: 25f2b6930dfb763074317a679b8021d4f53ca366 [file] [log] [blame]
Mathias Bynens79e2cf02020-05-29 16:46:17 +02001'use strict';
2
3const { isRoot, isAtRule, isRule } = require('./typeGuards');
4
5/** @typedef {import('postcss').Root} Root */
6/** @typedef {import('postcss').Root} Document */
7/** @typedef {import('postcss').Node} PostcssNode */
Tim van der Lippe16b82282021-11-08 13:50:26 +00008/** @typedef {import('postcss').Container} PostcssContainerNode */
9/** @typedef {import('postcss').Declaration} Declaration */
10/** @typedef {(callbackFn: (decl: Declaration, index: number, decls: Declaration[]) => void) => void} EachDeclaration */
Mathias Bynens79e2cf02020-05-29 16:46:17 +020011
12/**
13 * @param {PostcssNode} node
14 * @returns {node is PostcssContainerNode}
15 */
16function isContainerNode(node) {
17 return isRule(node) || isAtRule(node) || isRoot(node);
18}
19
20/**
21 * In order to accommodate nested blocks (postcss-nested),
22 * we need to run a shallow loop (instead of eachDecl() or eachRule(),
23 * which loop recursively) and allow each nested block to accumulate
24 * its own list of properties -- so that a property in a nested rule
25 * does not conflict with the same property in the parent rule
26 * executes a provided function once for each declaration block.
27 *
28 * @param {Root | Document} root - root element of file.
Tim van der Lippe16b82282021-11-08 13:50:26 +000029 * @param {(eachDecl: EachDeclaration) => void} callback - Function to execute for each declaration block
Mathias Bynens79e2cf02020-05-29 16:46:17 +020030 *
31 * @returns {void}
32 */
Tim van der Lippe16b82282021-11-08 13:50:26 +000033module.exports = function eachDeclarationBlock(root, callback) {
Mathias Bynens79e2cf02020-05-29 16:46:17 +020034 /**
35 * @param {PostcssNode} statement
36 *
37 * @returns {void}
38 */
39 function each(statement) {
40 if (!isContainerNode(statement)) return;
41
42 if (statement.nodes && statement.nodes.length) {
Tim van der Lippe16b82282021-11-08 13:50:26 +000043 /** @type {Declaration[]} */
Mathias Bynens79e2cf02020-05-29 16:46:17 +020044 const decls = [];
45
Tim van der Lippe4cb09742022-01-07 14:25:03 +010046 for (const node of statement.nodes) {
Mathias Bynens79e2cf02020-05-29 16:46:17 +020047 if (node.type === 'decl') {
48 decls.push(node);
49 }
50
51 each(node);
Tim van der Lippe4cb09742022-01-07 14:25:03 +010052 }
Mathias Bynens79e2cf02020-05-29 16:46:17 +020053
54 if (decls.length) {
Tim van der Lippe16b82282021-11-08 13:50:26 +000055 callback(decls.forEach.bind(decls));
Mathias Bynens79e2cf02020-05-29 16:46:17 +020056 }
57 }
58 }
59
60 each(root);
61};