unnestcss
Version:
Parse nested css
91 lines • 3.32 kB
JavaScript
import postcss from "postcss";
import { combineSelectors, combineAtRules } from "./combine.js";
import { isAtRule, isDecl, isRule } from "./help.js";
export class Parser {
get css() {
return this.toString();
}
constructor(raw) {
this.raw = raw;
this.root = postcss.parse(raw);
}
unnest() {
const originalNodes = [...this.root.nodes];
originalNodes.forEach((node) => {
this.__processNode(node, node, undefined, undefined);
});
}
__processNode(currentNode, originalNode, parentSelectors, parentAtRules) {
if (isRule(currentNode)) {
this.__processRuleNode(currentNode, originalNode, parentSelectors, parentAtRules);
}
else if (isAtRule(currentNode)) {
this.__processAtRuleNode(currentNode, originalNode, parentSelectors, parentAtRules);
}
}
__processRuleNode(currentNode, originalNode, parentSelectors, parentAtRules) {
const declNodes = currentNode.nodes.filter(isDecl);
const ruleNodes = currentNode.nodes.filter(isRule);
const atRuleNodes = currentNode.nodes.filter(isAtRule);
const selectors = combineSelectors(currentNode.selectors, parentSelectors);
ruleNodes.forEach((ruleNode) => {
this.__processNode(ruleNode, originalNode, selectors, parentAtRules);
});
atRuleNodes.forEach((atNode) => {
this.__processNode(atNode, originalNode, selectors, parentAtRules);
});
if (declNodes.length) {
const { topNode, insertAtRuleNode } = this.__createParentAtRules(parentAtRules);
const newRule = new postcss.Rule({
selectors,
nodes: declNodes,
});
if (insertAtRuleNode) {
insertAtRuleNode.nodes.push(newRule);
}
this.root.insertBefore(originalNode, topNode || newRule);
originalNode.remove();
}
}
__processAtRuleNode(currentNode, originalNode, parentSelectors, parentAtRules) {
const { name, params } = currentNode;
const currentAtRules = [
...(parentAtRules || []),
{
name,
params,
},
];
currentNode.nodes.forEach((node) => {
if (isRule(node) || isAtRule(node)) {
this.__processNode(node, originalNode, parentSelectors, currentAtRules);
}
});
}
__createParentAtRules(parentAtRules) {
let insertAtRuleNode;
let topNode;
if (parentAtRules) {
const atRules = combineAtRules(...parentAtRules);
atRules.forEach(({ name, params }, index) => {
const newAtRule = new postcss.AtRule({
name,
params,
nodes: [],
});
if (insertAtRuleNode) {
insertAtRuleNode.nodes.push(newAtRule);
}
insertAtRuleNode = newAtRule;
if (index === 0) {
topNode = newAtRule;
}
});
}
return { topNode, insertAtRuleNode };
}
toString() {
return this.root.toString();
}
}
//# sourceMappingURL=parser.js.map