at-rule-packer
Version:
Merge duplicate CSS media query and other at-rule rules together.
87 lines (86 loc) • 2.54 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = AtRulePacker;
const postcss_1 = __importDefault(require("postcss"));
function getAtRuleKey(atrule) {
return atrule.name + atrule.params;
}
var Direction;
(function (Direction) {
Direction["NEXT"] = "next";
Direction["PREV"] = "prev";
})(Direction || (Direction = {}));
/* eslint-disable consistent-return */
function untilAtRule(atrule, forward) {
const method = forward ? Direction.NEXT : Direction.PREV;
const sibling = atrule[method]();
if (sibling) {
if (sibling.type === 'atrule') {
return sibling;
}
return untilAtRule(sibling, forward);
}
}
/* eslint-enable consistent-return */
// List of Atrule's that should never be merged
const ignoredAtRules = [
'import',
'font-face',
'layer',
'property',
'when',
'else',
];
function processAtrule(atrule) {
// Ignore at-rules that should not be merged
if (~ignoredAtRules.indexOf(atrule.name)) {
return;
}
// Only process with the top level At-rule
if (untilAtRule(atrule)) {
return;
}
// Determine unique at-rules and remove ones that are not
const uniqueAtRules = new Map();
// loop through next At-rules
(function p(atr) {
const key = getAtRuleKey(atr);
if (uniqueAtRules.has(key)) {
const ref = uniqueAtRules.get(key);
ref.push(atr);
}
else {
uniqueAtRules.set(key, [atr]);
}
const nextAtRule = untilAtRule(atr, true);
if (nextAtRule) {
p(nextAtRule);
}
else {
uniqueAtRules.forEach((atrs) => {
if (atrs.length > 1) {
const target = atrs.pop();
atrs.reverse().forEach((a) => {
target.prepend(a.nodes);
a.remove();
});
}
});
}
})(atrule);
}
function AtRulePacker(css) {
const isTypeString = typeof css === 'string';
let ast = css;
// Parse into AST (if string)
if (isTypeString) {
ast = postcss_1.default.parse(ast);
}
// Process Atrules
ast.walkAtRules(processAtrule);
// Restore as string (if it originated as string)
return isTypeString ? ast.toString() : ast;
}