123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- 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);
- }
- });
- };
|