diff options
Diffstat (limited to 'node_modules/csso/cjs/restructure/7-mergeRuleset.cjs')
| -rw-r--r-- | node_modules/csso/cjs/restructure/7-mergeRuleset.cjs | 90 |
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; |
