summaryrefslogtreecommitdiff
path: root/node_modules/csso/cjs/restructure/8-restructRuleset.cjs
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/csso/cjs/restructure/8-restructRuleset.cjs')
-rw-r--r--node_modules/csso/cjs/restructure/8-restructRuleset.cjs175
1 files changed, 175 insertions, 0 deletions
diff --git a/node_modules/csso/cjs/restructure/8-restructRuleset.cjs b/node_modules/csso/cjs/restructure/8-restructRuleset.cjs
new file mode 100644
index 00000000..3eda382f
--- /dev/null
+++ b/node_modules/csso/cjs/restructure/8-restructRuleset.cjs
@@ -0,0 +1,175 @@
+'use strict';
+
+const cssTree = require('css-tree');
+const utils = require('./utils.cjs');
+
+function calcSelectorLength(list) {
+ return list.reduce((res, data) => res + data.id.length + 1, 0) - 1;
+}
+
+function calcDeclarationsLength(tokens) {
+ let length = 0;
+
+ for (const token of tokens) {
+ length += token.length;
+ }
+
+ return (
+ length + // declarations
+ tokens.length - 1 // delimeters
+ );
+}
+
+function processRule(node, item, list) {
+ const avoidRulesMerge = this.block !== null ? this.block.avoidRulesMerge : false;
+ const selectors = node.prelude.children;
+ const block = node.block;
+ const disallowDownMarkers = Object.create(null);
+ let allowMergeUp = true;
+ let allowMergeDown = true;
+
+ list.prevUntil(item.prev, function(prev, prevItem) {
+ const prevBlock = prev.block;
+ const prevType = prev.type;
+
+ if (prevType !== 'Rule') {
+ const unsafe = utils.unsafeToSkipNode.call(selectors, prev);
+
+ if (!unsafe && prevType === 'Atrule' && prevBlock) {
+ cssTree.walk(prevBlock, {
+ visit: 'Rule',
+ enter(node) {
+ node.prelude.children.forEach((data) => {
+ disallowDownMarkers[data.compareMarker] = true;
+ });
+ }
+ });
+ }
+
+ return unsafe;
+ }
+
+ if (node.pseudoSignature !== prev.pseudoSignature) {
+ return true;
+ }
+
+ const prevSelectors = prev.prelude.children;
+
+ allowMergeDown = !prevSelectors.some((selector) =>
+ 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.isEqualSelectors(prevSelectors, selectors)) {
+ prevBlock.children.appendList(block.children);
+ list.remove(item);
+
+ return true;
+ }
+
+ // try to join by properties
+ const diff = utils.compareDeclarations(block.children, prevBlock.children);
+
+ // 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
+ const selectorLength = calcSelectorLength(selectors);
+ const blockLength = calcDeclarationsLength(diff.eq); // declarations length
+
+ if (allowMergeUp && selectorLength < blockLength) {
+ utils.addSelectors(prevSelectors, selectors);
+ block.children.fromArray(diff.ne1);
+ }
+ } else if (!diff.ne1.length && diff.ne2.length) {
+ // node is subset of prevBlock
+ const selectorLength = calcSelectorLength(prevSelectors);
+ const blockLength = calcDeclarationsLength(diff.eq); // declarations length
+
+ if (allowMergeDown && selectorLength < blockLength) {
+ utils.addSelectors(selectors, prevSelectors);
+ prevBlock.children.fromArray(diff.ne2);
+ }
+ } else {
+ // diff.ne1.length && diff.ne2.length
+ // extract equal block
+ const newSelector = {
+ type: 'SelectorList',
+ loc: null,
+ children: utils.addSelectors(prevSelectors.copy(), selectors)
+ };
+ const newBlockLength = calcSelectorLength(newSelector.children) + 2; // selectors length + curly braces length
+ const blockLength = calcDeclarationsLength(diff.eq); // declarations length
+
+ // create new ruleset if declarations length greater than
+ // ruleset description overhead
+ if (blockLength >= newBlockLength) {
+ const newItem = list.createItem({
+ type: 'Rule',
+ loc: null,
+ prelude: newSelector,
+ block: {
+ type: 'Block',
+ loc: null,
+ children: new cssTree.List().fromArray(diff.eq)
+ },
+ pseudoSignature: node.pseudoSignature
+ });
+
+ block.children.fromArray(diff.ne1);
+ prevBlock.children.fromArray(diff.ne2overrided);
+
+ if (allowMergeUp) {
+ list.insert(newItem, prevItem);
+ } else {
+ list.insert(newItem, item);
+ }
+
+ 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((prevSelector) =>
+ selectors.some((selector) =>
+ selector.compareMarker === prevSelector.compareMarker
+ )
+ );
+ }
+
+ prevSelectors.forEach((data) => {
+ disallowDownMarkers[data.compareMarker] = true;
+ });
+ });
+}
+
+function restructRule(ast) {
+ cssTree.walk(ast, {
+ visit: 'Rule',
+ reverse: true,
+ enter: processRule
+ });
+}
+
+module.exports = restructRule;