Search code examples
javascriptabstract-syntax-treepostcss

Generate rule for all direct descendants in PostCSS


I would like to create a PostCSS plugin, where I can generate a new rule for all direct descendants.

For example, I would like to generate rule:

div > * {
   color: black;
}

For all divs, which are display: block.

I didn't find a good example how to do this.

module.exports = () => {
  let skipped = Symbol("isSkipped"); // skipped flag
  let counter = Symbol("skippedCounter"); // counter for test "isSkipped" optimization

  function generateRule(decl) {
    let rules = decl.parent;
    rules[counter] = Number.isInteger(rules[counter]) ? rules[counter] : 0;

    if (!rules[skipped]) {
      if (decl.value === "block") {
        
        // generate a new rule here

        rules[skipped] = true;
        rules[counter]++;
      }
    }
  }

  return {
    postcssPlugin: "postcss-example-plugin",
    Declaration: {
      display: (decl) => generateRule(decl),
    },
  };
};
module.exports.postcss = true;

Solution

  • I'm not 100% certain on what part you're looking for, so if this doesn't answer your question, feel free to clarify and I'll update the response.

    Here's some code that I think does what you want - though it's mostly what you've already written without the optimizations:

    module.exports = {
      postcssPlugin: "add-rule-to-descendants",
      Declaration: {
        // https://postcss.org/api/#declarationprocessor
        display(displayDecl, { Rule, Declaration }) {
          if (displayDecl.value === 'block') {
            // Add the new rule after the parent https://postcss.org/api/#rule-after
            displayDecl.parent.after(
              new Rule({
                selector: `${displayDecl.parent.selector} > *`,
                nodes: [
                  new Declaration({ prop: 'color', value: 'black' })
                ]
              })
            );
          }
        }
      }
    }
    

    I've also prepped the example with some quick tests on Repl.it https://repl.it/@dcwither/postcss-all-decendants-rule#plugin.js.