summaryrefslogtreecommitdiff
path: root/node_modules/clean-css/lib/optimizer/level-1/optimize.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/clean-css/lib/optimizer/level-1/optimize.js')
-rw-r--r--node_modules/clean-css/lib/optimizer/level-1/optimize.js325
1 files changed, 325 insertions, 0 deletions
diff --git a/node_modules/clean-css/lib/optimizer/level-1/optimize.js b/node_modules/clean-css/lib/optimizer/level-1/optimize.js
new file mode 100644
index 00000000..d0461e06
--- /dev/null
+++ b/node_modules/clean-css/lib/optimizer/level-1/optimize.js
@@ -0,0 +1,325 @@
+var sortSelectors = require('./sort-selectors');
+var tidyRules = require('./tidy-rules');
+var tidyBlock = require('./tidy-block');
+var tidyAtRule = require('./tidy-at-rule');
+
+var Hack = require('../hack');
+var removeUnused = require('../remove-unused');
+var restoreFromOptimizing = require('../restore-from-optimizing');
+var wrapForOptimizing = require('../wrap-for-optimizing').all;
+
+var configuration = require('../configuration');
+var optimizers = require('./value-optimizers');
+
+var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
+
+var Token = require('../../tokenizer/token');
+var Marker = require('../../tokenizer/marker');
+
+var formatPosition = require('../../utils/format-position');
+
+var serializeRules = require('../../writer/one-time').rules;
+
+var CHARSET_TOKEN = '@charset';
+var CHARSET_REGEXP = new RegExp('^' + CHARSET_TOKEN, 'i');
+
+var DEFAULT_ROUNDING_PRECISION = require('../../options/rounding-precision').DEFAULT;
+
+var VARIABLE_PROPERTY_NAME_PATTERN = /^--\S+$/;
+var PROPERTY_NAME_PATTERN = /^(?:-chrome-|-[\w-]+\w|\w[\w-]+\w|\w{1,})$/;
+var IMPORT_PREFIX_PATTERN = /^@import/i;
+var URL_PREFIX_PATTERN = /^url\(/i;
+
+function startsAsUrl(value) {
+ return URL_PREFIX_PATTERN.test(value);
+}
+
+function isImport(token) {
+ return IMPORT_PREFIX_PATTERN.test(token[1]);
+}
+
+function isLegacyFilter(property) {
+ var value;
+
+ if (property.name == 'filter' || property.name == '-ms-filter') {
+ value = property.value[0][1];
+
+ return value.indexOf('progid') > -1
+ || value.indexOf('alpha') === 0
+ || value.indexOf('chroma') === 0;
+ }
+ return false;
+}
+
+function noop() {}
+
+function noopValueOptimizer(_name, value, _options) { return value; }
+
+function optimizeBody(rule, properties, context) {
+ var options = context.options;
+ var valueOptimizers;
+ var property, name, type, value;
+ var propertyToken;
+ var propertyOptimizer;
+ var serializedRule = serializeRules(rule);
+ var _properties = wrapForOptimizing(properties);
+ var pluginValueOptimizers = context.options.plugins.level1Value;
+ var pluginPropertyOptimizers = context.options.plugins.level1Property;
+ var isVariable;
+ var i, l;
+
+ for (i = 0, l = _properties.length; i < l; i++) {
+ var j, k, m, n;
+
+ property = _properties[i];
+ name = property.name;
+ propertyOptimizer = configuration[name] && configuration[name].propertyOptimizer || noop;
+ valueOptimizers = configuration[name] && configuration[name].valueOptimizers || [optimizers.whiteSpace];
+ isVariable = VARIABLE_PROPERTY_NAME_PATTERN.test(name);
+
+ if (isVariable) {
+ valueOptimizers = options.variableOptimizers.length > 0
+ ? options.variableOptimizers
+ : [optimizers.whiteSpace];
+ }
+
+ if (!isVariable && !PROPERTY_NAME_PATTERN.test(name)) {
+ propertyToken = property.all[property.position];
+ context.warnings.push('Invalid property name \'' + name + '\' at ' + formatPosition(propertyToken[1][2][0]) + '. Ignoring.');
+ property.unused = true;
+ continue;
+ }
+
+ if (property.value.length === 0) {
+ propertyToken = property.all[property.position];
+ context.warnings.push('Empty property \'' + name + '\' at ' + formatPosition(propertyToken[1][2][0]) + '. Ignoring.');
+ property.unused = true;
+ continue;
+ }
+
+ if (property.hack && (
+ (property.hack[0] == Hack.ASTERISK || property.hack[0] == Hack.UNDERSCORE)
+ && !options.compatibility.properties.iePrefixHack
+ || property.hack[0] == Hack.BACKSLASH && !options.compatibility.properties.ieSuffixHack
+ || property.hack[0] == Hack.BANG && !options.compatibility.properties.ieBangHack)) {
+ property.unused = true;
+ continue;
+ }
+
+ if (!options.compatibility.properties.ieFilters && isLegacyFilter(property)) {
+ property.unused = true;
+ continue;
+ }
+
+ if (property.block) {
+ optimizeBody(rule, property.value[0][1], context);
+ continue;
+ }
+
+ for (j = 0, m = property.value.length; j < m; j++) {
+ type = property.value[j][0];
+ value = property.value[j][1];
+
+ if (type == Token.PROPERTY_BLOCK) {
+ property.unused = true;
+ context.warnings.push('Invalid value token at ' + formatPosition(value[0][1][2][0]) + '. Ignoring.');
+ break;
+ }
+
+ if (startsAsUrl(value) && !context.validator.isUrl(value)) {
+ property.unused = true;
+ context.warnings.push('Broken URL \'' + value + '\' at ' + formatPosition(property.value[j][2][0]) + '. Ignoring.');
+ break;
+ }
+
+ for (k = 0, n = valueOptimizers.length; k < n; k++) {
+ value = valueOptimizers[k](name, value, options);
+ }
+
+ for (k = 0, n = pluginValueOptimizers.length; k < n; k++) {
+ value = pluginValueOptimizers[k](name, value, options);
+ }
+
+ property.value[j][1] = value;
+ }
+
+ propertyOptimizer(serializedRule, property, options);
+
+ for (j = 0, m = pluginPropertyOptimizers.length; j < m; j++) {
+ pluginPropertyOptimizers[j](serializedRule, property, options);
+ }
+ }
+
+ restoreFromOptimizing(_properties);
+ removeUnused(_properties);
+ removeComments(properties, options);
+}
+
+function removeComments(tokens, options) {
+ var token;
+ var i;
+
+ for (i = 0; i < tokens.length; i++) {
+ token = tokens[i];
+
+ if (token[0] != Token.COMMENT) {
+ continue;
+ }
+
+ optimizeComment(token, options);
+
+ if (token[1].length === 0) {
+ tokens.splice(i, 1);
+ i--;
+ }
+ }
+}
+
+function optimizeComment(token, options) {
+ if (token[1][2] == Marker.EXCLAMATION && (options.level[OptimizationLevel.One].specialComments == 'all' || options.commentsKept < options.level[OptimizationLevel.One].specialComments)) {
+ options.commentsKept++;
+ return;
+ }
+
+ token[1] = [];
+}
+
+function cleanupCharsets(tokens) {
+ var hasCharset = false;
+
+ for (var i = 0, l = tokens.length; i < l; i++) {
+ var token = tokens[i];
+
+ if (token[0] != Token.AT_RULE) { continue; }
+
+ if (!CHARSET_REGEXP.test(token[1])) { continue; }
+
+ if (hasCharset || token[1].indexOf(CHARSET_TOKEN) == -1) {
+ tokens.splice(i, 1);
+ i--;
+ l--;
+ } else {
+ hasCharset = true;
+ tokens.splice(i, 1);
+ tokens.unshift([Token.AT_RULE, token[1].replace(CHARSET_REGEXP, CHARSET_TOKEN)]);
+ }
+ }
+}
+
+function buildUnitRegexp(options) {
+ var units = ['px', 'em', 'ex', 'cm', 'mm', 'in', 'pt', 'pc', '%'];
+ var otherUnits = ['ch', 'rem', 'vh', 'vm', 'vmax', 'vmin', 'vw'];
+
+ otherUnits.forEach(function(unit) {
+ if (options.compatibility.units[unit]) {
+ units.push(unit);
+ }
+ });
+
+ return new RegExp('(^|\\s|\\(|,)0(?:' + units.join('|') + ')(\\W|$)', 'g');
+}
+
+function buildPrecisionOptions(roundingPrecision) {
+ var precisionOptions = {
+ matcher: null,
+ units: {}
+ };
+ var optimizable = [];
+ var unit;
+ var value;
+
+ for (unit in roundingPrecision) {
+ value = roundingPrecision[unit];
+
+ if (value != DEFAULT_ROUNDING_PRECISION) {
+ precisionOptions.units[unit] = {};
+ precisionOptions.units[unit].value = value;
+ precisionOptions.units[unit].multiplier = 10 ** value;
+
+ optimizable.push(unit);
+ }
+ }
+
+ if (optimizable.length > 0) {
+ precisionOptions.enabled = true;
+ precisionOptions.decimalPointMatcher = new RegExp('(\\d)\\.($|' + optimizable.join('|') + ')($|\\W)', 'g');
+ precisionOptions.zeroMatcher = new RegExp('(\\d*)(\\.\\d+)(' + optimizable.join('|') + ')', 'g');
+ }
+
+ return precisionOptions;
+}
+
+function buildVariableOptimizers(options) {
+ return options.level[OptimizationLevel.One].variableValueOptimizers.map(function(optimizer) {
+ if (typeof (optimizer) == 'string') {
+ return optimizers[optimizer] || noopValueOptimizer;
+ }
+
+ return optimizer;
+ });
+}
+
+function level1Optimize(tokens, context) {
+ var options = context.options;
+ var levelOptions = options.level[OptimizationLevel.One];
+ var ie7Hack = options.compatibility.selectors.ie7Hack;
+ var adjacentSpace = options.compatibility.selectors.adjacentSpace;
+ var spaceAfterClosingBrace = options.compatibility.properties.spaceAfterClosingBrace;
+ var format = options.format;
+ var mayHaveCharset = false;
+ var afterRules = false;
+
+ options.unitsRegexp = options.unitsRegexp || buildUnitRegexp(options);
+ options.precision = options.precision || buildPrecisionOptions(levelOptions.roundingPrecision);
+ options.commentsKept = options.commentsKept || 0;
+ options.variableOptimizers = options.variableOptimizers || buildVariableOptimizers(options);
+
+ for (var i = 0, l = tokens.length; i < l; i++) {
+ var token = tokens[i];
+
+ switch (token[0]) {
+ case Token.AT_RULE:
+ token[1] = isImport(token) && afterRules ? '' : token[1];
+ token[1] = levelOptions.tidyAtRules ? tidyAtRule(token[1]) : token[1];
+ mayHaveCharset = true;
+ break;
+ case Token.AT_RULE_BLOCK:
+ optimizeBody(token[1], token[2], context);
+ afterRules = true;
+ break;
+ case Token.NESTED_BLOCK:
+ token[1] = levelOptions.tidyBlockScopes ? tidyBlock(token[1], spaceAfterClosingBrace) : token[1];
+ level1Optimize(token[2], context);
+ afterRules = true;
+ break;
+ case Token.COMMENT:
+ optimizeComment(token, options);
+ break;
+ case Token.RULE:
+ token[1] = levelOptions.tidySelectors
+ ? tidyRules(token[1], !ie7Hack, adjacentSpace, format, context.warnings)
+ : token[1];
+ token[1] = token[1].length > 1 ? sortSelectors(token[1], levelOptions.selectorsSortingMethod) : token[1];
+ optimizeBody(token[1], token[2], context);
+ afterRules = true;
+ break;
+ }
+
+ if (token[0] == Token.COMMENT
+ && token[1].length === 0
+ || levelOptions.removeEmpty
+ && (token[1].length === 0 || (token[2] && token[2].length === 0))) {
+ tokens.splice(i, 1);
+ i--;
+ l--;
+ }
+ }
+
+ if (levelOptions.cleanupCharsets && mayHaveCharset) {
+ cleanupCharsets(tokens);
+ }
+
+ return tokens;
+}
+
+module.exports = level1Optimize;