From 566b52eab9e17d075b38b5cd6f19ff7ae849a327 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Tue, 23 Jun 2015 06:42:53 +0100 Subject: [PATCH] Simplifies unit optimizations code. It follows a much simpler functional style, which is also easier to grasp. --- lib/clean.js | 4 +- lib/selectors/simple.js | 161 ++++++++++++++++++++-------------------- test/test-helper.js | 6 +- 3 files changed, 87 insertions(+), 84 deletions(-) diff --git a/lib/clean.js b/lib/clean.js index 87522ec5..5ca46346 100644 --- a/lib/clean.js +++ b/lib/clean.js @@ -9,7 +9,7 @@ var ImportInliner = require('./imports/inliner'); var rebaseUrls = require('./urls/rebase'); var tokenize = require('./tokenizer/tokenize'); -var SimpleOptimizer = require('./selectors/simple'); +var simpleOptimize = require('./selectors/simple'); var advancedOptimize = require('./selectors/advanced'); var addOptimizationMetadata = require('./selectors/optimization-metadata'); @@ -203,7 +203,7 @@ function minify(context, data) { addOptimizationMetadata(tokens); - new SimpleOptimizer(options).optimize(tokens); + simpleOptimize(tokens, options); if (options.advanced) advancedOptimize(tokens, options, context.validator, true); diff --git a/lib/selectors/simple.js b/lib/selectors/simple.js index 45acecfd..6dcff708 100644 --- a/lib/selectors/simple.js +++ b/lib/selectors/simple.js @@ -1,4 +1,6 @@ -var CleanUp = require('./clean-up'); +var cleanUpSelectors = require('./clean-up').selectors; +var cleanUpBlock = require('./clean-up').block; +var cleanUpAtRule = require('./clean-up').atRule; var Splitter = require('../utils/splitter'); var RGB = require('../colors/rgb'); @@ -12,27 +14,6 @@ var CHARSET_REGEXP = new RegExp('^' + CHARSET_TOKEN, 'i'); var FONT_NUMERAL_WEIGHTS = ['100', '200', '300', '400', '500', '600', '700', '800', '900']; var FONT_NAME_WEIGHTS = ['normal', 'bold', 'bolder', 'lighter']; -function SimpleOptimizer(options) { - this.options = 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); - }); - - options.unitsRegexp = new RegExp('(^|\\s|\\(|,)0(?:' + units.join('|') + ')(\\W|$)', 'g'); - - options.precision = {}; - options.precision.value = options.roundingPrecision === undefined ? - DEFAULT_ROUNDING_PRECISION : - options.roundingPrecision; - options.precision.multiplier = Math.pow(10, options.precision.value); - options.precision.regexp = new RegExp('(\\d*\\.\\d{' + (options.precision.value + 1) + ',})px', 'g'); -} - var valueMinifiers = { 'background': function (value, index, total) { return index == 1 && total == 2 && (value == 'none' || value == 'transparent') ? '0 0' : value; @@ -289,71 +270,93 @@ function optimizeBody(properties, options) { } } -SimpleOptimizer.prototype.optimize = function (tokens) { - var self = this; +function cleanupCharsets(tokens) { var hasCharset = false; - var options = this.options; - var ie7Hack = options.compatibility.selectors.ie7Hack; - var adjacentSpace = options.compatibility.selectors.adjacentSpace; - var spaceAfterClosingBrace = options.compatibility.properties.spaceAfterClosingBrace; - function _cleanupCharsets(tokens) { - for (var i = 0, l = tokens.length; i < l; i++) { - var token = tokens[i]; - - if (token[0] != 'at-rule') - continue; - - if (CHARSET_REGEXP.test(token[1][0])) { - if (hasCharset || token[1][0].indexOf(CHARSET_TOKEN) == -1) { - tokens.splice(i, 1); - i--; - l--; - } else { - hasCharset = true; - tokens.splice(i, 1); - tokens.unshift(['at-rule', [token[1][0].replace(CHARSET_REGEXP, CHARSET_TOKEN)]]); - } - } + for (var i = 0, l = tokens.length; i < l; i++) { + var token = tokens[i]; + + if (token[0] != 'at-rule') + continue; + + if (!CHARSET_REGEXP.test(token[1][0])) + continue; + + if (hasCharset || token[1][0].indexOf(CHARSET_TOKEN) == -1) { + tokens.splice(i, 1); + i--; + l--; + } else { + hasCharset = true; + tokens.splice(i, 1); + tokens.unshift(['at-rule', [token[1][0].replace(CHARSET_REGEXP, CHARSET_TOKEN)]]); } } +} - function _optimize(tokens) { - var mayHaveCharset = false; - - for (var i = 0, l = tokens.length; i < l; i++) { - var token = tokens[i]; - - switch (token[0]) { - case 'selector': - token[1] = CleanUp.selectors(token[1], !ie7Hack, adjacentSpace); - optimizeBody(token[2], self.options); - break; - case 'block': - CleanUp.block(token[1], spaceAfterClosingBrace); - _optimize(token[2]); - break; - case 'flat-block': - CleanUp.block(token[1], spaceAfterClosingBrace); - optimizeBody(token[2], self.options); - break; - case 'at-rule': - CleanUp.atRule(token[1]); - mayHaveCharset = true; - } +function buildUnitRegexp(options) { + var units = ['px', 'em', 'ex', 'cm', 'mm', 'in', 'pt', 'pc', '%']; + var otherUnits = ['ch', 'rem', 'vh', 'vm', 'vmax', 'vmin', 'vw']; - if (token[1].length === 0 || (token[2] && token[2].length === 0)) { - tokens.splice(i, 1); - i--; - l--; - } + otherUnits.forEach(function (unit) { + if (options.compatibility.units[unit]) + units.push(unit); + }); + + return new RegExp('(^|\\s|\\(|,)0(?:' + units.join('|') + ')(\\W|$)', 'g'); +} + +function buildPrecision(options) { + var precision = {}; + + precision.value = options.roundingPrecision === undefined ? + DEFAULT_ROUNDING_PRECISION : + options.roundingPrecision; + precision.multiplier = Math.pow(10, precision.value); + precision.regexp = new RegExp('(\\d*\\.\\d{' + (precision.value + 1) + ',})px', 'g'); + + return precision; +} + +function optimize(tokens, options) { + var ie7Hack = options.compatibility.selectors.ie7Hack; + var adjacentSpace = options.compatibility.selectors.adjacentSpace; + var spaceAfterClosingBrace = options.compatibility.properties.spaceAfterClosingBrace; + var mayHaveCharset = false; + + options.unitsRegexp = buildUnitRegexp(options); + options.precision = buildPrecision(options); + + for (var i = 0, l = tokens.length; i < l; i++) { + var token = tokens[i]; + + switch (token[0]) { + case 'selector': + token[1] = cleanUpSelectors(token[1], !ie7Hack, adjacentSpace); + optimizeBody(token[2], options); + break; + case 'block': + cleanUpBlock(token[1], spaceAfterClosingBrace); + optimize(token[2], options); + break; + case 'flat-block': + cleanUpBlock(token[1], spaceAfterClosingBrace); + optimizeBody(token[2], options); + break; + case 'at-rule': + cleanUpAtRule(token[1]); + mayHaveCharset = true; } - if (mayHaveCharset) - _cleanupCharsets(tokens); + if (token[1].length === 0 || (token[2] && token[2].length === 0)) { + tokens.splice(i, 1); + i--; + l--; + } } - _optimize(tokens); -}; + if (mayHaveCharset) + cleanupCharsets(tokens); +} -module.exports = SimpleOptimizer; +module.exports = optimize; diff --git a/test/test-helper.js b/test/test-helper.js index 0f3376bc..7ff5f0dd 100644 --- a/test/test-helper.js +++ b/test/test-helper.js @@ -2,7 +2,7 @@ var assert = require('assert'); var CleanCSS = require('../lib/clean'); var tokenize = require('../lib/tokenizer/tokenize'); -var SimpleOptimizer = require('../lib/selectors/simple'); +var simpleOptimize = require('../lib/selectors/simple'); var Compatibility = require('../lib/utils/compatibility'); var addOptimizationMetadata = require('../lib/selectors/optimization-metadata'); @@ -36,7 +36,7 @@ function selectorContext(group, specs, options) { function optimized(selectors) { return function (source) { var tokens = tokenize(source, { options: {} }); - new SimpleOptimizer(options).optimize(tokens); + simpleOptimize(tokens, options); assert.deepEqual(tokens[0] ? tokens[0][1] : null, selectors); }; @@ -61,7 +61,7 @@ function propertyContext(group, specs, options) { return function (source) { var tokens = tokenize(source, { options: {} }); addOptimizationMetadata(tokens); - new SimpleOptimizer(options).optimize(tokens); + simpleOptimize(tokens, options); var value = tokens[0] ? tokens[0][2].map(function (property) { -- 2.34.1