postcss-merge-rules
Advanced tools
Comparing version 2.1.2 to 4.0.0-nightly.2020.7.24
@@ -1,270 +0,435 @@ | ||
'use strict'; | ||
"use strict"; | ||
exports.__esModule = true; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = void 0; | ||
var _browserslist = require('browserslist'); | ||
var _browserslist = _interopRequireDefault(require("browserslist")); | ||
var _browserslist2 = _interopRequireDefault(_browserslist); | ||
var _postcss = _interopRequireDefault(require("postcss")); | ||
var _postcss = require('postcss'); | ||
var _vendors = _interopRequireDefault(require("vendors")); | ||
var _postcss2 = _interopRequireDefault(_postcss); | ||
var _cssnanoUtils = require("cssnano-utils"); | ||
var _vendors = require('vendors'); | ||
var _ensureCompatibility = _interopRequireDefault(require("./lib/ensureCompatibility")); | ||
var _vendors2 = _interopRequireDefault(_vendors); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var _clone = require('./lib/clone'); | ||
/** @type {string[]} */ | ||
const prefixes = _vendors.default.map(v => `-${v}-`); | ||
/** | ||
* @param {postcss.Declaration} a | ||
* @param {postcss.Declaration} b | ||
* @return {boolean} | ||
*/ | ||
var _clone2 = _interopRequireDefault(_clone); | ||
var _ensureCompatibility = require('./lib/ensureCompatibility'); | ||
function declarationIsEqual(a, b) { | ||
return a.important === b.important && a.prop === b.prop && a.value === b.value; | ||
} | ||
/** | ||
* @param {postcss.Declaration[]} array | ||
* @param {postcss.Declaration} decl | ||
* @return {number} | ||
*/ | ||
var _ensureCompatibility2 = _interopRequireDefault(_ensureCompatibility); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function indexOfDeclaration(array, decl) { | ||
return array.findIndex(d => declarationIsEqual(d, decl)); | ||
} | ||
/** | ||
* Returns filtered array of matched or unmatched declarations | ||
* @param {postcss.Declaration[]} a | ||
* @param {postcss.Declaration[]} b | ||
* @param {boolean} [not=false] | ||
* @return {postcss.Declaration[]} | ||
*/ | ||
var prefixes = _vendors2.default.map(function (v) { | ||
return '-' + v + '-'; | ||
}); | ||
function intersect(a, b, not) { | ||
return a.filter(function (c) { | ||
var index = ~b.indexOf(c); | ||
return not ? !index : index; | ||
}); | ||
return a.filter(c => { | ||
const index = ~indexOfDeclaration(b, c); | ||
return not ? !index : index; | ||
}); | ||
} | ||
/** | ||
* @param {postcss.Declaration[]} a | ||
* @param {postcss.Declaration[]} b | ||
* @return {boolean} | ||
*/ | ||
var different = function different(a, b) { | ||
return intersect(a, b, true).concat(intersect(b, a, true)); | ||
}; | ||
var filterPrefixes = function filterPrefixes(selector) { | ||
return intersect(prefixes, selector); | ||
}; | ||
function sameDeclarationsAndOrder(a, b) { | ||
if (a.length !== b.length) { | ||
return false; | ||
} | ||
return a.every((d, index) => declarationIsEqual(d, b[index])); | ||
} // Internet Explorer use :-ms-input-placeholder. | ||
// Microsoft Edge use ::-ms-input-placeholder. | ||
const findMsInputPlaceholder = selector => ~selector.search(/-ms-input-placeholder/i); | ||
/** | ||
* @param {string} selector | ||
* @return {string[]} | ||
*/ | ||
function filterPrefixes(selector) { | ||
return prefixes.filter(prefix => selector.indexOf(prefix) !== -1); | ||
} | ||
function sameVendor(selectorsA, selectorsB) { | ||
var same = function same(selectors) { | ||
return selectors.map(filterPrefixes).join(); | ||
}; | ||
return same(selectorsA) === same(selectorsB); | ||
let same = selectors => selectors.map(filterPrefixes).join(); | ||
let findMsVendor = selectors => selectors.find(findMsInputPlaceholder); | ||
return same(selectorsA) === same(selectorsB) && !(findMsVendor(selectorsA) && findMsVendor(selectorsB)); | ||
} | ||
/** | ||
* @param {string} selector | ||
* @return {boolean} | ||
*/ | ||
var noVendor = function noVendor(selector) { | ||
return !filterPrefixes(selector).length; | ||
}; | ||
function sameParent(ruleA, ruleB) { | ||
var hasParent = ruleA.parent && ruleB.parent; | ||
var sameType = hasParent && ruleA.parent.type === ruleB.parent.type; | ||
// If an at rule, ensure that the parameters are the same | ||
if (hasParent && ruleA.parent.type !== 'root' && ruleB.parent.type !== 'root') { | ||
sameType = sameType && ruleA.parent.params === ruleB.parent.params && ruleA.parent.name === ruleB.parent.name; | ||
} | ||
return hasParent ? sameType : true; | ||
function noVendor(selector) { | ||
return !filterPrefixes(selector).length; | ||
} | ||
/** | ||
* @param {postcss.Rule} ruleA | ||
* @param {postcss.Rule} ruleB | ||
* @param {string[]=} browsers | ||
* @param {Object.<string, boolean>=} compatibilityCache | ||
* @return {boolean} | ||
*/ | ||
function canMerge(ruleA, ruleB, browsers, compatibilityCache) { | ||
var a = ruleA.selectors; | ||
var b = ruleB.selectors; | ||
const a = ruleA.selectors; | ||
const b = ruleB.selectors; | ||
const selectors = a.concat(b); | ||
var selectors = a.concat(b); | ||
if (!(0, _ensureCompatibility.default)(selectors, browsers, compatibilityCache)) { | ||
return false; | ||
} | ||
if (!(0, _ensureCompatibility2.default)(selectors, browsers, compatibilityCache)) { | ||
return false; | ||
} | ||
const parent = (0, _cssnanoUtils.sameParent)(ruleA, ruleB); | ||
const { | ||
name | ||
} = ruleA.parent; | ||
var parent = sameParent(ruleA, ruleB); | ||
var name = ruleA.parent.name; | ||
if (parent && name && ~name.indexOf('keyframes')) { | ||
return false; | ||
} | ||
if (parent && name && ~name.indexOf('keyframes')) { | ||
return false; | ||
} | ||
return parent && (selectors.every(noVendor) || sameVendor(a, b)); | ||
return parent && (selectors.every(noVendor) || sameVendor(a, b)); | ||
} | ||
/** | ||
* @param {postcss.Rule} rule | ||
* @return {postcss.Declaration[]} | ||
*/ | ||
var getDecls = function getDecls(rule) { | ||
return rule.nodes ? rule.nodes.map(String) : []; | ||
}; | ||
var joinSelectors = function joinSelectors() { | ||
for (var _len = arguments.length, rules = Array(_len), _key = 0; _key < _len; _key++) { | ||
rules[_key] = arguments[_key]; | ||
} | ||
return rules.map(function (s) { | ||
return s.selector; | ||
}).join(); | ||
}; | ||
function getDecls(rule) { | ||
return rule.nodes.filter(node => node.type === 'decl'); | ||
} | ||
function ruleLength() { | ||
for (var _len2 = arguments.length, rules = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
rules[_key2] = arguments[_key2]; | ||
} | ||
const joinSelectors = (...rules) => rules.map(s => s.selector).join(); | ||
return rules.map(function (r) { | ||
return r.nodes.length ? String(r) : ''; | ||
}).join('').length; | ||
function ruleLength(...rules) { | ||
return rules.map(r => r.nodes.length ? String(r) : '').join('').length; | ||
} | ||
/** | ||
* @param {string} prop | ||
* @return {{prefix: string, base:string, rest:string[]}} | ||
*/ | ||
function splitProp(prop) { | ||
var parts = prop.split('-'); | ||
var base = void 0, | ||
rest = void 0; | ||
// Treat vendor prefixed properties as if they were unprefixed; | ||
// moving them when combined with non-prefixed properties can | ||
// cause issues. e.g. moving -webkit-background-clip when there | ||
// is a background shorthand definition. | ||
if (prop[0] === '-') { | ||
base = parts[2]; | ||
rest = parts.slice(3); | ||
} else { | ||
base = parts[0]; | ||
rest = parts.slice(1); | ||
} | ||
return [base, rest]; | ||
// Treat vendor prefixed properties as if they were unprefixed; | ||
// moving them when combined with non-prefixed properties can | ||
// cause issues. e.g. moving -webkit-background-clip when there | ||
// is a background shorthand definition. | ||
const parts = prop.split('-'); | ||
if (prop[0] !== '-') { | ||
return { | ||
prefix: '', | ||
base: parts[0], | ||
rest: parts.slice(1) | ||
}; | ||
} // Don't split css variables | ||
if (prop[1] === '-') { | ||
return { | ||
prefix: null, | ||
base: null, | ||
rest: [prop] | ||
}; | ||
} // Found prefix | ||
return { | ||
prefix: parts[1], | ||
base: parts[2], | ||
rest: parts.slice(3) | ||
}; | ||
} | ||
/** | ||
* @param {string} propA | ||
* @param {string} propB | ||
*/ | ||
function isConflictingProp(propA, propB) { | ||
if (propA === propB) { | ||
return true; | ||
} | ||
var a = splitProp(propA); | ||
var b = splitProp(propB); | ||
return a[0] === b[0] && a[1].length !== b[1].length; | ||
if (propA === propB) { | ||
// Same specificity | ||
return true; | ||
} | ||
const a = splitProp(propA); | ||
const b = splitProp(propB); // Don't resort css variables | ||
if (!a.base && !b.base) { | ||
return true; | ||
} // Different base; | ||
if (a.base !== b.base) { | ||
return false; | ||
} // Conflict if rest-count mismatches | ||
if (a.rest.length !== b.rest.length) { | ||
return true; | ||
} // Conflict if rest parameters are equal (same but unprefixed) | ||
return a.rest.every((s, index) => b.rest[index] === s); | ||
} | ||
/** | ||
* @param {postcss.Rule} first | ||
* @param {postcss.Rule} second | ||
* @return {boolean} merged | ||
*/ | ||
function hasConflicts(declProp, notMoved) { | ||
return notMoved.some(function (prop) { | ||
return isConflictingProp(prop, declProp); | ||
}); | ||
function mergeParents(first, second) { | ||
// Null check for detached rules | ||
if (!first.parent || !second.parent) { | ||
return false; | ||
} // Check if parents share node | ||
if (first.parent === second.parent) { | ||
return false; | ||
} // sameParent() already called by canMerge() | ||
second.remove(); | ||
first.parent.append(second); | ||
return true; | ||
} | ||
/** | ||
* @param {postcss.Rule} first | ||
* @param {postcss.Rule} second | ||
* @return {postcss.Rule} mergedRule | ||
*/ | ||
function partialMerge(first, second) { | ||
var _this = this; | ||
let intersection = intersect(getDecls(first), getDecls(second)); | ||
var intersection = intersect(getDecls(first), getDecls(second)); | ||
if (!intersection.length) { | ||
return second; | ||
if (!intersection.length) { | ||
return second; | ||
} | ||
let nextRule = second.next(); | ||
if (!nextRule) { | ||
// Grab next cousin | ||
const parentSibling = second.parent.next(); | ||
nextRule = parentSibling && parentSibling.nodes && parentSibling.nodes[0]; | ||
} | ||
if (nextRule && nextRule.type === 'rule' && canMerge(second, nextRule)) { | ||
let nextIntersection = intersect(getDecls(second), getDecls(nextRule)); | ||
if (nextIntersection.length > intersection.length) { | ||
mergeParents(second, nextRule); | ||
first = second; | ||
second = nextRule; | ||
intersection = nextIntersection; | ||
} | ||
var nextRule = second.next(); | ||
if (nextRule && nextRule.type === 'rule' && canMerge(second, nextRule)) { | ||
var nextIntersection = intersect(getDecls(second), getDecls(nextRule)); | ||
if (nextIntersection.length > intersection.length) { | ||
first = second;second = nextRule;intersection = nextIntersection; | ||
} | ||
} | ||
const firstDecls = getDecls(first); // Filter out intersections with later conflicts in First | ||
intersection = intersection.filter((decl, intersectIndex) => { | ||
const index = indexOfDeclaration(firstDecls, decl); | ||
const nextConflictInFirst = firstDecls.slice(index + 1).find(d => isConflictingProp(d.prop, decl.prop)); | ||
if (!nextConflictInFirst) { | ||
return true; | ||
} | ||
var recievingBlock = (0, _clone2.default)(second); | ||
recievingBlock.selector = joinSelectors(first, second); | ||
recievingBlock.nodes = []; | ||
second.parent.insertBefore(second, recievingBlock); | ||
var difference = different(getDecls(first), getDecls(second)); | ||
var filterConflicts = function filterConflicts(decls, intersectn) { | ||
var willNotMove = []; | ||
return decls.reduce(function (willMove, decl) { | ||
var intersects = ~intersectn.indexOf(decl); | ||
var prop = decl.split(':')[0]; | ||
var base = prop.split('-')[0]; | ||
var canMove = difference.every(function (d) { | ||
return d.split(':')[0] !== base; | ||
}); | ||
if (intersects && canMove && !hasConflicts(prop, willNotMove)) { | ||
willMove.push(decl); | ||
} else { | ||
willNotMove.push(prop); | ||
} | ||
return willMove; | ||
}, []); | ||
const nextConflictInIntersection = intersection.slice(intersectIndex + 1).find(d => isConflictingProp(d.prop, decl.prop)); | ||
if (!nextConflictInIntersection) { | ||
return false; | ||
} | ||
if (declarationIsEqual(nextConflictInFirst, nextConflictInIntersection)) { | ||
return true; | ||
} | ||
return false; | ||
}); // Filter out intersections with previous conflicts in Second | ||
const secondDecls = getDecls(second); | ||
intersection = intersection.filter(decl => { | ||
const nextConflictIndex = secondDecls.findIndex(d => isConflictingProp(d.prop, decl.prop)); | ||
if (nextConflictIndex === -1) { | ||
return false; | ||
} | ||
if (!declarationIsEqual(secondDecls[nextConflictIndex], decl)) { | ||
return false; | ||
} | ||
if (decl.prop.toLowerCase() !== 'direction' && decl.prop.toLowerCase() !== 'unicode-bidi' && secondDecls.some(declaration => declaration.prop.toLowerCase() === 'all')) { | ||
return false; | ||
} | ||
secondDecls.splice(nextConflictIndex, 1); | ||
return true; | ||
}); | ||
if (!intersection.length) { | ||
// Nothing to merge | ||
return second; | ||
} | ||
const receivingBlock = second.clone(); | ||
receivingBlock.selector = joinSelectors(first, second); | ||
receivingBlock.nodes = []; | ||
second.parent.insertBefore(second, receivingBlock); | ||
const firstClone = first.clone(); | ||
const secondClone = second.clone(); | ||
/** | ||
* @param {function(postcss.Declaration):void} callback | ||
* @return {function(postcss.Declaration)} | ||
*/ | ||
function moveDecl(callback) { | ||
return decl => { | ||
if (~indexOfDeclaration(intersection, decl)) { | ||
callback.call(this, decl); | ||
} | ||
}; | ||
intersection = filterConflicts(getDecls(first).reverse(), intersection); | ||
intersection = filterConflicts(getDecls(second), intersection); | ||
var firstClone = (0, _clone2.default)(first); | ||
var secondClone = (0, _clone2.default)(second); | ||
var moveDecl = function moveDecl(callback) { | ||
return function (decl) { | ||
if (~intersection.indexOf(String(decl))) { | ||
callback.call(_this, decl); | ||
} | ||
}; | ||
}; | ||
firstClone.walkDecls(moveDecl(function (decl) { | ||
decl.remove(); | ||
recievingBlock.append(decl); | ||
})); | ||
secondClone.walkDecls(moveDecl(function (decl) { | ||
return decl.remove(); | ||
})); | ||
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.remove(); | ||
} | ||
}); | ||
if (!secondClone.parent) { | ||
return recievingBlock; | ||
} | ||
return secondClone; | ||
} else { | ||
recievingBlock.remove(); | ||
return second; | ||
} | ||
firstClone.walkDecls(moveDecl(decl => { | ||
decl.remove(); | ||
receivingBlock.append(decl); | ||
})); | ||
secondClone.walkDecls(moveDecl(decl => decl.remove())); | ||
const merged = ruleLength(firstClone, receivingBlock, secondClone); | ||
const original = ruleLength(first, second); | ||
if (merged < original) { | ||
first.replaceWith(firstClone); | ||
second.replaceWith(secondClone); | ||
[firstClone, receivingBlock, secondClone].forEach(r => { | ||
if (!r.nodes.length) { | ||
r.remove(); | ||
} | ||
}); | ||
if (!secondClone.parent) { | ||
return receivingBlock; | ||
} | ||
return secondClone; | ||
} else { | ||
receivingBlock.remove(); | ||
return second; | ||
} | ||
} | ||
/** | ||
* @param {string[]} browsers | ||
* @param {Object.<string, boolean>} compatibilityCache | ||
* @return {function(postcss.Rule)} | ||
*/ | ||
function selectorMerger(browsers, compatibilityCache) { | ||
var cache = null; | ||
return function (rule) { | ||
// Prime the cache with the first rule, or alternately ensure that it is | ||
// safe to merge both declarations before continuing | ||
if (!cache || !canMerge(rule, cache, browsers, compatibilityCache)) { | ||
cache = rule; | ||
return; | ||
/** @type {postcss.Rule} */ | ||
let cache = null; | ||
return function (rule) { | ||
// Prime the cache with the first rule, or alternately ensure that it is | ||
// safe to merge both declarations before continuing | ||
if (!cache || !canMerge(rule, cache, browsers, compatibilityCache)) { | ||
cache = rule; | ||
return; | ||
} // Ensure that we don't deduplicate the same rule; this is sometimes | ||
// caused by a partial merge | ||
if (cache === rule) { | ||
cache = rule; | ||
return; | ||
} // Parents merge: check if the rules have same parents, but not same parent nodes | ||
mergeParents(cache, rule); // Merge when declarations are exactly equal | ||
// e.g. h1 { color: red } h2 { color: red } | ||
if (sameDeclarationsAndOrder(getDecls(rule), getDecls(cache))) { | ||
rule.selector = joinSelectors(cache, rule); | ||
cache.remove(); | ||
cache = rule; | ||
return; | ||
} // Merge when both selectors are exactly equal | ||
// e.g. a { color: blue } a { font-weight: bold } | ||
if (cache.selector === rule.selector) { | ||
const cached = getDecls(cache); | ||
rule.walk(decl => { | ||
if (~indexOfDeclaration(cached, decl)) { | ||
return decl.remove(); | ||
} | ||
// Ensure that we don't deduplicate the same rule; this is sometimes | ||
// caused by a partial merge | ||
if (cache === rule) { | ||
cache = rule; | ||
return; | ||
} | ||
// Merge when declarations are exactly equal | ||
// e.g. h1 { color: red } h2 { color: red } | ||
if (getDecls(rule).join(';') === getDecls(cache).join(';')) { | ||
rule.selector = joinSelectors(cache, rule); | ||
cache.remove(); | ||
cache = rule; | ||
return; | ||
} | ||
// Merge when both selectors are exactly equal | ||
// e.g. a { color: blue } a { font-weight: bold } | ||
if (cache.selector === rule.selector) { | ||
var cached = getDecls(cache); | ||
rule.walk(function (decl) { | ||
if (~cached.indexOf(String(decl))) { | ||
return decl.remove(); | ||
} | ||
decl.moveTo(cache); | ||
}); | ||
rule.remove(); | ||
return; | ||
} | ||
// Partial merge: check if the rule contains a subset of the last; if | ||
// so create a joined selector with the subset, if smaller. | ||
cache = partialMerge(cache, rule); | ||
}; | ||
cache.append(decl); | ||
}); | ||
rule.remove(); | ||
return; | ||
} // Partial merge: check if the rule contains a subset of the last; if | ||
// so create a joined selector with the subset, if smaller. | ||
cache = partialMerge(cache, rule); | ||
}; | ||
} | ||
exports.default = _postcss2.default.plugin('postcss-merge-rules', function () { | ||
return function (css, result) { | ||
var opts = result.opts; | ||
var _default = _postcss.default.plugin('postcss-merge-rules', () => { | ||
return (css, result) => { | ||
const resultOpts = result.opts || {}; | ||
const browsers = (0, _browserslist.default)(null, { | ||
stats: resultOpts.stats, | ||
path: __dirname, | ||
env: resultOpts.env | ||
}); | ||
const compatibilityCache = {}; | ||
css.walkRules(selectorMerger(browsers, compatibilityCache)); | ||
}; | ||
}); | ||
var browsers = (0, _browserslist2.default)(null, { | ||
stats: opts && opts.stats, | ||
path: opts && opts.from, | ||
env: opts && opts.env | ||
}); | ||
var compatibilityCache = {}; | ||
css.walkRules(selectorMerger(browsers, compatibilityCache)); | ||
}; | ||
}); | ||
module.exports = exports['default']; | ||
exports.default = _default; | ||
module.exports = exports.default; |
@@ -1,140 +0,170 @@ | ||
'use strict'; | ||
"use strict"; | ||
exports.__esModule = true; | ||
exports.pseudoElements = undefined; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = ensureCompatibility; | ||
exports.pseudoElements = void 0; | ||
var _caniuseApi = require('caniuse-api'); | ||
var _caniuseApi = require("caniuse-api"); | ||
var _postcssSelectorParser = require('postcss-selector-parser'); | ||
var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser")); | ||
var _postcssSelectorParser2 = _interopRequireDefault(_postcssSelectorParser); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var simpleSelectorRe = /^#?[-._a-z0-9 ]+$/i; | ||
var cssSel2 = 'css-sel2'; | ||
var cssSel3 = 'css-sel3'; | ||
var cssGencontent = 'css-gencontent'; | ||
var cssFirstLetter = 'css-first-letter'; | ||
var cssFirstLine = 'css-first-line'; | ||
var cssInOutOfRange = 'css-in-out-of-range'; | ||
var pseudoElements = exports.pseudoElements = { | ||
':active': cssSel2, | ||
':after': cssGencontent, | ||
':before': cssGencontent, | ||
':checked': cssSel3, | ||
':default': 'css-default-pseudo', | ||
':dir': 'css-dir-pseudo', | ||
':disabled': cssSel3, | ||
':empty': cssSel3, | ||
':enabled': cssSel3, | ||
':first-child': cssSel2, | ||
':first-letter': cssFirstLetter, | ||
':first-line': cssFirstLine, | ||
':first-of-type': cssSel3, | ||
':focus': cssSel2, | ||
':focus-within': 'css-focus-within', | ||
':has': 'css-has', | ||
':hover': cssSel2, | ||
':in-range': cssInOutOfRange, | ||
':indeterminate': 'css-indeterminate-pseudo', | ||
':lang': cssSel2, | ||
':last-child': cssSel3, | ||
':last-of-type': cssSel3, | ||
':matches': 'css-matches-pseudo', | ||
':not': cssSel3, | ||
':nth-child': cssSel3, | ||
':nth-last-child': cssSel3, | ||
':nth-last-of-type': cssSel3, | ||
':nth-of-type': cssSel3, | ||
':only-child': cssSel3, | ||
':only-of-type': cssSel3, | ||
':optional': 'css-optional-pseudo', | ||
':out-of-range': cssInOutOfRange, | ||
':placeholder-shown': 'css-placeholder-shown', | ||
':root': cssSel3, | ||
':target': cssSel3, | ||
'::after': cssGencontent, | ||
'::backdrop': 'dialog', | ||
'::before': cssGencontent, | ||
'::first-letter': cssFirstLetter, | ||
'::first-line': cssFirstLine, | ||
'::marker': 'css-marker-pseudo', | ||
'::placeholder': 'css-placeholder', | ||
'::selection': 'css-selection' | ||
const simpleSelectorRe = /^#?[-._a-z0-9 ]+$/i; | ||
const cssSel2 = 'css-sel2'; | ||
const cssSel3 = 'css-sel3'; | ||
const cssGencontent = 'css-gencontent'; | ||
const cssFirstLetter = 'css-first-letter'; | ||
const cssFirstLine = 'css-first-line'; | ||
const cssInOutOfRange = 'css-in-out-of-range'; | ||
const pseudoElements = { | ||
':active': cssSel2, | ||
':after': cssGencontent, | ||
':before': cssGencontent, | ||
':checked': cssSel3, | ||
':default': 'css-default-pseudo', | ||
':dir': 'css-dir-pseudo', | ||
':disabled': cssSel3, | ||
':empty': cssSel3, | ||
':enabled': cssSel3, | ||
':first-child': cssSel2, | ||
':first-letter': cssFirstLetter, | ||
':first-line': cssFirstLine, | ||
':first-of-type': cssSel3, | ||
':focus': cssSel2, | ||
':focus-within': 'css-focus-within', | ||
':focus-visible': 'css-focus-visible', | ||
':has': 'css-has', | ||
':hover': cssSel2, | ||
':in-range': cssInOutOfRange, | ||
':indeterminate': 'css-indeterminate-pseudo', | ||
':lang': cssSel2, | ||
':last-child': cssSel3, | ||
':last-of-type': cssSel3, | ||
':matches': 'css-matches-pseudo', | ||
':not': cssSel3, | ||
':nth-child': cssSel3, | ||
':nth-last-child': cssSel3, | ||
':nth-last-of-type': cssSel3, | ||
':nth-of-type': cssSel3, | ||
':only-child': cssSel3, | ||
':only-of-type': cssSel3, | ||
':optional': 'css-optional-pseudo', | ||
':out-of-range': cssInOutOfRange, | ||
':placeholder-shown': 'css-placeholder-shown', | ||
':root': cssSel3, | ||
':target': cssSel3, | ||
'::after': cssGencontent, | ||
'::backdrop': 'dialog', | ||
'::before': cssGencontent, | ||
'::first-letter': cssFirstLetter, | ||
'::first-line': cssFirstLine, | ||
'::marker': 'css-marker-pseudo', | ||
'::placeholder': 'css-placeholder', | ||
'::selection': 'css-selection' | ||
}; | ||
exports.pseudoElements = pseudoElements; | ||
function isCssMixin(selector) { | ||
return selector[selector.length - 1] === ':'; | ||
return selector[selector.length - 1] === ':'; | ||
} | ||
const isSupportedCache = {}; // Move to util in future | ||
function isSupportedCached(feature, browsers) { | ||
const key = JSON.stringify({ | ||
feature, | ||
browsers | ||
}); | ||
let result = isSupportedCache[key]; | ||
if (!result) { | ||
result = (0, _caniuseApi.isSupported)(feature, browsers); | ||
isSupportedCache[key] = result; | ||
} | ||
return result; | ||
} | ||
function ensureCompatibility(selectors, browsers, compatibilityCache) { | ||
// Should not merge mixins | ||
if (selectors.some(isCssMixin)) { | ||
return false; | ||
// Should not merge mixins | ||
if (selectors.some(isCssMixin)) { | ||
return false; | ||
} | ||
return selectors.every(selector => { | ||
if (simpleSelectorRe.test(selector)) { | ||
return true; | ||
} | ||
return selectors.every(function (selector) { | ||
if (simpleSelectorRe.test(selector)) { | ||
return true; | ||
if (compatibilityCache && selector in compatibilityCache) { | ||
return compatibilityCache[selector]; | ||
} | ||
let compatible = true; | ||
(0, _postcssSelectorParser.default)(ast => { | ||
ast.walk(node => { | ||
const { | ||
type, | ||
value | ||
} = node; | ||
if (type === 'pseudo') { | ||
const entry = pseudoElements[value]; | ||
if (entry && compatible) { | ||
compatible = isSupportedCached(entry, browsers); | ||
} | ||
} | ||
if (compatibilityCache && selector in compatibilityCache) { | ||
return compatibilityCache[selector]; | ||
if (type === 'combinator') { | ||
if (~value.indexOf('~')) { | ||
compatible = isSupportedCached(cssSel3, browsers); | ||
} | ||
if (~value.indexOf('>') || ~value.indexOf('+')) { | ||
compatible = isSupportedCached(cssSel2, browsers); | ||
} | ||
} | ||
var compatible = true; | ||
(0, _postcssSelectorParser2.default)(function (ast) { | ||
ast.walk(function (node) { | ||
var type = node.type, | ||
value = node.value; | ||
if (type === 'pseudo') { | ||
var entry = pseudoElements[value]; | ||
if (entry && compatible) { | ||
compatible = (0, _caniuseApi.isSupported)(entry, browsers); | ||
} | ||
} | ||
if (type === 'combinator') { | ||
if (~value.indexOf('~')) { | ||
compatible = (0, _caniuseApi.isSupported)(cssSel3, browsers); | ||
} | ||
if (~value.indexOf('>') || ~value.indexOf('+')) { | ||
compatible = (0, _caniuseApi.isSupported)(cssSel2, browsers); | ||
} | ||
} | ||
if (type === 'attribute' && node.attribute) { | ||
// [foo] | ||
if (!node.operator) { | ||
compatible = (0, _caniuseApi.isSupported)(cssSel2, browsers); | ||
} | ||
if (type === 'attribute' && node.attribute) { | ||
// [foo] | ||
if (!node.operator) { | ||
compatible = isSupportedCached(cssSel2, browsers); | ||
} | ||
if (value) { | ||
// [foo="bar"], [foo~="bar"], [foo|="bar"] | ||
if (~['=', '~=', '|='].indexOf(node.operator)) { | ||
compatible = (0, _caniuseApi.isSupported)(cssSel2, browsers); | ||
} | ||
// [foo^="bar"], [foo$="bar"], [foo*="bar"] | ||
if (~['^=', '$=', '*='].indexOf(node.operator)) { | ||
compatible = (0, _caniuseApi.isSupported)(cssSel3, browsers); | ||
} | ||
} | ||
if (value) { | ||
// [foo="bar"], [foo~="bar"], [foo|="bar"] | ||
if (~['=', '~=', '|='].indexOf(node.operator)) { | ||
compatible = isSupportedCached(cssSel2, browsers); | ||
} // [foo^="bar"], [foo$="bar"], [foo*="bar"] | ||
// [foo="bar" i] | ||
if (node.insensitive) { | ||
compatible = (0, _caniuseApi.isSupported)('css-case-insensitive', browsers); | ||
} | ||
} | ||
if (!compatible) { | ||
// If this node was not compatible, | ||
// break out early from walking the rest | ||
return false; | ||
} | ||
}); | ||
}).process(selector); | ||
if (compatibilityCache) { | ||
compatibilityCache[selector] = compatible; | ||
if (~['^=', '$=', '*='].indexOf(node.operator)) { | ||
compatible = isSupportedCached(cssSel3, browsers); | ||
} | ||
} // [foo="bar" i] | ||
if (node.insensitive) { | ||
compatible = isSupportedCached('css-case-insensitive', browsers); | ||
} | ||
} | ||
return compatible; | ||
}); | ||
if (!compatible) { | ||
// If this node was not compatible, | ||
// break out early from walking the rest | ||
return false; | ||
} | ||
}); | ||
}).processSync(selector); | ||
if (compatibilityCache) { | ||
compatibilityCache[selector] = compatible; | ||
} | ||
return compatible; | ||
}); | ||
} |
{ | ||
"name": "postcss-merge-rules", | ||
"version": "2.1.2", | ||
"version": "4.0.0-nightly.2020.7.24", | ||
"description": "Merge CSS rules with PostCSS.", | ||
@@ -11,7 +11,5 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"pretest": "eslint src", | ||
"prepublish": "del-cli dist && cross-env BABEL_ENV=publish babel src --out-dir dist --ignore /__tests__/", | ||
"report": "nyc report --reporter=html", | ||
"test": "cross-env BABEL_ENV=test nyc ava src/__tests__", | ||
"test-012": "cross-env BABEL_ENV=test nyc ava src/__tests__" | ||
"prebuild": "", | ||
"build": "cross-env BABEL_ENV=publish babel src --config-file ../../babel.config.js --out-dir dist --ignore \"**/__tests__/\"", | ||
"prepublish": "" | ||
}, | ||
@@ -25,23 +23,3 @@ "keywords": [ | ||
"license": "MIT", | ||
"devDependencies": { | ||
"ava": "^0.17.0", | ||
"babel-cli": "^6.3.17", | ||
"babel-core": "^6.3.26", | ||
"babel-plugin-add-module-exports": "^0.2.1", | ||
"babel-plugin-istanbul": "^2.0.0", | ||
"babel-preset-es2015": "^6.3.13", | ||
"babel-preset-es2015-loose": "^7.0.0", | ||
"babel-preset-stage-0": "^6.3.13", | ||
"babel-register": "^6.9.0", | ||
"cross-env": "^2.0.1", | ||
"del-cli": "^0.2.0", | ||
"eslint": "^3.0.0", | ||
"eslint-config-cssnano": "^3.0.0", | ||
"eslint-plugin-babel": "^3.3.0", | ||
"eslint-plugin-import": "^2.0.1", | ||
"nyc": "^10.0.0", | ||
"postcss-discard-comments": "^2.0.4", | ||
"postcss-simple-vars": "^3.0.0" | ||
}, | ||
"homepage": "https://github.com/ben-eb/postcss-merge-rules", | ||
"homepage": "https://github.com/cssnano/cssnano", | ||
"author": { | ||
@@ -52,34 +30,17 @@ "name": "Ben Briggs", | ||
}, | ||
"repository": "ben-eb/postcss-merge-rules", | ||
"repository": "cssnano/cssnano", | ||
"dependencies": { | ||
"browserslist": "^1.5.2", | ||
"caniuse-api": "^1.5.2", | ||
"postcss": "^5.0.4", | ||
"postcss-selector-parser": "^2.2.2", | ||
"vendors": "^1.0.0" | ||
"browserslist": "^4.6.0", | ||
"caniuse-api": "^3.0.0", | ||
"cssnano-utils": "nightly", | ||
"postcss": "^7.0.16", | ||
"postcss-selector-parser": "^3.1.1", | ||
"vendors": "^1.0.3" | ||
}, | ||
"eslintConfig": { | ||
"extends": "cssnano" | ||
"bugs": { | ||
"url": "https://github.com/cssnano/cssnano/issues" | ||
}, | ||
"ava": { | ||
"require": "babel-register" | ||
}, | ||
"nyc": { | ||
"sourceMap": false, | ||
"instrument": false | ||
}, | ||
"browserslist": { | ||
"chrome58": [ | ||
"Chrome 58" | ||
], | ||
"edge15": [ | ||
"Edge 15" | ||
], | ||
"ie6": [ | ||
"IE 6" | ||
], | ||
"ie7": [ | ||
"IE 7" | ||
] | ||
"engines": { | ||
"node": ">=6.9.0" | ||
} | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
# [postcss][postcss]-merge-rules [![Build Status](https://travis-ci.org/ben-eb/postcss-merge-rules.svg?branch=master)][ci] [![NPM version](https://badge.fury.io/js/postcss-merge-rules.svg)][npm] [![Dependency Status](https://gemnasium.com/ben-eb/postcss-merge-rules.svg)][deps] | ||
# [postcss][postcss]-merge-rules | ||
@@ -97,6 +97,5 @@ > Merge CSS rules with PostCSS. | ||
## Contributing | ||
## Contributors | ||
Pull requests are welcome. If you add functionality, then please add unit tests | ||
to cover it. | ||
See [CONTRIBUTORS.md](https://github.com/cssnano/cssnano/blob/master/CONTRIBUTORS.md). | ||
@@ -107,5 +106,2 @@ ## License | ||
[ci]: https://travis-ci.org/ben-eb/postcss-merge-rules | ||
[deps]: https://gemnasium.com/ben-eb/postcss-merge-rules | ||
[npm]: http://badge.fury.io/js/postcss-merge-rules | ||
[postcss]: https://github.com/postcss/postcss |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
0
477
0
18690
6
5
106
2
+ Addedcssnano-utils@nightly
+ Addedbrowserslist@4.24.2(transitive)
+ Addedcaniuse-api@3.0.0(transitive)
+ Addedcaniuse-lite@1.0.30001680(transitive)
+ Addedcssnano-utils@4.0.0-nightly.2020.2.6(transitive)
+ Addeddot-prop@5.3.0(transitive)
+ Addedescalade@3.2.0(transitive)
+ Addedis-obj@2.0.0(transitive)
+ Addednanoid@3.3.7(transitive)
+ Addednode-releases@2.0.18(transitive)
+ Addedpicocolors@0.2.11.1.1(transitive)
+ Addedpostcss@7.0.398.4.49(transitive)
+ Addedpostcss-selector-parser@3.1.2(transitive)
+ Addedsource-map@0.6.1(transitive)
+ Addedsource-map-js@1.2.1(transitive)
+ Addedupdate-browserslist-db@1.1.1(transitive)
- Removedansi-regex@2.1.1(transitive)
- Removedansi-styles@2.2.1(transitive)
- Removedbrowserslist@1.7.7(transitive)
- Removedcaniuse-api@1.6.1(transitive)
- Removedcaniuse-db@1.0.30001680(transitive)
- Removedchalk@1.1.3(transitive)
- Removedescape-string-regexp@1.0.5(transitive)
- Removedflatten@1.0.3(transitive)
- Removedhas-ansi@2.0.0(transitive)
- Removedhas-flag@1.0.0(transitive)
- Removedjs-base64@2.6.4(transitive)
- Removedpostcss@5.2.18(transitive)
- Removedpostcss-selector-parser@2.2.3(transitive)
- Removedsource-map@0.5.7(transitive)
- Removedstrip-ansi@3.0.1(transitive)
- Removedsupports-color@2.0.03.2.3(transitive)
Updatedbrowserslist@^4.6.0
Updatedcaniuse-api@^3.0.0
Updatedpostcss@^7.0.16
Updatedvendors@^1.0.3