lepu-test-platform-web/node_modules/csso/lib/compressor/restructure/6-restructBlock.js

262 lines
8.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var resolveProperty = require('../../utils/names.js').property;
var resolveKeyword = require('../../utils/names.js').keyword;
var walkRulesRight = require('../../utils/walk.js').rulesRight;
var translate = require('../../utils/translate.js');
var dontRestructure = {
'src': 1 // https://github.com/afelix/csso/issues/50
};
var DONT_MIX_VALUE = {
// https://developer.mozilla.org/en-US/docs/Web/CSS/display#Browser_compatibility
'display': /table|ruby|flex|-(flex)?box$|grid|contents|run-in/i,
// https://developer.mozilla.org/en/docs/Web/CSS/text-align
'text-align': /^(start|end|match-parent|justify-all)$/i
};
var CURSOR_SAFE_VALUE = [
'auto', 'crosshair', 'default', 'move', 'text', 'wait', 'help',
'n-resize', 'e-resize', 's-resize', 'w-resize',
'ne-resize', 'nw-resize', 'se-resize', 'sw-resize',
'pointer', 'progress', 'not-allowed', 'no-drop', 'vertical-text', 'all-scroll',
'col-resize', 'row-resize'
];
var NEEDLESS_TABLE = {
'border-width': ['border'],
'border-style': ['border'],
'border-color': ['border'],
'border-top': ['border'],
'border-right': ['border'],
'border-bottom': ['border'],
'border-left': ['border'],
'border-top-width': ['border-top', 'border-width', 'border'],
'border-right-width': ['border-right', 'border-width', 'border'],
'border-bottom-width': ['border-bottom', 'border-width', 'border'],
'border-left-width': ['border-left', 'border-width', 'border'],
'border-top-style': ['border-top', 'border-style', 'border'],
'border-right-style': ['border-right', 'border-style', 'border'],
'border-bottom-style': ['border-bottom', 'border-style', 'border'],
'border-left-style': ['border-left', 'border-style', 'border'],
'border-top-color': ['border-top', 'border-color', 'border'],
'border-right-color': ['border-right', 'border-color', 'border'],
'border-bottom-color': ['border-bottom', 'border-color', 'border'],
'border-left-color': ['border-left', 'border-color', 'border'],
'margin-top': ['margin'],
'margin-right': ['margin'],
'margin-bottom': ['margin'],
'margin-left': ['margin'],
'padding-top': ['padding'],
'padding-right': ['padding'],
'padding-bottom': ['padding'],
'padding-left': ['padding'],
'font-style': ['font'],
'font-variant': ['font'],
'font-weight': ['font'],
'font-size': ['font'],
'font-family': ['font'],
'list-style-type': ['list-style'],
'list-style-position': ['list-style'],
'list-style-image': ['list-style']
};
function getPropertyFingerprint(propertyName, declaration, fingerprints) {
var realName = resolveProperty(propertyName).name;
if (realName === 'background' ||
(realName === 'filter' && declaration.value.sequence.first().type === 'Progid')) {
return propertyName + ':' + translate(declaration.value);
}
var declarationId = declaration.id;
var fingerprint = fingerprints[declarationId];
if (!fingerprint) {
var vendorId = '';
var iehack = '';
var special = {};
declaration.value.sequence.each(function walk(node) {
switch (node.type) {
case 'Argument':
case 'Value':
case 'Braces':
node.sequence.each(walk);
break;
case 'Identifier':
var name = node.name;
if (!vendorId) {
vendorId = resolveKeyword(name).vendor;
}
if (/\\[09]/.test(name)) {
iehack = RegExp.lastMatch;
}
if (realName === 'cursor') {
if (CURSOR_SAFE_VALUE.indexOf(name) === -1) {
special[name] = true;
}
} else if (DONT_MIX_VALUE.hasOwnProperty(realName)) {
if (DONT_MIX_VALUE[realName].test(name)) {
special[name] = true;
}
}
break;
case 'Function':
var name = node.name;
if (!vendorId) {
vendorId = resolveKeyword(name).vendor;
}
if (name === 'rect') {
// there are 2 forms of rect:
// rect(<top>, <right>, <bottom>, <left>) - standart
// rect(<top> <right> <bottom> <left>) backwards compatible syntax
// only the same form values can be merged
if (node.arguments.size < 4) {
name = 'rect-backward';
}
}
special[name + '()'] = true;
// check nested tokens too
node.arguments.each(walk);
break;
case 'Dimension':
var unit = node.unit;
switch (unit) {
// is not supported until IE11
case 'rem':
// v* units is too buggy across browsers and better
// don't merge values with those units
case 'vw':
case 'vh':
case 'vmin':
case 'vmax':
case 'vm': // IE9 supporting "vm" instead of "vmin".
special[unit] = true;
break;
}
break;
}
});
fingerprint = '|' + Object.keys(special).sort() + '|' + iehack + vendorId;
fingerprints[declarationId] = fingerprint;
}
return propertyName + fingerprint;
}
function needless(props, declaration, fingerprints) {
var property = resolveProperty(declaration.property.name);
if (NEEDLESS_TABLE.hasOwnProperty(property.name)) {
var table = NEEDLESS_TABLE[property.name];
for (var i = 0; i < table.length; i++) {
var ppre = getPropertyFingerprint(property.prefix + table[i], declaration, fingerprints);
var prev = props[ppre];
if (prev && (!declaration.value.important || prev.item.data.value.important)) {
return prev;
}
}
}
}
function processRuleset(ruleset, item, list, props, fingerprints) {
var declarations = ruleset.block.declarations;
declarations.eachRight(function(declaration, declarationItem) {
var property = declaration.property.name;
var fingerprint = getPropertyFingerprint(property, declaration, fingerprints);
var prev = props[fingerprint];
if (prev && !dontRestructure.hasOwnProperty(property)) {
if (declaration.value.important && !prev.item.data.value.important) {
props[fingerprint] = {
block: declarations,
item: declarationItem
};
prev.block.remove(prev.item);
declaration.info = {
primary: declaration.info,
merged: prev.item.data.info
};
} else {
declarations.remove(declarationItem);
prev.item.data.info = {
primary: prev.item.data.info,
merged: declaration.info
};
}
} else {
var prev = needless(props, declaration, fingerprints);
if (prev) {
declarations.remove(declarationItem);
prev.item.data.info = {
primary: prev.item.data.info,
merged: declaration.info
};
} else {
declaration.fingerprint = fingerprint;
props[fingerprint] = {
block: declarations,
item: declarationItem
};
}
}
});
if (declarations.isEmpty()) {
list.remove(item);
}
};
module.exports = function restructBlock(ast) {
var stylesheetMap = {};
var fingerprints = Object.create(null);
walkRulesRight(ast, function(node, item, list) {
if (node.type !== 'Ruleset') {
return;
}
var stylesheet = this.stylesheet;
var rulesetId = (node.pseudoSignature || '') + '|' + node.selector.selectors.first().id;
var rulesetMap;
var props;
if (!stylesheetMap.hasOwnProperty(stylesheet.id)) {
rulesetMap = {};
stylesheetMap[stylesheet.id] = rulesetMap;
} else {
rulesetMap = stylesheetMap[stylesheet.id];
}
if (rulesetMap.hasOwnProperty(rulesetId)) {
props = rulesetMap[rulesetId];
} else {
props = {};
rulesetMap[rulesetId] = props;
}
processRuleset.call(this, node, item, list, props, fingerprints);
});
};