'use strict'; const { isRoot, isAtRule, isRule } = require('./typeGuards'); /** @typedef {import('postcss').Root} Root */ /** @typedef {import('postcss').Root} Document */ /** @typedef {import('postcss').Node} PostcssNode */ /** @typedef {import('postcss').Container} PostcssContainerNode */ /** @typedef {import('postcss').Declaration} Declaration */ /** @typedef {(callbackFn: (decl: Declaration, index: number, decls: Declaration[]) => void) => void} EachDeclaration */ /** * @param {PostcssNode} node * @returns {node is PostcssContainerNode} */ function isContainerNode(node) { return isRule(node) || isAtRule(node) || isRoot(node); } /** * In order to accommodate nested blocks (postcss-nested), * we need to run a shallow loop (instead of eachDecl() or eachRule(), * which loop recursively) and allow each nested block to accumulate * its own list of properties -- so that a property in a nested rule * does not conflict with the same property in the parent rule * executes a provided function once for each declaration block. * * @param {Root | Document} root - root element of file. * @param {(eachDecl: EachDeclaration) => void} callback - Function to execute for each declaration block * * @returns {void} */ module.exports = function eachDeclarationBlock(root, callback) { /** * @param {PostcssNode} statement * * @returns {void} */ function each(statement) { if (!isContainerNode(statement)) return; if (statement.nodes && statement.nodes.length) { /** @type {Declaration[]} */ const decls = []; for (const node of statement.nodes) { if (node.type === 'decl') { decls.push(node); } each(node); } if (decls.length) { callback(decls.forEach.bind(decls)); } } } each(root); };