postcss-merge-rules
Advanced tools
Comparing version 1.2.2 to 1.3.0
@@ -0,1 +1,8 @@ | ||
# 1.3.0 | ||
* Better support for merging properties without the existance of a shorthand | ||
override. | ||
* Can now 'merge forward' adjacent rules as well as the previous 'merge behind' | ||
behaviour, leading to better compression. | ||
# 1.2.2 | ||
@@ -2,0 +9,0 @@ |
127
index.js
@@ -6,8 +6,10 @@ 'use strict'; | ||
var flatten = require('flatten'); | ||
var clone = require('./lib/clone'); | ||
var prefixes = ['-webkit-', '-moz-', '-ms-', '-o-']; | ||
function intersect (a, b) { | ||
function intersect (a, b, not) { | ||
return a.filter(function (c) { | ||
return ~b.indexOf(c); | ||
var index = ~b.indexOf(c); | ||
return not ? !index : index; | ||
}); | ||
@@ -17,11 +19,3 @@ } | ||
function different (a, b) { | ||
var ab = a.filter(function (c) { | ||
return !~b.indexOf(c); | ||
}); | ||
var ba = b.filter(function (c) { | ||
return !~a.indexOf(c); | ||
}); | ||
return ab.concat(ba); | ||
return intersect(a, b, true).concat(intersect(b, a, true)); | ||
} | ||
@@ -66,8 +60,69 @@ | ||
function joinSelectors () { | ||
var selectors = Array.prototype.slice.call(arguments); | ||
selectors = selectors.map(function (s) { return s.selector; }); | ||
return Array.prototype.concat.apply([], selectors).join(','); | ||
function joinSelectors (/* rules... */) { | ||
var args = Array.prototype.slice.call(arguments); | ||
return flatten(args.map(function (s) { return s.selector; })).join(','); | ||
} | ||
function ruleLength (/* rules... */) { | ||
var args = Array.prototype.slice.call(arguments); | ||
return args.map(function (selector) { | ||
return selector.nodes.length ? String(selector) : ''; | ||
}).join('').length; | ||
} | ||
function partialMerge (first, second) { | ||
var intersection = intersect(getDeclarations(first), getDeclarations(second)); | ||
if (!intersection.length) { | ||
return second; | ||
} | ||
var nextRule = second.next(); | ||
if (nextRule) { | ||
var nextIntersection = intersect(getDeclarations(second), getDeclarations(nextRule)); | ||
if (nextIntersection.length > intersection.length) { | ||
first = second; second = nextRule; intersection = nextIntersection; | ||
} | ||
} | ||
var recievingBlock = second.cloneBefore({ | ||
selector: joinSelectors(first, second), | ||
nodes: [], | ||
before: '' | ||
}); | ||
var difference = different(getDeclarations(first), getDeclarations(second)); | ||
var firstClone = clone(first); | ||
var secondClone = clone(second); | ||
var moveDecl = function (callback) { | ||
return function (decl) { | ||
var intersects = ~intersection.indexOf(String(decl)); | ||
var baseProperty = decl.prop.split('-')[0]; | ||
var canMove = difference.every(function (d) { | ||
return d.split(':')[0] !== baseProperty; | ||
}); | ||
if (intersects && canMove) { | ||
callback.call(this, decl); | ||
} | ||
}; | ||
}; | ||
firstClone.eachInside(moveDecl(function (decl) { | ||
decl.moveTo(recievingBlock); | ||
})); | ||
secondClone.eachInside(moveDecl(function (decl) { | ||
decl.removeSelf(); | ||
})); | ||
var merged = ruleLength(firstClone, recievingBlock, secondClone); | ||
var original = ruleLength(first, second); | ||
if (merged < original) { | ||
first.replaceWith(firstClone); | ||
second.replaceWith(secondClone); | ||
[firstClone, recievingBlock, secondClone].forEach(function (r) { | ||
if (!r.nodes.length) { | ||
r.removeSelf(); | ||
} | ||
}); | ||
return secondClone; | ||
} else { | ||
recievingBlock.removeSelf(); | ||
return first; | ||
} | ||
} | ||
function selectorMerger () { | ||
@@ -103,43 +158,3 @@ var cache = null; | ||
// so create a joined selector with the subset, if smaller. | ||
var intersection = intersect(cacheDecls, ruleDecls); | ||
if (intersection.length) { | ||
var decls = intersection.join(';'); | ||
var merged = joinSelectors(cache, rule) + '{' + decls + '}'; | ||
var shouldMerge = merged.length < (decls + decls).length; | ||
if (shouldMerge) { | ||
var difference = different(ruleDecls, cacheDecls); | ||
difference = difference.map(function (d) { | ||
return d.split(':')[0].split('-')[0]; | ||
}); | ||
var recievingBlock = cache.cloneAfter({ | ||
selector: joinSelectors(cache, rule), | ||
nodes: [], | ||
before: '' | ||
}); | ||
var moveDecl = function (callback) { | ||
return function (decl) { | ||
var intersects = ~intersection.indexOf('' + decl); | ||
var baseProperty = decl.prop.split('-')[0]; | ||
var canMove = !~difference.indexOf(baseProperty); | ||
if (intersects && (canMove || baseProperty === 'text')) { | ||
callback.call(this, decl); | ||
} | ||
}; | ||
}; | ||
cache.eachInside(moveDecl(function (decl) { | ||
decl.moveTo(recievingBlock); | ||
})); | ||
rule.eachInside(moveDecl(function (decl) { | ||
decl.removeSelf(); | ||
})); | ||
// Clean up any rules that have no declarations left | ||
[rule, recievingBlock, cache].forEach(function (r) { | ||
if (!r.nodes.length) { | ||
r.removeSelf(); | ||
} | ||
}); | ||
} | ||
} | ||
cache = rule; | ||
cache = partialMerge(cache, rule); | ||
}; | ||
@@ -146,0 +161,0 @@ } |
{ | ||
"name": "postcss-merge-rules", | ||
"version": "1.2.2", | ||
"version": "1.3.0", | ||
"description": "Merge CSS rules with PostCSS.", | ||
"main": "index.js", | ||
"scripts": { | ||
"lint": "jshint index.js --reporter node_modules/jshint-stylish/stylish.js", | ||
"lint": "jshint index.js lib/*.js --reporter node_modules/jshint-stylish/stylish.js", | ||
"test": "tape test.js | tap-spec" | ||
@@ -9,0 +9,0 @@ }, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
10372
7
175