4
0

eachDeclarationBlock.mjs 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import { isAtRule, isRoot, isRule } from './typeGuards.mjs';
  2. /** @typedef {import('postcss').Root} Root */
  3. /** @typedef {import('postcss').Root} Document */
  4. /** @typedef {import('postcss').Node} PostcssNode */
  5. /** @typedef {import('postcss').Container} PostcssContainerNode */
  6. /** @typedef {import('postcss').Declaration} Declaration */
  7. /** @typedef {(callbackFn: (decl: Declaration, index: number, decls: Declaration[]) => void) => void} EachDeclaration */
  8. /**
  9. * @param {PostcssNode} node
  10. * @returns {node is PostcssContainerNode}
  11. */
  12. function isContainerNode(node) {
  13. return isRule(node) || isAtRule(node) || isRoot(node);
  14. }
  15. /**
  16. * In order to accommodate nested blocks (postcss-nested),
  17. * we need to run a shallow loop (instead of eachDecl() or eachRule(),
  18. * which loop recursively) and allow each nested block to accumulate
  19. * its own list of properties -- so that a property in a nested rule
  20. * does not conflict with the same property in the parent rule
  21. * executes a provided function once for each declaration block.
  22. *
  23. * @param {Root | Document} root - root element of file.
  24. * @param {(eachDecl: EachDeclaration) => void} callback - Function to execute for each declaration block
  25. *
  26. * @returns {void}
  27. */
  28. export default function eachDeclarationBlock(root, callback) {
  29. /**
  30. * @param {PostcssNode} statement
  31. *
  32. * @returns {void}
  33. */
  34. function each(statement) {
  35. if (!isContainerNode(statement)) return;
  36. if (statement.nodes && statement.nodes.length) {
  37. /** @type {Declaration[]} */
  38. const decls = [];
  39. for (const node of statement.nodes) {
  40. if (node.type === 'decl') {
  41. decls.push(node);
  42. }
  43. each(node);
  44. }
  45. if (decls.length) {
  46. callback(decls.forEach.bind(decls));
  47. }
  48. }
  49. }
  50. each(root);
  51. }