aboutsummaryrefslogtreecommitdiff
path: root/node_modules/csso/lib/compressor/restructure/8-restructRuleset.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/csso/lib/compressor/restructure/8-restructRuleset.js')
-rw-r--r--node_modules/csso/lib/compressor/restructure/8-restructRuleset.js157
1 files changed, 157 insertions, 0 deletions
diff --git a/node_modules/csso/lib/compressor/restructure/8-restructRuleset.js b/node_modules/csso/lib/compressor/restructure/8-restructRuleset.js
new file mode 100644
index 00000000..9a9e545f
--- /dev/null
+++ b/node_modules/csso/lib/compressor/restructure/8-restructRuleset.js
@@ -0,0 +1,157 @@
+var List = require('../../utils/list.js');
+var utils = require('./utils.js');
+var walkRulesRight = require('../../utils/walk.js').rulesRight;
+
+function calcSelectorLength(list) {
+ var length = 0;
+
+ list.each(function(data) {
+ length += data.id.length + 1;
+ });
+
+ return length - 1;
+}
+
+function calcDeclarationsLength(tokens) {
+ var length = 0;
+
+ for (var i = 0; i < tokens.length; i++) {
+ length += tokens[i].length;
+ }
+
+ return (
+ length + // declarations
+ tokens.length - 1 // delimeters
+ );
+}
+
+function processRuleset(node, item, list) {
+ var avoidRulesMerge = this.stylesheet.avoidRulesMerge;
+ var selectors = node.selector.selectors;
+ var block = node.block;
+ var disallowDownMarkers = Object.create(null);
+ var allowMergeUp = true;
+ var allowMergeDown = true;
+
+ list.prevUntil(item.prev, function(prev, prevItem) {
+ // skip non-ruleset node if safe
+ if (prev.type !== 'Ruleset') {
+ return utils.unsafeToSkipNode.call(selectors, prev);
+ }
+
+ var prevSelectors = prev.selector.selectors;
+ var prevBlock = prev.block;
+
+ if (node.pseudoSignature !== prev.pseudoSignature) {
+ return true;
+ }
+
+ allowMergeDown = !prevSelectors.some(function(selector) {
+ return selector.compareMarker in disallowDownMarkers;
+ });
+
+ // try prev ruleset if simpleselectors has no equal specifity and element selector
+ if (!allowMergeDown && !allowMergeUp) {
+ return true;
+ }
+
+ // try to join by selectors
+ if (allowMergeUp && utils.isEqualLists(prevSelectors, selectors)) {
+ prevBlock.declarations.appendList(block.declarations);
+ list.remove(item);
+ return true;
+ }
+
+ // try to join by properties
+ var diff = utils.compareDeclarations(block.declarations, prevBlock.declarations);
+
+ // console.log(diff.eq, diff.ne1, diff.ne2);
+
+ if (diff.eq.length) {
+ if (!diff.ne1.length && !diff.ne2.length) {
+ // equal blocks
+ if (allowMergeDown) {
+ utils.addSelectors(selectors, prevSelectors);
+ list.remove(prevItem);
+ }
+
+ return true;
+ } else if (!avoidRulesMerge) { /* probably we don't need to prevent those merges for @keyframes
+ TODO: need to be checked */
+
+ if (diff.ne1.length && !diff.ne2.length) {
+ // prevBlock is subset block
+ var selectorLength = calcSelectorLength(selectors);
+ var blockLength = calcDeclarationsLength(diff.eq); // declarations length
+
+ if (allowMergeUp && selectorLength < blockLength) {
+ utils.addSelectors(prevSelectors, selectors);
+ block.declarations = new List(diff.ne1);
+ }
+ } else if (!diff.ne1.length && diff.ne2.length) {
+ // node is subset of prevBlock
+ var selectorLength = calcSelectorLength(prevSelectors);
+ var blockLength = calcDeclarationsLength(diff.eq); // declarations length
+
+ if (allowMergeDown && selectorLength < blockLength) {
+ utils.addSelectors(selectors, prevSelectors);
+ prevBlock.declarations = new List(diff.ne2);
+ }
+ } else {
+ // diff.ne1.length && diff.ne2.length
+ // extract equal block
+ var newSelector = {
+ type: 'Selector',
+ info: {},
+ selectors: utils.addSelectors(prevSelectors.copy(), selectors)
+ };
+ var newBlockLength = calcSelectorLength(newSelector.selectors) + 2; // selectors length + curly braces length
+ var blockLength = calcDeclarationsLength(diff.eq); // declarations length
+
+ // create new ruleset if declarations length greater than
+ // ruleset description overhead
+ if (allowMergeDown && blockLength >= newBlockLength) {
+ var newRuleset = {
+ type: 'Ruleset',
+ info: {},
+ pseudoSignature: node.pseudoSignature,
+ selector: newSelector,
+ block: {
+ type: 'Block',
+ info: {},
+ declarations: new List(diff.eq)
+ }
+ };
+
+ block.declarations = new List(diff.ne1);
+ prevBlock.declarations = new List(diff.ne2.concat(diff.ne2overrided));
+ list.insert(list.createItem(newRuleset), prevItem);
+ return true;
+ }
+ }
+ }
+ }
+
+ if (allowMergeUp) {
+ // TODO: disallow up merge only if any property interception only (i.e. diff.ne2overrided.length > 0);
+ // await property families to find property interception correctly
+ allowMergeUp = !prevSelectors.some(function(prevSelector) {
+ return selectors.some(function(selector) {
+ return selector.compareMarker === prevSelector.compareMarker;
+ });
+ });
+ }
+
+ prevSelectors.each(function(data) {
+ disallowDownMarkers[data.compareMarker] = true;
+ });
+ });
+};
+
+module.exports = function restructRuleset(ast) {
+ walkRulesRight(ast, function(node, item, list) {
+ if (node.type === 'Ruleset') {
+ processRuleset.call(this, node, item, list);
+ }
+ });
+};