eachDeclarationBlock.js 1.7 KB

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