summaryrefslogtreecommitdiff
path: root/node_modules/csso/cjs/restructure/7-mergeRuleset.cjs
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/csso/cjs/restructure/7-mergeRuleset.cjs')
-rw-r--r--node_modules/csso/cjs/restructure/7-mergeRuleset.cjs90
1 files changed, 90 insertions, 0 deletions
diff --git a/node_modules/csso/cjs/restructure/7-mergeRuleset.cjs b/node_modules/csso/cjs/restructure/7-mergeRuleset.cjs
new file mode 100644
index 00000000..797b9401
--- /dev/null
+++ b/node_modules/csso/cjs/restructure/7-mergeRuleset.cjs
@@ -0,0 +1,90 @@
+'use strict';
+
+const cssTree = require('css-tree');
+const utils = require('./utils.cjs');
+
+/*
+ At this step all rules has single simple selector. We try to join by equal
+ declaration blocks to first rule, e.g.
+
+ .a { color: red }
+ b { ... }
+ .b { color: red }
+ ->
+ .a, .b { color: red }
+ b { ... }
+*/
+
+function processRule(node, item, list) {
+ const selectors = node.prelude.children;
+ const declarations = node.block.children;
+ const nodeCompareMarker = selectors.first.compareMarker;
+ const skippedCompareMarkers = {};
+
+ list.nextUntil(item.next, function(next, nextItem) {
+ // skip non-ruleset node if safe
+ if (next.type !== 'Rule') {
+ return utils.unsafeToSkipNode.call(selectors, next);
+ }
+
+ if (node.pseudoSignature !== next.pseudoSignature) {
+ return true;
+ }
+
+ const nextFirstSelector = next.prelude.children.head;
+ const nextDeclarations = next.block.children;
+ const nextCompareMarker = nextFirstSelector.data.compareMarker;
+
+ // if next ruleset has same marked as one of skipped then stop joining
+ if (nextCompareMarker in skippedCompareMarkers) {
+ return true;
+ }
+
+ // try to join by selectors
+ if (selectors.head === selectors.tail) {
+ if (selectors.first.id === nextFirstSelector.data.id) {
+ declarations.appendList(nextDeclarations);
+ list.remove(nextItem);
+ return;
+ }
+ }
+
+ // try to join by properties
+ if (utils.isEqualDeclarations(declarations, nextDeclarations)) {
+ const nextStr = nextFirstSelector.data.id;
+
+ selectors.some((data, item) => {
+ const curStr = data.id;
+
+ if (nextStr < curStr) {
+ selectors.insert(nextFirstSelector, item);
+ return true;
+ }
+
+ if (!item.next) {
+ selectors.insert(nextFirstSelector);
+ return true;
+ }
+ });
+
+ list.remove(nextItem);
+ return;
+ }
+
+ // go to next ruleset if current one can be skipped (has no equal specificity nor element selector)
+ if (nextCompareMarker === nodeCompareMarker) {
+ return true;
+ }
+
+ skippedCompareMarkers[nextCompareMarker] = true;
+ });
+}
+
+function mergeRule(ast) {
+ cssTree.walk(ast, {
+ visit: 'Rule',
+ enter: processRule
+ });
+}
+
+module.exports = mergeRule;