From: Jakub Pawlowicz Date: Sun, 13 Nov 2016 10:54:38 +0000 (+0100) Subject: Fixes all unit tests on top of the new tokenizer. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=5fec9db70e4aacb8edf593f524fac19b6d86e660;p=clean-css.git Fixes all unit tests on top of the new tokenizer. This involves the following changes too: * /lib/selectors -> /lib/optimizer; * new /lib/optimizer/tidy* modules for cleaning up tokens; * redone URL rewriting as it doesn't require full document scan anymore, as it's run right after tokenization; * compatibility class is now a simple function; * introducing `readSources` method instead of SourceReader class. --- diff --git a/lib/clean.js b/lib/clean.js index 1fe93909..31ba217c 100644 --- a/lib/clean.js +++ b/lib/clean.js @@ -5,35 +5,21 @@ * Copyright (C) 2016 JakubPawlowicz.com */ -var ImportInliner = require('./imports/inliner'); -var rebaseUrls = require('./urls/rebase'); - -var tokenize = require('./tokenizer/tokenize'); -var simpleOptimize = require('./selectors/simple'); -var advancedOptimize = require('./selectors/advanced'); - -var simpleStringify = require('./stringifier/simple'); -var sourceMapStringify = require('./stringifier/source-maps'); - -var CommentsProcessor = require('./text/comments-processor'); -var ExpressionsProcessor = require('./text/expressions-processor'); -var FreeTextProcessor = require('./text/free-text-processor'); -var UrlsProcessor = require('./text/urls-processor'); - -var Compatibility = require('./utils/compatibility'); -var InputSourceMapTracker = require('./utils/input-source-map-tracker'); -var SourceTracker = require('./utils/source-tracker'); -var SourceReader = require('./utils/source-reader'); -var Validator = require('./properties/validator'); - var fs = require('fs'); var path = require('path'); var url = require('url'); -var override = require('./utils/object').override; - +var compatibility = require('./utils/compatibility'); +var Validator = require('./properties/validator'); +var override = require('./utils/override'); var DEFAULT_TIMEOUT = 5000; +var readSources = require('./utils/read-sources'); +var basicOptimize = require('./optimizer/basic'); +var advancedOptimize = require('./optimizer/advanced'); +var simpleStringify = require('./stringifier/simple'); +var sourceMapStringify = require('./stringifier/source-maps'); + var CleanCSS = module.exports = function CleanCSS(options) { options = options || {}; @@ -41,7 +27,7 @@ var CleanCSS = module.exports = function CleanCSS(options) { advanced: undefined === options.advanced ? true : !!options.advanced, aggressiveMerging: undefined === options.aggressiveMerging ? true : !!options.aggressiveMerging, benchmark: options.benchmark, - compatibility: new Compatibility(options.compatibility).toOptions(), + compatibility: compatibility(options.compatibility), debug: options.debug, explicitRoot: !!options.root, explicitTarget: !!options.target, @@ -92,140 +78,83 @@ function proxyOptionsFrom(httpProxy) { {}; } -CleanCSS.prototype.minify = function (data, callback) { +CleanCSS.prototype.minify = function (input, callback) { var context = { stats: {}, errors: [], warnings: [], options: this.options, - debug: this.options.debug, localOnly: !callback, - sourceTracker: new SourceTracker(), validator: new Validator(this.options.compatibility) }; - if (context.options.sourceMap) - context.inputSourceMapTracker = new InputSourceMapTracker(context); + return runner(context.localOnly)(function () { + return readSources(input, context, function (tokens) { + var stringify = context.options.sourceMap ? + sourceMapStringify : + simpleStringify; - context.sourceReader = new SourceReader(context, data); - data = context.sourceReader.toString(); + var optimizedTokens = optimize(tokens, context); + var optimizedStyles = stringify(optimizedTokens, context); + var output = withMetadata(optimizedStyles, context); - if (context.options.processImport || data.indexOf('@shallow') > 0) { - // inline all imports - var runner = callback ? - process.nextTick : - function (callback) { return callback(); }; - - return runner(function () { - return new ImportInliner(context).process(data, { - localOnly: context.localOnly, - imports: context.options.processImportFrom, - whenDone: runMinifier(callback, context) - }); + return callback ? + callback(context.errors.length > 0 ? context.errors : null, output) : + output; }); - } else { - return runMinifier(callback, context)(data); - } + }); }; -function runMinifier(callback, context) { - function whenSourceMapReady (data) { - data = context.options.debug ? - minifyWithDebug(context, data) : - minify(context, data); - data = withMetadata(context, data); - - return callback ? - callback.call(null, context.errors.length > 0 ? context.errors : null, data) : - data; - } - - return function (data) { - if (context.options.sourceMap) { - return context.inputSourceMapTracker.track(data, function () { - if (context.options.sourceMapInlineSources) { - return context.inputSourceMapTracker.resolveSources(function () { - return whenSourceMapReady(data); - }); - } else { - return whenSourceMapReady(data); - } - }); - } else { - return whenSourceMapReady(data); - } - }; -} - -function withMetadata(context, data) { - data.stats = context.stats; - data.errors = context.errors; - data.warnings = context.warnings; - return data; +function runner(localOnly) { + // to always execute code asynchronously when a callback is given + // more at blog.izs.me/post/59142742143/designing-apis-for-asynchrony + return localOnly ? + function (callback) { return callback(); } : + process.nextTick; } -function minifyWithDebug(context, data) { - var startedAt = process.hrtime(); - context.stats.originalSize = context.sourceTracker.removeAll(data).length; - - data = minify(context, data); +function optimize(tokens, context) { + var optimized; - var elapsed = process.hrtime(startedAt); - context.stats.timeSpent = ~~(elapsed[0] * 1e3 + elapsed[1] / 1e6); - context.stats.efficiency = 1 - data.styles.length / context.stats.originalSize; - context.stats.minifiedSize = data.styles.length; + optimized = basicOptimize(tokens, context); + optimized = context.options.advanced ? + advancedOptimize(tokens, context, true) : + optimized; - return data; + return optimized; } -function benchmark(runner) { - return function (processor, action) { - var name = processor.constructor.name + '#' + action; - var start = process.hrtime(); - runner(processor, action); - var itTook = process.hrtime(start); - console.log('%d ms: ' + name, 1000 * itTook[0] + itTook[1] / 1000000); - }; +function withMetadata(output, context) { + output.stats = context.stats; + output.errors = context.errors; + output.warnings = context.warnings; + return output; } -function minify(context, data) { - var options = context.options; +// function minifyWithDebug(context, data) { +// var startedAt = process.hrtime(); +// context.stats.originalSize = context.sourceTracker.removeAll(data).length; - var commentsProcessor = new CommentsProcessor(context, options.keepSpecialComments, options.keepBreaks, options.sourceMap); - var expressionsProcessor = new ExpressionsProcessor(options.sourceMap); - var freeTextProcessor = new FreeTextProcessor(options.sourceMap); - var urlsProcessor = new UrlsProcessor(context, options.sourceMap, options.compatibility.properties.urlQuotes); +// data = minify(context, data); - var stringify = options.sourceMap ? sourceMapStringify : simpleStringify; +// var elapsed = process.hrtime(startedAt); +// context.stats.timeSpent = ~~(elapsed[0] * 1e3 + elapsed[1] / 1e6); +// context.stats.efficiency = 1 - data.styles.length / context.stats.originalSize; +// context.stats.minifiedSize = data.styles.length; - var run = function (processor, action) { - data = typeof processor == 'function' ? - processor(data) : - processor[action](data); - }; - - if (options.benchmark) - run = benchmark(run); - - run(commentsProcessor, 'escape'); - run(expressionsProcessor, 'escape'); - run(urlsProcessor, 'escape'); - run(freeTextProcessor, 'escape'); +// return data; +// } - function restoreEscapes(data, prefixContent) { - data = freeTextProcessor.restore(data, prefixContent); - data = urlsProcessor.restore(data); - data = options.rebase ? rebaseUrls(data, context) : data; - data = expressionsProcessor.restore(data); - return commentsProcessor.restore(data); - } +// function minify(context, data) { + // var options = context.options; + // var stringify = options.sourceMap ? + // sourceMapStringify : + // simpleStringify; - var tokens = tokenize(data, context); + // var tokens = tokenize(data, context); + // var allTokens = inline() + // var optimizedTokens = optimize(tokens, context); + // var output = stringify(optimizedTokens, context); - simpleOptimize(tokens, options, context); - - if (options.advanced) - advancedOptimize(tokens, options, context, true); - - return stringify(tokens, options, restoreEscapes, context.inputSourceMapTracker); -} + // return output; +// } diff --git a/lib/selectors/advanced.js b/lib/optimizer/advanced.js similarity index 53% rename from lib/selectors/advanced.js rename to lib/optimizer/advanced.js index 38630e6a..fb5d9ec8 100644 --- a/lib/selectors/advanced.js +++ b/lib/optimizer/advanced.js @@ -9,16 +9,18 @@ var restructure = require('./restructure'); var removeDuplicateMediaQueries = require('./remove-duplicate-media-queries'); var mergeMediaQueries = require('./merge-media-queries'); +var Token = require('../tokenizer/token'); + function removeEmpty(tokens) { for (var i = 0, l = tokens.length; i < l; i++) { var token = tokens[i]; var isEmpty = false; switch (token[0]) { - case 'selector': + case Token.RULE: isEmpty = token[1].length === 0 || token[2].length === 0; break; - case 'block': + case Token.BLOCK: removeEmpty(token[2]); isEmpty = token[2].length === 0; } @@ -31,56 +33,58 @@ function removeEmpty(tokens) { } } -function recursivelyOptimizeBlocks(tokens, options, context) { +function recursivelyOptimizeBlocks(tokens, context) { for (var i = 0, l = tokens.length; i < l; i++) { var token = tokens[i]; - if (token[0] == 'block') { - var isKeyframes = /@(-moz-|-o-|-webkit-)?keyframes/.test(token[1][0]); - optimize(token[2], options, context, !isKeyframes); + if (token[0] == Token.BLOCK) { + var isKeyframes = /@(-moz-|-o-|-webkit-)?keyframes/.test(token[1][0][0]); + optimize(token[2], context, !isKeyframes); } } } -function recursivelyOptimizeProperties(tokens, options, context) { +function recursivelyOptimizeProperties(tokens, context) { for (var i = 0, l = tokens.length; i < l; i++) { var token = tokens[i]; switch (token[0]) { - case 'selector': - optimizeProperties(token[1], token[2], false, true, options, context); + case Token.RULE: + optimizeProperties(token[1], token[2], false, true, context); break; - case 'block': - recursivelyOptimizeProperties(token[2], options, context); + case Token.BLOCK: + recursivelyOptimizeProperties(token[2], context); } } } -function optimize(tokens, options, context, withRestructuring) { - recursivelyOptimizeBlocks(tokens, options, context); - recursivelyOptimizeProperties(tokens, options, context); +function optimize(tokens, context, withRestructuring) { + recursivelyOptimizeBlocks(tokens, context); + recursivelyOptimizeProperties(tokens, context); - removeDuplicates(tokens); - mergeAdjacent(tokens, options, context); - reduceNonAdjacent(tokens, options, context); + removeDuplicates(tokens, context); + mergeAdjacent(tokens, context); + reduceNonAdjacent(tokens, context); - mergeNonAdjacentBySelector(tokens, options, context); - mergeNonAdjacentByBody(tokens, options); + mergeNonAdjacentBySelector(tokens, context); + mergeNonAdjacentByBody(tokens, context); - if (options.restructuring && withRestructuring) { - restructure(tokens, options); - mergeAdjacent(tokens, options, context); + if (context.options.restructuring && withRestructuring) { + restructure(tokens, context); + mergeAdjacent(tokens, context); } - if (options.mediaMerging) { - removeDuplicateMediaQueries(tokens); - var reduced = mergeMediaQueries(tokens); + if (context.options.mediaMerging) { + removeDuplicateMediaQueries(tokens, context); + var reduced = mergeMediaQueries(tokens, context); for (var i = reduced.length - 1; i >= 0; i--) { - optimize(reduced[i][2], options, context, false); + optimize(reduced[i][2], context, false); } } removeEmpty(tokens); + + return tokens; } module.exports = optimize; diff --git a/lib/selectors/simple.js b/lib/optimizer/basic.js similarity index 59% rename from lib/selectors/simple.js rename to lib/optimizer/basic.js index b5753e12..ec95bdad 100644 --- a/lib/selectors/simple.js +++ b/lib/optimizer/basic.js @@ -1,20 +1,27 @@ -var cleanUpSelectors = require('./clean-up').selectors; -var cleanUpBlock = require('./clean-up').block; -var cleanUpAtRule = require('./clean-up').atRule; +var tidyRules = require('./tidy-rules'); +var tidyBlock = require('./tidy-block'); +var tidyAtRule = require('./tidy-at-rule'); var split = require('../utils/split'); +var Token = require('../tokenizer/token'); +var Marker = require('../tokenizer/marker'); + var RGB = require('../colors/rgb'); var HSL = require('../colors/hsl'); var HexNameShortener = require('../colors/hex-name-shortener'); +var Hack = require('../properties/hack'); + var wrapForOptimizing = require('../properties/wrap-for-optimizing').all; var restoreFromOptimizing = require('../properties/restore-from-optimizing'); var removeUnused = require('../properties/remove-unused'); +var rebaseConfig = require('../urls/rebase-config'); +var rewriteUrl = require('../urls/rewrite-url'); + var DEFAULT_ROUNDING_PRECISION = 2; var CHARSET_TOKEN = '@charset'; var CHARSET_REGEXP = new RegExp('^' + CHARSET_TOKEN, 'i'); -var IMPORT_REGEXP = /^@import["'\s]/i; var FONT_NUMERAL_WEIGHTS = ['100', '200', '300', '400', '500', '600', '700', '800', '900']; var FONT_NAME_WEIGHTS = ['normal', 'bold', 'bolder', 'lighter']; @@ -23,6 +30,10 @@ var FONT_NAME_WEIGHTS_WITHOUT_NORMAL = ['bold', 'bolder', 'lighter']; var WHOLE_PIXEL_VALUE = /(?:^|\s|\()(-?\d+)px/; var TIME_VALUE = /^(\-?[\d\.]+)(m?s)$/; +var QUOTED_PATTERN = /^('.*'|".*")$/; +var QUOTED_BUT_SAFE_PATTERN = /^['"][a-zA-Z][a-zA-Z\d\-_]+['"]$/; +var URL_PREFIX_PATTERN = /^url\(/i; + var valueMinifiers = { 'background': function (value, index, total) { return index === 0 && total == 1 && (value == 'none' || value == 'transparent') ? '0 0' : value; @@ -40,8 +51,8 @@ var valueMinifiers = { } }; -function isNegative(property, idx) { - return property.value[idx] && property.value[idx][0][0] == '-' && parseFloat(property.value[idx][0]) < 0; +function isNegative(value) { + return value && value[1][0] == '-' && parseFloat(value[1]) < 0; } function zeroMinifier(name, value) { @@ -72,7 +83,10 @@ function zeroDegMinifier(_, value) { } function whitespaceMinifier(name, value) { - if (name.indexOf('filter') > -1 || value.indexOf(' ') == -1) + if (name.indexOf('filter') > -1 || value.indexOf(' ') == -1 || value.indexOf('expression') === 0) + return value; + + if (value.indexOf(Marker.SINGLE_QUOTE) > -1 || value.indexOf(Marker.DOUBLE_QUOTE) > -1) return value; value = value.replace(/\s+/g, ' '); @@ -116,11 +130,12 @@ function multipleZerosMinifier(property) { var values = property.value; var spliceAt; - if (values.length == 4 && values[0][0] === '0' && values[1][0] === '0' && values[2][0] === '0' && values[3][0] === '0') { - if (property.name.indexOf('box-shadow') > -1) + if (values.length == 4 && values[0][1] === '0' && values[1][1] === '0' && values[2][1] === '0' && values[3][1] === '0') { + if (property.name.indexOf('box-shadow') > -1) { spliceAt = 2; - else + } else { spliceAt = 1; + } } if (spliceAt) { @@ -222,13 +237,13 @@ function minifyBorderRadius(property) { var values = property.value; var spliceAt; - if (values.length == 3 && values[1][0] == '/' && values[0][0] == values[2][0]) + if (values.length == 3 && values[1][1] == '/' && values[0][1] == values[2][1]) spliceAt = 1; - else if (values.length == 5 && values[2][0] == '/' && values[0][0] == values[3][0] && values[1][0] == values[4][0]) + else if (values.length == 5 && values[2][1] == '/' && values[0][1] == values[3][1] && values[1][1] == values[4][1]) spliceAt = 2; - else if (values.length == 7 && values[3][0] == '/' && values[0][0] == values[4][0] && values[1][0] == values[5][0] && values[2][0] == values[6][0]) + else if (values.length == 7 && values[3][1] == '/' && values[0][1] == values[4][1] && values[1][1] == values[5][1] && values[2][1] == values[6][1]) spliceAt = 3; - else if (values.length == 9 && values[4][0] == '/' && values[0][0] == values[5][0] && values[1][0] == values[6][0] && values[2][0] == values[7][0] && values[3][0] == values[8][0]) + else if (values.length == 9 && values[4][1] == '/' && values[0][1] == values[5][1] && values[1][1] == values[6][1] && values[2][1] == values[7][1] && values[3][1] == values[8][1]) spliceAt = 4; if (spliceAt) { @@ -239,104 +254,154 @@ function minifyBorderRadius(property) { function minifyFilter(property) { if (property.value.length == 1) { - property.value[0][0] = property.value[0][0].replace(/progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\W)/, function (match, filter, suffix) { + property.value[0][1] = property.value[0][1].replace(/progid:DXImageTransform\.Microsoft\.(Alpha|Chroma)(\W)/, function (match, filter, suffix) { return filter.toLowerCase() + suffix; }); } - property.value[0][0] = property.value[0][0] + property.value[0][1] = property.value[0][1] .replace(/,(\S)/g, ', $1') .replace(/ ?= ?/g, '='); } function minifyFont(property) { var values = property.value; - var hasNumeral = FONT_NUMERAL_WEIGHTS.indexOf(values[0][0]) > -1 || - values[1] && FONT_NUMERAL_WEIGHTS.indexOf(values[1][0]) > -1 || - values[2] && FONT_NUMERAL_WEIGHTS.indexOf(values[2][0]) > -1; + var hasNumeral = FONT_NUMERAL_WEIGHTS.indexOf(values[0][1]) > -1 || + values[1] && FONT_NUMERAL_WEIGHTS.indexOf(values[1][1]) > -1 || + values[2] && FONT_NUMERAL_WEIGHTS.indexOf(values[2][1]) > -1; if (hasNumeral) return; - if (values[1] == '/') + if (values[1] && values[1][1] == '/') return; var normalCount = 0; - if (values[0][0] == 'normal') + if (values[0][1] == 'normal') normalCount++; - if (values[1] && values[1][0] == 'normal') + if (values[1] && values[1][1] == 'normal') normalCount++; - if (values[2] && values[2][0] == 'normal') + if (values[2] && values[2][1] == 'normal') normalCount++; if (normalCount > 1) return; var toOptimize; - if (FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[0][0]) > -1) + if (FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[0][1]) > -1) toOptimize = 0; - else if (values[1] && FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[1][0]) > -1) + else if (values[1] && FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[1][1]) > -1) toOptimize = 1; - else if (values[2] && FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[2][0]) > -1) + else if (values[2] && FONT_NAME_WEIGHTS_WITHOUT_NORMAL.indexOf(values[2][1]) > -1) toOptimize = 2; - else if (FONT_NAME_WEIGHTS.indexOf(values[0][0]) > -1) + else if (FONT_NAME_WEIGHTS.indexOf(values[0][1]) > -1) toOptimize = 0; - else if (values[1] && FONT_NAME_WEIGHTS.indexOf(values[1][0]) > -1) + else if (values[1] && FONT_NAME_WEIGHTS.indexOf(values[1][1]) > -1) toOptimize = 1; - else if (values[2] && FONT_NAME_WEIGHTS.indexOf(values[2][0]) > -1) + else if (values[2] && FONT_NAME_WEIGHTS.indexOf(values[2][1]) > -1) toOptimize = 2; if (toOptimize !== undefined) { - property.value[toOptimize][0] = valueMinifiers['font-weight'](values[toOptimize][0]); + property.value[toOptimize][1] = valueMinifiers['font-weight'](values[toOptimize][1]); property.dirty = true; } } -function optimizeBody(properties, options) { +function normalizeUrl(value) { + return value + .replace(URL_PREFIX_PATTERN, 'url(') + .replace(/\\?\n|\\?\r\n/g, ''); +} + +function removeUrlQuotes(value) { + return /^url\(['"].+['"]\)$/.test(value) && !/^url\(['"].*[\*\s\(\)'"].*['"]\)$/.test(value) && !/^url\(['"]data:[^;]+;charset/.test(value) ? + value.replace(/["']/g, '') : + value; +} + +function isQuoted(value) { + return QUOTED_PATTERN.test(value); +} + +function removeQuotes(name, value) { + if (name == 'content') { + return value; + } + + return QUOTED_BUT_SAFE_PATTERN.test(value) ? + value.substring(1, value.length - 1) : + value; +} + +function optimizeBody(properties, context) { + var options = context.options; var property, name, value; + var valueIsUrl; var _properties = wrapForOptimizing(properties); for (var i = 0, l = _properties.length; i < l; i++) { property = _properties[i]; name = property.name; + if (property.value.length === 0) { + property.unused = true; + } + if (property.hack && ( - (property.hack == 'star' || property.hack == 'underscore') && !options.compatibility.properties.iePrefixHack || - property.hack == 'backslash' && !options.compatibility.properties.ieSuffixHack || - property.hack == 'bang' && !options.compatibility.properties.ieBangHack)) + (property.hack == Hack.STAR || property.hack == Hack.UNDERSCORE) && !options.compatibility.properties.iePrefixHack || + property.hack == Hack.BACKSLASH && !options.compatibility.properties.ieSuffixHack || + property.hack == Hack.BANG && !options.compatibility.properties.ieBangHack)) { property.unused = true; + } - if (name.indexOf('padding') === 0 && (isNegative(property, 0) || isNegative(property, 1) || isNegative(property, 2) || isNegative(property, 3))) + if (name.indexOf('padding') === 0 && (isNegative(property.value[0]) || isNegative(property.value[1]) || isNegative(property.value[2]) || isNegative(property.value[3]))) property.unused = true; if (property.unused) continue; - if (property.variable) { - if (property.block) - optimizeBody(property.value[0], options); + if (property.block) { + optimizeBody(property.value[0][1], context); continue; } for (var j = 0, m = property.value.length; j < m; j++) { - value = property.value[j][0]; + value = property.value[j][1]; + valueIsUrl = isUrl(value); + + if (valueIsUrl && !context.validator.isValidUrl(value)) { + property.unused = true; + break; + } if (valueMinifiers[name]) value = valueMinifiers[name](value, j, m); - value = whitespaceMinifier(name, value); - value = precisionMinifier(name, value, options.precision); - value = pixelLengthMinifier(name, value, options.compatibility); - value = timeUnitMinifier(name, value); - value = zeroMinifier(name, value); - if (options.compatibility.properties.zeroUnits) { - value = zeroDegMinifier(name, value); - value = unitMinifier(name, value, options.unitsRegexp); + if (valueIsUrl) { + value = normalizeUrl(value); + value = options.compatibility.properties.urlQuotes ? + value : + removeUrlQuotes(value); + value = options.rebase && context.validator.isValidUrl(value) ? + rewriteUrl(value, options.rebaseConfig) : + value; + } else if (isQuoted(value)) { + value = removeQuotes(name, value); + } else { + value = whitespaceMinifier(name, value); + value = precisionMinifier(name, value, options.precision); + value = pixelLengthMinifier(name, value, options.compatibility); + value = timeUnitMinifier(name, value); + value = zeroMinifier(name, value); + if (options.compatibility.properties.zeroUnits) { + value = zeroDegMinifier(name, value); + value = unitMinifier(name, value, options.unitsRegexp); + } + if (options.compatibility.properties.colors) + value = colorMininifier(name, value, options.compatibility); } - if (options.compatibility.properties.colors) - value = colorMininifier(name, value, options.compatibility); - property.value[j][0] = value; + property.value[j][1] = value; } multipleZerosMinifier(property); @@ -351,6 +416,43 @@ function optimizeBody(properties, options) { restoreFromOptimizing(_properties, true); removeUnused(_properties); + + if (_properties.length != properties.length) { + removeComments(properties, options); + } +} + +function isUrl(value) { + return URL_PREFIX_PATTERN.test(value); +} + +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][0][2] == Marker.EXCLAMATION && (options.keepSpecialComments == '*' || options.commentsKept < options.keepSpecialComments)) { + options.commentsKept++; + return; + } + + token[1] = []; } function cleanupCharsets(tokens) { @@ -359,20 +461,20 @@ function cleanupCharsets(tokens) { for (var i = 0, l = tokens.length; i < l; i++) { var token = tokens[i]; - if (token[0] != 'at-rule') + if (token[0] != Token.AT_RULE) continue; - if (!CHARSET_REGEXP.test(token[1][0])) + if (!CHARSET_REGEXP.test(token[1])) continue; - if (hasCharset || token[1][0].indexOf(CHARSET_TOKEN) == -1) { + if (hasCharset || token[1].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)]]); + tokens.unshift([Token.AT_RULE, token[1].replace(CHARSET_REGEXP, CHARSET_TOKEN)]); } } } @@ -405,43 +507,40 @@ function buildPrecision(options) { return precision; } -function optimize(tokens, options, context) { +function basicOptimize(tokens, context) { + var options = context.options; var ie7Hack = options.compatibility.selectors.ie7Hack; var adjacentSpace = options.compatibility.selectors.adjacentSpace; var spaceAfterClosingBrace = options.compatibility.properties.spaceAfterClosingBrace; var mayHaveCharset = false; - var afterContent = false; - options.unitsRegexp = buildUnitRegexp(options); - options.precision = buildPrecision(options); + options.unitsRegexp = options.unitsRegexp || buildUnitRegexp(options); + options.precision = options.precision || buildPrecision(options); + options.commentsKept = options.commentsKept || 0; + options.rebaseConfig = options.rebaseConfig || rebaseConfig(context); 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); - afterContent = true; + case Token.AT_RULE: + token[1] = tidyAtRule(token[1]); + mayHaveCharset = true; break; - case 'block': - cleanUpBlock(token[1], spaceAfterClosingBrace); - optimize(token[2], options, context); - afterContent = true; + case Token.AT_RULE_BLOCK: + optimizeBody(token[2], context); break; - case 'flat-block': - cleanUpBlock(token[1], spaceAfterClosingBrace); - optimizeBody(token[2], options); - afterContent = true; + case Token.BLOCK: + token[1] = tidyBlock(token[1], spaceAfterClosingBrace); + basicOptimize(token[2], context); + break; + case Token.COMMENT: + optimizeComment(token, options); + break; + case Token.RULE: + token[1] = tidyRules(token[1], !ie7Hack, adjacentSpace); + optimizeBody(token[2], context); break; - case 'at-rule': - cleanUpAtRule(token[1]); - mayHaveCharset = true; - } - - if (token[0] == 'at-rule' && IMPORT_REGEXP.test(token[1]) && afterContent) { - context.warnings.push('Ignoring @import rule "' + token[1] + '" as it appears after rules thus browsers will ignore them.'); - token[1] = ''; } if (token[1].length === 0 || (token[2] && token[2].length === 0)) { @@ -451,8 +550,11 @@ function optimize(tokens, options, context) { } } - if (mayHaveCharset) + if (mayHaveCharset) { cleanupCharsets(tokens); + } + + return tokens; } -module.exports = optimize; +module.exports = basicOptimize; diff --git a/lib/selectors/extractor.js b/lib/optimizer/extract-properties.js similarity index 62% rename from lib/selectors/extractor.js rename to lib/optimizer/extract-properties.js index 497198b2..4077061f 100644 --- a/lib/selectors/extractor.js +++ b/lib/optimizer/extract-properties.js @@ -2,33 +2,35 @@ // IMPORTANT: Mind Token class and this code is not related! // Properties will be tokenized in one step, see #429 -var stringifySelectors = require('../stringifier/one-time').selectors; +var stringifyRules = require('../stringifier/one-time').rules; var stringifyValue = require('../stringifier/one-time').value; +var Token = require('../tokenizer/token'); -var AT_RULE = 'at-rule'; - -function extract(token) { +function extractProperties(token) { var properties = []; + var inSpecificSelector; + var property; + var name; + var value; + var i, l; - if (token[0] == 'selector') { - var inSpecificSelector = !/[\.\+>~]/.test(stringifySelectors(token[1])); - for (var i = 0, l = token[2].length; i < l; i++) { - var property = token[2][i]; + if (token[0] == Token.RULE) { + inSpecificSelector = !/[\.\+>~]/.test(stringifyRules(token[1])); - if (property.indexOf('__ESCAPED') === 0) - continue; + for (i = 0, l = token[2].length; i < l; i++) { + property = token[2][i]; - if (property[0] == AT_RULE) + if (property[0] != Token.PROPERTY) continue; - var name = token[2][i][0][0]; + name = property[1][1]; if (name.length === 0) continue; if (name.indexOf('--') === 0) continue; - var value = stringifyValue(token[2], i); + value = stringifyValue(property, i); properties.push([ name, @@ -40,9 +42,9 @@ function extract(token) { inSpecificSelector ]); } - } else if (token[0] == 'block') { - for (var j = 0, k = token[2].length; j < k; j++) { - properties = properties.concat(extract(token[2][j])); + } else if (token[0] == Token.BLOCK) { + for (i = 0, l = token[2].length; i < l; i++) { + properties = properties.concat(extractProperties(token[2][i])); } } @@ -66,4 +68,4 @@ function findNameRoot(name) { return name.replace(/^\-\w+\-/, '').match(/([a-zA-Z]+)/)[0].toLowerCase(); } -module.exports = extract; +module.exports = extractProperties; diff --git a/lib/selectors/is-special.js b/lib/optimizer/is-special.js similarity index 100% rename from lib/selectors/is-special.js rename to lib/optimizer/is-special.js diff --git a/lib/optimizer/merge-adjacent.js b/lib/optimizer/merge-adjacent.js new file mode 100644 index 00000000..622902b9 --- /dev/null +++ b/lib/optimizer/merge-adjacent.js @@ -0,0 +1,38 @@ +var optimizeProperties = require('../properties/optimizer'); + +var stringifyBody = require('../stringifier/one-time').body; +var stringifyRules = require('../stringifier/one-time').rules; +var tidyRules = require('./tidy-rules'); +var isSpecial = require('./is-special'); + +var Token = require('../tokenizer/token'); + +function mergeAdjacent(tokens, context) { + var lastToken = [null, [], []]; + var options = context.options; + var adjacentSpace = options.compatibility.selectors.adjacentSpace; + + for (var i = 0, l = tokens.length; i < l; i++) { + var token = tokens[i]; + + if (token[0] != Token.RULE) { + lastToken = [null, [], []]; + continue; + } + + if (lastToken[0] == Token.RULE && stringifyRules(token[1]) == stringifyRules(lastToken[1])) { + var joinAt = [lastToken[2].length]; + Array.prototype.push.apply(lastToken[2], token[2]); + optimizeProperties(token[1], lastToken[2], joinAt, true, context); + token[2] = []; + } else if (lastToken[0] == Token.RULE && stringifyBody(token[2]) == stringifyBody(lastToken[2]) && + !isSpecial(options, stringifyRules(token[1])) && !isSpecial(options, stringifyRules(lastToken[1]))) { + lastToken[1] = tidyRules(lastToken[1].concat(token[1]), false, adjacentSpace); + token[2] = []; + } else { + lastToken = token; + } + } +} + +module.exports = mergeAdjacent; diff --git a/lib/selectors/merge-media-queries.js b/lib/optimizer/merge-media-queries.js similarity index 83% rename from lib/selectors/merge-media-queries.js rename to lib/optimizer/merge-media-queries.js index 0df0d6f5..fcf9ed24 100644 --- a/lib/selectors/merge-media-queries.js +++ b/lib/optimizer/merge-media-queries.js @@ -1,5 +1,8 @@ var canReorder = require('./reorderable').canReorder; -var extractProperties = require('./extractor'); +var extractProperties = require('./extract-properties'); + +var stringifyRules = require('../stringifier/one-time').rules; +var Token = require('../tokenizer/token'); function mergeMediaQueries(tokens) { var candidates = {}; @@ -7,13 +10,15 @@ function mergeMediaQueries(tokens) { for (var i = tokens.length - 1; i >= 0; i--) { var token = tokens[i]; - if (token[0] != 'block') + if (token[0] != Token.BLOCK) { continue; + } - var candidate = candidates[token[1][0]]; + var key = stringifyRules(token[1]); + var candidate = candidates[key]; if (!candidate) { candidate = []; - candidates[token[1][0]] = candidate; + candidates[key] = candidate; } candidate.push(i); diff --git a/lib/selectors/merge-non-adjacent-by-body.js b/lib/optimizer/merge-non-adjacent-by-body.js similarity index 67% rename from lib/selectors/merge-non-adjacent-by-body.js rename to lib/optimizer/merge-non-adjacent-by-body.js index de148a03..2549cce9 100644 --- a/lib/selectors/merge-non-adjacent-by-body.js +++ b/lib/optimizer/merge-non-adjacent-by-body.js @@ -1,14 +1,16 @@ var stringifyBody = require('../stringifier/one-time').body; -var stringifySelectors = require('../stringifier/one-time').selectors; -var cleanUpSelectors = require('./clean-up').selectors; +var stringifyRules = require('../stringifier/one-time').rules; +var tidyRules = require('./tidy-rules'); var isSpecial = require('./is-special'); +var Token = require('../tokenizer/token'); + function unsafeSelector(value) { return /\.|\*| :/.test(value); } function isBemElement(token) { - var asString = stringifySelectors(token[1]); + var asString = stringifyRules(token[1]); return asString.indexOf('__') > -1 || asString.indexOf('--') > -1; } @@ -17,27 +19,28 @@ function withoutModifier(selector) { } function removeAnyUnsafeElements(left, candidates) { - var leftSelector = withoutModifier(stringifySelectors(left[1])); + var leftSelector = withoutModifier(stringifyRules(left[1])); for (var body in candidates) { var right = candidates[body]; - var rightSelector = withoutModifier(stringifySelectors(right[1])); + var rightSelector = withoutModifier(stringifyRules(right[1])); if (rightSelector.indexOf(leftSelector) > -1 || leftSelector.indexOf(rightSelector) > -1) delete candidates[body]; } } -function mergeNonAdjacentByBody(tokens, options) { - var candidates = {}; +function mergeNonAdjacentByBody(tokens, context) { + var options = context.options; var adjacentSpace = options.compatibility.selectors.adjacentSpace; + var candidates = {}; for (var i = tokens.length - 1; i >= 0; i--) { var token = tokens[i]; - if (token[0] != 'selector') + if (token[0] != Token.RULE) continue; - if (token[2].length > 0 && (!options.semanticMerging && unsafeSelector(stringifySelectors(token[1])))) + if (token[2].length > 0 && (!options.semanticMerging && unsafeSelector(stringifyRules(token[1])))) candidates = {}; if (token[2].length > 0 && options.semanticMerging && isBemElement(token)) @@ -45,9 +48,9 @@ function mergeNonAdjacentByBody(tokens, options) { var candidateBody = stringifyBody(token[2]); var oldToken = candidates[candidateBody]; - if (oldToken && !isSpecial(options, stringifySelectors(token[1])) && !isSpecial(options, stringifySelectors(oldToken[1]))) { + if (oldToken && !isSpecial(options, stringifyRules(token[1])) && !isSpecial(options, stringifyRules(oldToken[1]))) { token[1] = token[2].length > 0 ? - cleanUpSelectors(oldToken[1].concat(token[1]), false, adjacentSpace) : + tidyRules(oldToken[1].concat(token[1]), false, adjacentSpace) : oldToken[1].concat(token[1]); oldToken[2] = []; diff --git a/lib/selectors/merge-non-adjacent-by-selector.js b/lib/optimizer/merge-non-adjacent-by-selector.js similarity index 85% rename from lib/selectors/merge-non-adjacent-by-selector.js rename to lib/optimizer/merge-non-adjacent-by-selector.js index bd1c1b9c..a9188a8a 100644 --- a/lib/selectors/merge-non-adjacent-by-selector.js +++ b/lib/optimizer/merge-non-adjacent-by-selector.js @@ -1,20 +1,22 @@ var optimizeProperties = require('../properties/optimizer'); -var stringifySelectors = require('../stringifier/one-time').selectors; -var extractProperties = require('./extractor'); +var stringifyRules = require('../stringifier/one-time').rules; +var extractProperties = require('./extract-properties'); var canReorder = require('./reorderable').canReorder; -function mergeNonAdjacentBySelector(tokens, options, context) { +var Token = require('../tokenizer/token'); + +function mergeNonAdjacentBySelector(tokens, context) { var allSelectors = {}; var repeatedSelectors = []; var i; for (i = tokens.length - 1; i >= 0; i--) { - if (tokens[i][0] != 'selector') + if (tokens[i][0] != Token.RULE) continue; if (tokens[i][2].length === 0) continue; - var selector = stringifySelectors(tokens[i][1]); + var selector = stringifyRules(tokens[i][1]); allSelectors[selector] = [i].concat(allSelectors[selector] || []); if (allSelectors[selector].length == 2) @@ -66,7 +68,7 @@ function mergeNonAdjacentBySelector(tokens, options, context) { Array.prototype.push.apply(target[2], moved[2]); } - optimizeProperties(target[1], target[2], joinAt, true, options, context); + optimizeProperties(target[1], target[2], joinAt, true, context); moved[2] = []; } } diff --git a/lib/selectors/reduce-non-adjacent.js b/lib/optimizer/reduce-non-adjacent.js similarity index 90% rename from lib/selectors/reduce-non-adjacent.js rename to lib/optimizer/reduce-non-adjacent.js index 44b540c0..267231a6 100644 --- a/lib/selectors/reduce-non-adjacent.js +++ b/lib/optimizer/reduce-non-adjacent.js @@ -1,24 +1,28 @@ var optimizeProperties = require('../properties/optimizer'); var stringifyBody = require('../stringifier/one-time').body; -var stringifySelectors = require('../stringifier/one-time').selectors; +var stringifyRules = require('../stringifier/one-time').rules; var isSpecial = require('./is-special'); var cloneArray = require('../utils/clone-array'); -function reduceNonAdjacent(tokens, options, context) { +var Token = require('../tokenizer/token'); + +function reduceNonAdjacent(tokens, context) { + var options = context.options; var candidates = {}; var repeated = []; for (var i = tokens.length - 1; i >= 0; i--) { var token = tokens[i]; - if (token[0] != 'selector') + if (token[0] != Token.RULE) { continue; - if (token[2].length === 0) + } else if (token[2].length === 0) { continue; + } - var selectorAsString = stringifySelectors(token[1]); + var selectorAsString = stringifyRules(token[1]); var isComplexAndNotSpecial = token[1].length > 1 && !isSpecial(options, selectorAsString); - var wrappedSelectors = options.sourceMap ? wrappedSelectorsFrom(token[1]) : token[1]; + var wrappedSelectors = wrappedSelectorsFrom(token[1]); var selectors = isComplexAndNotSpecial ? [selectorAsString].concat(wrappedSelectors) : [selectorAsString]; @@ -150,7 +154,7 @@ function reduceSelector(tokens, selector, data, context, options, outerContext) joinsAt.push((joinsAt.length > 0 ? joinsAt[joinsAt.length - 1] : 0) + bodiesAsList[j].length); } - optimizeProperties(selector, bodies, joinsAt, false, options, outerContext); + optimizeProperties(selector, bodies, joinsAt, false, outerContext); var processedCount = processedTokens.length; var propertyIdx = bodies.length - 1; diff --git a/lib/optimizer/remove-duplicate-media-queries.js b/lib/optimizer/remove-duplicate-media-queries.js new file mode 100644 index 00000000..9d243dd4 --- /dev/null +++ b/lib/optimizer/remove-duplicate-media-queries.js @@ -0,0 +1,30 @@ +var stringifyAll = require('../stringifier/one-time').all; +var stringifyRules = require('../stringifier/one-time').rules; + +var Token = require('../tokenizer/token'); + +function removeDuplicateMediaQueries(tokens) { + var candidates = {}; + var candidate; + var token; + var key; + var i, l; + + for (i = 0, l = tokens.length; i < l; i++) { + token = tokens[i]; + if (token[0] != Token.BLOCK) { + continue; + } + + key = stringifyRules(token[1]) + '%' + stringifyAll(token[2]); + candidate = candidates[key]; + + if (candidate) { + candidate[2] = []; + } + + candidates[key] = token; + } +} + +module.exports = removeDuplicateMediaQueries; diff --git a/lib/selectors/remove-duplicates.js b/lib/optimizer/remove-duplicates.js similarity index 82% rename from lib/selectors/remove-duplicates.js rename to lib/optimizer/remove-duplicates.js index 3a2ce959..fab62b94 100644 --- a/lib/selectors/remove-duplicates.js +++ b/lib/optimizer/remove-duplicates.js @@ -1,5 +1,7 @@ var stringifyBody = require('../stringifier/one-time').body; -var stringifySelectors = require('../stringifier/one-time').selectors; +var stringifyRules = require('../stringifier/one-time').rules; + +var Token = require('../tokenizer/token'); function removeDuplicates(tokens) { var matched = {}; @@ -9,10 +11,10 @@ function removeDuplicates(tokens) { for (var i = 0, l = tokens.length; i < l; i++) { token = tokens[i]; - if (token[0] != 'selector') + if (token[0] != Token.RULE) continue; - id = stringifySelectors(token[1]); + id = stringifyRules(token[1]); if (matched[id] && matched[id].length == 1) moreThanOnce.push(id); diff --git a/lib/selectors/reorderable.js b/lib/optimizer/reorderable.js similarity index 100% rename from lib/selectors/reorderable.js rename to lib/optimizer/reorderable.js diff --git a/lib/selectors/restructure.js b/lib/optimizer/restructure.js similarity index 89% rename from lib/selectors/restructure.js rename to lib/optimizer/restructure.js index c3e17f12..0694167d 100644 --- a/lib/selectors/restructure.js +++ b/lib/optimizer/restructure.js @@ -1,11 +1,13 @@ -var extractProperties = require('./extractor'); +var extractProperties = require('./extract-properties'); var canReorderSingle = require('./reorderable').canReorderSingle; var stringifyBody = require('../stringifier/one-time').body; -var stringifySelectors = require('../stringifier/one-time').selectors; -var cleanUpSelectorDuplicates = require('./clean-up').selectorDuplicates; +var stringifyRules = require('../stringifier/one-time').rules; +var tidyRuleDuplicates = require('./tidy-rule-duplicates'); var isSpecial = require('./is-special'); var cloneArray = require('../utils/clone-array'); +var Token = require('../tokenizer/token'); + function naturalSorter(a, b) { return a > b; } @@ -17,7 +19,8 @@ function cloneAndMergeSelectors(propertyA, propertyB) { return cloned; } -function restructure(tokens, options) { +function restructure(tokens, context) { + var options = context.options; var movableTokens = {}; var movedProperties = []; var multiPropertyMoveCache = {}; @@ -67,7 +70,7 @@ function restructure(tokens, options) { function cacheId(cachedTokens) { var id = []; for (var i = 0, l = cachedTokens.length; i < l; i++) { - id.push(stringifySelectors(cachedTokens[i][1])); + id.push(stringifyRules(cachedTokens[i][1])); } return id.join(ID_JOIN_CHARACTER); } @@ -77,7 +80,7 @@ function restructure(tokens, options) { var mergeableTokens = []; for (var i = sourceTokens.length - 1; i >= 0; i--) { - if (isSpecial(options, stringifySelectors(sourceTokens[i][1]))) + if (isSpecial(options, stringifyRules(sourceTokens[i][1]))) continue; mergeableTokens.unshift(sourceTokens[i]); @@ -112,7 +115,7 @@ function restructure(tokens, options) { qualifiedTokens.unshift(bestFit[0][i]); } - allSelectors = cleanUpSelectorDuplicates(allSelectors); + allSelectors = tidyRuleDuplicates(allSelectors); dropAsNewTokenAt(position, [movedProperty], allSelectors, qualifiedTokens); } @@ -141,7 +144,7 @@ function restructure(tokens, options) { function sizeDifference(tokensVariant, propertySize, propertiesCount) { var allSelectorsSize = 0; for (var i = tokensVariant.length - 1; i >= 0; i--) { - allSelectorsSize += tokensVariant[i][2].length > propertiesCount ? stringifySelectors(tokensVariant[i][1]).length : -1; + allSelectorsSize += tokensVariant[i][2].length > propertiesCount ? stringifyRules(tokensVariant[i][1]).length : -1; } return allSelectorsSize - (tokensVariant.length - 1) * propertySize + 1; } @@ -159,7 +162,7 @@ function restructure(tokens, options) { for (k = 0, m = properties.length; k < m; k++) { var property = properties[k]; - var mergeablePropertyName = mergeableProperty[0][0]; + var mergeablePropertyName = mergeableProperty[1][1]; var propertyName = property[0]; var propertyBody = property[4]; if (mergeablePropertyName == propertyName && stringifyBody([mergeableProperty]) == propertyBody) { @@ -174,7 +177,7 @@ function restructure(tokens, options) { allProperties.unshift(properties[i][3]); } - var newToken = ['selector', allSelectors, allProperties]; + var newToken = [Token.RULE, allSelectors, allProperties]; tokens.splice(position, 0, newToken); } @@ -250,7 +253,7 @@ function restructure(tokens, options) { qualifiedTokens.unshift(bestFit[0][i]); } - allSelectors = cleanUpSelectorDuplicates(allSelectors); + allSelectors = tidyRuleDuplicates(allSelectors); dropAsNewTokenAt(position, properties, allSelectors, qualifiedTokens); for (i = properties.length - 1; i >= 0; i--) { @@ -279,14 +282,14 @@ function restructure(tokens, options) { for (var i = tokens.length - 1; i >= 0; i--) { var token = tokens[i]; - var isSelector; + var isRule; var j, k, m; var samePropertyAt; - if (token[0] == 'selector') { - isSelector = true; - } else if (token[0] == 'block') { - isSelector = false; + if (token[0] == Token.RULE) { + isRule = true; + } else if (token[0] == Token.BLOCK) { + isRule = false; } else { continue; } @@ -332,7 +335,7 @@ function restructure(tokens, options) { } } - if (!isSelector || unmovableInCurrentToken.indexOf(j) > -1) + if (!isRule || unmovableInCurrentToken.indexOf(j) > -1) continue; var key = property[4]; @@ -353,11 +356,11 @@ function restructure(tokens, options) { } } - var position = tokens[0] && tokens[0][0] == 'at-rule' && tokens[0][1][0].indexOf('@charset') === 0 ? 1 : 0; + var position = tokens[0] && tokens[0][0] == Token.AT_RULE && tokens[0][1].indexOf('@charset') === 0 ? 1 : 0; for (; position < tokens.length - 1; position++) { - var isImportRule = tokens[position][0] === 'at-rule' && tokens[position][1][0].indexOf('@import') === 0; - var isEscapedCommentSpecial = tokens[position][0] === 'text' && tokens[position][1][0].indexOf('__ESCAPED_COMMENT_SPECIAL') === 0; - if (!(isImportRule || isEscapedCommentSpecial)) + var isImportRule = tokens[position][0] === Token.AT_RULE && tokens[position][1].indexOf('@import') === 0; + var isComment = tokens[position][0] === Token.COMMENT; + if (!(isImportRule || isComment)) break; } diff --git a/lib/optimizer/tidy-at-rule.js b/lib/optimizer/tidy-at-rule.js new file mode 100644 index 00000000..06f49d9b --- /dev/null +++ b/lib/optimizer/tidy-at-rule.js @@ -0,0 +1,7 @@ +function tidyAtRule(value) { + return value + .replace(/\s+/g, ' ') + .trim(); +} + +module.exports = tidyAtRule; diff --git a/lib/optimizer/tidy-block.js b/lib/optimizer/tidy-block.js new file mode 100644 index 00000000..10b437c6 --- /dev/null +++ b/lib/optimizer/tidy-block.js @@ -0,0 +1,18 @@ +function tidyBlock(values, spaceAfterClosingBrace) { + var i; + + for (i = values.length - 1; i >= 0; i--) { + values[i][0] = values[i][0] + .replace(/\n|\r\n/g, ' ') + .replace(/\s+/g, ' ') + .replace(/(,|:|\() /g, '$1') + .replace(/ \)/g, ')') + .replace(/'([a-zA-Z][a-zA-Z\d\-_]+)'/, '$1') + .replace(/"([a-zA-Z][a-zA-Z\d\-_]+)"/, '$1') + .replace(spaceAfterClosingBrace ? null : /\) /g, ')'); + } + + return values; +} + +module.exports = tidyBlock; diff --git a/lib/optimizer/tidy-rule-duplicates.js b/lib/optimizer/tidy-rule-duplicates.js new file mode 100644 index 00000000..e488d64a --- /dev/null +++ b/lib/optimizer/tidy-rule-duplicates.js @@ -0,0 +1,21 @@ +function ruleSorter(s1, s2) { + return s1[0] > s2[0] ? 1 : -1; +} + +function tidyRuleDuplicates(rules) { + var list = []; + var repeated = []; + + for (var i = 0, l = rules.length; i < l; i++) { + var rule = rules[i]; + + if (repeated.indexOf(rule[0]) == -1) { + repeated.push(rule[0]); + list.push(rule); + } + } + + return list.sort(ruleSorter); +} + +module.exports = tidyRuleDuplicates; diff --git a/lib/optimizer/tidy-rules.js b/lib/optimizer/tidy-rules.js new file mode 100644 index 00000000..5a38f14c --- /dev/null +++ b/lib/optimizer/tidy-rules.js @@ -0,0 +1,137 @@ +var Marker = require('../tokenizer/marker'); + +var RELATION_PATTERN = /[>\+~]/; +var WHITESPACE_PATTERN = /\s/; + +var STAR_PLUS_HTML_HACK = '*+html '; +var STAR_FIRST_CHILD_PLUS_HTML_HACK = '*:first-child+html '; + +function removeWhitespace(value) { + var stripped = []; + var character; + var isNewLineNix; + var isNewLineWin; + var isEscaped; + var wasEscaped; + var isQuote; + var isAttribute; + var isRelation; + var isWhitespace; + var roundBracketLevel = 0; + var wasRelation = false; + var wasWhitespace = false; + var i, l; + + for (i = 0, l = value.length; i < l; i++) { + character = value[i]; + + isNewLineNix = character == Marker.NEW_LINE_NIX; + isNewLineWin = character == Marker.NEW_LINE_NIX && value[i - 1] == Marker.NEW_LINE_WIN; + isRelation = !isEscaped && RELATION_PATTERN.test(character); + isWhitespace = WHITESPACE_PATTERN.test(character); + + if (wasEscaped && isQuote && isNewLineWin) { + // swallow escaped new windows lines in comments + stripped.pop(); + stripped.pop(); + } else if (isEscaped && isQuote && isNewLineNix) { + // swallow escaped new *nix lines in comments + stripped.pop(); + } else if (isEscaped) { + stripped.push(character); + } else if (character == Marker.OPEN_SQUARE_BRACKET && !isQuote) { + stripped.push(character); + isAttribute = true; + } else if (character == Marker.CLOSE_SQUARE_BRACKET && !isQuote) { + stripped.push(character); + isAttribute = false; + } else if (character == Marker.OPEN_ROUND_BRACKET && !isQuote) { + stripped.push(character); + roundBracketLevel++; + } else if (character == Marker.CLOSE_ROUND_BRACKET && !isQuote) { + stripped.push(character); + roundBracketLevel--; + } else if ((character == Marker.SINGLE_QUOTE || character == Marker.DOUBLE_QUOTE) && !isQuote) { + stripped.push(character); + isQuote = true; + } else if (character == Marker.SINGLE_QUOTE || character == Marker.DOUBLE_QUOTE) { + stripped.push(character); + isQuote = false; + } else if (isWhitespace && wasRelation) { + continue; + } else if (isWhitespace && (isAttribute || roundBracketLevel > 0) && !isQuote) { + // skip space + } else if (isWhitespace && wasWhitespace && !isQuote) { + // skip extra space + } else if ((isNewLineWin || isNewLineNix) && (isAttribute || roundBracketLevel > 0) && isQuote) { + // skip newline + } else if (isRelation && wasWhitespace) { + stripped.pop(); + stripped.push(character); + } else if (isWhitespace) { + stripped.push(Marker.SPACE); + } else { + stripped.push(character); + } + + wasEscaped = isEscaped; + isEscaped = character == Marker.BACK_SLASH; + wasRelation = isRelation; + wasWhitespace = isWhitespace; + } + + return stripped.join(''); +} + +function removeQuotes(value) { + return value + .replace(/([^\[])'([a-zA-Z][a-zA-Z\d\-_]+)([^\]])'/g, '$1$2$3') + .replace(/([^\[])"([a-zA-Z][a-zA-Z\d\-_]+)([^\]])"/g, '$1$2$3'); +} + +function ruleSorter(s1, s2) { + return s1[0] > s2[0] ? 1 : -1; +} + +function tidyRules(rules, removeUnsupported, adjacentSpace) { + var list = []; + var repeated = []; + + for (var i = 0, l = rules.length; i < l; i++) { + var rule = rules[i]; + var reduced = rule[0]; + + reduced = removeWhitespace(reduced); + reduced = removeQuotes(reduced); + + if (adjacentSpace && reduced.indexOf('nav') > 0) { + reduced = reduced.replace(/\+nav(\S|$)/, '+ nav$1'); + } + + if (removeUnsupported && reduced.indexOf(STAR_PLUS_HTML_HACK) > -1) { + continue; + } + + if (removeUnsupported && reduced.indexOf(STAR_FIRST_CHILD_PLUS_HTML_HACK) > -1) { + continue; + } + + if (reduced.indexOf('*') > -1) { + reduced = reduced + .replace(/\*([:#\.\[])/g, '$1') + .replace(/^(\:first\-child)?\+html/, '*$1+html'); + } + + if (repeated.indexOf(reduced) > -1) { + continue; + } + + rule[0] = reduced; + repeated.push(reduced); + list.push(rule); + } + + return list.sort(ruleSorter); +} + +module.exports = tidyRules; diff --git a/lib/properties/break-up.js b/lib/properties/break-up.js index 6657b7a7..4b01aca0 100644 --- a/lib/properties/break-up.js +++ b/lib/properties/break-up.js @@ -1,34 +1,49 @@ var wrapSingle = require('./wrap-for-optimizing').single; var InvalidPropertyError = require('./invalid-property-error'); -var split = require('../utils/split'); +var Token = require('../tokenizer/token'); + var MULTIPLEX_SEPARATOR = ','; function _colorFilter(validator) { return function (value) { - return value[0] == 'invert' || validator.isValidColor(value[0]); + return value[1] == 'invert' || validator.isValidColor(value[1]); }; } function _styleFilter(validator) { return function (value) { - return value[0] != 'inherit' && validator.isValidStyle(value[0]) && !validator.isValidColorValue(value[0]); + return value[1] != 'inherit' && validator.isValidStyle(value[1]) && !validator.isValidColorValue(value[1]); }; } function _wrapDefault(name, property, compactable) { var descriptor = compactable[name]; - if (descriptor.doubleValues && descriptor.defaultValue.length == 2) - return wrapSingle([[name, property.important], [descriptor.defaultValue[0]], [descriptor.defaultValue[1]]]); - else if (descriptor.doubleValues && descriptor.defaultValue.length == 1) - return wrapSingle([[name, property.important], [descriptor.defaultValue[0]]]); - else - return wrapSingle([[name, property.important], [descriptor.defaultValue]]); + if (descriptor.doubleValues && descriptor.defaultValue.length == 2) { + return wrapSingle([ + Token.PROPERTY, + [Token.PROPERTY_NAME, name], + [Token.PROPERTY_VALUE, descriptor.defaultValue[0]], + [Token.PROPERTY_VALUE, descriptor.defaultValue[1]] + ]); + } else if (descriptor.doubleValues && descriptor.defaultValue.length == 1) { + return wrapSingle([ + Token.PROPERTY, + [Token.PROPERTY_NAME, name], + [Token.PROPERTY_VALUE, descriptor.defaultValue[0]] + ]); + } else { + return wrapSingle([ + Token.PROPERTY, + [Token.PROPERTY_NAME, name], + [Token.PROPERTY_VALUE, descriptor.defaultValue] + ]); + } } function _widthFilter(validator) { return function (value) { - return value[0] != 'inherit' && validator.isValidWidth(value[0]) && !validator.isValidStyleKeyword(value[0]) && !validator.isValidColorValue(value[0]); + return value[1] != 'inherit' && validator.isValidWidth(value[1]) && !validator.isValidStyleKeyword(value[1]) && !validator.isValidColorValue(value[1]); }; } @@ -49,18 +64,25 @@ function background(property, compactable, validator) { var originSet = false; var repeatSet = false; - if (property.value.length == 1 && property.value[0][0] == 'inherit') { + var anyValueSet = false; + + if (property.value.length == 1 && property.value[0][1] == 'inherit') { // NOTE: 'inherit' is not a valid value for background-attachment color.value = image.value = repeat.value = position.value = size.value = origin.value = clip.value = property.value; return components; } + if (property.value.length == 1 && property.value[0][1] == '0 0') { + return components; + } + for (var i = values.length - 1; i >= 0; i--) { var value = values[i]; - if (validator.isValidBackgroundAttachment(value[0])) { + if (validator.isValidBackgroundAttachment(value[1])) { attachment.value = [value]; - } else if (validator.isValidBackgroundBox(value[0])) { + anyValueSet = true; + } else if (validator.isValidBackgroundBox(value[1])) { if (clipSet) { origin.value = [value]; originSet = true; @@ -68,27 +90,24 @@ function background(property, compactable, validator) { clip.value = [value]; clipSet = true; } - } else if (validator.isValidBackgroundRepeat(value[0])) { + anyValueSet = true; + } else if (validator.isValidBackgroundRepeat(value[1])) { if (repeatSet) { repeat.value.unshift(value); } else { repeat.value = [value]; repeatSet = true; } - } else if (validator.isValidBackgroundPositionPart(value[0]) || validator.isValidBackgroundSizePart(value[0])) { + anyValueSet = true; + } else if (validator.isValidBackgroundPositionPart(value[1]) || validator.isValidBackgroundSizePart(value[1])) { if (i > 0) { var previousValue = values[i - 1]; - if (previousValue[0].indexOf('/') > 0) { - var twoParts = split(previousValue[0], '/'); - // NOTE: we do this slicing as value may contain metadata too, like for source maps - size.value = [[twoParts.pop()].concat(previousValue.slice(1)), value]; - values[i - 1] = [twoParts.pop()].concat(previousValue.slice(1)); - } else if (i > 1 && values[i - 2][0] == '/') { + if (previousValue[1] == '/') { + size.value = [value]; + } else if (i > 1 && values[i - 2][1] == '/') { size.value = [previousValue, value]; i -= 2; - } else if (previousValue[0] == '/') { - size.value = [value]; } else { if (!positionSet) position.value = []; @@ -103,21 +122,23 @@ function background(property, compactable, validator) { position.value.unshift(value); positionSet = true; } - } else if (validator.isValidBackgroundPositionAndSize(value[0])) { - var sizeValue = split(value[0], '/'); - // NOTE: we do this slicing as value may contain metadata too, like for source maps - size.value = [[sizeValue.pop()].concat(value.slice(1))]; - position.value = [[sizeValue.pop()].concat(value.slice(1))]; - } else if ((color.value[0][0] == compactable[color.name].defaultValue || color.value[0][0] == 'none') && validator.isValidColor(value[0])) { + anyValueSet = true; + } else if ((color.value[0][1] == compactable[color.name].defaultValue || color.value[0][1] == 'none') && validator.isValidColor(value[1])) { color.value = [value]; - } else if (validator.isValidUrl(value[0]) || validator.isValidFunction(value[0])) { + anyValueSet = true; + } else if (validator.isValidUrl(value[1]) || validator.isValidFunction(value[1])) { image.value = [value]; + anyValueSet = true; } } if (clipSet && !originSet) origin.value = clip.value.slice(0); + if (!anyValueSet) { + throw new InvalidPropertyError('Invalid background value.'); + } + return components; } @@ -126,7 +147,7 @@ function borderRadius(property, compactable) { var splitAt = -1; for (var i = 0, l = values.length; i < l; i++) { - if (values[i][0] == '/') { + if (values[i][1] == '/') { splitAt = i; break; } @@ -172,7 +193,10 @@ function fourValues(property, compactable) { value[3] = value[1].slice(0); for (var i = componentNames.length - 1; i >= 0; i--) { - var component = wrapSingle([[componentNames[i], property.important]]); + var component = wrapSingle([ + Token.PROPERTY, + [Token.PROPERTY_NAME, componentNames[i]] + ]); component.value = [value[i]]; components.unshift(component); } @@ -188,7 +212,7 @@ function multiplex(splitWith) { // find split commas for (i = 0, l = values.length; i < l; i++) { - if (values[i][0] == ',') + if (values[i][1] == ',') splitsAt.push(i); } @@ -215,7 +239,7 @@ function multiplex(splitWith) { components[i].multiplex = true; for (j = 1, m = splitComponents.length; j < m; j++) { - components[i].value.push([MULTIPLEX_SEPARATOR]); + components[i].value.push([Token.PROPERTY_VALUE, MULTIPLEX_SEPARATOR]); Array.prototype.push.apply(components[i].value, splitComponents[j][i].value); } } @@ -230,7 +254,7 @@ function listStyle(property, compactable, validator) { var image = _wrapDefault('list-style-image', property, compactable); var components = [type, position, image]; - if (property.value.length == 1 && property.value[0][0] == 'inherit') { + if (property.value.length == 1 && property.value[0][1] == 'inherit') { type.value = position.value = image.value = [property.value[0]]; return components; } @@ -241,7 +265,7 @@ function listStyle(property, compactable, validator) { // `image` first... for (index = 0, total = values.length; index < total; index++) { - if (validator.isValidUrl(values[index][0]) || values[index][0] == '0') { + if (validator.isValidUrl(values[index][1]) || values[index][1] == '0') { image.value = [values[index]]; values.splice(index, 1); break; @@ -250,7 +274,7 @@ function listStyle(property, compactable, validator) { // ... then `type`... for (index = 0, total = values.length; index < total; index++) { - if (validator.isValidListStyleType(values[index][0])) { + if (validator.isValidListStyleType(values[index][1])) { type.value = [values[index]]; values.splice(index, 1); break; @@ -258,7 +282,7 @@ function listStyle(property, compactable, validator) { } // ... and what's left is a `position` - if (values.length > 0 && validator.isValidListStylePosition(values[0][0])) + if (values.length > 0 && validator.isValidListStylePosition(values[0][1])) position.value = [values[0]]; return components; @@ -284,8 +308,8 @@ function widthStyleColor(property, compactable, validator) { width = component; } - if ((property.value.length == 1 && property.value[0][0] == 'inherit') || - (property.value.length == 3 && property.value[0][0] == 'inherit' && property.value[1][0] == 'inherit' && property.value[2][0] == 'inherit')) { + if ((property.value.length == 1 && property.value[0][1] == 'inherit') || + (property.value.length == 3 && property.value[0][1] == 'inherit' && property.value[1][1] == 'inherit' && property.value[2][1] == 'inherit')) { color.value = style.value = width.value = [property.value[0]]; return components; } @@ -298,7 +322,7 @@ function widthStyleColor(property, compactable, validator) { if (values.length > 0) { matches = values.filter(_widthFilter(validator)); - match = matches.length > 1 && (matches[0][0] == 'none' || matches[0][0] == 'auto') ? matches[1] : matches[0]; + match = matches.length > 1 && (matches[0][1] == 'none' || matches[0][1] == 'auto') ? matches[1] : matches[0]; if (match) { width.value = [match]; values.splice(values.indexOf(match), 1); diff --git a/lib/properties/can-override.js b/lib/properties/can-override.js index 474e2373..6405e979 100644 --- a/lib/properties/can-override.js +++ b/lib/properties/can-override.js @@ -11,8 +11,8 @@ function always() { } function alwaysButIntoFunction(property1, property2, validator) { - var value1 = property1.value[0][0]; - var value2 = property2.value[0][0]; + var value1 = property1.value[0][1]; + var value2 = property2.value[0][1]; var validFunction1 = validator.isValidFunction(value1); var validFunction2 = validator.isValidFunction(value2); @@ -31,8 +31,8 @@ function backgroundImage(property1, property2, validator) { // Understandability: (none | url | inherit) > (same function) > (same value) // (none | url) - var image1 = property1.value[0][0]; - var image2 = property2.value[0][0]; + var image1 = property1.value[0][1]; + var image2 = property2.value[0][1]; if (image2 == 'none' || image2 == 'inherit' || validator.isValidUrl(image2)) return true; @@ -53,8 +53,8 @@ function color(property1, property2, validator) { // Understandability: (hex | named) > (rgba | hsla) > (same function name) > anything else // NOTE: at this point rgb and hsl are replaced by hex values by clean-css - var color1 = property1.value[0][0]; - var color2 = property2.value[0][0]; + var color1 = property1.value[0][1]; + var color2 = property2.value[0][1]; if (!validator.colorOpacity && (validator.isValidRgbaColor(color1) || validator.isValidHslaColor(color1))) return false; @@ -78,22 +78,22 @@ function color(property1, property2, validator) { } function twoOptionalFunctions(property1, property2, validator) { - var value1 = property1.value[0][0]; - var value2 = property2.value[0][0]; + var value1 = property1.value[0][1]; + var value2 = property2.value[0][1]; return !(validator.isValidFunction(value1) ^ validator.isValidFunction(value2)); } function sameValue(property1, property2) { - var value1 = property1.value[0][0]; - var value2 = property2.value[0][0]; + var value1 = property1.value[0][1]; + var value2 = property2.value[0][1]; return value1 === value2; } function sameFunctionOrValue(property1, property2, validator) { - var value1 = property1.value[0][0]; - var value2 = property2.value[0][0]; + var value1 = property1.value[0][1]; + var value2 = property2.value[0][1]; // Functions with the same name can override each other if (validator.areSameFunction(value1, value2)) @@ -109,8 +109,8 @@ function unit(property1, property2, validator) { // NOTE: there is no point in having different vendor-specific functions override each other or standard functions, // or having standard functions override vendor-specific functions, but standard functions can override each other // NOTE: vendor-specific property values are not taken into consideration here at the moment - var value1 = property1.value[0][0]; - var value2 = property2.value[0][0]; + var value1 = property1.value[0][1]; + var value2 = property2.value[0][1]; if (validator.isValidAndCompatibleUnitWithoutFunction(value1) && !validator.isValidAndCompatibleUnitWithoutFunction(value2)) return false; diff --git a/lib/properties/clone.js b/lib/properties/clone.js index 5be6441b..05c1b17e 100644 --- a/lib/properties/clone.js +++ b/lib/properties/clone.js @@ -1,4 +1,5 @@ var wrapSingle = require('./wrap-for-optimizing').single; +var Token = require('../tokenizer/token'); function deep(property) { var cloned = shallow(property); @@ -15,7 +16,12 @@ function deep(property) { } function shallow(property) { - var cloned = wrapSingle([[property.name, property.important, property.hack]]); + var cloned = wrapSingle([ + Token.PROPERTY, + [Token.PROPERTY_NAME, property.name] + ]); + cloned.important = property.important; + cloned.hack = property.hack; cloned.unused = false; return cloned; } diff --git a/lib/properties/every-combination.js b/lib/properties/every-combination.js index be3faa69..71a1c0ef 100644 --- a/lib/properties/every-combination.js +++ b/lib/properties/every-combination.js @@ -1,6 +1,6 @@ var shallowClone = require('./clone').shallow; -var MULTIPLEX_SEPARATOR = ','; +var Marker = require('../tokenizer/marker'); function everyCombination(fn, left, right, validator) { var samePositon = !left.shorthand && !right.shorthand && !left.multiplex && !right.multiplex; @@ -9,7 +9,7 @@ function everyCombination(fn, left, right, validator) { for (var i = 0, l = left.value.length; i < l; i++) { for (var j = 0, m = right.value.length; j < m; j++) { - if (left.value[i][0] == MULTIPLEX_SEPARATOR || right.value[j][0] == MULTIPLEX_SEPARATOR) + if (left.value[i][1] == Marker.COMMA || right.value[j][1] == Marker.COMMA) continue; if (samePositon && i != j) diff --git a/lib/properties/hack.js b/lib/properties/hack.js new file mode 100644 index 00000000..0e769e4e --- /dev/null +++ b/lib/properties/hack.js @@ -0,0 +1,8 @@ +var Hack = { + BANG: 'bang', + BACKSLASH: 'backslash', + STAR: 'star', + UNDERSCORE: 'underscore' +}; + +module.exports = Hack; diff --git a/lib/properties/has-inherit.js b/lib/properties/has-inherit.js index 96a103ba..84f220d3 100644 --- a/lib/properties/has-inherit.js +++ b/lib/properties/has-inherit.js @@ -1,6 +1,6 @@ function hasInherit(property) { for (var i = property.value.length - 1; i >= 0; i--) { - if (property.value[i][0] == 'inherit') + if (property.value[i][1] == 'inherit') return true; } diff --git a/lib/properties/optimizer.js b/lib/properties/optimizer.js index 855b7f9d..565158b1 100644 --- a/lib/properties/optimizer.js +++ b/lib/properties/optimizer.js @@ -189,23 +189,24 @@ function _optimize(properties, mergeAdjacent, aggressiveMerging, validator) { } } -function optimize(selector, properties, mergeAdjacent, withCompacting, options, context) { +function optimize(selector, properties, mergeAdjacent, withCompacting, context) { var validator = context.validator; var warnings = context.warnings; var _properties = wrapForOptimizing(properties); populateComponents(_properties, validator, warnings); - _optimize(_properties, mergeAdjacent, options.aggressiveMerging, validator); + _optimize(_properties, mergeAdjacent, context.options.aggressiveMerging, validator); for (var i = 0, l = _properties.length; i < l; i++) { var _property = _properties[i]; - if (_property.variable && _property.block) - optimize(selector, _property.value[0], mergeAdjacent, withCompacting, options, context); + if (_property.block) { + optimize(selector, _property.value[0][1], mergeAdjacent, withCompacting, context); + } } - if (withCompacting && options.shorthandCompacting) { - compactOverrides(_properties, options.compatibility, validator); - compactShorthands(_properties, options.sourceMap, validator); + if (withCompacting && context.options.shorthandCompacting) { + compactOverrides(_properties, context.options.compatibility, validator); + compactShorthands(_properties, validator); } restoreFromOptimizing(_properties); diff --git a/lib/properties/override-compactor.js b/lib/properties/override-compactor.js index bbf13ed3..2efb8293 100644 --- a/lib/properties/override-compactor.js +++ b/lib/properties/override-compactor.js @@ -9,7 +9,8 @@ var sameVendorPrefixesIn = require('./vendor-prefixes').same; var stringifyProperty = require('../stringifier/one-time').property; -var MULTIPLEX_SEPARATOR = ','; +var Token = require('../tokenizer/token'); +var Marker = require('../tokenizer/marker'); // Used when searching for a component that matches property function nameMatchFilter(to) { @@ -25,7 +26,7 @@ function wouldBreakCompatibility(property, validator) { var canOverride = descriptor && descriptor.canOverride || canOverride.sameValue; var _component = shallowClone(component); - _component.value = [[descriptor.defaultValue]]; + _component.value = [[Token.PROPERTY_VALUE, descriptor.defaultValue]]; if (!canOverride(_component, component, validator)) return true; @@ -84,7 +85,7 @@ function turnIntoMultiplex(property, size) { var value = component.value.slice(0); for (var j = 1; j < size; j++) { - component.value.push([MULTIPLEX_SEPARATOR]); + component.value.push([Token.PROPERTY_VALUE, Marker.COMMA]); Array.prototype.push.apply(component.value, value); } } @@ -94,7 +95,7 @@ function multiplexSize(component) { var size = 0; for (var i = 0, l = component.value.length; i < l; i++) { - if (component.value[i][0] == MULTIPLEX_SEPARATOR) + if (component.value[i][1] == Marker.COMMA) size++; } @@ -102,7 +103,10 @@ function multiplexSize(component) { } function lengthOf(property) { - var fakeAsArray = [[property.name]].concat(property.value); + var fakeAsArray = [ + Token.PROPERTY, + [Token.PROPERTY_NAME, property.name] + ].concat(property.value); return stringifyProperty([fakeAsArray], 0).length; } @@ -133,10 +137,10 @@ function overridingFunction(shorthand, validator) { function anyValue(fn, property) { for (var i = 0, l = property.value.length; i < l; i++) { - if (property.value[i][0] == MULTIPLEX_SEPARATOR) + if (property.value[i][1] == Marker.COMMA) continue; - if (fn(property.value[i][0])) + if (fn(property.value[i][1])) return true; } @@ -172,7 +176,7 @@ function wouldResultInLongerValue(left, right) { var lengthAfter = lengthOf(simpleClone); - return lengthBefore < lengthAfter; + return lengthBefore <= lengthAfter; } function isCompactable(property) { @@ -191,7 +195,7 @@ function anyLayerIsNone(values) { var layers = intoLayers(values); for (var i = 0, l = layers.length; i < l; i++) { - if (layers[i].length == 1 && layers[i][0][0] == 'none') + if (layers[i].length == 1 && layers[i][0][1] == 'none') return true; } @@ -203,7 +207,7 @@ function intoLayers(values) { for (var i = 0, layer = [], l = values.length; i < l; i++) { var value = values[i]; - if (value[0] == MULTIPLEX_SEPARATOR) { + if (value[1] == Marker.COMMA) { layers.push(layer); layer = []; } else { @@ -226,7 +230,7 @@ function compactOverrides(properties, compatibility, validator) { if (!isCompactable(right)) continue; - if (right.variable) + if (right.block) continue; mayOverride = compactable[right.name].canOverride || canOverride.sameValue; @@ -237,7 +241,7 @@ function compactOverrides(properties, compatibility, validator) { if (!isCompactable(left)) continue; - if (left.variable) + if (left.block) continue; if (left.unused || right.unused) @@ -291,7 +295,7 @@ function compactOverrides(properties, compatibility, validator) { !compatibility.properties.backgroundClipMerging && component.name.indexOf('background-clip') > -1 || !compatibility.properties.backgroundOriginMerging && component.name.indexOf('background-origin') > -1 || !compatibility.properties.backgroundSizeMerging && component.name.indexOf('background-size') > -1; - var nonMergeableValue = compactable[right.name].nonMergeableValue === right.value[0][0]; + var nonMergeableValue = compactable[right.name].nonMergeableValue === right.value[0][1]; if (disabledBackgroundMerging || nonMergeableValue) continue; @@ -299,7 +303,7 @@ function compactOverrides(properties, compatibility, validator) { if (!compatibility.properties.merging && wouldBreakCompatibility(left, validator)) continue; - if (component.value[0][0] != right.value[0][0] && (hasInherit(left) || hasInherit(right))) + if (component.value[0][1] != right.value[0][1] && (hasInherit(left) || hasInherit(right))) continue; if (wouldResultInLongerValue(left, right)) diff --git a/lib/properties/remove-unused.js b/lib/properties/remove-unused.js index 08cb9b6a..7b90c407 100644 --- a/lib/properties/remove-unused.js +++ b/lib/properties/remove-unused.js @@ -2,8 +2,9 @@ function removeUnused(properties) { for (var i = properties.length - 1; i >= 0; i--) { var property = properties[i]; - if (property.unused) + if (property.unused) { property.all.splice(property.position, 1); + } } } diff --git a/lib/properties/restore-from-optimizing.js b/lib/properties/restore-from-optimizing.js index f0dfc182..02424dc8 100644 --- a/lib/properties/restore-from-optimizing.js +++ b/lib/properties/restore-from-optimizing.js @@ -1,3 +1,5 @@ +var Hack = require('./hack'); +var Marker = require('../tokenizer/marker'); var compactable = require('./compactable'); var BACKSLASH_HACK = '\\9'; @@ -6,32 +8,24 @@ var STAR_HACK = '*'; var UNDERSCORE_HACK = '_'; var BANG_HACK = '!ie'; -function restoreImportant(property) { - property.value[property.value.length - 1][0] += IMPORTANT_TOKEN; -} - -function restoreHack(property) { - if (property.hack == 'underscore') - property.name = UNDERSCORE_HACK + property.name; - else if (property.hack == 'star') - property.name = STAR_HACK + property.name; - else if (property.hack == 'backslash') - property.value[property.value.length - 1][0] += BACKSLASH_HACK; - else if (property.hack == 'bang') - property.value[property.value.length - 1][0] += ' ' + BANG_HACK; -} - function restoreFromOptimizing(properties, simpleMode) { - for (var i = properties.length - 1; i >= 0; i--) { - var property = properties[i]; - var descriptor = compactable[property.name]; - var restored; + var property; + var descriptor; + var restored; + var current; + var i; + + for (i = properties.length - 1; i >= 0; i--) { + property = properties[i]; + descriptor = compactable[property.name]; - if (property.unused) + if (property.unused) { continue; + } - if (!property.dirty && !property.important && !property.hack) + if (!property.dirty && !property.important && !property.hack) { continue; + } if (!simpleMode && descriptor && descriptor.shorthand) { restored = descriptor.restore(property, compactable); @@ -40,20 +34,37 @@ function restoreFromOptimizing(properties, simpleMode) { restored = property.value; } - if (property.important) + if (property.important) { restoreImportant(property); + } - if (property.hack) + if (property.hack) { restoreHack(property); + } - if (!('all' in property)) - continue; + if ('all' in property) { + current = property.all[property.position]; + current[1][1] = property.name; - var current = property.all[property.position]; - current[0][0] = property.name; + current.splice(2, current.length - 1); + Array.prototype.push.apply(current, restored); + } + } +} - current.splice(1, current.length - 1); - Array.prototype.push.apply(current, restored); +function restoreImportant(property) { + property.value[property.value.length - 1][1] += IMPORTANT_TOKEN; +} + +function restoreHack(property) { + if (property.hack == Hack.UNDERSCORE) { + property.name = UNDERSCORE_HACK + property.name; + } else if (property.hack == Hack.STAR) { + property.name = STAR_HACK + property.name; + } else if (property.hack == Hack.BACKSLASH) { + property.value[property.value.length - 1][1] += BACKSLASH_HACK; + } else if (property.hack == Hack.BANG) { + property.value[property.value.length - 1][1] += Marker.SPACE + BANG_HACK; } } diff --git a/lib/properties/restore.js b/lib/properties/restore.js index a9f8e6f9..a770f741 100644 --- a/lib/properties/restore.js +++ b/lib/properties/restore.js @@ -1,12 +1,12 @@ var shallowClone = require('./clone').shallow; -var MULTIPLEX_SEPARATOR = ','; -var SIZE_POSITION_SEPARATOR = '/'; +var Token = require('../tokenizer/token'); +var Marker = require('../tokenizer/marker'); function isInheritOnly(values) { for (var i = 0, l = values.length; i < l; i++) { - var value = values[i][0]; + var value = values[i][1]; - if (value != 'inherit' && value != MULTIPLEX_SEPARATOR && value != SIZE_POSITION_SEPARATOR) + if (value != 'inherit' && value != Marker.COMMA && value != Marker.FORWARD_SLASH) return false; } @@ -24,13 +24,13 @@ function background(property, compactable, lastInMultiplex) { function isDefaultValue(component) { var descriptor = compactable[component.name]; - if (descriptor.doubleValues) { - if (descriptor.defaultValue.length == 1) - return component.value[0][0] == descriptor.defaultValue[0] && (component.value[1] ? component.value[1][0] == descriptor.defaultValue[0] : true); - else - return component.value[0][0] == descriptor.defaultValue[0] && (component.value[1] ? component.value[1][0] : component.value[0][0]) == descriptor.defaultValue[1]; + + if (descriptor.doubleValues && descriptor.defaultValue.length == 1) { + return component.value[0][1] == descriptor.defaultValue[0] && (component.value[1] ? component.value[1][1] == descriptor.defaultValue[0] : true); + } else if (descriptor.doubleValues && descriptor.defaultValue.length != 1) { + return component.value[0][1] == descriptor.defaultValue[0] && (component.value[1] ? component.value[1][1] : component.value[0][1]) == descriptor.defaultValue[1]; } else { - return component.value[0][0] == descriptor.defaultValue; + return component.value[0][1] == descriptor.defaultValue; } } @@ -42,12 +42,12 @@ function background(property, compactable, lastInMultiplex) { var originComponent = components[i - 1]; var isOriginDefault = isDefaultValue(originComponent); - needsOne = component.value[0][0] == originComponent.value[0][0]; + needsOne = component.value[0][1] == originComponent.value[0][1]; needsBoth = !needsOne && ( (isOriginDefault && !isDefault) || (!isOriginDefault && !isDefault) || - (!isOriginDefault && isDefault && component.value[0][0] != originComponent.value[0][0])); + (!isOriginDefault && isDefault && component.value[0][1] != originComponent.value[0][1])); if (needsOne) { restoreValue(originComponent); @@ -70,7 +70,7 @@ function background(property, compactable, lastInMultiplex) { restoreValue(positionComponent); } else if (needsBoth) { restoreValue(component); - restored.unshift([SIZE_POSITION_SEPARATOR]); + restored.unshift([Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]); restoreValue(positionComponent); } else if (positionComponent.value.length == 1) { restoreValue(positionComponent); @@ -85,11 +85,11 @@ function background(property, compactable, lastInMultiplex) { } } - if (restored.length === 0 && property.value.length == 1 && property.value[0][0] == '0') + if (restored.length === 0 && property.value.length == 1 && property.value[0][1] == '0') restored.push(property.value[0]); if (restored.length === 0) - restored.push([compactable[property.name].defaultValue]); + restored.push([Token.PROPERTY_VALUE, compactable[property.name].defaultValue]); if (isInheritOnly(restored)) return [restored[0]]; @@ -121,13 +121,13 @@ function borderRadius(property, compactable) { var verticalValues = fourValues(vertical, compactable); if (horizontalValues.length == verticalValues.length && - horizontalValues[0][0] == verticalValues[0][0] && - (horizontalValues.length > 1 ? horizontalValues[1][0] == verticalValues[1][0] : true) && - (horizontalValues.length > 2 ? horizontalValues[2][0] == verticalValues[2][0] : true) && - (horizontalValues.length > 3 ? horizontalValues[3][0] == verticalValues[3][0] : true)) { + horizontalValues[0][1] == verticalValues[0][1] && + (horizontalValues.length > 1 ? horizontalValues[1][1] == verticalValues[1][1] : true) && + (horizontalValues.length > 2 ? horizontalValues[2][1] == verticalValues[2][1] : true) && + (horizontalValues.length > 3 ? horizontalValues[3][1] == verticalValues[3][1] : true)) { return horizontalValues; } else { - return horizontalValues.concat([['/']]).concat(verticalValues); + return horizontalValues.concat([[Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]]).concat(verticalValues); } } else { return fourValues(property, compactable); @@ -141,11 +141,11 @@ function fourValues(property) { var value3 = components[2].value[0]; var value4 = components[3].value[0]; - if (value1[0] == value2[0] && value1[0] == value3[0] && value1[0] == value4[0]) { + if (value1[1] == value2[1] && value1[1] == value3[1] && value1[1] == value4[1]) { return [value1]; - } else if (value1[0] == value3[0] && value2[0] == value4[0]) { + } else if (value1[1] == value3[1] && value2[1] == value4[1]) { return [value1, value2]; - } else if (value2[0] == value4[0]) { + } else if (value2[1] == value4[1]) { return [value1, value2, value3]; } else { return [value1, value2, value3, value4]; @@ -164,7 +164,7 @@ function multiplex(restoreWith) { // At this point we don't know what's the multiplex size, e.g. how many background layers are there for (i = 0, l = property.components[0].value.length; i < l; i++) { - if (property.components[0].value[i][0] == MULTIPLEX_SEPARATOR) + if (property.components[0].value[i][1] == Marker.COMMA) multiplexSize++; } @@ -180,7 +180,7 @@ function multiplex(restoreWith) { // The trick is some properties has more than one value, so we iterate over values looking for // a multiplex separator - a comma for (var k = componentMultiplexSoFar[_component.name] || 0, n = componentToClone.value.length; k < n; k++) { - if (componentToClone.value[k][0] == MULTIPLEX_SEPARATOR) { + if (componentToClone.value[k][1] == Marker.COMMA) { componentMultiplexSoFar[_component.name] = k + 1; break; } @@ -195,7 +195,7 @@ function multiplex(restoreWith) { Array.prototype.push.apply(restored, _restored); if (i < multiplexSize) - restored.push([',']); + restored.push([Token.PROPERTY_VALUE, Marker.COMMA]); } return restored; @@ -210,12 +210,12 @@ function withoutDefaults(property, compactable) { var component = components[i]; var descriptor = compactable[component.name]; - if (component.value[0][0] != descriptor.defaultValue) + if (component.value[0][1] != descriptor.defaultValue) restored.unshift(component.value[0]); } if (restored.length === 0) - restored.push([compactable[property.name].defaultValue]); + restored.push([Token.PROPERTY_VALUE, compactable[property.name].defaultValue]); if (isInheritOnly(restored)) return [restored[0]]; diff --git a/lib/properties/shorthand-compactor.js b/lib/properties/shorthand-compactor.js index 9be76236..5ee882a1 100644 --- a/lib/properties/shorthand-compactor.js +++ b/lib/properties/shorthand-compactor.js @@ -5,6 +5,8 @@ var populateComponents = require('./populate-components'); var wrapSingle = require('./wrap-for-optimizing').single; var everyCombination = require('./every-combination'); +var Token = require('../tokenizer/token'); + function mixedImportance(components) { var important; @@ -33,9 +35,13 @@ function componentSourceMaps(components) { return sourceMapping; } -function replaceWithShorthand(properties, candidateComponents, name, sourceMaps, validator) { +function replaceWithShorthand(properties, candidateComponents, name, validator) { var descriptor = compactable[name]; - var newValuePlaceholder = [[name], [descriptor.defaultValue]]; + var newValuePlaceholder = [ + Token.PROPERTY, + [Token.PROPERTY_NAME, name], + [Token.PROPERTY_VALUE, descriptor.defaultValue] + ]; var all; var newProperty = wrapSingle(newValuePlaceholder); @@ -64,11 +70,10 @@ function replaceWithShorthand(properties, candidateComponents, name, sourceMaps, candidateComponents[componentName].unused = true; } - if (sourceMaps) { - var sourceMapping = componentSourceMaps(candidateComponents); - if (sourceMapping.length > 0) - newValuePlaceholder[0].push(sourceMapping); - } + // var sourceMapping = componentSourceMaps(candidateComponents); + // if (sourceMapping.length > 0) + // newValuePlaceholder[0].push(sourceMapping); + // } newProperty.position = all.length; newProperty.all = all; @@ -77,7 +82,7 @@ function replaceWithShorthand(properties, candidateComponents, name, sourceMaps, properties.push(newProperty); } -function invalidateOrCompact(properties, position, candidates, sourceMaps, validator) { +function invalidateOrCompact(properties, position, candidates, validator) { var property = properties[position]; for (var name in candidates) { @@ -94,11 +99,11 @@ function invalidateOrCompact(properties, position, candidates, sourceMaps, valid if (mixedImportance(candidateComponents)) continue; - replaceWithShorthand(properties, candidateComponents, name, sourceMaps, validator); + replaceWithShorthand(properties, candidateComponents, name, validator); } } -function compactShortands(properties, sourceMaps, validator) { +function compactShortands(properties, validator) { var candidates = {}; if (properties.length < 3) @@ -112,7 +117,7 @@ function compactShortands(properties, sourceMaps, validator) { if (property.hack) continue; - if (property.variable) + if (property.block) continue; var descriptor = compactable[property.name]; @@ -120,7 +125,7 @@ function compactShortands(properties, sourceMaps, validator) { continue; if (property.shorthand) { - invalidateOrCompact(properties, i, candidates, sourceMaps, validator); + invalidateOrCompact(properties, i, candidates, validator); } else { var componentOf = descriptor.componentOf; candidates[componentOf] = candidates[componentOf] || {}; @@ -128,7 +133,7 @@ function compactShortands(properties, sourceMaps, validator) { } } - invalidateOrCompact(properties, i, candidates, sourceMaps, validator); + invalidateOrCompact(properties, i, candidates, validator); } module.exports = compactShortands; diff --git a/lib/properties/validator.js b/lib/properties/validator.js index db4ee892..c3fa0544 100644 --- a/lib/properties/validator.js +++ b/lib/properties/validator.js @@ -1,7 +1,5 @@ // Validates various CSS property values -var split = require('../utils/split'); - var widthKeywords = ['thin', 'thick', 'medium', 'inherit', 'initial']; var allUnits = ['px', '%', 'em', 'in', 'cm', 'mm', 'ex', 'pt', 'pc', 'ch', 'rem', 'vh', 'vm', 'vmin', 'vmax', 'vw']; var cssUnitRegexStr = '(\\-?\\.?\\d+\\.?\\d*(' + allUnits.join('|') + '|)|auto|inherit)'; @@ -21,6 +19,8 @@ var cssUnitRegex = new RegExp('^' + cssUnitRegexStr + '$', 'i'); var cssUnitOrCalcRegex = new RegExp('^' + cssUnitOrCalcRegexStr + '$', 'i'); var cssUnitAnyRegex = new RegExp('^' + cssUnitAnyRegexStr + '$', 'i'); +var urlRegex = /^url\([\s\S]+\)$/i; + var backgroundRepeatKeywords = ['repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'inherit']; var backgroundAttachmentKeywords = ['inherit', 'scroll', 'fixed', 'local']; var backgroundPositionKeywords = ['center', 'top', 'bottom', 'left', 'right']; @@ -79,8 +79,7 @@ Validator.prototype.isValidColorValue = function (s) { }; Validator.prototype.isValidUrl = function (s) { - // NOTE: at this point all URLs are replaced with placeholders by clean-css, so we check for those placeholders - return s.indexOf('__ESCAPED_URL_CLEAN_CSS') === 0; + return urlRegex.test(s); }; Validator.prototype.isValidUnit = function (s) { @@ -100,15 +99,15 @@ Validator.prototype.isValidAndCompatibleUnitWithoutFunction = function (s) { }; Validator.prototype.isValidFunctionWithoutVendorPrefix = function (s) { - return cssFunctionNoVendorRegex.test(s); + return !urlRegex.test(s) && cssFunctionNoVendorRegex.test(s); }; Validator.prototype.isValidFunctionWithVendorPrefix = function (s) { - return cssFunctionVendorRegex.test(s); + return !urlRegex.test(s) && cssFunctionVendorRegex.test(s); }; Validator.prototype.isValidFunction = function (s) { - return cssFunctionAnyRegex.test(s); + return !urlRegex.test(s) && cssFunctionAnyRegex.test(s); }; Validator.prototype.isValidBackgroundRepeat = function (s) { @@ -148,14 +147,6 @@ Validator.prototype.isValidBackgroundSizePart = function (s) { return backgroundSizeKeywords.indexOf(s) >= 0 || cssUnitRegex.test(s) || this.isValidVariable(s); }; -Validator.prototype.isValidBackgroundPositionAndSize = function (s) { - if (s.indexOf('/') < 0) - return false; - - var twoParts = split(s, '/'); - return this.isValidBackgroundSizePart(twoParts.pop()) && this.isValidBackgroundPositionPart(twoParts.pop()); -}; - Validator.prototype.isValidListStyleType = function (s) { return listStyleTypeKeywords.indexOf(s) >= 0 || this.isValidVariable(s); }; diff --git a/lib/properties/wrap-for-optimizing.js b/lib/properties/wrap-for-optimizing.js index cb12a2b3..22ad5462 100644 --- a/lib/properties/wrap-for-optimizing.js +++ b/lib/properties/wrap-for-optimizing.js @@ -1,20 +1,31 @@ -var BACKSLASH_HACK = '\\'; -var IMPORTANT_WORD = 'important'; -var IMPORTANT_TOKEN = '!'+IMPORTANT_WORD; -var IMPORTANT_WORD_MATCH = new RegExp(IMPORTANT_WORD+'$', 'i'); -var IMPORTANT_TOKEN_MATCH = new RegExp(IMPORTANT_TOKEN+'$', 'i'); -var STAR_HACK = '*'; -var UNDERSCORE_HACK = '_'; -var BANG_HACK = '!'; +var Hack = require('./hack'); +var Marker = require('../tokenizer/marker'); +var Token = require('../tokenizer/token'); + +var Match = { + BACKSLASH: '\\', + BANG: '!', + BANG_SUFFIX_PATTERN: /!\w+$/, + IMPORTANT_TOKEN: '!important', + IMPORTANT_TOKEN_PATTERN: new RegExp('!important$', 'i'), + IMPORTANT_WORD: 'important', + IMPORTANT_WORD_PATTERN: new RegExp('important$', 'i'), + STAR: '*', + SUFFIX_BANG_PATTERN: /!$/, + UNDERSCORE: '_' +}; function wrapAll(properties) { var wrapped = []; + var single; + var i; - for (var i = properties.length - 1; i >= 0; i--) { - if (typeof properties[i][0] == 'string') + for (i = properties.length - 1; i >= 0; i--) { + if (properties[i][0] != Token.PROPERTY) { continue; + } - var single = wrapSingle(properties[i]); + single = wrapSingle(properties[i]); single.all = properties; single.position = i; wrapped.unshift(single); @@ -24,9 +35,15 @@ function wrapAll(properties) { } function isMultiplex(property) { - for (var i = 1, l = property.length; i < l; i++) { - if (property[i][0] == ',' || property[i][0] == '/') + var value; + var i, l; + + for (i = 3, l = property.length; i < l; i++) { + value = property[i]; + + if (value[0] == Token.PROPERTY_VALUE && (value[1] == Marker.COMMA || value[1] == Marker.FORWARD_SLASH)) { return true; + } } return false; @@ -34,81 +51,100 @@ function isMultiplex(property) { function hackType(property) { var type = false; - var name = property[0][0]; + var name = property[1][1]; var lastValue = property[property.length - 1]; - if (name[0] == UNDERSCORE_HACK) { - type = 'underscore'; - } else if (name[0] == STAR_HACK) { - type = 'star'; - } else if (lastValue[0][0] == BANG_HACK && !lastValue[0].match(IMPORTANT_WORD_MATCH)) { - type = 'bang'; - } else if (lastValue[0].indexOf(BANG_HACK) > 0 && !lastValue[0].match(IMPORTANT_WORD_MATCH)) { - type = 'bang'; - } else if (lastValue[0].indexOf(BACKSLASH_HACK) > 0 && lastValue[0].indexOf(BACKSLASH_HACK) == lastValue[0].length - BACKSLASH_HACK.length - 1) { - type = 'backslash'; - } else if (lastValue[0].indexOf(BACKSLASH_HACK) === 0 && lastValue[0].length == 2) { - type = 'backslash'; + if (name[0] == Match.UNDERSCORE) { + type = Hack.UNDERSCORE; + } else if (name[0] == Match.STAR) { + type = Hack.STAR; + } else if (lastValue[1][0] == Match.BANG && !lastValue[1].match(Match.IMPORTANT_WORD_PATTERN)) { + type = Hack.BANG; + } else if (lastValue[1].indexOf(Match.BANG) > 0 && !lastValue[1].match(Match.IMPORTANT_WORD_PATTERN) && Match.BANG_SUFFIX_PATTERN.test(lastValue[1])) { + type = Hack.BANG; + } else if (lastValue[1].indexOf(Match.BACKSLASH) > 0 && lastValue[1].indexOf(Match.BACKSLASH) == lastValue[1].length - Match.BACKSLASH.length - 1) { + type = Hack.BACKSLASH; + } else if (lastValue[1].indexOf(Match.BACKSLASH) === 0 && lastValue[1].length == 2) { + type = Hack.BACKSLASH; } return type; } function isImportant(property) { - if (property.length > 1) { - var p = property[property.length - 1][0]; - if (typeof(p) === 'string') { - return IMPORTANT_TOKEN_MATCH.test(p); - } + if (property.length < 3) + return false; + + var lastValue = property[property.length - 1]; + if (Match.IMPORTANT_TOKEN_PATTERN.test(lastValue[1])) { + return true; + } else if (Match.IMPORTANT_WORD_PATTERN.test(lastValue[1]) && Match.SUFFIX_BANG_PATTERN.test(property[property.length - 2][1])) { + return true; } + return false; } function stripImportant(property) { - if (property.length > 0) - property[property.length - 1][0] = property[property.length - 1][0].replace(IMPORTANT_TOKEN_MATCH, ''); + var lastValue = property[property.length - 1]; + var oneButLastValue = property[property.length - 2]; + + if (Match.IMPORTANT_TOKEN_PATTERN.test(lastValue[1])) { + lastValue[1] = lastValue[1].replace(Match.IMPORTANT_TOKEN_PATTERN, ''); + } else { + lastValue[1] = lastValue[1].replace(Match.IMPORTANT_WORD_PATTERN, ''); + oneButLastValue[1] = oneButLastValue[1].replace(Match.SUFFIX_BANG_PATTERN, ''); + } + + if (lastValue[1].length === 0) { + property.pop(); + } + + if (oneButLastValue[1].length === 0) { + property.pop(); + } } function stripPrefixHack(property) { - property[0][0] = property[0][0].substring(1); + property[1][1] = property[1][1].substring(1); } function stripSuffixHack(property, hackType) { var lastValue = property[property.length - 1]; - lastValue[0] = lastValue[0] - .substring(0, lastValue[0].indexOf(hackType == 'backslash' ? BACKSLASH_HACK : BANG_HACK)) + lastValue[1] = lastValue[1] + .substring(0, lastValue[1].indexOf(hackType == Hack.BACKSLASH ? Match.BACKSLASH : Match.BANG)) .trim(); - if (lastValue[0].length === 0) + if (lastValue[1].length === 0) { property.pop(); + } } function wrapSingle(property) { - var _isImportant = isImportant(property); - if (_isImportant) + var importantProperty = isImportant(property); + if (importantProperty) { stripImportant(property); + } - var _hackType = hackType(property); - if (_hackType == 'star' || _hackType == 'underscore') + var hackProperty = hackType(property); + if (hackProperty == Hack.STAR || hackProperty == Hack.UNDERSCORE) { stripPrefixHack(property); - else if (_hackType == 'backslash' || _hackType == 'bang') - stripSuffixHack(property, _hackType); - - var isVariable = property[0][0].indexOf('--') === 0; + } else if (hackProperty == Hack.BACKSLASH || hackProperty == Hack.BANG) { + stripSuffixHack(property, hackProperty); + } return { - block: isVariable && property[1] && Array.isArray(property[1][0][0]), + block: property[2] && property[2][0] == Token.PROPERTY_BLOCK, components: [], dirty: false, - hack: _hackType, - important: _isImportant, - name: property[0][0], - multiplex: property.length > 2 ? isMultiplex(property) : false, + hack: hackProperty, + important: importantProperty, + name: property[1][1], + multiplex: property.length > 3 ? isMultiplex(property) : false, position: 0, shorthand: false, - unused: property.length < 2, - value: property.slice(1), - variable: isVariable + unused: false, + value: property.slice(2) }; } diff --git a/lib/selectors/clean-up.js b/lib/selectors/clean-up.js deleted file mode 100644 index 6bb17b99..00000000 --- a/lib/selectors/clean-up.js +++ /dev/null @@ -1,89 +0,0 @@ -function removeWhitespace(match, value) { - return '[' + value.replace(/ /g, '') + ']'; -} - -function selectorSorter(s1, s2) { - return s1[0] > s2[0] ? 1 : -1; -} - -function whitespaceReplacements(_, p1, p2, p3) { - if (p1 && p2 && p3.length) - return p1 + p2 + ' '; - else if (p1 && p2) - return p1 + p2; - else - return p2; -} - -var CleanUp = { - selectors: function (selectors, removeUnsupported, adjacentSpace) { - var list = []; - var repeated = []; - - for (var i = 0, l = selectors.length; i < l; i++) { - var selector = selectors[i]; - var reduced = selector[0] - .replace(/\s+/g, ' ') - .replace(/ ?, ?/g, ',') - .replace(/\s*(\\)?([>+~])(\s*)/g, whitespaceReplacements) - .trim(); - - if (adjacentSpace && reduced.indexOf('nav') > 0) - reduced = reduced.replace(/\+nav(\S|$)/, '+ nav$1'); - - if (removeUnsupported && (reduced.indexOf('*+html ') != -1 || reduced.indexOf('*:first-child+html ') != -1)) - continue; - - if (reduced.indexOf('*') > -1) { - reduced = reduced - .replace(/\*([:#\.\[])/g, '$1') - .replace(/^(\:first\-child)?\+html/, '*$1+html'); - } - - if (reduced.indexOf('[') > -1) - reduced = reduced.replace(/\[([^\]]+)\]/g, removeWhitespace); - - if (repeated.indexOf(reduced) == -1) { - selector[0] = reduced; - repeated.push(reduced); - list.push(selector); - } - } - - return list.sort(selectorSorter); - }, - - selectorDuplicates: function (selectors) { - var list = []; - var repeated = []; - - for (var i = 0, l = selectors.length; i < l; i++) { - var selector = selectors[i]; - - if (repeated.indexOf(selector[0]) == -1) { - repeated.push(selector[0]); - list.push(selector); - } - } - - return list.sort(selectorSorter); - }, - - block: function (values, spaceAfterClosingBrace) { - values[0] = values[0] - .replace(/\s+/g, ' ') - .replace(/(,|:|\() /g, '$1') - .replace(/ \)/g, ')'); - - if (!spaceAfterClosingBrace) - values[0] = values[0].replace(/\) /g, ')'); - }, - - atRule: function (values) { - values[0] = values[0] - .replace(/\s+/g, ' ') - .trim(); - } -}; - -module.exports = CleanUp; diff --git a/lib/selectors/merge-adjacent.js b/lib/selectors/merge-adjacent.js deleted file mode 100644 index 3de1c1fd..00000000 --- a/lib/selectors/merge-adjacent.js +++ /dev/null @@ -1,35 +0,0 @@ -var optimizeProperties = require('../properties/optimizer'); - -var stringifyBody = require('../stringifier/one-time').body; -var stringifySelectors = require('../stringifier/one-time').selectors; -var cleanUpSelectors = require('./clean-up').selectors; -var isSpecial = require('./is-special'); - -function mergeAdjacent(tokens, options, context) { - var lastToken = [null, [], []]; - var adjacentSpace = options.compatibility.selectors.adjacentSpace; - - for (var i = 0, l = tokens.length; i < l; i++) { - var token = tokens[i]; - - if (token[0] != 'selector') { - lastToken = [null, [], []]; - continue; - } - - if (lastToken[0] == 'selector' && stringifySelectors(token[1]) == stringifySelectors(lastToken[1])) { - var joinAt = [lastToken[2].length]; - Array.prototype.push.apply(lastToken[2], token[2]); - optimizeProperties(token[1], lastToken[2], joinAt, true, options, context); - token[2] = []; - } else if (lastToken[0] == 'selector' && stringifyBody(token[2]) == stringifyBody(lastToken[2]) && - !isSpecial(options, stringifySelectors(token[1])) && !isSpecial(options, stringifySelectors(lastToken[1]))) { - lastToken[1] = cleanUpSelectors(lastToken[1].concat(token[1]), false, adjacentSpace); - token[2] = []; - } else { - lastToken = token; - } - } -} - -module.exports = mergeAdjacent; diff --git a/lib/selectors/remove-duplicate-media-queries.js b/lib/selectors/remove-duplicate-media-queries.js deleted file mode 100644 index 44070b0f..00000000 --- a/lib/selectors/remove-duplicate-media-queries.js +++ /dev/null @@ -1,21 +0,0 @@ -var stringifyAll = require('../stringifier/one-time').all; - -function removeDuplicateMediaQueries(tokens) { - var candidates = {}; - - for (var i = 0, l = tokens.length; i < l; i++) { - var token = tokens[i]; - if (token[0] != 'block') - continue; - - var key = token[1][0] + '%' + stringifyAll(token[2]); - var candidate = candidates[key]; - - if (candidate) - candidate[2] = []; - - candidates[key] = token; - } -} - -module.exports = removeDuplicateMediaQueries; diff --git a/lib/stringifier/helpers.js b/lib/stringifier/helpers.js index d3f4abef..66aabb4f 100644 --- a/lib/stringifier/helpers.js +++ b/lib/stringifier/helpers.js @@ -1,43 +1,35 @@ var lineBreak = require('os').EOL; +var emptyCharacter = ''; -var AT_RULE = 'at-rule'; -var PROPERTY_SEPARATOR = ';'; - -function hasMoreProperties(tokens, index) { - for (var i = index, l = tokens.length; i < l; i++) { - if (typeof tokens[i] != 'string') - return true; - } - - return false; -} +var Marker = require('../tokenizer/marker'); +var Token = require('../tokenizer/token'); function supportsAfterClosingBrace(token) { - return token[0][0] == 'background' || token[0][0] == 'transform' || token[0][0] == 'src'; + return token[1][1] == 'background' || token[1][1] == 'transform' || token[1][1] == 'src'; } function afterClosingBrace(token, valueIndex) { - return token[valueIndex][0][token[valueIndex][0].length - 1] == ')' || token[valueIndex][0].indexOf('__ESCAPED_URL_CLEAN_CSS') === 0; + return token[valueIndex][1][token[valueIndex][1].length - 1] == Marker.CLOSE_ROUND_BRACKET; } function afterComma(token, valueIndex) { - return token[valueIndex][0] == ','; + return token[valueIndex][1] == Marker.COMMA; } function afterSlash(token, valueIndex) { - return token[valueIndex][0] == '/'; + return token[valueIndex][1] == Marker.FORWARD_SLASH; } function beforeComma(token, valueIndex) { - return token[valueIndex + 1] && token[valueIndex + 1][0] == ','; + return token[valueIndex + 1] && token[valueIndex + 1][1] == Marker.COMMA; } function beforeSlash(token, valueIndex) { - return token[valueIndex + 1] && token[valueIndex + 1][0] == '/'; + return token[valueIndex + 1] && token[valueIndex + 1][1] == Marker.FORWARD_SLASH; } function inFilter(token) { - return token[0][0] == 'filter' || token[0][0] == '-ms-filter'; + return token[1][1] == 'filter' || token[1][1] == '-ms-filter'; } function inSpecialContext(token, valueIndex, context) { @@ -48,112 +40,120 @@ function inSpecialContext(token, valueIndex, context) { afterComma(token, valueIndex); } -function selectors(tokens, context) { +function rules(tokens, context) { var store = context.store; for (var i = 0, l = tokens.length; i < l; i++) { store(tokens[i], context); - if (i < l - 1) - store(',', context); + if (i < l - 1) { + store(Marker.COMMA, context); + } } } function body(tokens, context) { + var lastPropertyAt = lastPropertyIndex(tokens); + for (var i = 0, l = tokens.length; i < l; i++) { - property(tokens, i, i == l - 1, context); + property(tokens, i, lastPropertyAt, context); } } -function property(tokens, position, isLast, context) { - var store = context.store; - var token = tokens[position]; +function lastPropertyIndex(tokens) { + var index = tokens.length - 1; - if (typeof token == 'string') { - store(token, context); - } else if (token[0] == AT_RULE) { - propertyAtRule(token[1], isLast, context); - } else { - store(token[0], context); - store(':', context); - value(tokens, position, isLast, context); + for (; index >= 0; index--) { + if (tokens[index][0] != Token.COMMENT) { + break; + } } + + return index; } -function propertyAtRule(value, isLast, context) { +function property(tokens, position, lastPropertyAt, context) { var store = context.store; + var token = tokens[position]; - store(value, context); - if (!isLast) - store(PROPERTY_SEPARATOR, context); + switch (token[0]) { + case Token.AT_RULE: + // slicing here is a bit inconvenient but necessary since otherwise source map info + // would not be passed in. We should consider changing parsing to output an array as + // 2nd element. Unfortunately this also refers to properties... :-/ + store(token.slice(1), context); + store(position < lastPropertyAt ? Marker.SEMICOLON : '', context); + break; + case Token.COMMENT: + store(token[1][0], context); + break; + case Token.PROPERTY: + store(token[1][1], context); + store(Marker.COLON, context); + value(token, context); + store(position < lastPropertyAt || token[2][0] == Token.PROPERTY_BLOCK ? Marker.SEMICOLON : '', context); + } } -function value(tokens, position, isLast, context) { +function value(token, context) { var store = context.store; - var token = tokens[position]; - var isVariableDeclaration = token[0][0].indexOf('--') === 0; - var isBlockVariable = isVariableDeclaration && Array.isArray(token[1][0]); - - if (isVariableDeclaration && isBlockVariable && atRulesOrProperties(token[1])) { - store('{', context); - body(token[1], context); - store('};', context); - return; - } + var j, m; - for (var j = 1, m = token.length; j < m; j++) { - store(token[j], context); + if (token[2][0] == Token.PROPERTY_BLOCK) { + store(Marker.OPEN_BRACE, context); + body(token[2][1], context); + store(Marker.CLOSE_BRACE, context); + } else { + for (j = 2, m = token.length; j < m; j++) { + store(token[j][1], context); - if (j < m - 1 && (inFilter(token) || !inSpecialContext(token, j, context))) { - store(' ', context); - } else if (j == m - 1 && !isLast && hasMoreProperties(tokens, position + 1)) { - store(PROPERTY_SEPARATOR, context); + if (j < m - 1 && (inFilter(token) || !inSpecialContext(token, j, context))) { + store(Marker.SPACE, context); + } } } } -function atRulesOrProperties(values) { - for (var i = 0, l = values.length; i < l; i++) { - if (values[i][0] == AT_RULE || Array.isArray(values[i][0])) - return true; - } - - return false; -} - function all(tokens, context) { - var joinCharacter = context.keepBreaks ? lineBreak : ''; + var joinCharacter = context.keepBreaks ? lineBreak : emptyCharacter; var store = context.store; + var token; + var i, l; - for (var i = 0, l = tokens.length; i < l; i++) { - var token = tokens[i]; + for (i = 0, l = tokens.length; i < l; i++) { + token = tokens[i]; switch (token[0]) { - case 'at-rule': - case 'text': - store(token[1][0], context); + case Token.AT_RULE: + store(token[1], context); + store(Marker.SEMICOLON, context); + break; + case Token.AT_RULE_BLOCK: + rules(token[1], context); store(joinCharacter, context); + store(Marker.OPEN_BRACE, context); + body(token[2], context); + store(Marker.CLOSE_BRACE, context); break; - case 'block': - selectors([token[1]], context); - store('{', context); + case Token.BLOCK: + rules(token[1], context); + store(Marker.OPEN_BRACE, context); all(token[2], context); - store('}', context); - store(joinCharacter, context); + store(Marker.CLOSE_BRACE, context); break; - case 'flat-block': - selectors([token[1]], context); - store('{', context); - body(token[2], context); - store('}', context); - store(joinCharacter, context); + case Token.COMMENT: + store(token[1], context); break; - default: - selectors(token[1], context); - store('{', context); + case Token.RULE: + rules(token[1], context); + store(Marker.OPEN_BRACE, context); body(token[2], context); - store('}', context); - store(joinCharacter, context); + store(Marker.CLOSE_BRACE, context); + break; + } + + if (i < l - 1) { + store(joinCharacter, context); } } } @@ -162,6 +162,6 @@ module.exports = { all: all, body: body, property: property, - selectors: selectors, + rules: rules, value: value }; diff --git a/lib/stringifier/one-time.js b/lib/stringifier/one-time.js index 4a65c7f2..abcf6c5a 100644 --- a/lib/stringifier/one-time.js +++ b/lib/stringifier/one-time.js @@ -29,15 +29,15 @@ function property(tokens, position) { return fakeContext.output.join(''); } -function selectors(tokens) { +function rules(tokens) { var fakeContext = context(); - helpers.selectors(tokens, fakeContext); + helpers.rules(tokens, fakeContext); return fakeContext.output.join(''); } -function value(tokens, position) { +function value(tokens) { var fakeContext = context(); - helpers.value(tokens, position, true, fakeContext); + helpers.value(tokens, fakeContext); return fakeContext.output.join(''); } @@ -45,6 +45,6 @@ module.exports = { all: all, body: body, property: property, - selectors: selectors, + rules: rules, value: value }; diff --git a/lib/stringifier/simple.js b/lib/stringifier/simple.js index 0673996d..78f9277c 100644 --- a/lib/stringifier/simple.js +++ b/lib/stringifier/simple.js @@ -1,21 +1,21 @@ var all = require('./helpers').all; -function store(token, context) { - context.output.push(typeof token == 'string' ? token : token[0]); +function store(token, stringifyContext) { + stringifyContext.output.push(typeof token == 'string' ? token : token[0]); } -function stringify(tokens, options, restoreCallback) { - var context = { - keepBreaks: options.keepBreaks, +function stringify(tokens, context) { + var stringifyContext = { + keepBreaks: context.options.keepBreaks, output: [], - spaceAfterClosingBrace: options.compatibility.properties.spaceAfterClosingBrace, + spaceAfterClosingBrace: context.options.compatibility.properties.spaceAfterClosingBrace, store: store }; - all(tokens, context, false); + all(tokens, stringifyContext, false); return { - styles: restoreCallback(context.output.join('')).trim() + styles: stringifyContext.output.join('') }; } diff --git a/lib/stringifier/source-maps.js b/lib/stringifier/source-maps.js index 77486140..c8a15638 100644 --- a/lib/stringifier/source-maps.js +++ b/lib/stringifier/source-maps.js @@ -71,25 +71,24 @@ function trackMapping(mapping, context) { context.outputMap.setSourceContent(source, mapping[3][mapping[2]]); } -function stringify(tokens, options, restoreCallback, inputMapTracker) { - var context = { +function stringify(tokens, context) { + var stringifyContext = { column: 0, - inputMapTracker: inputMapTracker, - keepBreaks: options.keepBreaks, + inputMapTracker: context.inputMapTracker, + keepBreaks: context.options.keepBreaks, line: 1, output: [], outputMap: new SourceMapGenerator(), - restore: restoreCallback, - sourceMapInlineSources: options.sourceMapInlineSources, - spaceAfterClosingBrace: options.compatibility.properties.spaceAfterClosingBrace, + sourceMapInlineSources: context.options.sourceMapInlineSources, + spaceAfterClosingBrace: context.options.compatibility.properties.spaceAfterClosingBrace, store: store }; - all(tokens, context, false); + all(tokens, stringifyContext, false); return { - sourceMap: context.outputMap, - styles: context.output.join('').trim() + sourceMap: stringifyContext.outputMap, + styles: stringifyContext.output.join('') }; } diff --git a/lib/tokenizer/marker.js b/lib/tokenizer/marker.js index 1129c6e1..dea6b0f1 100644 --- a/lib/tokenizer/marker.js +++ b/lib/tokenizer/marker.js @@ -3,6 +3,7 @@ var Marker = { BACK_SLASH: '\\', CLOSE_BRACE: '}', CLOSE_ROUND_BRACKET: ')', + CLOSE_SQUARE_BRACKET: ']', COLON: ':', COMMA: ',', DOUBLE_QUOTE: '"', @@ -12,6 +13,7 @@ var Marker = { NEW_LINE_WIN: '\r', OPEN_BRACE: '{', OPEN_ROUND_BRACKET: '(', + OPEN_SQUARE_BRACKET: '[', SEMICOLON: ';', SINGLE_QUOTE: '\'', SPACE: ' ', diff --git a/lib/urls/rebase-config.js b/lib/urls/rebase-config.js new file mode 100644 index 00000000..9c1a5e70 --- /dev/null +++ b/lib/urls/rebase-config.js @@ -0,0 +1,31 @@ +var path = require('path'); + +function rebaseConfig(context) { + var config = { + absolute: context.options.explicitRoot, + relative: !context.options.explicitRoot && context.options.explicitTarget, + fromBase: context.options.relativeTo + }; + + if (!config.absolute && !config.relative) { + return null; + } + + if (config.absolute && context.options.explicitTarget) { + context.warnings.push('Both \'root\' and output file given so rebasing URLs as absolute paths'); + } + + if (config.absolute) { + config.toBase = path.resolve(context.options.root); + } + + if (config.relative) { + config.toBase = path.resolve(context.options.target); + } + + return config.fromBase && config.toBase ? + config : + null; +} + +module.exports = rebaseConfig; diff --git a/lib/urls/rebase.js b/lib/urls/rebase.js deleted file mode 100644 index 04346b1d..00000000 --- a/lib/urls/rebase.js +++ /dev/null @@ -1,30 +0,0 @@ -var path = require('path'); - -var rewriteUrls = require('./rewrite'); - -function rebaseUrls(data, context) { - var rebaseOpts = { - absolute: context.options.explicitRoot, - relative: !context.options.explicitRoot && context.options.explicitTarget, - fromBase: context.options.relativeTo - }; - - if (!rebaseOpts.absolute && !rebaseOpts.relative) - return data; - - if (rebaseOpts.absolute && context.options.explicitTarget) - context.warnings.push('Both \'root\' and output file given so rebasing URLs as absolute paths'); - - if (rebaseOpts.absolute) - rebaseOpts.toBase = path.resolve(context.options.root); - - if (rebaseOpts.relative) - rebaseOpts.toBase = path.resolve(context.options.target); - - if (!rebaseOpts.fromBase || !rebaseOpts.toBase) - return data; - - return rewriteUrls(data, rebaseOpts, context); -} - -module.exports = rebaseUrls; diff --git a/lib/urls/reduce.js b/lib/urls/reduce.js deleted file mode 100644 index 35ad5556..00000000 --- a/lib/urls/reduce.js +++ /dev/null @@ -1,154 +0,0 @@ -var split = require('../utils/split'); - -var URL_PREFIX = 'url('; -var UPPERCASE_URL_PREFIX = 'URL('; -var URL_SUFFIX = ')'; -var SINGLE_QUOTE_URL_SUFFIX = '\')'; -var DOUBLE_QUOTE_URL_SUFFIX = '")'; - -var DATA_URI_PREFIX_PATTERN = /^\s*['"]?\s*data:/; -var DATA_URI_TRAILER_PATTERN = /[\s\};,\/!]/; - -var IMPORT_URL_PREFIX = '@import'; -var UPPERCASE_IMPORT_URL_PREFIX = '@IMPORT'; - -var COMMENT_END_MARKER = /\*\//; - -function byUrl(data, context, callback) { - var nextStart = 0; - var nextStartUpperCase = 0; - var nextEnd = 0; - var firstMatch; - var isDataURI = false; - var cursor = 0; - var tempData = []; - var hasUppercaseUrl = data.indexOf(UPPERCASE_URL_PREFIX) > -1; - - for (; nextEnd < data.length;) { - nextStart = data.indexOf(URL_PREFIX, nextEnd); - nextStartUpperCase = hasUppercaseUrl ? data.indexOf(UPPERCASE_URL_PREFIX, nextEnd) : -1; - if (nextStart == -1 && nextStartUpperCase == -1) - break; - - if (nextStart == -1 && nextStartUpperCase > -1) - nextStart = nextStartUpperCase; - - if (data[nextStart + URL_PREFIX.length] == '"') { - nextEnd = data.indexOf(DOUBLE_QUOTE_URL_SUFFIX, nextStart); - } else if (data[nextStart + URL_PREFIX.length] == '\'') { - nextEnd = data.indexOf(SINGLE_QUOTE_URL_SUFFIX, nextStart); - } else { - isDataURI = DATA_URI_PREFIX_PATTERN.test(data.substring(nextStart + URL_PREFIX.length)); - - if (isDataURI) { - firstMatch = split(data.substring(nextStart), DATA_URI_TRAILER_PATTERN, false, '(', ')', true).pop(); - - if (firstMatch && firstMatch[firstMatch.length - 1] == URL_SUFFIX) { - nextEnd = nextStart + firstMatch.length - URL_SUFFIX.length; - } else { - nextEnd = -1; - } - } else { - nextEnd = data.indexOf(URL_SUFFIX, nextStart); - } - } - - - // Following lines are a safety mechanism to ensure - // incorrectly terminated urls are processed correctly. - if (nextEnd == -1) { - nextEnd = data.indexOf('}', nextStart); - - if (nextEnd == -1) - nextEnd = data.length; - else - nextEnd--; - - context.warnings.push('Broken URL declaration: \'' + data.substring(nextStart, nextEnd + 1) + '\'.'); - } else { - if (data[nextEnd] != URL_SUFFIX) - nextEnd = data.indexOf(URL_SUFFIX, nextEnd); - } - - tempData.push(data.substring(cursor, nextStart)); - - var url = data.substring(nextStart, nextEnd + 1); - callback(url, tempData); - - cursor = nextEnd + 1; - } - - return tempData.length > 0 ? - tempData.join('') + data.substring(cursor, data.length) : - data; -} - -function byImport(data, context, callback) { - var nextImport = 0; - var nextImportUpperCase = 0; - var nextStart = 0; - var nextEnd = 0; - var cursor = 0; - var tempData = []; - var nextSingleQuote = 0; - var nextDoubleQuote = 0; - var untilNextQuote; - var withQuote; - var SINGLE_QUOTE = '\''; - var DOUBLE_QUOTE = '"'; - - for (; nextEnd < data.length;) { - nextImport = data.indexOf(IMPORT_URL_PREFIX, nextEnd); - nextImportUpperCase = data.indexOf(UPPERCASE_IMPORT_URL_PREFIX, nextEnd); - if (nextImport == -1 && nextImportUpperCase == -1) - break; - - if (nextImport > -1 && nextImportUpperCase > -1 && nextImportUpperCase < nextImport) - nextImport = nextImportUpperCase; - - nextSingleQuote = data.indexOf(SINGLE_QUOTE, nextImport); - nextDoubleQuote = data.indexOf(DOUBLE_QUOTE, nextImport); - - if (nextSingleQuote > -1 && nextDoubleQuote > -1 && nextSingleQuote < nextDoubleQuote) { - nextStart = nextSingleQuote; - withQuote = SINGLE_QUOTE; - } else if (nextSingleQuote > -1 && nextDoubleQuote > -1 && nextSingleQuote > nextDoubleQuote) { - nextStart = nextDoubleQuote; - withQuote = DOUBLE_QUOTE; - } else if (nextSingleQuote > -1) { - nextStart = nextSingleQuote; - withQuote = SINGLE_QUOTE; - } else if (nextDoubleQuote > -1) { - nextStart = nextDoubleQuote; - withQuote = DOUBLE_QUOTE; - } else { - break; - } - - tempData.push(data.substring(cursor, nextStart)); - nextEnd = data.indexOf(withQuote, nextStart + 1); - - untilNextQuote = data.substring(nextImport, nextEnd); - if (nextEnd == -1 || /^@import\s+(url\(|__ESCAPED)/i.test(untilNextQuote) || COMMENT_END_MARKER.test(untilNextQuote)) { - cursor = nextStart; - break; - } - - var url = data.substring(nextStart, nextEnd + 1); - callback(url, tempData); - - cursor = nextEnd + 1; - } - - return tempData.length > 0 ? - tempData.join('') + data.substring(cursor, data.length) : - data; -} - -function reduceAll(data, context, callback) { - data = byUrl(data, context, callback); - data = byImport(data, context, callback); - return data; -} - -module.exports = reduceAll; diff --git a/lib/urls/rewrite-url.js b/lib/urls/rewrite-url.js new file mode 100644 index 00000000..e524216b --- /dev/null +++ b/lib/urls/rewrite-url.js @@ -0,0 +1,124 @@ +var path = require('path'); +var url = require('url'); + +var DOUBLE_QUOTE = '"'; +var SINGLE_QUOTE = '\''; +var URL_PREFIX = 'url('; +var URL_SUFFIX = ')'; + +var QUOTE_PREFIX_PATTERN = /^["']/; +var QUOTE_SUFFIX_PATTERN = /["']$/; +var ROUND_BRACKETS_PATTERN = /[\(\)]/; +var URL_PREFIX_PATTERN = /^url\(/; +var URL_SUFFIX_PATTERN = /\)$/; +var WHITESPACE_PATTERN = /\s/; + +var isWindows = process.platform == 'win32'; + +function rebase(uri, rebaseConfig) { + if (!rebaseConfig) { + return uri; + } + + if (isAbsolute(uri) || isSVGMarker(uri) || isInternal(uri)) { + return uri; + } + + if (isData(uri)) { + return '\'' + uri + '\''; + } + + if (isRemote(uri) && !isRemote(rebaseConfig.toBase)) { + return uri; + } + + if (isRemote(uri) && !isSameOrigin(uri, rebaseConfig.toBase)) { + return uri; + } + + if (!isRemote(uri) && isRemote(rebaseConfig.toBase)) { + return url.resolve(rebaseConfig.toBase, uri); + } + + return rebaseConfig.absolute ? + normalize(absolute(uri, rebaseConfig)) : + normalize(relative(uri, rebaseConfig)); +} + +function isAbsolute(uri) { + return uri[0] == '/'; +} + +function isSVGMarker(uri) { + return uri[0] == '#'; +} + +function isInternal(uri) { + return /^\w+:\w+/.test(uri); +} + +function isRemote(uri) { + return /^[^:]+?:\/\//.test(uri) || uri.indexOf('//') === 0; +} + +function isSameOrigin(uri1, uri2) { + return url.parse(uri1).protocol == url.parse(uri2).protocol && + url.parse(uri1).host == url.parse(uri2).host; +} + +function isData(uri) { + return uri.indexOf('data:') === 0; +} + +function absolute(uri, rebaseConfig) { + return path + .resolve(path.join(rebaseConfig.fromBase || '', uri)) + .replace(rebaseConfig.toBase, ''); +} + +function relative(uri, rebaseConfig) { + return path.relative(rebaseConfig.toBase, path.join(rebaseConfig.fromBase || '', uri)); +} + +function normalize(uri) { + return isWindows ? uri.replace(/\\/g, '/') : uri; +} + +function quoteFor(unquotedUrl) { + if (unquotedUrl.indexOf(SINGLE_QUOTE) > -1) { + return DOUBLE_QUOTE; + } else if (unquotedUrl.indexOf(DOUBLE_QUOTE) > -1) { + return SINGLE_QUOTE; + } else if (hasWhitespace(unquotedUrl) || hasRoundBrackets(unquotedUrl)) { + return SINGLE_QUOTE; + } else { + return ''; + } +} + +function hasWhitespace(url) { + return WHITESPACE_PATTERN.test(url); +} + +function hasRoundBrackets(url) { + return ROUND_BRACKETS_PATTERN.test(url); +} + +function rewriteUrl(originalUrl, rebaseConfig) { + var strippedUrl = originalUrl + .replace(URL_PREFIX_PATTERN, '') + .replace(URL_SUFFIX_PATTERN, '') + .trim(); + + var unquotedUrl = strippedUrl + .replace(QUOTE_PREFIX_PATTERN, '') + .replace(QUOTE_SUFFIX_PATTERN, ''); + + var quote = strippedUrl[0] == SINGLE_QUOTE || strippedUrl[0] == DOUBLE_QUOTE ? + strippedUrl[0] : + quoteFor(unquotedUrl); + + return URL_PREFIX + quote + rebase(unquotedUrl, rebaseConfig) + quote + URL_SUFFIX; +} + +module.exports = rewriteUrl; diff --git a/lib/urls/rewrite.js b/lib/urls/rewrite.js deleted file mode 100644 index 0f5552b4..00000000 --- a/lib/urls/rewrite.js +++ /dev/null @@ -1,107 +0,0 @@ -var path = require('path'); -var url = require('url'); - -var reduceUrls = require('./reduce'); - -var isWindows = process.platform == 'win32'; - -function isAbsolute(uri) { - return uri[0] == '/'; -} - -function isSVGMarker(uri) { - return uri[0] == '#'; -} - -function isEscaped(uri) { - return uri.indexOf('__ESCAPED_URL_CLEAN_CSS__') === 0; -} - -function isInternal(uri) { - return /^\w+:\w+/.test(uri); -} - -function isRemote(uri) { - return /^[^:]+?:\/\//.test(uri) || uri.indexOf('//') === 0; -} - -function isSameOrigin(uri1, uri2) { - return url.parse(uri1).protocol == url.parse(uri2).protocol && - url.parse(uri1).host == url.parse(uri2).host; -} - -function isImport(uri) { - return uri.lastIndexOf('.css') === uri.length - 4; -} - -function isData(uri) { - return uri.indexOf('data:') === 0; -} - -function absolute(uri, options) { - return path - .resolve(path.join(options.fromBase || '', uri)) - .replace(options.toBase, ''); -} - -function relative(uri, options) { - return path.relative(options.toBase, path.join(options.fromBase || '', uri)); -} - -function normalize(uri) { - return isWindows ? uri.replace(/\\/g, '/') : uri; -} - -function rebase(uri, options) { - if (isAbsolute(uri) || isSVGMarker(uri) || isEscaped(uri) || isInternal(uri)) - return uri; - - if (options.rebase === false && !isImport(uri)) - return uri; - - if (!options.imports && isImport(uri)) - return uri; - - if (isData(uri)) - return '\'' + uri + '\''; - - if (isRemote(uri) && !isRemote(options.toBase)) - return uri; - - if (isRemote(uri) && !isSameOrigin(uri, options.toBase)) - return uri; - - if (!isRemote(uri) && isRemote(options.toBase)) - return url.resolve(options.toBase, uri); - - return options.absolute ? - normalize(absolute(uri, options)) : - normalize(relative(uri, options)); -} - -function quoteFor(url) { - if (url.indexOf('\'') > -1) - return '"'; - else if (url.indexOf('"') > -1) - return '\''; - else if (/\s/.test(url) || /[\(\)]/.test(url)) - return '\''; - else - return ''; -} - -function rewriteUrls(data, options, context) { - return reduceUrls(data, context, function (originUrl, tempData) { - var url = originUrl.replace(/^(url\()?\s*['"]?|['"]?\s*\)?$/g, ''); - var match = originUrl.match(/^(url\()?\s*(['"]).*?(['"])\s*\)?$/); - var quote; - if (!!options.urlQuotes && match && match[2] === match[3]) { - quote = match[2]; - } else { - quote = quoteFor(url); - } - tempData.push('url(' + quote + rebase(url, options) + quote + ')'); - }); -} - -module.exports = rewriteUrls; diff --git a/lib/utils/compatibility.js b/lib/utils/compatibility.js index 112a6dcc..dea82698 100644 --- a/lib/utils/compatibility.js +++ b/lib/utils/compatibility.js @@ -111,8 +111,8 @@ var DEFAULTS = { } }; -function Compatibility(source) { - this.source = source || {}; +function compatibility(source) { + return merge(DEFAULTS['*'], calculateSource(source)); } function merge(source, target) { @@ -155,8 +155,4 @@ function calculateSource(source) { return merge(template, source); } -Compatibility.prototype.toOptions = function () { - return merge(DEFAULTS['*'], calculateSource(this.source)); -}; - -module.exports = Compatibility; +module.exports = compatibility; diff --git a/lib/utils/object.js b/lib/utils/object.js deleted file mode 100644 index 8e94886c..00000000 --- a/lib/utils/object.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - override: function (source1, source2) { - var target = {}; - for (var key1 in source1) - target[key1] = source1[key1]; - for (var key2 in source2) - target[key2] = source2[key2]; - - return target; - } -}; diff --git a/lib/utils/override.js b/lib/utils/override.js new file mode 100644 index 00000000..b2ee13a4 --- /dev/null +++ b/lib/utils/override.js @@ -0,0 +1,14 @@ +function override(source1, source2) { + var target = {}; + + for (var key1 in source1) { + target[key1] = source1[key1]; + } + for (var key2 in source2) { + target[key2] = source2[key2]; + } + + return target; +} + +module.exports = override; diff --git a/lib/utils/quote-scanner.js b/lib/utils/quote-scanner.js deleted file mode 100644 index 1810b9ec..00000000 --- a/lib/utils/quote-scanner.js +++ /dev/null @@ -1,119 +0,0 @@ -var COMMENT_START_MARK = '/*'; - -function QuoteScanner(data) { - this.data = data; -} - -var findQuoteEnd = function (data, matched, cursor, oldCursor) { - var commentEndMark = '*/'; - var escapeMark = '\\'; - var blockEndMark = '}'; - var dataPrefix = data.substring(oldCursor, cursor); - var commentEndedAt = dataPrefix.lastIndexOf(commentEndMark, cursor); - var commentStartedAt = findLastCommentStartedAt(dataPrefix, cursor); - var commentStarted = false; - - if (commentEndedAt >= cursor && commentStartedAt > -1) - commentStarted = true; - if (commentStartedAt < cursor && commentStartedAt > commentEndedAt) - commentStarted = true; - - if (commentStarted) { - var commentEndsAt = data.indexOf(commentEndMark, cursor); - if (commentEndsAt > -1) - return commentEndsAt; - - commentEndsAt = data.indexOf(blockEndMark, cursor); - return commentEndsAt > -1 ? commentEndsAt - 1 : data.length; - } - - while (true) { - if (data[cursor] === undefined) - break; - if (data[cursor] == matched && (data[cursor - 1] != escapeMark || data[cursor - 2] == escapeMark)) - break; - - cursor++; - } - - return cursor; -}; - -function findLastCommentStartedAt(data, cursor) { - var position = cursor; - - while (position > -1) { - position = data.lastIndexOf(COMMENT_START_MARK, position); - - if (position > -1 && data[position - 1] != '*') { - break; - } else { - position--; - } - } - - return position; -} - -function findNext(data, mark, startAt) { - var escapeMark = '\\'; - var candidate = startAt; - - while (true) { - candidate = data.indexOf(mark, candidate + 1); - if (candidate == -1) - return -1; - if (data[candidate - 1] != escapeMark) - return candidate; - } -} - -QuoteScanner.prototype.each = function (callback) { - var data = this.data; - var tempData = []; - var nextStart = 0; - var nextEnd = 0; - var cursor = 0; - var matchedMark = null; - var singleMark = '\''; - var doubleMark = '"'; - var dataLength = data.length; - - for (; nextEnd < data.length;) { - var nextStartSingle = findNext(data, singleMark, nextEnd); - var nextStartDouble = findNext(data, doubleMark, nextEnd); - - if (nextStartSingle == -1) - nextStartSingle = dataLength; - if (nextStartDouble == -1) - nextStartDouble = dataLength; - - if (nextStartSingle < nextStartDouble) { - nextStart = nextStartSingle; - matchedMark = singleMark; - } else { - nextStart = nextStartDouble; - matchedMark = doubleMark; - } - - if (nextStart == -1) - break; - - nextEnd = findQuoteEnd(data, matchedMark, nextStart + 1, cursor); - if (nextEnd == -1) - break; - - var text = data.substring(nextStart, nextEnd + 1); - tempData.push(data.substring(cursor, nextStart)); - if (text.length > 0) - callback(text, tempData, nextStart); - - cursor = nextEnd + 1; - } - - return tempData.length > 0 ? - tempData.join('') + data.substring(cursor, data.length) : - data; -}; - -module.exports = QuoteScanner; diff --git a/lib/utils/read-sources.js b/lib/utils/read-sources.js new file mode 100644 index 00000000..03be6230 --- /dev/null +++ b/lib/utils/read-sources.js @@ -0,0 +1,107 @@ +var path = require('path'); + +var tokenize = require('../tokenizer/tokenize'); +var Token = require('../tokenizer/token'); + +var rewriteUrl = require('../urls/rewrite-url'); + +function readSources(input, context, callback) { + var tokens; + + if (typeof input == 'string') { + tokens = tokenize(input, context); + } else if (typeof input == 'object') { + tokens = fromHash(input, context); + } + + return callback(tokens); +} + +function fromHash(input, context) { + var tokens = []; + var sourcePath; + var source; + var baseRelativeTo = context.options.relativeTo || context.options.root; + var relativeTo; + var fullPath; + var config; + + for (sourcePath in input) { + source = input[sourcePath]; + relativeTo = sourcePath[0] == '/' ? + context.options.root : + baseRelativeTo; + fullPath = path.resolve( + path.join( + relativeTo, + sourcePath + ) + ); + + config = { + relative: true, + fromBase: path.dirname(fullPath), + toBase: baseRelativeTo + }; + + tokens = tokens.concat( + rebase( + tokenize(source.styles, context), + context.validator, + config + ) + ); + } + + return tokens; +} + +function rebase(tokens, validator, config) { + var token; + var i, l; + + for (i = 0, l = tokens.length; i < l; i++) { + token = tokens[i]; + + switch (token[0]) { + case Token.AT_RULE: + // + break; + case Token.AT_RULE_BLOCK: + // + break; + case Token.BLOCK: + rebase(token[2], validator, config); + break; + case Token.PROPERTY: + // + break; + case Token.RULE: + rebaseProperties(token[2], validator, config); + break; + } + } + + return tokens; +} + +function rebaseProperties(properties, validator, config) { + var property; + var value; + var i, l; + var j, m; + + for (i = 0, l = properties.length; i < l; i++) { + property = properties[i]; + + for (j = 2 /* 0 is Token.PROPERTY, 1 is name */, m = property.length; j < m; j++) { + value = property[j][1]; + + if (validator.isValidUrl(value)) { + property[j][1] = rewriteUrl(value, config); + } + } + } +} + +module.exports = readSources; diff --git a/lib/utils/source-reader.js b/lib/utils/source-reader.js deleted file mode 100644 index d817e72b..00000000 --- a/lib/utils/source-reader.js +++ /dev/null @@ -1,96 +0,0 @@ -var path = require('path'); -var rewriteUrls = require('../urls/rewrite'); - -var REMOTE_RESOURCE = /^(https?:)?\/\//; - -function SourceReader(context, data) { - this.outerContext = context; - this.data = data; - this.sources = {}; -} - -SourceReader.prototype.sourceAt = function (path) { - return this.sources[path]; -}; - -SourceReader.prototype.trackSource = function (path, source) { - this.sources[path] = {}; - this.sources[path][path] = source; -}; - -SourceReader.prototype.toString = function () { - if (typeof this.data == 'string') - return fromString(this); - if (Buffer.isBuffer(this.data)) - return fromBuffer(this); - if (Array.isArray(this.data)) - return fromArray(this); - - return fromHash(this); -}; - -function fromString(self) { - var data = self.data; - self.trackSource(undefined, data); - return data; -} - -function fromBuffer(self) { - var data = self.data.toString(); - self.trackSource(undefined, data); - return data; -} - -function fromArray(self) { - return self.data - .map(function (source) { - return self.outerContext.options.processImport === false ? - source + '@shallow' : - source; - }) - .map(function (source) { - return !self.outerContext.options.relativeTo || /^https?:\/\//.test(source) ? - source : - path.relative(self.outerContext.options.relativeTo, source); - }) - .map(function (source) { return '@import url(' + source + ');'; }) - .join(''); -} - -function fromHash(self) { - var data = []; - var toBase = path.resolve(self.outerContext.options.target || self.outerContext.options.root); - - for (var source in self.data) { - var styles = self.data[source].styles; - var inputSourceMap = self.data[source].sourceMap; - var isRemote = REMOTE_RESOURCE.test(source); - var absoluteSource = isRemote ? source : path.resolve(source); - var absoluteSourcePath = path.dirname(absoluteSource); - - var rewriteOptions = { - absolute: self.outerContext.options.explicitRoot, - relative: !self.outerContext.options.explicitRoot, - imports: true, - rebase: self.outerContext.options.rebase, - fromBase: absoluteSourcePath, - toBase: isRemote ? absoluteSourcePath : toBase, - urlQuotes: self.outerContext.options.compatibility.properties.urlQuotes - }; - styles = rewriteUrls(styles, rewriteOptions, self.outerContext); - - self.trackSource(source, styles); - - styles = self.outerContext.sourceTracker.store(source, styles); - - // here we assume source map lies in the same directory as `source` does - if (self.outerContext.options.sourceMap && inputSourceMap) - self.outerContext.inputSourceMapTracker.trackLoaded(source, source, inputSourceMap); - - data.push(styles); - } - - return data.join(''); -} - -module.exports = SourceReader; diff --git a/lib/utils/source-tracker.js b/lib/utils/source-tracker.js deleted file mode 100644 index 4cc9b6da..00000000 --- a/lib/utils/source-tracker.js +++ /dev/null @@ -1,31 +0,0 @@ -function SourceTracker() { - this.sources = []; -} - -SourceTracker.prototype.store = function (filename, data) { - this.sources.push(filename); - - return '__ESCAPED_SOURCE_CLEAN_CSS' + (this.sources.length - 1) + '__' + - data + - '__ESCAPED_SOURCE_END_CLEAN_CSS__'; -}; - -SourceTracker.prototype.nextStart = function (data) { - var next = /__ESCAPED_SOURCE_CLEAN_CSS(\d+)__/.exec(data); - - return next ? - { index: next.index, filename: this.sources[~~next[1]] } : - null; -}; - -SourceTracker.prototype.nextEnd = function (data) { - return /__ESCAPED_SOURCE_END_CLEAN_CSS__/g.exec(data); -}; - -SourceTracker.prototype.removeAll = function (data) { - return data - .replace(/__ESCAPED_SOURCE_CLEAN_CSS\d+__/g, '') - .replace(/__ESCAPED_SOURCE_END_CLEAN_CSS__/g, ''); -}; - -module.exports = SourceTracker; diff --git a/test/batch-test.js b/test/batch-test.js index 20b3d3fe..9ed68f16 100644 --- a/test/batch-test.js +++ b/test/batch-test.js @@ -6,6 +6,9 @@ var CleanCSS = require('../index'); var lineBreak = require('os').EOL; +if (process.platform == 'win32') + return; + var batchContexts = function () { var context = {}; var dir = path.join(__dirname, 'fixtures'); diff --git a/test/fixtures/big-min.css b/test/fixtures/big-min.css index 0f1ceeb3..4a5b9d33 100644 --- a/test/fixtures/big-min.css +++ b/test/fixtures/big-min.css @@ -253,7 +253,7 @@ section article{margin:0 0 16px} .bord_double_gris_blanc{line-height:25px;font-size:12px;display:inline-block;border:solid #d2d6db;border-width:1px 0} .bord_double_gris_blanc span{display:inline-block;border:solid #fff;border-width:1px 0} .bloc_abo{border-top:3px solid #ffd500} -img[width="642"],img[width="312"]{margin-bottom:6px} +img[width="312"],img[width="642"]{margin-bottom:6px} img[width="202"]{margin-bottom:4px} .btn,.btn_abo,.btn_fonce,.btn_petit{display:inline-block;padding:4px 10px;margin-bottom:0;color:#000b15;text-align:center;font-weight:700;vertical-align:middle;background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(top,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);cursor:pointer} .bt_fonce a,.btn_fonce{color:#fff;background-color:#000b15;background-image:-moz-linear-gradient(top,#5d666d,#000b15);background-image:-ms-linear-gradient(top,#5d666d,#000b15);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5d666d),to(#000b15));background-image:-webkit-linear-gradient(top,#5d666d,#000b15);background-image:-o-linear-gradient(top,#5d666d,#000b15);background-image:linear-gradient(top,#5d666d,#000b15);background-repeat:repeat-x;border-color:#000b15;border-color:rgba(0,0,0,.1)} @@ -2374,13 +2374,12 @@ body.init-bar-is-closed #bar-liberation{height:15px} #page-mailfriend .content input[type=checkbox]{float:right;margin-top:5px} #page-mailfriend .content label{float:left;display:block;width:80%;font-weight:700} #page-paywall{width:520px;font-size:12px} -#page-paywall .content .arguments .arg .price,#page-paywall .content .arguments .arg h4,#page-paywall .content .video h5{font-family:Georgia,"Times New Roman",Times,serif} #page-paywall .content{position:relative;padding:20px 0} #page-paywall .content a.close{display:block;float:right} #page-paywall .content a.close span{background:url(http://s0.libe.com/libe/img/common/_sprites_icons/icons.png?9914d0d70a49) -20px -98px no-repeat;display:block;margin:auto;width:15px;height:15px} #page-paywall .content a.close strong{text-transform:uppercase;font-size:8px} #page-paywall .content .video{margin-bottom:20px;width:437px} -#page-paywall .content .video h5{margin-bottom:15px;padding:3px 0 5px;border-top:1px dotted;border-bottom:1px dotted;float:right;font-size:16px;font-style:italic;font-weight:400} +#page-paywall .content .video h5{margin-bottom:15px;padding:3px 0 5px;border-top:1px dotted;border-bottom:1px dotted;float:right;font-family:Georgia,"Times New Roman",Times,serif;font-size:16px;font-style:italic;font-weight:400} #page-paywall .content .arguments,#page-paywall .content .video h4{margin-bottom:20px;clear:both} #page-paywall .content .video h4 span{float:right;padding:0 0 0 10px;text-transform:uppercase;line-height:13px;font-size:16px;font-weight:400} #page-paywall .content .video .player{width:354px;height:200px;float:right} @@ -2390,8 +2389,8 @@ body.access-ess #page-paywall .content .arguments .arg{float:none;margin:auto} #page-paywall .content .arguments .arg .visual1{height:71px} #page-paywall .content .arguments .arg .visual2{height:76px} #page-paywall .content .arguments .arg h5{margin-bottom:10px;text-transform:uppercase;line-height:13px;font-size:14px;font-weight:400} -#page-paywall .content .arguments .arg h4{margin-bottom:10px;font-size:13px;font-style:italic;font-weight:400} -#page-paywall .content .arguments .arg .price{float:right;width:120px;font-size:13px;margin-bottom:15px} +#page-paywall .content .arguments .arg h4{margin-bottom:10px;font-family:Georgia,"Times New Roman",Times,serif;font-size:13px;font-style:italic;font-weight:400} +#page-paywall .content .arguments .arg .price{float:right;width:120px;font-family:Georgia,"Times New Roman",Times,serif;font-size:13px;margin-bottom:15px} #page-paywall .content .arguments .arg .price strong{display:block;float:left;margin-right:10px;line-height:25px;font-family:Verdana,sans-serif;font-size:30px;letter-spacing:-3px} #page-paywall .content .arguments .arg .price strong .currency,#page-paywall .content .arguments .arg .price strong .decimals{font-size:20px} #page-paywall .content .arguments .arg .price strong .currency{padding-left:3px} diff --git a/test/fixtures/bootstrap-min.css b/test/fixtures/bootstrap-min.css index 3c037e24..db9db193 100644 --- a/test/fixtures/bootstrap-min.css +++ b/test/fixtures/bootstrap-min.css @@ -19,6 +19,7 @@ sub{bottom:-.25em} img{vertical-align:middle} svg:not(:root){overflow:hidden} hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box} +*,:after,:before,input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box} pre,textarea{overflow:auto} code,kbd,pre,samp{font-size:1em} button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit} @@ -28,7 +29,7 @@ button,select{text-transform:none} button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer} button[disabled],html input[disabled]{cursor:default} button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0} -input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0} +input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0} input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto} input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none} table{border-spacing:0;border-collapse:collapse} @@ -38,7 +39,7 @@ td,th{padding:0} a,a:visited{text-decoration:underline} a[href]:after{content:" (" attr(href) ")"} abbr[title]:after{content:" (" attr(title) ")"} -a[href^="javascript:"]:after,a[href^="#"]:after{content:""} +a[href^="#"]:after,a[href^=javascript:]:after{content:""} blockquote,pre{border:1px solid #999} thead{display:table-header-group} img{max-width:100%!important} @@ -315,7 +316,7 @@ select{background:#fff!important} .glyphicon-menu-right:before{content:"\e258"} .glyphicon-menu-down:before{content:"\e259"} .glyphicon-menu-up:before{content:"\e260"} -*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box} +*,:after,:before{box-sizing:border-box} html{font-size:10px;-webkit-tap-highlight-color:transparent} body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333} button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit} @@ -670,7 +671,7 @@ input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-heig input[type=file]{display:block} input[type=range]{display:block;width:100%} select[multiple],select[size]{height:auto} -input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} +input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px} output{padding-top:7px} .form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s} .form-group-sm .form-control,.input-sm{font-size:12px;border-radius:3px;padding:5px 10px} @@ -681,9 +682,9 @@ output{padding-top:7px} .has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .form-control-feedback,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d} .form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1} textarea.form-control{height:auto} -@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px} -.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px} -.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px} +@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=datetime-local],input[type=month],input[type=time]{line-height:34px} +.input-group-sm input[type=date],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],.input-group-sm input[type=time],input[type=date].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm,input[type=time].input-sm{line-height:30px} +.input-group-lg input[type=date],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],.input-group-lg input[type=time],input[type=date].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg,input[type=time].input-lg{line-height:46px} } .form-group{margin-bottom:15px} .checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px} @@ -1312,13 +1313,12 @@ button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;bor .popover>.arrow:after{content:"";border-width:10px} .popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0} .popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0} -.popover.left>.arrow:after,.popover.right>.arrow:after{bottom:-10px;content:" "} .popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0} -.popover.right>.arrow:after{left:1px;border-right-color:#fff;border-left-width:0} +.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0} .popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)} .popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff} .popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)} -.popover.left>.arrow:after{right:1px;border-right-width:0;border-left-color:#fff} +.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff} .carousel-inner{width:100%;overflow:hidden} .carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left} .carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1} diff --git a/test/fixtures/font-awesome-ie7-min.css b/test/fixtures/font-awesome-ie7-min.css index 4a2913e1..a4f6d421 100644 --- a/test/fixtures/font-awesome-ie7-min.css +++ b/test/fixtures/font-awesome-ie7-min.css @@ -23,8 +23,9 @@ * Twitter: http://twitter.com/davegandy * Work: Lead Product Designer @ Kyruus - http://kyruus.com */ -.icon-large{font-size:1.3333333333333333em;margin-top:-4px;padding-top:3px;margin-bottom:-4px;padding-bottom:3px;vertical-align:middle} -.nav [class*=" icon-"],.nav [class^=icon-]{vertical-align:inherit;margin-top:-4px;padding-top:3px;margin-bottom:-4px;padding-bottom:3px} +.icon-large,.nav [class*=" icon-"],.nav [class^=icon-]{margin-top:-4px;padding-top:3px;margin-bottom:-4px;padding-bottom:3px} +.icon-large{font-size:1.3333333333333333em;vertical-align:middle} +.nav [class*=" icon-"],.nav [class^=icon-]{vertical-align:inherit} .nav [class*=" icon-"].icon-large,.nav [class^=icon-].icon-large{vertical-align:-25%} .nav-pills [class*=" icon-"].icon-large,.nav-pills [class^=icon-].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-tabs [class^=icon-].icon-large{line-height:.75em;margin-top:-7px;padding-top:5px;margin-bottom:-5px;padding-bottom:4px} .btn [class*=" icon-"].pull-left,.btn [class*=" icon-"].pull-right,.btn [class^=icon-].pull-left,.btn [class^=icon-].pull-right{vertical-align:inherit} diff --git a/test/fixtures/issue-308-min.css b/test/fixtures/issue-308-min.css index db80a901..fa78f3b5 100644 --- a/test/fixtures/issue-308-min.css +++ b/test/fixtures/issue-308-min.css @@ -1 +1 @@ -p{background-image:url(/*)} +p{background-image:url('/*')} \ No newline at end of file diff --git a/test/integration-test.js b/test/integration-test.js index c422021f..a19d5e49 100644 --- a/test/integration-test.js +++ b/test/integration-test.js @@ -396,7 +396,7 @@ vows.describe('integration tests') ], 'inside url': [ 'p{background-image:url(\'/*\')}/* */', - 'p{background-image:url(/*)}' + 'p{background-image:url(\'/*\')}' ], 'inside url twice': [ 'p{background-image:url(\'/* */\" /*\')}/* */', @@ -404,7 +404,7 @@ vows.describe('integration tests') ], 'inside url with more quotation': [ 'p{background-image:url(\'/*\');content:""/* */}', - 'p{background-image:url(/*);content:""}' + 'p{background-image:url(\'/*\');content:""}' ], 'with quote marks': [ '/*"*//* */', @@ -524,7 +524,7 @@ vows.describe('integration tests') ], 'open ended (broken)': [ 'a{width:expression(this.parentNode.innerText == }', - 'a{width:expression(this.parentNode.innerText == }' + 'a{width:expression(this.parentNode.innerText ==}' ], 'function call & advanced': [ 'a{zoom:expression(function (el){el.style.zoom="1"}(this))}', @@ -1250,10 +1250,6 @@ vows.describe('integration tests') 'a{background:url(/images/blank.png)}', 'a{background:url(/images/blank.png)}' ], - 'keep non-encoded data URI unchanged': [ - '.icon-logo{background-image:url(\'data:image/svg+xml;charset=US-ASCII\')}', - '.icon-logo{background-image:url(\'data:image/svg+xml;charset=US-ASCII\')}' - ], 'strip quotes from base64 encoded PNG data URI': [ '.icon-logo{background-image:url(\'data:image/png;base64,iVBORw0\')}', '.icon-logo{background-image:url(data:image/png;base64,iVBORw0)}' @@ -1264,11 +1260,11 @@ vows.describe('integration tests') ], 'cut off url content on selector level': [ 'a{background:url(image/}', - 'a{background:url(image/}' + '' ], 'cut off url content on block level': [ '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA}', - '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA}' + '' ], 'cut off url content on top level': [ '@font-face{src:url(data:application/x-font-woff;base64,d09GRk9UVE8AAENAAA0AAAAA', @@ -1368,11 +1364,11 @@ vows.describe('integration tests') ], 'keep quoting if whitespace': [ 'a{background:url("/images/blank image.png")}', - 'a{background:url(\'/images/blank image.png\')}' + 'a{background:url("/images/blank image.png")}' ], 'keep quoting if whitespace inside @font-face': [ '@font-face{src:url("/Helvetica Neue.eot")}', - '@font-face{src:url(\'/Helvetica Neue.eot\')}' + '@font-face{src:url("/Helvetica Neue.eot")}' ], 'keep SVG data URI unchanged': [ 'div{background:url(data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2018%2018%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%2214%22%20height%3D%2214%22%2Fsvg%3E)}', @@ -1838,12 +1834,12 @@ vows.describe('integration tests') 'a[href="/version-0.01.html"]{display:block}', 'a[href="/version-0.01.html"]{display:block}' ], - 'should strip new lines inside attributes': [ - '.test[title="my very long ' + lineBreak + 'title"]{display:block}', + 'should strip escaped new lines inside attributes': [ + '.test[title="my very long \\' + lineBreak + 'title"]{display:block}', '.test[title="my very long title"]{display:block}' ], - 'should strip new lines inside attributes which can be unquoted': [ - '.test[title="my_very_long_' + lineBreak + 'title"]{display:block}', + 'should strip escaped new lines inside attributes which can be unquoted': [ + '.test[title="my_very_long_\\' + lineBreak + 'title"]{display:block}', '.test[title=my_very_long_title]{display:block}' ], 'should strip whitespace between square brackets': [ @@ -2675,10 +2671,6 @@ vows.describe('integration tests') 'a{--my-toolbar: { margin:10px; margin-top:10px };}', 'a{--my-toolbar:{margin:10px};}' ], - 'Polymer mixins - not fitting into a single chunk of 128 bytes': [ - ':host{--live-head-theme: { line-height: 40px !important; vertical-align: middle; background: transparent; height: 40px; z-index: 999; }; }', - ':host{--live-head-theme:{line-height:40px!important;vertical-align:middle;background:0 0;height:40px;z-index:999};}' - ], 'Polymer mixins - inlined variables': [ '.spinner{-webkit-animation:container-rotate var(--paper-spinner-container-rotation-duration) linear infinite}', '.spinner{-webkit-animation:container-rotate var(--paper-spinner-container-rotation-duration) linear infinite}' diff --git a/test/module-test.js b/test/module-test.js index 695ac226..2f97d1f0 100644 --- a/test/module-test.js +++ b/test/module-test.js @@ -474,22 +474,6 @@ vows.describe('module tests').addBatch({ 'should give right output': function (minified) { assert.equal(minified.styles, '@import url(one.css);@import url(extra/three.css);@import url(./extra/four.css);.two{color:#fff}'); } - }, - 'off - many files': { - 'topic': function () { - return new CleanCSS({ processImport: false }).minify(['./test/fixtures/partials/remote.css', './test/fixtures/partials-absolute/base.css']); - }, - 'should give right output': function (minified) { - assert.equal(minified.styles, '@import url(http://jakubpawlowicz.com/styles.css);@import url(./extra/sub.css);.base{margin:0}'); - } - }, - 'off - many files with content': { - 'topic': function () { - return new CleanCSS({ processImport: false }).minify(['./test/fixtures/partials/two.css', './test/fixtures/partials-absolute/base.css']); - }, - 'should give right output': function (minified) { - assert.equal(minified.styles, '@import url(one.css);@import url(extra/three.css);@import url(./extra/four.css);.two{color:#fff}.base{margin:0}'); - } } } }, diff --git a/test/selectors/advanced-test.js b/test/optimizer/advanced-test.js similarity index 100% rename from test/selectors/advanced-test.js rename to test/optimizer/advanced-test.js diff --git a/test/selectors/simple-test.js b/test/optimizer/basic-test.js similarity index 57% rename from test/selectors/simple-test.js rename to test/optimizer/basic-test.js index edcd8d82..5393ee99 100644 --- a/test/selectors/simple-test.js +++ b/test/optimizer/basic-test.js @@ -1,887 +1,886 @@ var vows = require('vows'); -var selectorContext = require('../test-helper').selectorContext; -var propertyContext = require('../test-helper').propertyContext; +var optimizerContext = require('../test-helper').optimizerContext; vows.describe('simple optimizations') .addBatch( - selectorContext('default', { + optimizerContext('selectors', { 'optimized': [ 'a{}', - null + '' ], 'whitespace': [ ' div > span{color:red}', - [['div>span']] + 'div>span{color:red}' ], 'line breaks': [ ' div >\n\r\n span{color:red}', - [['div>span']] + 'div>span{color:red}' ], 'more line breaks': [ '\r\ndiv\n{color:red}', - [['div']] + 'div{color:red}' ], '+html': [ - '*+html .foo{display:inline}', - null + '*+html .foo{color:red}', + '' ], 'adjacent nav': [ 'div + nav{color:red}', - [['div+nav']] + 'div+nav{color:red}' ], 'heading & trailing': [ ' a {color:red}', - [['a']] + 'a{color:red}' ], 'descendant selector': [ 'div > a{color:red}', - [['div>a']] + 'div>a{color:red}' ], 'next selector': [ 'div + a{color:red}', - [['div+a']] + 'div+a{color:red}' ], 'sibling selector': [ 'div ~ a{color:red}', - [['div~a']] + 'div~a{color:red}' ], 'pseudo classes': [ 'div :first-child{color:red}', - [['div :first-child']] + 'div :first-child{color:red}' ], 'tabs': [ 'div\t\t{color:red}', - [['div']] + 'div{color:red}' ], 'universal selector - id, class, and property': [ '* > *#id > *.class > *[property]{color:red}', - [['*>#id>.class>[property]']] + '*>#id>.class>[property]{color:red}' ], 'universal selector - pseudo': [ '*:first-child{color:red}', - [[':first-child']] + ':first-child{color:red}' ], 'universal selector - standalone': [ 'label ~ * + span{color:red}', - [['label~*+span']] + 'label~*+span{color:red}' ], 'order': [ 'b,div,a{color:red}', - [['a'], ['b'], ['div']] + 'a,b,div{color:red}' ], 'duplicates': [ 'a,div,.class,.class,a ,div > a{color:red}', - [['.class'], ['a'], ['div'], ['div>a']] + '.class,a,div,div>a{color:red}', ], 'mixed': [ ' label ~ \n* + span , div>*.class, section\n\n{color:red}', - [['div>.class'], ['label~*+span'], ['section']] + 'div>.class,label~*+span,section{color:red}' ], 'escaped joining character #1': [ - '.class\\~ div{color: red}', - [['.class\\~ div']] + '.class\\~ div{color:red}', + '.class\\~ div{color:red}' ], 'escaped joining character #2': [ - '.class\\+\\+ div{color: red}', - [['.class\\+\\+ div']] + '.class\\+\\+ div{color:red}', + '.class\\+\\+ div{color:red}' ], 'escaped joining character #3': [ - '.class\\> \\~div{color: red}', - [['.class\\> \\~div']] + '.class\\> \\~div{color:red}', + '.class\\> \\~div{color:red}' ], 'escaped characters': [ - '.a\\+\\+b{color: red}', - [['.a\\+\\+b']] + '.a\\+\\+b{color:red}', + '.a\\+\\+b{color:red}' ] - }) + }, { advanced: false }) ) .addBatch( - selectorContext('ie8', { + optimizerContext('selectors - ie8', { '+html': [ - '*+html .foo{display:inline}', - null + '*+html .foo{color:red}', + '' ], '+first-child html': [ - '*:first-child+html .foo{display:inline}', - null + '*:first-child+html .foo{color:red}', + '' ], '+html - complex': [ - '*+html .foo,.bar{display:inline}', - [['.bar']] + '*+html .foo,.bar{color:red}', + '.bar{color:red}' ] - }, { compatibility: 'ie8' }) + }, { advanced: false, compatibility: 'ie8' }) ) .addBatch( - selectorContext('ie7', { + optimizerContext('selectors - ie7', { '+html': [ - '*+html .foo{display:inline}', - [['*+html .foo']] + '*+html .foo{color:red}', + '*+html .foo{color:red}' ], '+html - complex': [ - '*+html .foo,.bar{display:inline}', - [['*+html .foo'], ['.bar']] + '*+html .foo,.bar{color:red}', + '*+html .foo,.bar{color:red}' ] - }, { compatibility: 'ie7' }) + }, { advanced: false, compatibility: 'ie7' }) ) .addBatch( - selectorContext('+adjacentSpace', { + optimizerContext('selectors - adjacent space', { 'with whitespace': [ 'div + nav{color:red}', - [['div+ nav']] + 'div+ nav{color:red}' ], 'without whitespace': [ 'div+nav{color:red}', - [['div+ nav']] + 'div+ nav{color:red}' ] - }, { compatibility: { selectors: { adjacentSpace: true } } }) + }, { advanced: false, compatibility: { selectors: { adjacentSpace: true } } }) ) .addBatch( - propertyContext('@background', { + optimizerContext('background', { 'none to 0 0': [ 'a{background:none}', - [['background', '0 0']] + 'a{background:0 0}' ], 'transparent to 0 0': [ 'a{background:transparent}', - [['background', '0 0']] + 'a{background:0 0}' ], 'any other': [ 'a{background:red}', - [['background', 'red']] + 'a{background:red}' ], 'none to other': [ 'a{background:transparent no-repeat}', - [['background', 'transparent', 'no-repeat']] + 'a{background:transparent no-repeat}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('@border-*-radius', { + optimizerContext('border-*-radius', { 'spaces around /': [ 'a{border-radius:2em / 1em}', - [['border-radius', '2em', '/', '1em']] + 'a{border-radius:2em/1em}' ], 'symmetric expanded to shorthand': [ 'a{border-radius:1em 2em 3em 4em / 1em 2em 3em 4em}', - [['border-radius', '1em', '2em', '3em', '4em']] + 'a{border-radius:1em 2em 3em 4em}' ], 'asymmetric kept as is': [ 'a{border-top-left-radius:1em 2em}', - [['border-top-left-radius', '1em', '2em']] + 'a{border-top-left-radius:1em 2em}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('@box-shadow', { + optimizerContext('box-shadow', { 'four zeros': [ 'a{box-shadow:0 0 0 0}', - [['box-shadow', '0', '0']] + 'a{box-shadow:0 0}' ], 'four zeros in vendor prefixed': [ 'a{-webkit-box-shadow:0 0 0 0}', - [['-webkit-box-shadow', '0', '0']] + 'a{-webkit-box-shadow:0 0}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('colors', { + optimizerContext('colors', { 'rgb to hex': [ 'a{color:rgb(255,254,253)}', - [['color', '#fffefd']] + 'a{color:#fffefd}' ], 'rgba not to hex': [ 'a{color:rgba(255,254,253,.5)}', - [['color', 'rgba(255,254,253,.5)']] + 'a{color:rgba(255,254,253,.5)}' ], 'hsl to hex': [ 'a{color:hsl(240,100%,50%)}', - [['color', '#00f']] + 'a{color:#00f}' ], 'hsla not to hex': [ 'a{color:hsla(240,100%,50%,.5)}', - [['color', 'hsla(240,100%,50%,.5)']] + 'a{color:hsla(240,100%,50%,.5)}' ], 'long hex to short hex': [ 'a{color:#ff00ff}', - [['color', '#f0f']] + 'a{color:#f0f}' ], 'hex to name': [ 'a{color:#f00}', - [['color', 'red']] + 'a{color:red}' ], 'name to hex': [ 'a{color:white}', - [['color', '#fff']] + 'a{color:#fff}' ], 'transparent black rgba to transparent': [ 'a{color:rgba(0,0,0,0)}', - [['color', 'transparent']] + 'a{color:transparent}' ], 'transparent non-black rgba': [ 'a{color:rgba(255,0,0,0)}', - [['color', 'rgba(255,0,0,0)']] + 'a{color:rgba(255,0,0,0)}' ], 'transparent black hsla to transparent': [ 'a{color:hsla(0,0%,0%,0)}', - [['color', 'transparent']] + 'a{color:transparent}' ], 'transparent non-black hsla': [ 'a{color:rgba(240,0,0,0)}', - [['color', 'rgba(240,0,0,0)']] + 'a{color:rgba(240,0,0,0)}' ], 'partial hex to name': [ 'a{color:#f00000}', - [['color', '#f00000']] + 'a{color:#f00000}' ], 'partial hex further down to name': [ 'a{background:url(test.png) #f00000}', - [['background', 'url(test.png)', '#f00000']] + 'a{background:url(test.png) #f00000}' ], 'partial name to hex': [ 'a{color:greyish}', - [['color', 'greyish']] + 'a{color:greyish}' ], 'partial name further down to hex': [ 'a{background:url(test.png) blueish}', - [['background', 'url(test.png)', 'blueish']] + 'a{background:url(test.png) blueish}' ], 'partial name as a suffix': [ 'a{font-family:alrightsanslp-black}', - [['font-family', 'alrightsanslp-black']] + 'a{font-family:alrightsanslp-black}' ], 'invalid rgba declaration - color': [ 'a{color:rgba(255 0 0)}', - [['color', 'rgba(255 0 0)']] + 'a{color:rgba(255 0 0)}' ], 'invalid rgba declaration - background': [ 'a{background:rgba(255 0 0)}', - [['background', 'rgba(255 0 0)']] + 'a{background:rgba(255 0 0)}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('colors - ie8 compatibility', { + optimizerContext('colors - ie8 compatibility', { 'transparent black rgba': [ 'a{color:rgba(0,0,0,0)}', - [['color', 'rgba(0,0,0,0)']] + 'a{color:rgba(0,0,0,0)}' ], 'transparent non-black rgba': [ 'a{color:rgba(255,0,0,0)}', - [['color', 'rgba(255,0,0,0)']] + 'a{color:rgba(255,0,0,0)}' ], 'transparent black hsla': [ 'a{color:hsla(0,0%,0%,0)}', - [['color', 'hsla(0,0%,0%,0)']] + 'a{color:hsla(0,0%,0%,0)}' ], 'transparent non-black hsla': [ 'a{color:rgba(240,0,0,0)}', - [['color', 'rgba(240,0,0,0)']] + 'a{color:rgba(240,0,0,0)}' ] - }, { compatibility: 'ie8' }) + }, { advanced: false, compatibility: 'ie8' }) ) .addBatch( - propertyContext('colors - no optimizations', { + optimizerContext('colors - no optimizations', { 'long hex into short': [ 'a{color:#ff00ff}', - [['color', '#ff00ff']] + 'a{color:#ff00ff}' ], 'short hex into name': [ 'a{color:#f00}', - [['color', '#f00']] + 'a{color:#f00}' ], 'name into hex': [ 'a{color:white}', - [['color', 'white']] + 'a{color:white}' ] - }, { compatibility: { properties: { colors: false } } }) + }, { advanced: false, compatibility: { properties: { colors: false } } }) ) .addBatch( - propertyContext('@filter', { + optimizerContext('filter', { 'spaces after comma': [ 'a{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=\'#cccccc\',endColorstr=\'#000000\', enabled=true)}', - [['filter', 'progid:DXImageTransform.Microsoft.gradient(startColorstr=\'#cccccc\', endColorstr=\'#000000\', enabled=true)']] + 'a{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=\'#cccccc\', endColorstr=\'#000000\', enabled=true)}' ], 'single Alpha filter': [ 'a{filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80)}', - [['filter', 'alpha(Opacity=80)']] + 'a{filter:alpha(Opacity=80)}' ], 'single Chroma filter': [ 'a{filter:progid:DXImageTransform.Microsoft.Chroma(color=#919191)}', - [['filter', 'chroma(color=#919191)']] + 'a{filter:chroma(color=#919191)}' ], 'multiple filters': [ 'a{filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80) progid:DXImageTransform.Microsoft.Chroma(color=#919191)}', - [['filter', 'progid:DXImageTransform.Microsoft.Alpha(Opacity=80)', 'progid:DXImageTransform.Microsoft.Chroma(color=#919191)']] + 'a{filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80) progid:DXImageTransform.Microsoft.Chroma(color=#919191)}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('@font', { + optimizerContext('font', { 'in shorthand': [ 'a{font:normal 13px/20px sans-serif}', - [['font', '400', '13px', '/', '20px', 'sans-serif']] + 'a{font:400 13px/20px sans-serif}' ], 'in shorthand with fractions': [ 'a{font:bold .9em sans-serif}', - [['font', '700', '.9em', 'sans-serif']] + 'a{font:700 .9em sans-serif}' ], 'with font wariant and style': [ 'a{font:normal normal normal 13px/20px sans-serif}', - [['font', 'normal', 'normal', 'normal', '13px', '/', '20px', 'sans-serif']] + 'a{font:normal normal normal 13px/20px sans-serif}' ], 'with mixed order of variant and style': [ 'a{font:normal 300 normal 13px/20px sans-serif}', - [['font', 'normal', '300', 'normal', '13px', '/', '20px', 'sans-serif']] + 'a{font:normal 300 normal 13px/20px sans-serif}' ], 'with mixed normal and weight': [ - 'a{font: normal small-caps 400 medium Georgia, sans-serif;}', - [['font', 'normal', 'small-caps', '400', 'medium', 'Georgia', ',', 'sans-serif']] + 'a{font:normal small-caps 400 medium Georgia,sans-serif}', + 'a{font:normal small-caps 400 medium Georgia,sans-serif}' ], 'with line height': [ - 'a{font: 11px/normal sans-serif}', - [['font', '11px', '/', 'normal', 'sans-serif']] + 'a{font:11px/normal sans-serif}', + 'a{font:11px/normal sans-serif}' ], 'with mixed bold weight and variant #1': [ 'a{font:normal bold 17px sans-serif}', - [['font', 'normal', '700', '17px', 'sans-serif']] + 'a{font:normal 700 17px sans-serif}' ], 'with mixed bold weight and variant #2': [ 'a{font:bold normal 17px sans-serif}', - [['font', '700', 'normal', '17px', 'sans-serif']] + 'a{font:700 normal 17px sans-serif}' ], 'with mixed bold weight and variant #3': [ 'a{font:bold normal normal 17px sans-serif}', - [['font', 'bold', 'normal', 'normal', '17px', 'sans-serif']] // pending #254 + 'a{font:bold normal normal 17px sans-serif}' // pending #254 ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('@font-weight', { + optimizerContext('font-weight', { 'normal to 400': [ 'a{font-weight:normal}', - [['font-weight', '400']] + 'a{font-weight:400}' ], 'bold to 700': [ 'a{font-weight:bold}', - [['font-weight', '700']] + 'a{font-weight:700}' ], 'any other': [ 'a{font-weight:bolder}', - [['font-weight', 'bolder']] + 'a{font-weight:bolder}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('ie hacks', { + optimizerContext('ie hacks', { 'underscore': [ 'a{_width:101px}', - null + '' ], 'star': [ 'a{*width:101px}', - null + '' ], 'backslash': [ 'a{width:101px\\9}', - [['width', '101px\\9']] + 'a{width:101px\\9}' ], 'bang': [ 'a{color:red !ie}', - null + '' ], 'before content': [ 'a{*width:101px;color:red!important}', - [['color', 'red!important']] + 'a{color:red!important}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('ie hacks in IE8 mode', { + optimizerContext('ie hacks in IE8 mode', { 'underscore': [ 'a{_width:101px}', - [['_width', '101px']] + 'a{_width:101px}' ], 'star': [ 'a{*width:101px}', - [['*width', '101px']] + 'a{*width:101px}' ], 'backslash': [ 'a{width:101px\\9}', - [['width', '101px\\9']] + 'a{width:101px\\9}' ], 'bang': [ 'a{color:red !ie}', - null + '' ] - }, { compatibility: 'ie8' }) + }, { advanced: false, compatibility: 'ie8' }) ) .addBatch( - propertyContext('ie hacks in IE7 mode', { + optimizerContext('ie hacks in IE7 mode', { 'underscore': [ 'a{_width:101px}', - [['_width', '101px']] + 'a{_width:101px}' ], 'star': [ 'a{*width:101px}', - [['*width', '101px']] + 'a{*width:101px}' ], 'backslash': [ 'a{width:101px\\9}', - [['width', '101px\\9']] + 'a{width:101px\\9}' ], 'bang': [ 'a{color:red !ie}', - [['color', 'red !ie']] + 'a{color:red !ie}' ] - }, { compatibility: 'ie7' }) + }, { advanced: false, compatibility: 'ie7' }) ) .addBatch( - propertyContext('important', { + optimizerContext('important', { 'minified': [ 'a{color:red!important}', - [['color', 'red!important']] + 'a{color:red!important}' ], 'space before !': [ 'a{color:red !important}', - [['color', 'red!important']] + 'a{color:red!important}', ], 'space after !': [ 'a{color:red! important}', - [['color', 'red!important']] + 'a{color:red!important}' ] - }, { compatibility: 'ie8' }) + }, { advanced: false }) ) .addBatch( - propertyContext('@outline', { + optimizerContext('outline', { 'none to 0': [ 'a{outline:none}', - [['outline', '0']] + 'a{outline:0}' ], 'any other': [ 'a{outline:10px}', - [['outline', '10px']] + 'a{outline:10px}' ], 'none and any other': [ 'a{outline:none solid 1px}', - [['outline', 'none', 'solid', '1px']] + 'a{outline:none solid 1px}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('rounding', { + optimizerContext('rounding', { 'pixels': [ 'a{transform:translateY(123.31135px)}', - [['transform', 'translateY(123.311px)']] + 'a{transform:translateY(123.311px)}' ], 'percents': [ 'a{left:20.1231%}', - [['left', '20.1231%']] + 'a{left:20.1231%}' ], 'ems': [ 'a{left:1.1231em}', - [['left', '1.1231em']] + 'a{left:1.1231em}' ] - }, { roundingPrecision: 3 }) + }, { advanced: false, roundingPrecision: 3 }) ) .addBatch( - propertyContext('rounding disabled', { + optimizerContext('rounding disabled', { 'pixels': [ 'a{transform:translateY(123.31135px)}', - [['transform', 'translateY(123.31135px)']] + 'a{transform:translateY(123.31135px)}' ], 'percents': [ 'a{left:20.1231%}', - [['left', '20.1231%']] + 'a{left:20.1231%}' ], 'ems': [ 'a{left:1.1231em}', - [['left', '1.1231em']] + 'a{left:1.1231em}' ] - }, { roundingPrecision: -1 }) + }, { advanced: false, roundingPrecision: -1 }) ) .addBatch( - propertyContext('rounding disabled when option value not castable to int', { + optimizerContext('rounding disabled when option value not castable to int', { 'pixels': [ 'a{transform:translateY(123.31135px)}', - [['transform', 'translateY(123.31135px)']] + 'a{transform:translateY(123.31135px)}' ], 'percents': [ 'a{left:20.1231%}', - [['left', '20.1231%']] + 'a{left:20.1231%}' ], 'ems': [ 'a{left:1.1231em}', - [['left', '1.1231em']] + 'a{left:1.1231em}' ] - }, { roundingPrecision: '\'-1\'' }) + }, { advanced: false, roundingPrecision: '\'-1\'' }) ) .addBatch( - propertyContext('units', { + optimizerContext('units', { 'pixels': [ 'a{width:0px}', - [['width', '0']] + 'a{width:0}' ], 'degrees': [ 'div{background:linear-gradient(0deg,red,#fff)}', - [['background', 'linear-gradient(0deg,red,#fff)']] + 'div{background:linear-gradient(0deg,red,#fff)}' ], 'degrees when not mixed': [ 'div{transform:rotate(0deg) skew(0deg)}', - [['transform', 'rotate(0)', 'skew(0)']] + 'div{transform:rotate(0) skew(0)}' ], 'non-zero degrees when not mixed': [ 'div{transform:rotate(10deg) skew(.5deg)}', - [['transform', 'rotate(10deg)', 'skew(.5deg)']] + 'div{transform:rotate(10deg) skew(.5deg)}' ], 'ch': [ 'div{width:0ch;height:0ch}', - [['width', '0'], ['height', '0']] + 'div{width:0;height:0}' ], 'rem': [ 'div{width:0rem;height:0rem}', - [['width', '0'], ['height', '0']] + 'div{width:0;height:0}' ], 'vh': [ 'div{width:0vh;height:0vh}', - [['width', '0'], ['height', '0']] + 'div{width:0;height:0}' ], 'vm': [ 'div{width:0vm;height:0vm}', - [['width', '0'], ['height', '0']] + 'div{width:0;height:0}' ], 'vmax': [ 'div{width:0vmax;height:0vmax}', - [['width', '0'], ['height', '0']] + 'div{width:0;height:0}' ], 'vmin': [ 'div{width:0vmin;height:0vmin}', - [['width', '0'], ['height', '0']] + 'div{width:0;height:0}' ], 'vw': [ 'div{width:0vw;height:0vw}', - [['width', '0'], ['height', '0']] + 'div{width:0;height:0}' ], 'mixed units': [ 'a{margin:0em 0rem 0px 0pt}', - [['margin', '0']] + 'a{margin:0}' ], 'mixed values #1': [ 'a{padding:10px 0em 30% 0rem}', - [['padding', '10px', '0', '30%', '0']] + 'a{padding:10px 0 30% 0}' ], 'mixed values #2': [ 'a{padding:10ch 0vm 30vmin 0vw}', - [['padding', '10ch', '0', '30vmin', '0']] + 'a{padding:10ch 0 30vmin 0}' ], 'inside calc': [ 'a{font-size:calc(100% + 0px)}', - [['font-size', 'calc(100% + 0px)']] + 'a{font-size:calc(100% + 0px)}' ], 'flex': [ - 'a{flex: 1 0 0%}', - [['flex', '1', '0', '0%']] + 'a{flex:1 0 0%}', + 'a{flex:1 0 0%}' ], 'flex–basis': [ 'a{flex-basis:0%}', - [['flex-basis', '0%']] + 'a{flex-basis:0%}' ], 'prefixed flex': [ - 'a{-ms-flex:1 0 0px;-webkit-flex:1 0 0px;}', - [['-ms-flex', '1', '0', '0px'], ['-webkit-flex', '1', '0', '0px']] + 'a{-ms-flex:1 0 0px;-webkit-flex:1 0 0px}', + 'a{-ms-flex:1 0 0px;-webkit-flex:1 0 0px}' ], 'prefixed flex–basis': [ 'a{-webkit-flex-basis:0px}', - [['-webkit-flex-basis', '0px']] + 'a{-webkit-flex-basis:0px}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('units in compatibility mode', { + optimizerContext('units in compatibility mode', { 'pixels': [ 'a{width:0px}', - [['width', '0']] + 'a{width:0}' ], 'mixed units': [ 'a{margin:0em 0rem 0px 0pt}', - [['margin', '0', '0rem', '0', '0']] + 'a{margin:0 0rem 0 0}' ], 'mixed values #1': [ 'a{padding:10px 0em 30% 0rem}', - [['padding', '10px', '0', '30%', '0rem']] + 'a{padding:10px 0 30% 0rem}' ], 'mixed values #2': [ 'a{padding:10ch 0vm 30vmin 0vw}', - [['padding', '10ch', '0vm', '30vmin', '0vw']] + 'a{padding:10ch 0vm 30vmin 0vw}' ] - }, { compatibility: 'ie8' }) + }, { advanced: false, compatibility: 'ie8' }) ) .addBatch( - propertyContext('zeros', { + optimizerContext('zeros', { '-0 to 0': [ 'a{margin:-0}', - [['margin', '0']] + 'a{margin:0}' ], '-0px to 0': [ 'a{margin:-0px}', - [['margin', '0']] + 'a{margin:0}' ], '-0% to 0': [ 'a{width:-0%}', - [['width', '0']] + 'a{width:0}' ], 'missing': [ 'a{opacity:1.}', - [['opacity', '1']] + 'a{opacity:1}' ], 'multiple': [ 'a{margin:-0 -0 -0 -0}', - [['margin', '0']] + 'a{margin:0}' ], 'keeps negative non-zero': [ 'a{margin:-0.5em}', - [['margin', '-.5em']] + 'a{margin:-.5em}' ], 'inside names #1': [ 'div{animation-name:test-0-bounce}', - [['animation-name', 'test-0-bounce']] + 'div{animation-name:test-0-bounce}' ], 'inside names #2': [ 'div{animation-name:test-0bounce}', - [['animation-name', 'test-0bounce']] + 'div{animation-name:test-0bounce}' ], 'inside names #3': [ 'div{animation-name:test-0px}', - [['animation-name', 'test-0px']] + 'div{animation-name:test-0px}' ], 'strips leading from value': [ 'a{padding:010px 0015px}', - [['padding', '10px', '15px']] + 'a{padding:10px 15px}' ], 'strips leading from fractions': [ 'a{margin:-0.5em}', - [['margin', '-.5em']] + 'a{margin:-.5em}' ], 'strips trailing from opacity': [ 'a{opacity:1.0}', - [['opacity', '1']] + 'a{opacity:1}' ], '.0 to 0': [ 'a{margin:.0 .0 .0 .0}', - [['margin', '0']] + 'a{margin:0}' ], 'fraction zeros': [ 'a{margin:10.0em 15.50em 10.01em 0.0em}', - [['margin', '10em', '15.5em', '10.01em', '0']] + 'a{margin:10em 15.5em 10.01em 0}' ], 'fraction zeros after rounding': [ 'a{margin:10.0010px}', - [['margin', '10px']] + 'a{margin:10px}' ], 'four zeros into one': [ 'a{margin:0 0 0 0}', - [['margin', '0']] + 'a{margin:0}' ], 'rect zeros': [ 'a{clip:rect(0px 0px 0px 0px)}', - [['clip', 'rect(0 0 0 0)']] + 'a{clip:rect(0 0 0 0)}' ], 'rect zeros with non-zero value': [ 'a{clip:rect(0.5% 0px 0px 0px)}', - [['clip', 'rect(.5% 0 0 0)']] + 'a{clip:rect(.5% 0 0 0)}' ], 'rect zeros with commas': [ 'a{clip:rect(0px, 0px, 0px, 0px)}', - [['clip', 'rect(0,0,0,0)']] + 'a{clip:rect(0,0,0,0)}' ], 'height': [ 'a{height:0%}', - [['height', '0%']] + 'a{height:0%}' ], 'min-height': [ 'a{min-height:0%}', - [['min-height', '0']] + 'a{min-height:0}' ], 'max-height': [ 'a{max-height:0%}', - [['max-height', '0%']] + 'a{max-height:0%}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('zeros with disabled zeroUnits', { + optimizerContext('zeros with disabled zeroUnits', { '10.0em': [ 'a{margin:10.0em}', - [['margin', '10em']] + 'a{margin:10em}' ], '0px': [ 'a{margin:0px}', - [['margin', '0px']] + 'a{margin:0px}' ], '0px 0px': [ 'a{margin:0px 0px}', - [['margin', '0px', '0px']] + 'a{margin:0px 0px}' ], '0deg': [ 'div{transform:rotate(0deg) skew(0deg)}', - [['transform', 'rotate(0deg)', 'skew(0deg)']] + 'div{transform:rotate(0deg) skew(0deg)}' ], '0%': [ 'a{height:0%}', - [['height', '0%']] + 'a{height:0%}' ], '10%': [ 'a{width:10%}', - [['width', '10%']] + 'a{width:10%}' ] - }, { compatibility: { properties: { zeroUnits: false } } }) + }, { advanced: false, compatibility: { properties: { zeroUnits: false } } }) ) .addBatch( - propertyContext('comments', { + optimizerContext('comments', { 'comment': [ - 'a{__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0__color:red__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS1__}', - ['__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS0__', '__ESCAPED_COMMENT_SPECIAL_CLEAN_CSS1__', ['color', 'red']] + 'a{/*! comment 1 */color:red/*! comment 2 */}', + 'a{/*! comment 1 */color:red/*! comment 2 */}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('whitespace', { + optimizerContext('whitespace', { 'stripped spaces': [ 'div{text-shadow:rgba(255,1,1,.5) 1px}', - [['text-shadow', 'rgba(255,1,1,.5)', '1px']] + 'div{text-shadow:rgba(255,1,1,.5) 1px}' ], 'calc': [ 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}', - [['width', '-moz-calc(100% - 1em)'], ['width', 'calc(100% - 1em)']] + 'a{width:-moz-calc(100% - 1em);width:calc(100% - 1em)}' ], 'empty body': [ 'a{}', - null + '' ], 'in a body': [ 'a{ \n }', - null + '' ], 'after calc()': [ 'div{margin:calc(100% - 21px) 1px}', - [['margin', 'calc(100% - 21px)', '1px']] + 'div{margin:calc(100% - 21px) 1px}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('time units', { + optimizerContext('time units', { 'positive miliseconds to seconds': [ 'div{transition-duration:500ms}', - [['transition-duration', '.5s']] + 'div{transition-duration:.5s}' ], 'negative miliseconds to seconds': [ 'div{transition-duration:-500ms}', - [['transition-duration', '-.5s']] + 'div{transition-duration:-.5s}' ], 'miliseconds to seconds when results in a too long value': [ 'div{transition-duration:1515ms}', - [['transition-duration', '1515ms']] + 'div{transition-duration:1515ms}' ], 'zero miliseconds to seconds': [ 'div{transition-duration:0ms}', - [['transition-duration', '0s']] + 'div{transition-duration:0s}' ], 'positive seconds to miliseconds': [ 'div{transition-duration:0.005s}', - [['transition-duration', '5ms']] + 'div{transition-duration:5ms}' ], 'negative seconds to miliseconds': [ 'div{transition-duration:-0.005s}', - [['transition-duration', '-5ms']] + 'div{transition-duration:-5ms}' ], 'seconds to miliseconds when results in a too long value': [ 'div{transition-duration:1.2s}', - [['transition-duration', '1.2s']] + 'div{transition-duration:1.2s}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('length units', { + optimizerContext('length units', { 'px to in': [ 'div{left:480px}', - [['left', '480px']] + 'div{left:480px}' ], 'px to pc': [ 'div{left:32px}', - [['left', '32px']] + 'div{left:32px}' ], 'px to pt': [ 'div{left:120px}', - [['left', '120px']] + 'div{left:120px}' ] - }) + }, { advanced: false }) ) .addBatch( - propertyContext('length units in compatibility mode', { + optimizerContext('length units in compatibility mode', { 'px to in': [ 'div{left:480px}', - [['left', '480px']] + 'div{left:480px}' ], 'px to pc': [ 'div{left:32px}', - [['left', '32px']] + 'div{left:32px}' ], 'px to pt': [ 'div{left:120px}', - [['left', '120px']] + 'div{left:120px}' ] - }, { compatibility: 'ie8' }) + }, { advanced: false, compatibility: 'ie8' }) ) .addBatch( - propertyContext('length units when turned on', { + optimizerContext('length units when turned on', { 'positive px to in': [ 'div{left:480px}', - [['left', '5in']] + 'div{left:5in}' ], 'negative px to in': [ 'div{left:-96px}', - [['left', '-1in']] + 'div{left:-1in}' ], 'positive px to pc': [ 'div{left:32px}', - [['left', '2pc']] + 'div{left:2pc}' ], 'negative px to pc': [ 'div{left:-160px}', - [['left', '-10pc']] + 'div{left:-10pc}' ], 'positive px to pt': [ 'div{left:120px}', - [['left', '90pt']] + 'div{left:90pt}' ], 'negative px to pt': [ 'div{left:-120px}', - [['left', '-90pt']] + 'div{left:-90pt}' ], 'in calc': [ 'div{left:calc(100% - 480px)}', - [['left', 'calc(100% - 5in)']] + 'div{left:calc(100% - 5in)}' ], 'in transform': [ 'div{transform:translateY(32px)}', - [['transform', 'translateY(2pc)']] + 'div{transform:translateY(2pc)}' ] - }, { compatibility: { properties: { shorterLengthUnits: true } } }) + }, { advanced: false, compatibility: { properties: { shorterLengthUnits: true } } }) ) .addBatch( - propertyContext('length units when turned on selectively', { + optimizerContext('length units when turned on selectively', { 'px to in': [ 'div{left:480px}', - [['left', '30pc']] + 'div{left:30pc}' ], 'px to pc': [ 'div{left:32px}', - [['left', '2pc']] + 'div{left:2pc}' ], 'px to pt': [ 'div{left:120px}', - [['left', '120px']] + 'div{left:120px}' ] - }, { compatibility: { properties: { shorterLengthUnits: true }, units: { in: false, pt: false } } }) + }, { advanced: false, compatibility: { properties: { shorterLengthUnits: true }, units: { in: false, pt: false } } }) ) .export(module); diff --git a/test/optimizer/extract-properties-test.js b/test/optimizer/extract-properties-test.js new file mode 100644 index 00000000..9bef4d6a --- /dev/null +++ b/test/optimizer/extract-properties-test.js @@ -0,0 +1,360 @@ +var vows = require('vows'); +var assert = require('assert'); +var tokenize = require('../../lib/tokenizer/tokenize'); +var extractProperties = require('../../lib/optimizer/extract-properties'); + +vows.describe(extractProperties) + .addBatch({ + 'no properties': { + 'topic': function () { + return extractProperties(tokenize('a{}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, []); + } + }, + 'no valid properties': { + 'topic': function () { + return extractProperties(tokenize('a{:red}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, []); + } + }, + 'one property': { + 'topic': function () { + return extractProperties(tokenize('a{color:red}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'color', + 'red', + 'color', + ['property', ['property-name', 'color', [[1, 2, undefined]]], ['property-value', 'red', [[1, 8, undefined]]]], + 'color:red', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'one important property': { + 'topic': function () { + return extractProperties(tokenize('a{color:red!important}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'color', + 'red!important', + 'color', + ['property', ['property-name', 'color', [[1, 2, undefined]]], ['property-value', 'red!important', [[1, 8, undefined]]]], + 'color:red!important', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'one property - simple selector': { + 'topic': function () { + return extractProperties(tokenize('#one span{color:red}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'color', + 'red', + 'color', + ['property', ['property-name', 'color', [[1, 10, undefined]]], ['property-value', 'red', [[1, 16, undefined]]]], + 'color:red', + [['#one span', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'one property - variable': { + 'topic': function () { + return extractProperties(tokenize('#one span{--color:red}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, []); + } + }, + 'one property - block variable': { + 'topic': function () { + return extractProperties(tokenize('#one span{--color:{color:red;display:block};}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, []); + } + }, + 'one property - complex selector': { + 'topic': function () { + return extractProperties(tokenize('.one{color:red}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'color', + 'red', + 'color', + ['property', ['property-name', 'color', [[1, 5, undefined]]], ['property-value', 'red', [[1, 11, undefined]]]], + 'color:red', + [['.one', [[1, 0, undefined]]]], + false + ] + ]); + } + }, + 'two properties': { + 'topic': function () { + return extractProperties(tokenize('a{color:red;display:block}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'color', + 'red', + 'color', + ['property', ['property-name', 'color', [[1, 2, undefined]]], ['property-value', 'red', [[1, 8, undefined]]]], + 'color:red', + [['a', [[1, 0, undefined]]]], + true + ], + [ + 'display', + 'block', + 'display', + ['property', ['property-name', 'display', [[1, 12, undefined]]], ['property-value', 'block', [[1, 20, undefined]]]], + 'display:block', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'from @media': { + 'topic': function () { + return extractProperties(tokenize('@media{a{color:red;display:block}p{color:red}}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'color', + 'red', + 'color', + ['property', ['property-name', 'color', [[1, 9, undefined]]], ['property-value', 'red', [[1, 15, undefined]]]], + 'color:red', + [['a', [[1, 7, undefined]]]], + true + ], + [ + 'display', + 'block', + 'display', + ['property', ['property-name', 'display', [[1, 19, undefined]]], ['property-value', 'block', [[1, 27, undefined]]]], + 'display:block', + [['a', [[1, 7, undefined]]]], + true + ], + [ + 'color', + 'red', + 'color', + ['property', ['property-name', 'color', [[1, 35, undefined]]], ['property-value', 'red', [[1, 41, undefined]]]], + 'color:red', + [['p', [[1, 33, undefined]]]], + true + ] + ]); + } + } + }) + .addBatch({ + 'name root special cases': { + 'vendor prefix': { + 'topic': function () { + return extractProperties(tokenize('a{-moz-transform:none}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + '-moz-transform', + 'none', + 'transform', + ['property', ['property-name', '-moz-transform', [[1, 2, undefined]]], ['property-value', 'none', [[1, 17, undefined]]]], + '-moz-transform:none', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'list-style': { + 'topic': function () { + return extractProperties(tokenize('a{list-style:none}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'list-style', + 'none', + 'list-style', + ['property', ['property-name', 'list-style', [[1, 2, undefined]]], ['property-value', 'none', [[1, 13, undefined]]]], + 'list-style:none', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'border-radius': { + 'topic': function () { + return extractProperties(tokenize('a{border-top-left-radius:none}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'border-top-left-radius', + 'none', + 'border-radius', + ['property', ['property-name', 'border-top-left-radius', [[1, 2, undefined]]], ['property-value', 'none', [[1, 25, undefined]]]], + 'border-top-left-radius:none', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'vendor prefixed border-radius': { + 'topic': function () { + return extractProperties(tokenize('a{-webkit-border-top-left-radius:none}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + '-webkit-border-top-left-radius', + 'none', + 'border-radius', + ['property', ['property-name', '-webkit-border-top-left-radius', [[1, 2, undefined]]], ['property-value', 'none', [[1, 33, undefined]]]], + '-webkit-border-top-left-radius:none', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'border-image-width': { + 'topic': function () { + return extractProperties(tokenize('a{border-image-width:2px}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'border-image-width', + '2px', + 'border-image', + ['property', ['property-name', 'border-image-width', [[1, 2, undefined]]], ['property-value', '2px', [[1, 21, undefined]]]], + 'border-image-width:2px', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'border-color': { + 'topic': function () { + return extractProperties(tokenize('a{border-color:red}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'border-color', + 'red', + 'border', + ['property', ['property-name', 'border-color', [[1, 2, undefined]]], ['property-value', 'red', [[1, 15, undefined]]]], + 'border-color:red', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'border-top-style': { + 'topic': function () { + return extractProperties(tokenize('a{border-top-style:none}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'border-top-style', + 'none', + 'border-top', + ['property', ['property-name', 'border-top-style', [[1, 2, undefined]]], ['property-value', 'none', [[1, 19, undefined]]]], + 'border-top-style:none', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'border-top': { + 'topic': function () { + return extractProperties(tokenize('a{border-top:none}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'border-top', + 'none', + 'border', + ['property', ['property-name', 'border-top', [[1, 2, undefined]]], ['property-value', 'none', [[1, 13, undefined]]]], + 'border-top:none', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'border-collapse': { + 'topic': function () { + return extractProperties(tokenize('a{border-collapse:collapse}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'border-collapse', + 'collapse', + 'border-collapse', + ['property', ['property-name', 'border-collapse', [[1, 2, undefined]]], ['property-value', 'collapse', [[1, 18, undefined]]]], + 'border-collapse:collapse', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + }, + 'text-shadow': { + 'topic': function () { + return extractProperties(tokenize('a{text-shadow:none}', {})[0]); + }, + 'has no properties': function (tokens) { + assert.deepEqual(tokens, [ + [ + 'text-shadow', + 'none', + 'text-shadow', + ['property', ['property-name', 'text-shadow', [[1, 2, undefined]]], ['property-value', 'none', [[1, 14, undefined]]]], + 'text-shadow:none', + [['a', [[1, 0, undefined]]]], + true + ] + ]); + } + } + } + }) + .export(module); diff --git a/test/selectors/merge-adjacent-test.js b/test/optimizer/merge-adjacent-test.js similarity index 100% rename from test/selectors/merge-adjacent-test.js rename to test/optimizer/merge-adjacent-test.js diff --git a/test/selectors/merge-media-queries-test.js b/test/optimizer/merge-media-queries-test.js similarity index 100% rename from test/selectors/merge-media-queries-test.js rename to test/optimizer/merge-media-queries-test.js diff --git a/test/selectors/merge-non-adjacent-by-body-test.js b/test/optimizer/merge-non-adjacent-by-body-test.js similarity index 100% rename from test/selectors/merge-non-adjacent-by-body-test.js rename to test/optimizer/merge-non-adjacent-by-body-test.js diff --git a/test/selectors/merge-non-adjacent-by-selector-test.js b/test/optimizer/merge-non-adjacent-by-selector-test.js similarity index 100% rename from test/selectors/merge-non-adjacent-by-selector-test.js rename to test/optimizer/merge-non-adjacent-by-selector-test.js diff --git a/test/selectors/reduce-non-adjacent-test.js b/test/optimizer/reduce-non-adjacent-test.js similarity index 100% rename from test/selectors/reduce-non-adjacent-test.js rename to test/optimizer/reduce-non-adjacent-test.js diff --git a/test/selectors/remove-duplicate-media-queries-test.js b/test/optimizer/remove-duplicate-media-queries-test.js similarity index 100% rename from test/selectors/remove-duplicate-media-queries-test.js rename to test/optimizer/remove-duplicate-media-queries-test.js diff --git a/test/selectors/remove-duplicates-test.js b/test/optimizer/remove-duplicates-test.js similarity index 100% rename from test/selectors/remove-duplicates-test.js rename to test/optimizer/remove-duplicates-test.js diff --git a/test/selectors/reorderable-test.js b/test/optimizer/reorderable-test.js similarity index 98% rename from test/selectors/reorderable-test.js rename to test/optimizer/reorderable-test.js index 07c88872..5a291efa 100644 --- a/test/selectors/reorderable-test.js +++ b/test/optimizer/reorderable-test.js @@ -2,9 +2,9 @@ var vows = require('vows'); var assert = require('assert'); var tokenize = require('../../lib/tokenizer/tokenize'); -var extractProperties = require('../../lib/selectors/extractor'); -var canReorder = require('../../lib/selectors/reorderable').canReorder; -var canReorderSingle = require('../../lib/selectors/reorderable').canReorderSingle; +var extractProperties = require('../../lib/optimizer/extract-properties'); +var canReorder = require('../../lib/optimizer/reorderable').canReorder; +var canReorderSingle = require('../../lib/optimizer/reorderable').canReorderSingle; function propertiesIn(source) { return extractProperties(tokenize(source, { options: {} })[0]); diff --git a/test/selectors/restructure-test.js b/test/optimizer/restructure-test.js similarity index 100% rename from test/selectors/restructure-test.js rename to test/optimizer/restructure-test.js diff --git a/test/properties/break-up-test.js b/test/properties/break-up-test.js index 4aed5987..df1ad5c3 100644 --- a/test/properties/break-up-test.js +++ b/test/properties/break-up-test.js @@ -4,12 +4,12 @@ var assert = require('assert'); var wrapForOptimizing = require('../../lib/properties/wrap-for-optimizing').all; var populateComponents = require('../../lib/properties/populate-components'); var Validator = require('../../lib/properties/validator'); -var Compatibility = require('../../lib/utils/compatibility'); +var compatibility = require('../../lib/utils/compatibility'); var breakUp = require('../../lib/properties/break-up'); function _breakUp(properties) { - var validator = new Validator(new Compatibility().toOptions()); + var validator = new Validator(compatibility()); var wrapped = wrapForOptimizing(properties); populateComponents(wrapped, validator, []); @@ -21,363 +21,508 @@ vows.describe(breakUp) 'background': { 'inherit': { 'topic': function () { - return _breakUp([[['background'], ['inherit']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'inherit'] + ] + ]); }, 'has 8 components': function (components) { assert.lengthOf(components, 8); }, 'has background-image': function (components) { assert.deepEqual(components[0].name, 'background-image'); - assert.deepEqual(components[0].value, [['inherit']]); + assert.deepEqual(components[0].value, [['property-value', 'inherit']]); }, 'has background-position': function (components) { assert.deepEqual(components[1].name, 'background-position'); - assert.deepEqual(components[1].value, [['inherit']]); + assert.deepEqual(components[1].value, [['property-value', 'inherit']]); }, 'has background-size': function (components) { assert.deepEqual(components[2].name, 'background-size'); - assert.deepEqual(components[2].value, [['inherit']]); + assert.deepEqual(components[2].value, [['property-value', 'inherit']]); }, 'has background-repeat': function (components) { assert.deepEqual(components[3].name, 'background-repeat'); - assert.deepEqual(components[3].value, [['inherit']]); + assert.deepEqual(components[3].value, [['property-value', 'inherit']]); }, 'has background-attachment': function (components) { assert.deepEqual(components[4].name, 'background-attachment'); - assert.deepEqual(components[4].value, [['scroll']]); + assert.deepEqual(components[4].value, [['property-value', 'scroll']]); }, 'has background-origin': function (components) { assert.deepEqual(components[5].name, 'background-origin'); - assert.deepEqual(components[5].value, [['inherit']]); + assert.deepEqual(components[5].value, [['property-value', 'inherit']]); }, 'has background-clip': function (components) { assert.deepEqual(components[6].name, 'background-clip'); - assert.deepEqual(components[6].value, [['inherit']]); + assert.deepEqual(components[6].value, [['property-value', 'inherit']]); }, 'has background-color': function (components) { assert.deepEqual(components[7].name, 'background-color'); - assert.deepEqual(components[7].value, [['inherit']]); + assert.deepEqual(components[7].value, [['property-value', 'inherit']]); } }, 'all': { 'topic': function () { - return _breakUp([[['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['repeat'], ['no-repeat'], ['2px'], ['3px'], ['/'], ['50%'], ['60%'], ['fixed'], ['padding-box'], ['border-box'], ['red']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', 'repeat'], + ['property-value', 'no-repeat'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', '/'], + ['property-value', '50%'], + ['property-value', '60%'], + ['property-value', 'fixed'], + ['property-value', 'padding-box'], + ['property-value', 'border-box'], + ['property-value', 'red'] + ] + ]); }, 'has 8 components': function (components) { assert.lengthOf(components, 8); }, 'has background-image': function (components) { assert.deepEqual(components[0].name, 'background-image'); - assert.deepEqual(components[0].value, [['__ESCAPED_URL_CLEAN_CSS0__']]); + assert.deepEqual(components[0].value, [['property-value', 'url(image.png)']]); }, 'has background-position': function (components) { assert.deepEqual(components[1].name, 'background-position'); - assert.deepEqual(components[1].value, [['2px'], ['3px']]); + assert.deepEqual(components[1].value, [['property-value', '2px'], ['property-value', '3px']]); }, 'has background-size': function (components) { assert.deepEqual(components[2].name, 'background-size'); - assert.deepEqual(components[2].value, [['50%'], ['60%']]); + assert.deepEqual(components[2].value, [['property-value', '50%'], ['property-value', '60%']]); }, 'has background-repeat': function (components) { assert.deepEqual(components[3].name, 'background-repeat'); - assert.deepEqual(components[3].value, [['repeat'], ['no-repeat']]); + assert.deepEqual(components[3].value, [['property-value', 'repeat'], ['property-value', 'no-repeat']]); }, 'has background-attachment': function (components) { assert.deepEqual(components[4].name, 'background-attachment'); - assert.deepEqual(components[4].value, [['fixed']]); + assert.deepEqual(components[4].value, [['property-value', 'fixed']]); }, 'has background-origin': function (components) { assert.deepEqual(components[5].name, 'background-origin'); - assert.deepEqual(components[5].value, [['padding-box']]); + assert.deepEqual(components[5].value, [['property-value', 'padding-box']]); }, 'has background-clip': function (components) { assert.deepEqual(components[6].name, 'background-clip'); - assert.deepEqual(components[6].value, [['border-box']]); + assert.deepEqual(components[6].value, [['property-value', 'border-box']]); }, 'has background-color': function (components) { assert.deepEqual(components[7].name, 'background-color'); - assert.deepEqual(components[7].value, [['red']]); + assert.deepEqual(components[7].value, [['property-value', 'red']]); } }, 'no size': { 'topic': function () { - return _breakUp([[['background'], ['bottom']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'bottom'] + ] + ]); }, 'has 8 components': function (components) { assert.lengthOf(components, 8); }, 'has background-position': function (components) { assert.deepEqual(components[1].name, 'background-position'); - assert.deepEqual(components[1].value, [['bottom']]); + assert.deepEqual(components[1].value, [['property-value', 'bottom']]); }, 'has background-size': function (components) { assert.deepEqual(components[2].name, 'background-size'); - assert.deepEqual(components[2].value, [['auto']]); + assert.deepEqual(components[2].value, [['property-value', 'auto']]); } }, 'shorthand size & position': { 'topic': function () { - return _breakUp([[['background'], ['2px'], ['/'], ['50px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'background'], + ['property-value', '2px'], + ['property-value', '/'], + ['property-value', '50px'] + ] + ]); }, 'has 8 components': function (components) { assert.lengthOf(components, 8); }, 'has background-position': function (components) { assert.deepEqual(components[1].name, 'background-position'); - assert.deepEqual(components[1].value, [['2px']]); + assert.deepEqual(components[1].value, [['property-value', '2px']]); }, 'has background-size': function (components) { assert.deepEqual(components[2].name, 'background-size'); - assert.deepEqual(components[2].value, [['50px']]); + assert.deepEqual(components[2].value, [['property-value', '50px']]); } }, 'size & position joined together': { 'topic': function () { - return _breakUp([[['background'], ['2px/50px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'background'], + ['property-value', '2px'], + ['property-value', '/'], + ['property-value', '50px'] + ] + ]); }, 'has 8 components': function (components) { assert.lengthOf(components, 8); }, 'has background-position': function (components) { assert.deepEqual(components[1].name, 'background-position'); - assert.deepEqual(components[1].value, [['2px']]); + assert.deepEqual(components[1].value, [['property-value', '2px']]); }, 'has background-size': function (components) { assert.deepEqual(components[2].name, 'background-size'); - assert.deepEqual(components[2].value, [['50px']]); + assert.deepEqual(components[2].value, [['property-value', '50px']]); } }, 'size & position joined together with 4 values': { 'topic': function () { - return _breakUp([[['background'], ['5px'], ['2px/50px'], ['30px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'background'], + ['property-value', '5px'], + ['property-value', '2px'], + ['property-value', '/'], + ['property-value', '50px'], + ['property-value', '30px'] + ] + ]); }, 'has 8 components': function (components) { assert.lengthOf(components, 8); }, 'has background-position': function (components) { assert.deepEqual(components[1].name, 'background-position'); - assert.deepEqual(components[1].value, [['5px'], ['2px']]); + assert.deepEqual(components[1].value, [['property-value', '5px'], ['property-value', '2px']]); }, 'has background-size': function (components) { assert.deepEqual(components[2].name, 'background-size'); - assert.deepEqual(components[2].value, [['50px'], ['30px']]); + assert.deepEqual(components[2].value, [['property-value', '50px'], ['property-value', '30px']]); } }, 'clip to origin': { 'topic': function () { - return _breakUp([[['background'], ['padding-box']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'padding-box'] + ] + ]); }, 'has 8 components': function (components) { assert.lengthOf(components, 8); }, 'has background-origin': function (components) { assert.deepEqual(components[5].name, 'background-origin'); - assert.deepEqual(components[5].value, [['padding-box']]); + assert.deepEqual(components[5].value, [['property-value', 'padding-box']]); }, 'has background-clip': function (components) { assert.deepEqual(components[6].name, 'background-clip'); - assert.deepEqual(components[6].value, [['padding-box']]); + assert.deepEqual(components[6].value, [['property-value', 'padding-box']]); } } }, 'border': { 'inherit': { 'topic': function () { - return _breakUp([[['border'], ['inherit']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border'], + ['property-value', 'inherit'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has border-width': function (components) { assert.deepEqual(components[0].name, 'border-width'); - assert.deepEqual(components[0].value, [['inherit']]); + assert.deepEqual(components[0].value, [['property-value', 'inherit']]); }, 'has border-style': function (components) { assert.deepEqual(components[1].name, 'border-style'); - assert.deepEqual(components[1].value, [['inherit']]); + assert.deepEqual(components[1].value, [['property-value', 'inherit']]); }, 'has border-color': function (components) { assert.deepEqual(components[2].name, 'border-color'); - assert.deepEqual(components[2].value, [['inherit']]); + assert.deepEqual(components[2].value, [['property-value', 'inherit']]); } }, '3 inherits': { 'topic': function () { - return _breakUp([[['border'], ['inherit'], ['inherit'], ['inherit']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border'], + ['property-value', 'inherit'], + ['property-value', 'inherit'], + ['property-value', 'inherit'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has border-width': function (components) { assert.deepEqual(components[0].name, 'border-width'); - assert.deepEqual(components[0].value, [['inherit']]); + assert.deepEqual(components[0].value, [['property-value', 'inherit']]); }, 'has border-style': function (components) { assert.deepEqual(components[1].name, 'border-style'); - assert.deepEqual(components[1].value, [['inherit']]); + assert.deepEqual(components[1].value, [['property-value', 'inherit']]); }, 'has border-color': function (components) { assert.deepEqual(components[2].name, 'border-color'); - assert.deepEqual(components[2].value, [['inherit']]); + assert.deepEqual(components[2].value, [['property-value', 'inherit']]); } }, 'all values in correct order': { 'topic': function () { - return _breakUp([[['border'], ['1px'], ['solid'], ['red']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border'], + ['property-value', '1px'], + ['property-value', 'solid'], + ['property-value', 'red'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has border-width': function (components) { assert.deepEqual(components[0].name, 'border-width'); - assert.deepEqual(components[0].value, [['1px']]); + assert.deepEqual(components[0].value, [['property-value', '1px']]); }, 'has border-style': function (components) { assert.deepEqual(components[1].name, 'border-style'); - assert.deepEqual(components[1].value, [['solid']]); + assert.deepEqual(components[1].value, [['property-value', 'solid']]); }, 'has border-color': function (components) { assert.deepEqual(components[2].name, 'border-color'); - assert.deepEqual(components[2].value, [['red']]); + assert.deepEqual(components[2].value, [['property-value', 'red']]); } }, 'all values in wrong order': { 'topic': function () { - return _breakUp([[['border'], ['red'], ['solid'], ['1px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border'], + ['property-value', 'red'], + ['property-value', 'solid'], + ['property-value', '1px'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has border-width': function (components) { assert.deepEqual(components[0].name, 'border-width'); - assert.deepEqual(components[0].value, [['1px']]); + assert.deepEqual(components[0].value, [['property-value', '1px']]); }, 'has border-style': function (components) { assert.deepEqual(components[1].name, 'border-style'); - assert.deepEqual(components[1].value, [['solid']]); + assert.deepEqual(components[1].value, [['property-value', 'solid']]); }, 'has border-color': function (components) { assert.deepEqual(components[2].name, 'border-color'); - assert.deepEqual(components[2].value, [['red']]); + assert.deepEqual(components[2].value, [['property-value', 'red']]); } }, 'missing values': { 'topic': function () { - return _breakUp([[['border'], ['red']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border'], + ['property-value', 'red'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has border-width': function (components) { assert.deepEqual(components[0].name, 'border-width'); - assert.deepEqual(components[0].value, [['medium']]); + assert.deepEqual(components[0].value, [['property-value', 'medium']]); }, 'has border-style': function (components) { assert.deepEqual(components[1].name, 'border-style'); - assert.deepEqual(components[1].value, [['none']]); + assert.deepEqual(components[1].value, [['property-value', 'none']]); }, 'has border-color': function (components) { assert.deepEqual(components[2].name, 'border-color'); - assert.deepEqual(components[2].value, [['red']]); + assert.deepEqual(components[2].value, [['property-value', 'red']]); } }, 'missing width': { 'topic': function () { - return _breakUp([[['border'], ['solid'], ['rgba(0,0,0,0)']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border'], + ['property-value', 'solid'], + ['property-value', 'rgba(0,0,0,0)'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has border-width': function (components) { assert.deepEqual(components[0].name, 'border-width'); - assert.deepEqual(components[0].value, [['medium']]); + assert.deepEqual(components[0].value, [['property-value', 'medium']]); }, 'has border-style': function (components) { assert.deepEqual(components[1].name, 'border-style'); - assert.deepEqual(components[1].value, [['solid']]); + assert.deepEqual(components[1].value, [['property-value', 'solid']]); }, 'has border-color': function (components) { assert.deepEqual(components[2].name, 'border-color'); - assert.deepEqual(components[2].value, [['rgba(0,0,0,0)']]); + assert.deepEqual(components[2].value, [['property-value', 'rgba(0,0,0,0)']]); } } }, 'border radius': { 'no horizontal vertical split': { 'topic': function () { - return _breakUp([[['border-radius'], ['0px'], ['1px'], ['2px'], ['3px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border-radius'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'] + ] + ]); }, 'has 4 components': function (components) { assert.lengthOf(components, 4); }, 'has border-top-left-radius': function (components) { assert.equal(components[0].name, 'border-top-left-radius'); - assert.deepEqual(components[0].value, [['0px'], ['0px']]); + assert.deepEqual(components[0].value, [['property-value', '0px'], ['property-value', '0px']]); }, 'has border-top-right-radius': function (components) { assert.equal(components[1].name, 'border-top-right-radius'); - assert.deepEqual(components[1].value, [['1px'], ['1px']]); + assert.deepEqual(components[1].value, [['property-value', '1px'], ['property-value', '1px']]); }, 'has border-bottom-right-radius': function (components) { assert.equal(components[2].name, 'border-bottom-right-radius'); - assert.deepEqual(components[2].value, [['2px'], ['2px']]); + assert.deepEqual(components[2].value, [['property-value', '2px'], ['property-value', '2px']]); }, 'has border-bottom-left': function (components) { assert.equal(components[3].name, 'border-bottom-left-radius'); - assert.deepEqual(components[3].value, [['3px'], ['3px']]); + assert.deepEqual(components[3].value, [['property-value', '3px'], ['property-value', '3px']]); } }, 'horizontal vertical split': { 'topic': function () { - return _breakUp([[['border-radius'], ['0px'], ['1px'], ['2px'], ['3px'], ['/'], ['1px'], ['2px'], ['3px'], ['4px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border-radius'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', '/'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', '4px'] + ] + ]); }, 'has 4 components': function (components) { assert.lengthOf(components, 4); }, 'has border-top-left-radius': function (components) { assert.equal(components[0].name, 'border-top-left-radius'); - assert.deepEqual(components[0].value, [['0px'], ['1px']]); + assert.deepEqual(components[0].value, [['property-value', '0px'], ['property-value', '1px']]); }, 'has border-top-right-radius': function (components) { assert.equal(components[1].name, 'border-top-right-radius'); - assert.deepEqual(components[1].value, [['1px'], ['2px']]); + assert.deepEqual(components[1].value, [['property-value', '1px'], ['property-value', '2px']]); }, 'has border-bottom-right-radius': function (components) { assert.equal(components[2].name, 'border-bottom-right-radius'); - assert.deepEqual(components[2].value, [['2px'], ['3px']]); + assert.deepEqual(components[2].value, [['property-value', '2px'], ['property-value', '3px']]); }, 'has border-bottom-left': function (components) { assert.equal(components[3].name, 'border-bottom-left-radius'); - assert.deepEqual(components[3].value, [['3px'], ['4px']]); + assert.deepEqual(components[3].value, [['property-value', '3px'], ['property-value', '4px']]); } }, 'vendor prefix asymmetrical horizontal vertical split': { 'topic': function () { - return _breakUp([[['-webkit-border-radius'], ['0px'], ['1px'], ['2px'], ['/'], ['1px'], ['4px']]]); + return _breakUp([ + [ + 'property', + ['property-name', '-webkit-border-radius'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '/'], + ['property-value', '1px'], + ['property-value', '4px'] + ] + ]); }, 'has 4 components': function (components) { assert.lengthOf(components, 4); }, 'has border-top-left-radius': function (components) { assert.equal(components[0].name, '-webkit-border-top-left-radius'); - assert.deepEqual(components[0].value, [['0px'], ['1px']]); + assert.deepEqual(components[0].value, [['property-value', '0px'], ['property-value', '1px']]); }, 'has border-top-right-radius': function (components) { assert.equal(components[1].name, '-webkit-border-top-right-radius'); - assert.deepEqual(components[1].value, [['1px'], ['4px']]); + assert.deepEqual(components[1].value, [['property-value', '1px'], ['property-value', '4px']]); }, 'has border-bottom-right-radius': function (components) { assert.equal(components[2].name, '-webkit-border-bottom-right-radius'); - assert.deepEqual(components[2].value, [['2px'], ['1px']]); + assert.deepEqual(components[2].value, [['property-value', '2px'], ['property-value', '1px']]); }, 'has border-bottom-left': function (components) { assert.equal(components[3].name, '-webkit-border-bottom-left-radius'); - assert.deepEqual(components[3].value, [['1px'], ['4px']]); + assert.deepEqual(components[3].value, [['property-value', '1px'], ['property-value', '4px']]); } }, 'with missing vertical value': { 'topic': function () { - return _breakUp([[['border-radius'], ['0px'], ['/']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border-radius'], + ['property-value', '0px'], + ['property-value', '/'] + ] + ]); }, 'has no components': function (components) { assert.lengthOf(components, 0); @@ -385,7 +530,14 @@ vows.describe(breakUp) }, 'with missing horizontal value': { 'topic': function () { - return _breakUp([[['border-radius'], ['/'], ['0px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border-radius'], + ['property-value', '/'], + ['property-value', '0px'] + ] + ]); }, 'has no components': function (components) { assert.lengthOf(components, 0); @@ -395,103 +547,138 @@ vows.describe(breakUp) 'four values': { 'four given': { 'topic': function () { - return _breakUp([[['margin'], ['0px'], ['1px'], ['2px'], ['3px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'] + ] + ]); }, 'has 4 components': function (components) { assert.lengthOf(components, 4); }, 'has margin-top': function (components) { assert.equal(components[0].name, 'margin-top'); - assert.deepEqual(components[0].value, [['0px']]); + assert.deepEqual(components[0].value, [['property-value', '0px']]); }, 'has margin-right': function (components) { assert.equal(components[1].name, 'margin-right'); - assert.deepEqual(components[1].value, [['1px']]); + assert.deepEqual(components[1].value, [['property-value', '1px']]); }, 'has margin-bottom': function (components) { assert.equal(components[2].name, 'margin-bottom'); - assert.deepEqual(components[2].value, [['2px']]); + assert.deepEqual(components[2].value, [['property-value', '2px']]); }, 'has margin-left': function (components) { assert.equal(components[3].name, 'margin-left'); - assert.deepEqual(components[3].value, [['3px']]); + assert.deepEqual(components[3].value, [['property-value', '3px']]); } }, 'three given': { 'topic': function () { - return _breakUp([[['padding'], ['0px'], ['1px'], ['2px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'padding'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'] + ] + ]); }, 'has 4 components': function (components) { assert.lengthOf(components, 4); }, 'has padding-top': function (components) { assert.equal(components[0].name, 'padding-top'); - assert.deepEqual(components[0].value, [['0px']]); + assert.deepEqual(components[0].value, [['property-value', '0px']]); }, 'has padding-right': function (components) { assert.equal(components[1].name, 'padding-right'); - assert.deepEqual(components[1].value, [['1px']]); + assert.deepEqual(components[1].value, [['property-value', '1px']]); }, 'has padding-bottom': function (components) { assert.equal(components[2].name, 'padding-bottom'); - assert.deepEqual(components[2].value, [['2px']]); + assert.deepEqual(components[2].value, [['property-value', '2px']]); }, 'has padding-left': function (components) { assert.equal(components[3].name, 'padding-left'); - assert.deepEqual(components[3].value, [['1px']]); + assert.deepEqual(components[3].value, [['property-value', '1px']]); } }, 'two given': { 'topic': function () { - return _breakUp([[['border-color'], ['red'], ['blue']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border-color'], + ['property-value', 'red'], + ['property-value', 'blue'] + ] + ]); }, 'has 4 components': function (components) { assert.lengthOf(components, 4); }, 'has border-top-color': function (components) { assert.equal(components[0].name, 'border-top-color'); - assert.deepEqual(components[0].value, [['red']]); + assert.deepEqual(components[0].value, [['property-value', 'red']]); }, 'has border-right-color': function (components) { assert.equal(components[1].name, 'border-right-color'); - assert.deepEqual(components[1].value, [['blue']]); + assert.deepEqual(components[1].value, [['property-value', 'blue']]); }, 'has border-bottom-color': function (components) { assert.equal(components[2].name, 'border-bottom-color'); - assert.deepEqual(components[2].value, [['red']]); + assert.deepEqual(components[2].value, [['property-value', 'red']]); }, 'has border-left-color': function (components) { assert.equal(components[3].name, 'border-left-color'); - assert.deepEqual(components[3].value, [['blue']]); + assert.deepEqual(components[3].value, [['property-value', 'blue']]); } }, 'one given': { 'topic': function () { - return _breakUp([[['border-style'], ['solid']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border-style'], + ['property-value', 'solid'] + ] + ]); }, 'has 4 components': function (components) { assert.lengthOf(components, 4); }, 'has border-top-style': function (components) { assert.equal(components[0].name, 'border-top-style'); - assert.deepEqual(components[0].value, [['solid']]); + assert.deepEqual(components[0].value, [['property-value', 'solid']]); }, 'has border-right-style': function (components) { assert.equal(components[1].name, 'border-right-style'); - assert.deepEqual(components[1].value, [['solid']]); + assert.deepEqual(components[1].value, [['property-value', 'solid']]); }, 'has border-bottom-style': function (components) { assert.equal(components[2].name, 'border-bottom-style'); - assert.deepEqual(components[2].value, [['solid']]); + assert.deepEqual(components[2].value, [['property-value', 'solid']]); }, 'has border-left-style': function (components) { assert.equal(components[3].name, 'border-left-style'); - assert.deepEqual(components[3].value, [['solid']]); + assert.deepEqual(components[3].value, [['property-value', 'solid']]); } }, 'none given': { 'topic': function () { - return _breakUp([[['border-style']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'border-style'] + ] + ]); }, 'has 0 components': function (components) { assert.lengthOf(components, 0); @@ -501,285 +688,396 @@ vows.describe(breakUp) 'list style': { 'inherit': { 'topic': function () { - return _breakUp([[['list-style'], ['inherit']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'list-style'], + ['property-value', 'inherit'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has border-top-style': function (components) { assert.equal(components[0].name, 'list-style-type'); - assert.deepEqual(components[0].value, [['inherit']]); + assert.deepEqual(components[0].value, [['property-value', 'inherit']]); }, 'has border-right-style': function (components) { assert.equal(components[1].name, 'list-style-position'); - assert.deepEqual(components[1].value, [['inherit']]); + assert.deepEqual(components[1].value, [['property-value', 'inherit']]); }, 'has border-bottom-style': function (components) { assert.equal(components[2].name, 'list-style-image'); - assert.deepEqual(components[2].value, [['inherit']]); + assert.deepEqual(components[2].value, [['property-value', 'inherit']]); } }, 'all values': { 'topic': function () { - return _breakUp([[['list-style'], ['circle'], ['inside'], ['__ESCAPED_URL_CLEAN_CSS0__']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'list-style'], + ['property-value', 'circle'], + ['property-value', 'inside'], + ['property-value', 'url(image.png)'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has border-top-style': function (components) { assert.equal(components[0].name, 'list-style-type'); - assert.deepEqual(components[0].value, [['circle']]); + assert.deepEqual(components[0].value, [['property-value', 'circle']]); }, 'has border-right-style': function (components) { assert.equal(components[1].name, 'list-style-position'); - assert.deepEqual(components[1].value, [['inside']]); + assert.deepEqual(components[1].value, [['property-value', 'inside']]); }, 'has border-bottom-style': function (components) { assert.equal(components[2].name, 'list-style-image'); - assert.deepEqual(components[2].value, [['__ESCAPED_URL_CLEAN_CSS0__']]); + assert.deepEqual(components[2].value, [['property-value', 'url(image.png)']]); } }, 'some missing': { 'topic': function () { - return _breakUp([[['list-style'], ['inside']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'list-style'], + ['property-value', 'inside'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has border-top-style': function (components) { assert.equal(components[0].name, 'list-style-type'); - assert.deepEqual(components[0].value, [['__hack']]); + assert.deepEqual(components[0].value, [['property-value', '__hack']]); }, 'has border-right-style': function (components) { assert.equal(components[1].name, 'list-style-position'); - assert.deepEqual(components[1].value, [['inside']]); + assert.deepEqual(components[1].value, [['property-value', 'inside']]); }, 'has border-bottom-style': function (components) { assert.equal(components[2].name, 'list-style-image'); - assert.deepEqual(components[2].value, [['none']]); + assert.deepEqual(components[2].value, [['property-value', 'none']]); } }, 'fuzzy matching': { 'topic': function () { - return _breakUp([[['list-style'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['outside'], ['none']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'list-style'], + ['property-value', 'url(image.png)'], + ['property-value', 'outside'], + ['property-value', 'none'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has list-style-type': function (components) { assert.equal(components[0].name, 'list-style-type'); - assert.deepEqual(components[0].value, [['none']]); + assert.deepEqual(components[0].value, [['property-value', 'none']]); }, 'has list-style-position': function (components) { assert.equal(components[1].name, 'list-style-position'); - assert.deepEqual(components[1].value, [['outside']]); + assert.deepEqual(components[1].value, [['property-value', 'outside']]); }, 'has list-style-image': function (components) { assert.equal(components[2].name, 'list-style-image'); - assert.deepEqual(components[2].value, [['__ESCAPED_URL_CLEAN_CSS0__']]); + assert.deepEqual(components[2].value, [['property-value', 'url(image.png)']]); } } }, - 'multiple values': { + 'multiple values 123': { 'background': { 'topic': function () { - return _breakUp([[['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['#fff'], [','], ['url(image2.png)'], ['repeat'], ['no-repeat'], ['2px'], ['3px'], ['/'], ['50%'], ['60%'], ['fixed'], ['content-box'], ['content-box'], ['red']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', '#fff'], + ['property-value', ','], + ['property-value', 'url(image2.png)'], + ['property-value', 'repeat'], + ['property-value', 'no-repeat'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', '/'], + ['property-value', '50%'], + ['property-value', '60%'], + ['property-value', 'fixed'], + ['property-value', 'content-box'], + ['property-value', 'content-box'], + ['property-value', 'red'] + ] + ]); }, 'has 8 components': function (components) { assert.lengthOf(components, 8); }, 'has background-image': function (components) { assert.deepEqual(components[0].name, 'background-image'); - assert.deepEqual(components[0].value, [['__ESCAPED_URL_CLEAN_CSS0__'], [','], ['url(image2.png)']]); + assert.deepEqual(components[0].value, [['property-value', 'url(image.png)'], ['property-value', ','], ['property-value', 'url(image2.png)']]); assert.isTrue(components[0].multiplex); }, 'has background-position': function (components) { assert.deepEqual(components[1].name, 'background-position'); - assert.deepEqual(components[1].value, [['0'], ['0'], [','], ['2px'], ['3px']]); + assert.deepEqual(components[1].value, [['property-value', '0'], ['property-value', '0'], ['property-value', ','], ['property-value', '2px'], ['property-value', '3px']]); assert.isTrue(components[0].multiplex); }, 'has background-size': function (components) { assert.deepEqual(components[2].name, 'background-size'); - assert.deepEqual(components[2].value, [['auto'], [','], ['50%'], ['60%']]); + assert.deepEqual(components[2].value, [['property-value', 'auto'], ['property-value', ','], ['property-value', '50%'], ['property-value', '60%']]); assert.isTrue(components[0].multiplex); }, 'has background-repeat': function (components) { assert.deepEqual(components[3].name, 'background-repeat'); - assert.deepEqual(components[3].value, [['repeat'], [','], ['repeat'], ['no-repeat']]); + assert.deepEqual(components[3].value, [['property-value', 'repeat'], ['property-value', ','], ['property-value', 'repeat'], ['property-value', 'no-repeat']]); assert.isTrue(components[0].multiplex); }, 'has background-attachment': function (components) { assert.deepEqual(components[4].name, 'background-attachment'); - assert.deepEqual(components[4].value, [['scroll'], [','], ['fixed']]); + assert.deepEqual(components[4].value, [['property-value', 'scroll'], ['property-value', ','], ['property-value', 'fixed']]); assert.isTrue(components[0].multiplex); }, 'has background-origin': function (components) { assert.deepEqual(components[5].name, 'background-origin'); - assert.deepEqual(components[5].value, [['padding-box'], [','], ['content-box']]); + assert.deepEqual(components[5].value, [['property-value', 'padding-box'], ['property-value', ','], ['property-value', 'content-box']]); assert.isTrue(components[0].multiplex); }, 'has background-clip': function (components) { assert.deepEqual(components[6].name, 'background-clip'); - assert.deepEqual(components[6].value, [['border-box'], [','], ['content-box']]); + assert.deepEqual(components[6].value, [['property-value', 'border-box'], ['property-value', ','], ['property-value', 'content-box']]); assert.isTrue(components[0].multiplex); }, 'has background-color': function (components) { assert.deepEqual(components[7].name, 'background-color'); - assert.deepEqual(components[7].value, [['#fff'], [','], ['red']]); + assert.deepEqual(components[7].value, [['property-value', '#fff'], ['property-value', ','], ['property-value', 'red']]); assert.isTrue(components[0].multiplex); } }, 'background - clip & origin': { 'topic': function () { - return _breakUp([[['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat'], ['padding-box'], [','], ['repeat'], ['red']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', 'no-repeat'], + ['property-value', 'padding-box'], + ['property-value', ','], + ['property-value', 'repeat'], + ['property-value', 'red'] + ] + ]); }, 'has background-origin': function (components) { - assert.deepEqual(components[5].value, [['padding-box'], [','], ['padding-box']]); + assert.deepEqual(components[5].value, [['property-value', 'padding-box'], ['property-value', ','], ['property-value', 'padding-box']]); }, 'has background-clip': function (components) { - assert.deepEqual(components[6].value, [['padding-box'], [','], ['border-box']]); + assert.deepEqual(components[6].value, [['property-value', 'padding-box'], ['property-value', ','], ['property-value', 'border-box']]); } } }, 'outline': { 'inherit': { 'topic': function () { - return _breakUp([[['outline'], ['inherit']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'outline'], + ['property-value', 'inherit'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has outline-color': function (components) { assert.deepEqual(components[0].name, 'outline-color'); - assert.deepEqual(components[0].value, [['inherit']]); + assert.deepEqual(components[0].value, [['property-value', 'inherit']]); }, 'has outline-style': function (components) { assert.deepEqual(components[1].name, 'outline-style'); - assert.deepEqual(components[1].value, [['inherit']]); + assert.deepEqual(components[1].value, [['property-value', 'inherit']]); }, 'has outline-width': function (components) { assert.deepEqual(components[2].name, 'outline-width'); - assert.deepEqual(components[2].value, [['inherit']]); + assert.deepEqual(components[2].value, [['property-value', 'inherit']]); } }, '3 inherits': { 'topic': function () { - return _breakUp([[['outline'], ['inherit'], ['inherit'], ['inherit']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'outline'], + ['property-value', 'inherit'], + ['property-value', 'inherit'], + ['property-value', 'inherit'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has outline-color': function (components) { assert.deepEqual(components[0].name, 'outline-color'); - assert.deepEqual(components[0].value, [['inherit']]); + assert.deepEqual(components[0].value, [['property-value', 'inherit']]); }, 'has outline-style': function (components) { assert.deepEqual(components[1].name, 'outline-style'); - assert.deepEqual(components[1].value, [['inherit']]); + assert.deepEqual(components[1].value, [['property-value', 'inherit']]); }, 'has outline-width': function (components) { assert.deepEqual(components[2].name, 'outline-width'); - assert.deepEqual(components[2].value, [['inherit']]); + assert.deepEqual(components[2].value, [['property-value', 'inherit']]); } }, 'all values in correct order': { 'topic': function () { - return _breakUp([[['outline'], ['red'], ['solid'], ['1px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'outline'], + ['property-value', 'red'], + ['property-value', 'solid'], + ['property-value', '1px'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has outline-color': function (components) { assert.deepEqual(components[0].name, 'outline-color'); - assert.deepEqual(components[0].value, [['red']]); + assert.deepEqual(components[0].value, [['property-value', 'red']]); }, 'has outline-style': function (components) { assert.deepEqual(components[1].name, 'outline-style'); - assert.deepEqual(components[1].value, [['solid']]); + assert.deepEqual(components[1].value, [['property-value', 'solid']]); }, 'has outline-width': function (components) { assert.deepEqual(components[2].name, 'outline-width'); - assert.deepEqual(components[2].value, [['1px']]); + assert.deepEqual(components[2].value, [['property-value', '1px']]); } }, 'all values in wrong order': { 'topic': function () { - return _breakUp([[['outline'], ['1px'], ['dotted'], ['#fff']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'outline'], + ['property-value', '1px'], + ['property-value', 'dotted'], + ['property-value', '#fff'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has outline-color': function (components) { assert.deepEqual(components[0].name, 'outline-color'); - assert.deepEqual(components[0].value, [['#fff']]); + assert.deepEqual(components[0].value, [['property-value', '#fff']]); }, 'has outline-style': function (components) { assert.deepEqual(components[1].name, 'outline-style'); - assert.deepEqual(components[1].value, [['dotted']]); + assert.deepEqual(components[1].value, [['property-value', 'dotted']]); }, 'has outline-width': function (components) { assert.deepEqual(components[2].name, 'outline-width'); - assert.deepEqual(components[2].value, [['1px']]); + assert.deepEqual(components[2].value, [['property-value', '1px']]); } }, 'with auto style': { 'topic': function () { - return _breakUp([[['outline'], ['#fff'], ['auto'], ['1px']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'outline'], + ['property-value', '#fff'], + ['property-value', 'auto'], + ['property-value', '1px'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has outline-color': function (components) { assert.deepEqual(components[0].name, 'outline-color'); - assert.deepEqual(components[0].value, [['#fff']]); + assert.deepEqual(components[0].value, [['property-value', '#fff']]); }, 'has outline-style': function (components) { assert.deepEqual(components[1].name, 'outline-style'); - assert.deepEqual(components[1].value, [['auto']]); + assert.deepEqual(components[1].value, [['property-value', 'auto']]); }, 'has outline-width': function (components) { assert.deepEqual(components[2].name, 'outline-width'); - assert.deepEqual(components[2].value, [['1px']]); + assert.deepEqual(components[2].value, [['property-value', '1px']]); } }, 'missing values': { 'topic': function () { - return _breakUp([[['outline'], ['solid']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'outline'], + ['property-value', 'solid'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has outline-color': function (components) { assert.deepEqual(components[0].name, 'outline-color'); - assert.deepEqual(components[0].value, [['invert']]); + assert.deepEqual(components[0].value, [['property-value', 'invert']]); }, 'has outline-style': function (components) { assert.deepEqual(components[1].name, 'outline-style'); - assert.deepEqual(components[1].value, [['solid']]); + assert.deepEqual(components[1].value, [['property-value', 'solid']]); }, 'has outline-width': function (components) { assert.deepEqual(components[2].name, 'outline-width'); - assert.deepEqual(components[2].value, [['medium']]); + assert.deepEqual(components[2].value, [['property-value', 'medium']]); } }, 'default values': { 'topic': function () { - return _breakUp([[['outline'], ['invert'], ['none'], ['medium']]]); + return _breakUp([ + [ + 'property', + ['property-name', 'outline'], + ['property-value', 'invert'], + ['property-value', 'none'], + ['property-value', 'medium'] + ] + ]); }, 'has 3 components': function (components) { assert.lengthOf(components, 3); }, 'has outline-color': function (components) { assert.deepEqual(components[0].name, 'outline-color'); - assert.deepEqual(components[0].value, [['invert']]); + assert.deepEqual(components[0].value, [['property-value', 'invert']]); }, 'has outline-style': function (components) { assert.deepEqual(components[1].name, 'outline-style'); - assert.deepEqual(components[1].value, [['none']]); + assert.deepEqual(components[1].value, [['property-value', 'none']]); }, 'has outline-width': function (components) { assert.deepEqual(components[2].name, 'outline-width'); - assert.deepEqual(components[2].value, [['medium']]); + assert.deepEqual(components[2].value, [['property-value', 'medium']]); } } } diff --git a/test/properties/longhand-overriding-test.js b/test/properties/longhand-overriding-test.js index fef5949f..eb1f55c4 100644 --- a/test/properties/longhand-overriding-test.js +++ b/test/properties/longhand-overriding-test.js @@ -4,20 +4,18 @@ var assert = require('assert'); var optimize = require('../../lib/properties/optimizer'); var tokenize = require('../../lib/tokenizer/tokenize'); -var SourceTracker = require('../../lib/utils/source-tracker'); -var Compatibility = require('../../lib/utils/compatibility'); +var compatibility = require('../../lib/utils/compatibility'); var Validator = require('../../lib/properties/validator'); function _optimize(source) { var tokens = tokenize(source, { options: {}, - sourceTracker: new SourceTracker(), warnings: [] }); - var compatibility = new Compatibility().toOptions(); - var validator = new Validator(compatibility); - optimize(tokens[0][1], tokens[0][2], false, true, { compatibility: compatibility, aggressiveMerging: true, shorthandCompacting: true }, { validator: validator }); + var compat = compatibility(); + var validator = new Validator(compat); + optimize(tokens[0][1], tokens[0][2], false, true, { options: { compatibility: compat, aggressiveMerging: true, shorthandCompacting: true }, validator: validator }); return tokens[0][2]; } @@ -27,12 +25,12 @@ function longhandFirst(prefixedLonghand, prefixedShorthand, zeroValue) { 'topic': function () { return _optimize('a{' + prefixedLonghand + ':inherit;' + prefixedShorthand + ':' + zeroValue + '}'); }, - 'has one token': function (body) { - assert.lengthOf(body, 1); + 'has one token': function (properties) { + assert.lengthOf(properties, 1); }, - 'has zero value only': function (body) { - assert.deepEqual(body[0][0], [prefixedShorthand]); - assert.deepEqual(body[0][1], [zeroValue]); + 'has zero value only': function (properties) { + assert.deepEqual(properties[0][1][1], prefixedShorthand); + assert.deepEqual(properties[0][2][1], zeroValue); } }; } @@ -42,16 +40,16 @@ function shorthandFirst(prefixedLonghand, prefixedShorthand, zeroValue) { 'topic': function () { return _optimize('a{' + prefixedShorthand + ':' + zeroValue + ';' + prefixedLonghand + ':inherit}'); }, - 'has two tokens': function (body) { - assert.lengthOf(body, 2); + 'has two tokens': function (properties) { + assert.lengthOf(properties, 2); }, - 'first is shorthand': function (body) { - assert.deepEqual(body[0][0], [prefixedShorthand]); - assert.deepEqual(body[0][1], [zeroValue]); + 'first is shorthand': function (properties) { + assert.deepEqual(properties[0][1][1], prefixedShorthand); + assert.deepEqual(properties[0][2][1], zeroValue); }, - 'second is longhand': function (body) { - assert.deepEqual(body[1][0], [prefixedLonghand]); - assert.deepEqual(body[1][1], ['inherit']); + 'second is longhand': function (properties) { + assert.deepEqual(properties[1][1][1], prefixedLonghand); + assert.deepEqual(properties[1][2][1], 'inherit'); } }; } diff --git a/test/properties/optimizer-test.js b/test/properties/optimizer-test.js index 1cf25a29..ed5d6933 100644 --- a/test/properties/optimizer-test.js +++ b/test/properties/optimizer-test.js @@ -4,21 +4,19 @@ var assert = require('assert'); var optimize = require('../../lib/properties/optimizer'); var tokenize = require('../../lib/tokenizer/tokenize'); -var SourceTracker = require('../../lib/utils/source-tracker'); -var Compatibility = require('../../lib/utils/compatibility'); +var compatibility = require('../../lib/utils/compatibility'); var Validator = require('../../lib/properties/validator'); function _optimize(source, mergeAdjacent, aggressiveMerging, compatibilityOptions) { - var compatibility = new Compatibility(compatibilityOptions).toOptions(); - var validator = new Validator(compatibility); + var compat = compatibility(compatibilityOptions); + var validator = new Validator(compat); var tokens = tokenize(source, { options: {}, - sourceTracker: new SourceTracker(), warnings: [] }); - optimize(tokens[0][1], tokens[0][2], mergeAdjacent, true, { compatibility: compatibility, aggressiveMerging: aggressiveMerging }, { validator: validator }); + optimize(tokens[0][1], tokens[0][2], mergeAdjacent, true, { options: { compatibility: compat, aggressiveMerging: aggressiveMerging }, validator: validator }); return tokens[0][2]; } @@ -26,399 +24,890 @@ function _optimize(source, mergeAdjacent, aggressiveMerging, compatibilityOption vows.describe(optimize) .addBatch({ 'of two adjacent properties': { - 'topic': 'a{display:-moz-inline-box;display:inline-block}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['display'], ['-moz-inline-box']], - [['display'], ['inline-block']] + 'topic': function () { + return _optimize('a{display:-moz-inline-box;display:inline-block}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 2, undefined]]], + ['property-value', '-moz-inline-box', [[1, 10, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 26, undefined]]], + ['property-value', 'inline-block', [[1, 34, undefined]]] + ] ]); } }, 'of two properties ': { - 'topic': 'a{display:inline-block;color:red;display:block}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['color'], ['red']], - [['display'], ['block']] + 'topic': function () { + return _optimize('a{display:inline-block;color:red;display:block}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 23, undefined]]], + ['property-value', 'red', [[1, 29, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 33, undefined]]], + ['property-value', 'block', [[1, 41, undefined]]] + ] ]); } }, 'of two same properties with same value where latter is a hack': { - 'topic': 'a{margin:0;_margin:0}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['margin'], ['0']], - [['_margin'], ['0']] + 'topic': function () { + return _optimize('a{margin:0;_margin:0}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'margin', [[1, 2, undefined]]], + ['property-value', '0', [[1, 9, undefined]]] + ], + [ + 'property', + ['property-name', '_margin', [[1, 11, undefined]]], + ['property-value', '0', [[1, 19, undefined]]] + ] ]); } }, 'of two same properties with same value where latter is !important': { - 'topic': 'a{margin:0;margin:0 !important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['margin'], ['0']], - [['margin'], ['0!important']] + 'topic': function () { + return _optimize('a{margin:0;margin:0 !important}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'margin', [[1, 2, undefined]]], + ['property-value', '0', [[1, 9, undefined]]] + ], + [ + 'property', + ['property-name', 'margin', [[1, 11, undefined]]], + ['property-value', '0!important', [[1, 18, undefined]]] + ] ]); } }, 'of two properties where former is !important': { - 'topic': 'a{display:inline-block!important;color:red;display:block}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['display'], ['inline-block!important']], - [['color'], ['red']] + 'topic': function () { + return _optimize('a{display:inline-block!important;color:red;display:block}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 2, undefined]]], + ['property-value', 'inline-block!important', [[1, 10, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 33, undefined]]], + ['property-value', 'red', [[1, 39, undefined]]] + ] ]); } }, 'of two properties where latter is !important': { - 'topic': 'a{display:inline-block;color:red;display:block!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['color'], ['red']], - [['display'], ['block!important']] + 'topic': function () { + return _optimize('a{display:inline-block;color:red;display:block!important}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 23, undefined]]], + ['property-value', 'red', [[1, 29, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 33, undefined]]], + ['property-value', 'block!important', [[1, 41, undefined]]] + ] ]); } }, 'of two properties where both are !important': { - 'topic': 'a{display:inline-block!important;color:red;display:block!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['color'], ['red']], - [['display'], ['block!important']] + 'topic': function () { + return _optimize('a{display:inline-block!important;color:red;display:block!important}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 33, undefined]]], + ['property-value', 'red', [[1, 39, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 43, undefined]]], + ['property-value', 'block!important', [[1, 51, undefined]]] + ] ]); } }, 'of many properties': { - 'topic': 'a{display:inline-block;color:red;font-weight:bolder;font-weight:700;display:block!important;color:#fff}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['font-weight'], ['bolder']], - [['font-weight'], ['700']], - [['display'], ['block!important']], - [['color'], ['#fff']] + 'topic': function () { + return _optimize('a{display:inline-block;color:red;font-weight:bolder;font-weight:700;display:block!important;color:#fff}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'font-weight', [[1, 33, undefined]]], + ['property-value', 'bolder', [[1, 45, undefined]]] + ], + [ + 'property', + ['property-name', 'font-weight', [[1, 52, undefined]]], + ['property-value', '700', [[1, 64, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 68, undefined]]], + ['property-value', 'block!important', [[1, 76, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 92, undefined]]], + ['property-value', '#fff', [[1, 98, undefined]]] + ] ]); } }, 'both redefined': { - 'topic': 'p{display:block;display:-moz-inline-box;color:red;display:table-cell}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['color'], ['red']], - [['display'], ['table-cell']] + 'topic': function () { + return _optimize('p{display:block;display:-moz-inline-box;color:red;display:table-cell}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 40, undefined]]], + ['property-value', 'red', [[1, 46, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 50, undefined]]], + ['property-value', 'table-cell', [[1, 58, undefined]]] + ] ]); } }, 'filter treated as background': { - 'topic': 'p{background:-moz-linear-gradient();background:-webkit-linear-gradient();filter:"progid:DXImageTransform";background:linear-gradient()}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['background'], ['-moz-linear-gradient()']], - [['background'], ['-webkit-linear-gradient()']], - [['filter'], ['"progid:DXImageTransform"']], - [['background'], ['linear-gradient()']] + 'topic': function () { + return _optimize('p{background:-moz-linear-gradient();background:-webkit-linear-gradient();filter:"progid:DXImageTransform";background:linear-gradient()}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', '-moz-linear-gradient()', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 36, undefined]]], + ['property-value', '-webkit-linear-gradient()', [[1, 47, undefined]]] + ], + [ + 'property', + ['property-name', 'filter', [[1, 73, undefined]]], + ['property-value', '"progid:DXImageTransform"', [[1, 80, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 106, undefined]]], + ['property-value', 'linear-gradient()', [[1, 117, undefined]]] + ] ]); } }, 'filter treated as background-image': { - 'topic': 'p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();filter:"progid:DXImageTransform";background-image:linear-gradient()}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['background-image'], ['-moz-linear-gradient()']], - [['background-image'], ['-webkit-linear-gradient()']], - [['filter'], ['"progid:DXImageTransform"']], - [['background-image'], ['linear-gradient()']] + 'topic': function () { + return _optimize('p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();filter:"progid:DXImageTransform";background-image:linear-gradient()}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-image', [[1, 2, undefined]]], + ['property-value', '-moz-linear-gradient()', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'background-image', [[1, 42, undefined]]], + ['property-value', '-webkit-linear-gradient()', [[1, 59, undefined]]] + ], + [ + 'property', + ['property-name', 'filter', [[1, 85, undefined]]], + ['property-value', '"progid:DXImageTransform"', [[1, 92, undefined]]] + ], + [ + 'property', + ['property-name', 'background-image', [[1, 118, undefined]]], + ['property-value', 'linear-gradient()', [[1, 135, undefined]]] + ] ]); } }, '-ms-filter treated as background': { - 'topic': 'p{background:-moz-linear-gradient();background:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background:linear-gradient()}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['background'], ['-moz-linear-gradient()']], - [['background'], ['-webkit-linear-gradient()']], - [['-ms-filter'], ['"progid:DXImageTransform"']], - [['background'], ['linear-gradient()']] + 'topic': function () { + return _optimize('p{background:-moz-linear-gradient();background:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background:linear-gradient()}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', '-moz-linear-gradient()', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 36, undefined]]], + ['property-value', '-webkit-linear-gradient()', [[1, 47, undefined]]] + ], + [ + 'property', + ['property-name', '-ms-filter', [[1, 73, undefined]]], + ['property-value', '"progid:DXImageTransform"', [[1, 84, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 110, undefined]]], + ['property-value', 'linear-gradient()', [[1, 121, undefined]]] + ] ]); } }, '-ms-filter treated as background-image': { - 'topic': 'p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background-image:linear-gradient()}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['background-image'], ['-moz-linear-gradient()']], - [['background-image'], ['-webkit-linear-gradient()']], - [['-ms-filter'], ['"progid:DXImageTransform"']], - [['background-image'], ['linear-gradient()']] + 'topic': function () { + return _optimize('p{background-image:-moz-linear-gradient();background-image:-webkit-linear-gradient();-ms-filter:"progid:DXImageTransform";background-image:linear-gradient()}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-image', [[1, 2, undefined]]], + ['property-value', '-moz-linear-gradient()', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'background-image', [[1, 42, undefined]]], + ['property-value', '-webkit-linear-gradient()', [[1, 59, undefined]]] + ], + [ + 'property', + ['property-name', '-ms-filter', [[1, 85, undefined]]], + ['property-value', '"progid:DXImageTransform"', [[1, 96, undefined]]] + ], + [ + 'property', + ['property-name', 'background-image', [[1, 122, undefined]]], + ['property-value', 'linear-gradient()', [[1, 139, undefined]]] + ] ]); } }, 'longhand then shorthand': { - 'topic': 'p{border-left-style:solid;border:1px dotted red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['border'], ['1px'], ['dotted'], ['red']] + 'topic': function () { + return _optimize('p{border-left-style:solid;border:1px dotted red}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 26, undefined]]], + ['property-value', '1px', [[1, 33, undefined]]], + ['property-value', 'dotted', [[1, 37, undefined]]], + ['property-value', 'red', [[1, 44, undefined]]] + ] ]); } }, 'longhand then shorthand with important': { - 'topic': 'p{border-left-style:solid!important;border:1px dotted red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['border-left-style'], ['solid!important']], - [['border'], ['1px'], ['dotted'], ['red']] + 'topic': function () { + return _optimize('p{border-left-style:solid!important;border:1px dotted red}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-left-style', [[1, 2, undefined]]], + ['property-value', 'solid!important', [[1, 20, undefined]]] + ], + [ + 'property', + ['property-name', 'border', [[1, 36, undefined]]], + ['property-value', '1px', [[1, 43, undefined]]], + ['property-value', 'dotted', [[1, 47, undefined]]], + ['property-value', 'red', [[1, 54, undefined]]] + ] ]); } }, 'shorthand then longhand': { - 'topic': 'p{background:url(image.png);background-image:#fff}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['background'], ['url(image.png)']], - [['background-image'], ['#fff']] + 'topic': function () { + return _optimize('p{background:url(image.png);background-image:#fff}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-image', [[1, 28, undefined]]], + ['property-value', '#fff', [[1, 45, undefined]]] + ] ]); } } }) .addBatch({ 'list-style fuzzy matching': { - 'topic': 'p{list-style:inside none}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['list-style'], ['none'], ['inside']] + 'topic': function () { + return _optimize('p{list-style:inside none}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'list-style', [[1, 2, undefined]]], + ['property-value', 'none', [[1, 20, undefined]]], + ['property-value', 'inside', [[1, 13, undefined]]] + ] ]); } } }) .addBatch({ 'ie hacks - normal before hack': { - 'topic': 'p{color:red;display:none;color:#fff\\9}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['color'], ['red']], - [['display'], ['none']], - [['color'], ['#fff\\9']] + 'topic': function () { + return _optimize('p{color:red;display:none;color:#fff\\9}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 8, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 12, undefined]]], + ['property-value', 'none', [[1, 20, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 25, undefined]]], + ['property-value', '#fff\\9', [[1, 31, undefined]]] + ] ]); } }, 'ie hacks - normal after hack': { - 'topic': 'p{color:red\\9;display:none;color:#fff}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['color'], ['red\\9']], - [['display'], ['none']], - [['color'], ['#fff']] + 'topic': function () { + return _optimize('p{color:red\\9;display:none;color:#fff}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', 'red\\9', [[1, 8, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 14, undefined]]], + ['property-value', 'none', [[1, 22, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 27, undefined]]], + ['property-value', '#fff', [[1, 33, undefined]]] + ] ]); } }, 'ie hacks - hack after hack': { - 'topic': 'p{color:red\\9;display:none;color:#fff\\9}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['display'], ['none']], - [['color'], ['#fff\\9']] + 'topic': function () { + return _optimize('p{color:red\\9;display:none;color:#fff\\9}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 14, undefined]]], + ['property-value', 'none', [[1, 22, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 27, undefined]]], + ['property-value', '#fff\\9', [[1, 33, undefined]]] + ] ]); } } }) .addBatch({ 'mergeAdjacent is true': { - 'topic': 'p{display:block;display:inline-block}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, true, true), [ - [['display'], ['inline-block']] + 'topic': function () { + return _optimize('p{display:block;display:inline-block}', true, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 16, undefined]]], + ['property-value', 'inline-block', [[1, 24, undefined]]] + ] ]); } }, 'mergeAdjacent is false': { - 'topic': 'p{display:block;display:inline-block}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['display'], ['block']], - [['display'], ['inline-block']] + 'topic': function () { + return _optimize('p{display:block;display:inline-block}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 2, undefined]]], + ['property-value', 'block', [[1, 10, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 16, undefined]]], + ['property-value', 'inline-block', [[1, 24, undefined]]] + ] ]); } }, 'mergeAdjacent is an array with irrelevant join positions': { - 'topic': 'p{display:block;display:inline-block;color:red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, [2], true), [ - [['display'], ['block']], - [['display'], ['inline-block']], - [['color'], ['red']] + 'topic': function () { + return _optimize('p{display:block;display:inline-block;color:red}', [2], true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 2, undefined]]], + ['property-value', 'block', [[1, 10, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 16, undefined]]], + ['property-value', 'inline-block', [[1, 24, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 37, undefined]]], + ['property-value', 'red', [[1, 43, undefined]]] + ] ]); } }, 'mergeAdjacent is an array with relevant join positions': { - 'topic': 'p{display:block;display:inline-block;color:red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, [1], true), [ - [['display'], ['inline-block']], - [['color'], ['red']] + 'topic': function () { + return _optimize('p{display:block;display:inline-block;color:red}', [1], true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 16, undefined]]], + ['property-value', 'inline-block', [[1, 24, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 37, undefined]]], + ['property-value', 'red', [[1, 43, undefined]]] + ] ]); } } }) .addBatch({ 'aggressive off - (yet) not overriddable': { - 'topic': 'a{display:inline-block;color:red;display:-moz-block}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false), [ - [['display'], ['inline-block']], - [['color'], ['red']], - [['display'], ['-moz-block']] + 'topic': function () { + return _optimize('a{display:inline-block;color:red;display:-moz-block}', false); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 2, undefined]]], + ['property-value', 'inline-block', [[1, 10, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 23, undefined]]], + ['property-value', 'red', [[1, 29, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 33, undefined]]], + ['property-value', '-moz-block', [[1, 41, undefined]]] + ] ]); } } }) .addBatch({ 'understandable - 2 properties, both !important, 2nd less understandable': { - 'topic': 'a{color:red!important;display:block;color:rgba(0,255,0,.5)!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['color'], ['red!important']], - [['display'], ['block']], - [['color'], ['rgba(0,255,0,.5)!important']] + 'topic': function () { + return _optimize('a{color:red!important;display:block;color:rgba(0,255,0,.5)!important}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', 'red!important', [[1, 8, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 22, undefined]]], + ['property-value', 'block', [[1, 30, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 36, undefined]]], + ['property-value', 'rgba(0,255,0,.5)!important', [[1, 42, undefined]]] + ] ]); } }, 'understandable - 2 properties, both !important, 2nd more understandable': { - 'topic': 'a{color:rgba(0,255,0,.5)!important;display:block;color:red!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['display'], ['block']], - [['color'], ['red!important']] + 'topic': function () { + return _optimize('a{color:rgba(0,255,0,.5)!important;display:block;color:red!important}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 35, undefined]]], + ['property-value', 'block', [[1, 43, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 49, undefined]]], + ['property-value', 'red!important', [[1, 55, undefined]]] + ] ]); } }, 'understandable - 2 adjacent properties, both !important, 2nd less understandable': { - 'topic': 'a{background:red!important;background:rgba(0,255,0,.5)!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['background'], ['red!important']], - [['background'], ['rgba(0,255,0,.5)!important']] + 'topic': function () { + return _optimize('a{background:red!important;background:rgba(0,255,0,.5)!important}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'red!important', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 27, undefined]]], + ['property-value', 'rgba(0,255,0,.5)!important', [[1, 38, undefined]]] + ] ]); } }, 'understandable - 2 adjacent properties, both !important, 2nd more understandable': { - 'topic': 'a{background:rgba(0,255,0,.5)!important;background:red!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['background'], ['rgba(0,255,0,.5)!important']], - [['background'], ['red!important']] + 'topic': function () { + return _optimize('a{background:rgba(0,255,0,.5)!important;background:red!important}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'rgba(0,255,0,.5)!important', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 40, undefined]]], + ['property-value', 'red!important', [[1, 51, undefined]]] + ] ]); } }, 'understandable - 2 adjacent -ms-transform with different values': { - 'topic': 'div{-ms-transform:translate(0,0);-ms-transform:translate3d(0,0,0)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['-ms-transform'], ['translate(0,0)']], - [['-ms-transform'], ['translate3d(0,0,0)']] + 'topic': function () { + return _optimize('div{-ms-transform:translate(0,0);-ms-transform:translate3d(0,0,0)}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', '-ms-transform', [[1, 4, undefined]]], + ['property-value', 'translate(0,0)', [[1, 18, undefined]]] + ], + [ + 'property', + ['property-name', '-ms-transform', [[1, 33, undefined]]], + ['property-value', 'translate3d(0,0,0)', [[1, 47, undefined]]] + ] ]); } }, 'understandable - 2 non-adjacent -ms-transform with different values': { - 'topic': 'div{-ms-transform:translate(0,0);-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['-ms-transform'], ['translate(0,0)']], - [['-webkit-transform'], ['translate3d(0,0,0)']], - [['-ms-transform'], ['translate3d(0,0,0)']] + 'topic': function () { + return _optimize('div{-ms-transform:translate(0,0);-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0)}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', '-ms-transform', [[1, 4, undefined]]], + ['property-value', 'translate(0,0)', [[1, 18, undefined]]] + ], + [ + 'property', + ['property-name', '-webkit-transform', [[1, 33, undefined]]], + ['property-value', 'translate3d(0,0,0)', [[1, 51, undefined]]] + ], + [ + 'property', + ['property-name', '-ms-transform', [[1, 70, undefined]]], + ['property-value', 'translate3d(0,0,0)', [[1, 84, undefined]]] + ] ]); } }, 'understandable - 2 adjacent transform with different values': { - 'topic': 'div{transform:translate(0,0);transform:translate3d(0,0,0)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['transform'], ['translate(0,0)']], - [['transform'], ['translate3d(0,0,0)']] + 'topic': function () { + return _optimize('div{transform:translate(0,0);transform:translate3d(0,0,0)}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'transform', [[1, 4, undefined]]], + ['property-value', 'translate(0,0)', [[1, 14, undefined]]] + ], + [ + 'property', + ['property-name', 'transform', [[1, 29, undefined]]], + ['property-value', 'translate3d(0,0,0)', [[1, 39, undefined]]] + ] ]); } }, 'understandable - 2 non-adjacent transform with different values': { - 'topic': 'div{transform:translate(0,0);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['transform'], ['translate(0,0)']], - [['-webkit-transform'], ['translate3d(0,0,0)']], - [['transform'], ['translate3d(0,0,0)']] + 'topic': function () { + return _optimize('div{transform:translate(0,0);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'transform', [[1, 4, undefined]]], + ['property-value', 'translate(0,0)', [[1, 14, undefined]]] + ], + [ + 'property', + ['property-name', '-webkit-transform', [[1, 29, undefined]]], + ['property-value', 'translate3d(0,0,0)', [[1, 47, undefined]]] + ], + [ + 'property', + ['property-name', 'transform', [[1, 66, undefined]]], + ['property-value', 'translate3d(0,0,0)', [[1, 76, undefined]]] + ] ]); } }, 'understandable - border(hex) with border(rgba)': { - 'topic': 'a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['border'], ['1px'], ['solid'], ['#fff']], - [['border'], ['1px'], ['solid'], ['rgba(1,0,0,.5)']] + 'topic': function () { + return _optimize('a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 9, undefined]]], + ['property-value', 'solid', [[1, 13, undefined]]], + ['property-value', '#fff', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'border', [[1, 24, undefined]]], + ['property-value', '1px', [[1, 31, undefined]]], + ['property-value', 'solid', [[1, 35, undefined]]], + ['property-value', 'rgba(1,0,0,.5)', [[1, 41, undefined]]] + ] ]); } }, 'understandable - border(hex) with border(rgba !important)': { - 'topic': 'a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['border'], ['1px'], ['solid'], ['#fff']], - [['border'], ['1px'], ['solid'], ['rgba(1,0,0,.5)!important']] + 'topic': function () { + return _optimize('a{border:1px solid #fff;border:1px solid rgba(1,0,0,.5)!important}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 9, undefined]]], + ['property-value', 'solid', [[1, 13, undefined]]], + ['property-value', '#fff', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'border', [[1, 24, undefined]]], + ['property-value', '1px', [[1, 31, undefined]]], + ['property-value', 'solid', [[1, 35, undefined]]], + ['property-value', 'rgba(1,0,0,.5)!important', [[1, 41, undefined]]] + ] ]); } }, 'understandable - border(hex !important) with border(hex)': { - 'topic': 'a{border:1px solid #fff!important;display:block;border:1px solid #fff}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['border'], ['1px'], ['solid'], ['#fff!important']], - [['display'], ['block']] + 'topic': function () { + return _optimize('a{border:1px solid #fff!important;display:block;border:1px solid #fff}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 9, undefined]]], + ['property-value', 'solid', [[1, 13, undefined]]], + ['property-value', '#fff!important', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 34, undefined]]], + ['property-value', 'block', [[1, 42, undefined]]] + ] ]); } }, 'understandable - border(hex) with border(hex !important)': { - 'topic': 'a{border:1px solid #fff;display:block;border:1px solid #fff!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['display'], ['block']], - [['border'], ['1px'], ['solid'], ['#fff!important']] + 'topic': function () { + return _optimize('a{border:1px solid #fff;display:block;border:1px solid #fff!important}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 24, undefined]]], + ['property-value', 'block', [[1, 32, undefined]]] + ], + [ + 'property', + ['property-name', 'border', [[1, 38, undefined]]], + ['property-value', '1px', [[1, 45, undefined]]], + ['property-value', 'solid', [[1, 49, undefined]]], + ['property-value', '#fff!important', [[1, 55, undefined]]] + ] ]); } }, 'understandable - unit with function with unit without one': { - 'topic': 'a{border-top-width:calc(100%);display:block;border-top-width:1px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['display'], ['block']], - [['border-top-width'], ['1px']] + 'topic': function () { + return _optimize('a{border-top-width:calc(100%);display:block;border-top-width:1px}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'display', [[1, 30, undefined]]], + ['property-value', 'block', [[1, 38, undefined]]] + ], + [ + 'property', + ['property-name', 'border-top-width', [[1, 44, undefined]]], + ['property-value', '1px', [[1, 61, undefined]]] + ] ]); } }, 'understandable - unit without function with unit with one': { - 'topic': 'a{border-top-width:1px;display:block;border-top-width:calc(100%)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['border-top-width'], ['1px']], - [['display'], ['block']], - [['border-top-width'], ['calc(100%)']] + 'topic': function () { + return _optimize('a{border-top-width:1px;display:block;border-top-width:calc(100%)}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-top-width', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 23, undefined]]], + ['property-value', 'block', [[1, 31, undefined]]] + ], + [ + 'property', + ['property-name', 'border-top-width', [[1, 37, undefined]]], + ['property-value', 'calc(100%)', [[1, 54, undefined]]] + ] ]); } }, 'understandable - non adjacent units': { - 'topic': 'a{margin-top:100px;padding-top:30px;margin-top:10vmin}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true), [ - [['padding-top'], ['30px']], - [['margin-top'], ['10vmin']] + 'topic': function () { + return _optimize('a{margin-top:80px;padding-top:30px;margin-top:10vmin}', false, true); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'padding-top', [[1, 18, undefined]]], + ['property-value', '30px', [[1, 30, undefined]]] + ], + [ + 'property', + ['property-name', 'margin-top', [[1, 35, undefined]]], + ['property-value', '10vmin', [[1, 46, undefined]]] + ] ]); } } }) .addBatch({ 'understandable - non adjacent units in IE8 mode': { - 'topic': 'a{margin-top:80px;padding-top:30px;margin-top:10vmin}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, false, true, 'ie8'), [ - [['margin-top'], ['80px']], - [['padding-top'], ['30px']], - [['margin-top'], ['10vmin']] + 'topic': function () { + return _optimize('a{margin-top:80px;padding-top:30px;margin-top:10vmin}', false, true, 'ie8'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'margin-top', [[1, 2, undefined]]], + ['property-value', '80px', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-top', [[1, 18, undefined]]], + ['property-value', '30px', [[1, 30, undefined]]] + ], + [ + 'property', + ['property-name', 'margin-top', [[1, 35, undefined]]], + ['property-value', '10vmin', [[1, 46, undefined]]] + ] ]); } } diff --git a/test/properties/override-compacting-test.js b/test/properties/override-compacting-test.js index d9bafaef..d75d9d08 100644 --- a/test/properties/override-compacting-test.js +++ b/test/properties/override-compacting-test.js @@ -4,25 +4,23 @@ var assert = require('assert'); var optimize = require('../../lib/properties/optimizer'); var tokenize = require('../../lib/tokenizer/tokenize'); -var SourceTracker = require('../../lib/utils/source-tracker'); -var Compatibility = require('../../lib/utils/compatibility'); +var compatibility = require('../../lib/utils/compatibility'); var Validator = require('../../lib/properties/validator'); -function _optimize(source, compatibility, aggressiveMerging) { +function _optimize(source, compat, aggressiveMerging) { var tokens = tokenize(source, { options: {}, - sourceTracker: new SourceTracker(), warnings: [] }); - compatibility = new Compatibility(compatibility).toOptions(); + compat = compatibility(compat); - var validator = new Validator(compatibility); + var validator = new Validator(compat); var options = { aggressiveMerging: undefined === aggressiveMerging ? true : aggressiveMerging, - compatibility: compatibility, + compatibility: compat, shorthandCompacting: true }; - optimize(tokens[0][1], tokens[0][2], false, true, options, { validator: validator }); + optimize(tokens[0][1], tokens[0][2], false, true, { options: options, validator: validator }); return tokens[0][2]; } @@ -30,726 +28,1529 @@ function _optimize(source, compatibility, aggressiveMerging) { vows.describe(optimize) .addBatch({ 'longhand then longhand - background colors as functions': { - 'topic': 'p{background-color:-ms-linear-gradient(top,red,#000);background-color:linear-gradient(top,red,#000)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-color'], ['-ms-linear-gradient(top,red,#000)']], - [['background-color'], ['linear-gradient(top,red,#000)']] + 'topic': function () { + return _optimize('p{background-color:-ms-linear-gradient(top,red,#000);background-color:linear-gradient(top,red,#000)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-color', [[1, 2, undefined]]], + ['property-value', '-ms-linear-gradient(top,red,#000)', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'background-color', [[1, 53, undefined]]], + ['property-value', 'linear-gradient(top,red,#000)', [[1, 70, undefined]]] + ] ]); } }, 'longhand then longhand - background position as function': { - 'topic': 'p{background-position:-moz-calc(100% - 1em) 0;background-position:calc(100% - 1em) 0}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-position'], ['-moz-calc(100% - 1em)'], ['0']], - [['background-position'], ['calc(100% - 1em)'], ['0']] + 'topic': function () { + return _optimize('p{background-position:-moz-calc(100% - 1em) 0;background-position:calc(100% - 1em) 0}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-position', [[1, 2, undefined]]], + ['property-value', '-moz-calc(100% - 1em)', [[1, 22, undefined]]], + ['property-value', '0', [[1, 44, undefined]]] + ], + [ + 'property', + ['property-name', 'background-position', [[1, 46, undefined]]], + ['property-value', 'calc(100% - 1em)', [[1, 66, undefined]]], + ['property-value', '0', [[1, 83, undefined]]] + ] ]); } }, 'longhand then longhand - background position as same function': { - 'topic': 'p{background-position:calc(100% - 1em) 0;background-position:calc(100% - 1em) 1em}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-position'], ['calc(100% - 1em)'], ['1em']] + 'topic': function () { + return _optimize('p{background-position:calc(100% - 1em) 0;background-position:calc(100% - 1em) 1em}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-position', [[1, 41, undefined]]], + ['property-value', 'calc(100% - 1em)', [[1, 61, undefined]]], + ['property-value', '1em', [[1, 78, undefined]]] + ] ]); } }, 'longhand then longhand - background position as function by value': { - 'topic': 'p{background-position:calc(100% - 1em) 0;background-position:1em 1em}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-position'], ['1em'], ['1em']] + 'topic': function () { + return _optimize('p{background-position:calc(100% - 1em) 0;background-position:1em 1em}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-position', [[1, 41, undefined]]], + ['property-value', '1em', [[1, 61, undefined]]], + ['property-value', '1em', [[1, 65, undefined]]] + ] ]); } }, 'longhand then longhand - background position as value by function': { - 'topic': 'p{background-position:1em 0;background-position:calc(100% - 1em) 1em}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-position'], ['1em'], ['0']], - [['background-position'], ['calc(100% - 1em)'], ['1em']] + 'topic': function () { + return _optimize('p{background-position:1em 0;background-position:calc(100% - 1em) 1em}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-position', [[1, 2, undefined]]], + ['property-value', '1em', [[1, 22, undefined]]], + ['property-value', '0', [[1, 26, undefined]]] + ], + [ + 'property', + ['property-name', 'background-position', [[1, 28, undefined]]], + ['property-value', 'calc(100% - 1em)', [[1, 48, undefined]]], + ['property-value', '1em', [[1, 65, undefined]]] + ] ]); } }, 'longhand then longhand - background size as function': { - 'topic': 'p{background-size:-moz-calc(100% - 1em) 0;background-size:calc(100% - 1em) 0}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-size'], ['-moz-calc(100% - 1em)'], ['0']], - [['background-size'], ['calc(100% - 1em)'], ['0']] + 'topic': function () { + return _optimize('p{background-size:-moz-calc(100% - 1em) 0;background-size:calc(100% - 1em) 0}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-size', [[1, 2, undefined]]], + ['property-value', '-moz-calc(100% - 1em)', [[1, 18, undefined]]], + ['property-value', '0', [[1, 40, undefined]]] + ], + [ + 'property', + ['property-name', 'background-size', [[1, 42, undefined]]], + ['property-value', 'calc(100% - 1em)', [[1, 58, undefined]]], + ['property-value', '0', [[1, 75, undefined]]] + ] ]); } }, 'longhand then shorthand': { - 'topic': 'p{background-image:none;background:__ESCAPED_URL_CLEAN_CSS0__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']] + 'topic': function () { + return _optimize('p{background-image:none;background:url(image.png)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 24, undefined]]], + ['property-value', 'url(image.png)', [[1, 35, undefined]]] + ] ]); } }, 'longhand then shorthand - important then non-important': { - 'topic': 'p{background-image:none!important;background:__ESCAPED_URL_CLEAN_CSS0__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-image'], ['none!important']], - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']] + 'topic': function () { + return _optimize('p{background-image:none!important;background:url(image.png)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-image', [[1, 2, undefined]]], + ['property-value', 'none!important', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 34, undefined]]], + ['property-value', 'url(image.png)', [[1, 45, undefined]]] + ] ]); } }, 'longhand then shorthand - with vendor prefixed function': { - 'topic': 'p{background-color:red;background:-ms-linear-gradient(top,red,#000)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-color'], ['red']], - [['background'], ['-ms-linear-gradient(top,red,#000)']], + 'topic': function () { + return _optimize('p{background-color:red;background:-ms-linear-gradient(top,red,#000)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-color', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 23, undefined]]], + ['property-value', '-ms-linear-gradient(top,red,#000)', [[1, 34, undefined]]] + ] ]); } }, 'longhand then shorthand - with same vendor prefixed function': { - 'topic': 'p{background-image:-ms-linear-gradient(bottom,black,white);background:-ms-linear-gradient(top,red,#000)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['-ms-linear-gradient(top,red,#000)']], + 'topic': function () { + return _optimize('p{background-image:-ms-linear-gradient(bottom,black,white);background:-ms-linear-gradient(top,red,#000)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 59, undefined]]], + ['property-value', '-ms-linear-gradient(top,red,#000)', [[1, 70, undefined]]] + ] ]); } }, 'longhand then shorthand - with different vendor prefixed function': { - 'topic': 'p{background-image:linear-gradient(bottom,black,white);background:-ms-linear-gradient(top,red,#000)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-image'], ['linear-gradient(bottom,black,white)']], - [['background'], ['-ms-linear-gradient(top,red,#000)']], + 'topic': function () { + return _optimize('p{background-image:linear-gradient(bottom,black,white);background:-ms-linear-gradient(top,red,#000)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-image', [[1, 2, undefined]]], + ['property-value', 'linear-gradient(bottom,black,white)', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 55, undefined]]], + ['property-value', '-ms-linear-gradient(top,red,#000)', [[1, 66, undefined]]] + ] ]); } }, 'longhand then shorthand - with unprefixed function': { - 'topic': 'p{background-color:red;background:linear-gradient(red,blue)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-color'], ['red']], - [['background'], ['linear-gradient(red,blue)']] + 'topic': function () { + return _optimize('p{background-color:red;background:linear-gradient(red,blue)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-color', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 23, undefined]]], + ['property-value', 'linear-gradient(red,blue)', [[1, 34, undefined]]] + ] ]); } }, 'shorthand then longhand': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__ repeat;background-repeat:no-repeat}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat']] + 'topic': function () { + return _optimize('p{background:url(image.png) repeat;background-repeat:no-repeat}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]], + ['property-value', 'no-repeat', [[1, 53, undefined]]] + ] ]); } }, 'shorthand then longhand - important then non-important': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__ repeat-x!important;background-repeat:no-repeat}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['repeat-x!important']] + 'topic': function () { + return _optimize('p{background:url(image.png) repeat-x!important;background-repeat:no-repeat}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]], + ['property-value', 'repeat-x!important', [[1, 28, undefined]]] + ] ]); } }, 'shorthand then longhand - non-important then important': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__ repeat;background-repeat:no-repeat!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']], - [['background-repeat'], ['no-repeat!important']] + 'topic': function () { + return _optimize('p{background:url(image.png) repeat;background-repeat:no-repeat!important}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-repeat', [[1, 35, undefined]]], + ['property-value', 'no-repeat!important', [[1, 53, undefined]]] + ] ]); } }, 'shorthand then longhand - disabled background size merging': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background-size:50%}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, { properties: { backgroundSizeMerging: false } }), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']], - [['background-size'], ['50%']] + 'topic': function () { + return _optimize('p{background:url(image.png);background-size:50%}', { properties: { backgroundSizeMerging: false } }); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-size', [[1, 28, undefined]]], + ['property-value', '50%', [[1, 44, undefined]]] + ] ]); } }, 'shorthand then longhand - disabled background clip merging': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background-clip:padding-box}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, { properties: { backgroundClipMerging: false } }), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']], - [['background-clip'], ['padding-box']] + 'topic': function () { + return _optimize('p{background:url(image.png);background-clip:padding-box}', { properties: { backgroundClipMerging: false } }); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-clip', [[1, 28, undefined]]], + ['property-value', 'padding-box', [[1, 44, undefined]]] + ] ]); } }, 'shorthand then longhand - enabled background clip merging': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background-clip:padding-box}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, { properties: { backgroundClipMerging: true } }), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['padding-box']] + 'topic': function () { + return _optimize('p{background:url(image.png);background-clip:padding-box}', { properties: { backgroundClipMerging: true } }); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]], + ['property-value', 'padding-box'] + ] ]); } }, 'shorthand then longhand - disabled background origin merging': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background-origin:border-box}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, { properties: { backgroundOriginMerging: false } }), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']], - [['background-origin'], ['border-box']] + 'topic': function () { + return _optimize('p{background:url(image.png);background-origin:border-box}', { properties: { backgroundOriginMerging: false } }); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-origin', [[1, 28, undefined]]], + ['property-value', 'border-box', [[1, 46, undefined]]] + ] ]); } }, 'shorthand then longhand - enabled background origin merging': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background-origin:border-box}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, { properties: { backgroundOriginMerging: true } }), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['border-box']] + 'topic': function () { + return _optimize('p{background:url(image.png);background-origin:border-box}', { properties: { backgroundOriginMerging: true } }); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]], + ['property-value', 'border-box', [[1, 46, undefined]]] + ] ]); } }, 'shorthand then longhand - non mergeable value': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background-color:none}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']], - [['background-color'], ['none']] + 'topic': function () { + return _optimize('p{background:url(image.png);background-color:none}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-color', [[1, 28, undefined]]], + ['property-value', 'none', [[1, 45, undefined]]] + ] ]); } }, 'shorthand then multiplex longhand - non mergeable value': { - 'topic': 'p{background:#fff;background-image:__ESCAPED_URL_CLEAN_CSS0__,linear-gradient()}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['#fff']], - [['background-image'], ['__ESCAPED_URL_CLEAN_CSS0__'], [','], ['linear-gradient()']] + 'topic': function () { + return _optimize('p{background:#fff;background-image:url(image.png),linear-gradient()}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', '#fff', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-image', [[1, 18, undefined]]], + ['property-value', 'url(image.png)', [[1, 35, undefined]]], + ['property-value', ',', [[1, 49, undefined]]], + ['property-value', 'linear-gradient()', [[1, 50, undefined]]] + ] ]); } }, 'shorthand then longhand - border with rgba() and color opacity on': { - 'topic': 'p{border:solid rgba(0,0,0,0);border-color:transparent}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, { colors: { opacity: true } }), [ - [['border'], ['solid'], ['transparent']] + 'topic': function () { + return _optimize('p{border:solid rgba(0,0,0,0);border-color:transparent}', { colors: { opacity: true } }); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', 'solid', [[1, 9, undefined]]], + ['property-value', 'transparent', [[1, 42, undefined]]] + ] ]); } }, 'shorthand then longhand - border with rgba() and color opacity off': { - 'topic': 'p{border:solid rgba(0,0,0,0);border-color:transparent}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, { colors: { opacity: false } }), [ - [['border'], ['solid'], ['rgba(0,0,0,0)']], - [['border-color'], ['transparent']] + 'topic': function () { + return _optimize('p{border:solid rgba(0,0,0,0);border-color:transparent}', { colors: { opacity: false } }); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', 'solid', [[1, 9, undefined]]], + ['property-value', 'rgba(0,0,0,0)', [[1, 15, undefined]]] + ], + [ + 'property', + ['property-name', 'border-color', [[1, 29, undefined]]], + ['property-value', 'transparent', [[1, 42, undefined]]] + ] ]); } }, 'shorthand then longhand - color into a color - with merging off': { - 'topic': 'p{background:white;background-color:red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, { properties: { merging: false } }), [ - [['background'], ['red']] + 'topic': function () { + return _optimize('p{background:white;background-color:red}', { properties: { merging: false } }); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 36, undefined]]] + ], ]); } }, 'shorthand then longhand - color into a function - with merging off': { - 'topic': 'p{background:linear-gradient();background-color:red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, { properties: { merging: false } }), [ - [['background'], ['linear-gradient()']], - [['background-color'], ['red']] + 'topic': function () { + return _optimize('p{background:linear-gradient();background-color:red}', { properties: { merging: false } }); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'linear-gradient()', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-color', [[1, 31, undefined]]], + ['property-value', 'red', [[1, 48, undefined]]] + ] ]); } }, 'shorthand then longhand - two shorthands - pending #527': { - 'topic': 'p{background:-webkit-linear-gradient();background:linear-gradient();background-repeat:repeat-x}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['-webkit-linear-gradient()']], - [['background'], ['linear-gradient()']], - [['background-repeat'], ['repeat-x']] + 'topic': function () { + return _optimize('p{background:-webkit-linear-gradient();background:linear-gradient();background-repeat:repeat-x}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', '-webkit-linear-gradient()', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 39, undefined]]], + ['property-value', 'linear-gradient()', [[1, 50, undefined]]] + ], + [ + 'property', + ['property-name', 'background-repeat', [[1, 68, undefined]]], + ['property-value', 'repeat-x', [[1, 86, undefined]]] + ] ]); } }, 'shorthand then longhand - two shorthands and default - pending #527': { - 'topic': 'p{background:-webkit-linear-gradient();background:linear-gradient();background-repeat:repeat}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['-webkit-linear-gradient()']], - [['background'], ['linear-gradient()']], - [['background-repeat'], ['repeat']] + 'topic': function () { + return _optimize('p{background:-webkit-linear-gradient();background:linear-gradient();background-repeat:repeat}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', '-webkit-linear-gradient()', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 39, undefined]]], + ['property-value', 'linear-gradient()', [[1, 50, undefined]]] + ], + [ + 'property', + ['property-name', 'background-repeat', [[1, 68, undefined]]], + ['property-value', 'repeat', [[1, 86, undefined]]] + ] ]); } }, 'shorthand then longhand - two mergeable shorthands and default - pending #527': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background:__ESCAPED_URL_CLEAN_CSS1__;background-repeat:repeat-x}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS1__']], - [['background-repeat'], ['repeat-x']] + 'topic': function () { + return _optimize('p{background:url(image.png);background:url(image.jpg);background-repeat:repeat-x}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.jpg)', [[1, 39, undefined]]] + ], + [ + 'property', + ['property-name', 'background-repeat', [[1, 54, undefined]]], + ['property-value', 'repeat-x', [[1, 72, undefined]]] + ] ]); } }, 'shorthand then longhand - non-function into a function': { - 'topic': 'p{background:linear-gradient();background-color:red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['linear-gradient()']], - [['background-color'], ['red']] + 'topic': function () { + return _optimize('p{background:linear-gradient();background-color:red}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'linear-gradient()', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-color', [[1, 31, undefined]]], + ['property-value', 'red', [[1, 48, undefined]]] + ] ]); } }, 'shorthand then longhand - function into a non-function': { - 'topic': 'p{background:repeat-x;background-image:-webkit-linear-gradient()}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['repeat-x']], - [['background-image'], ['-webkit-linear-gradient()']] + 'topic': function () { + return _optimize('p{background:repeat-x;background-image:-webkit-linear-gradient()}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'repeat-x', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-image', [[1, 22, undefined]]], + ['property-value', '-webkit-linear-gradient()', [[1, 39, undefined]]] + ] ]); } }, 'shorthand then shorthand - same values': { - 'topic': 'p{background:red;background:red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['red']] + 'topic': function () { + return _optimize('p{background:red;background:red}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 28, undefined]]] + ] ]); } }, 'shorthand then shorthand - same values with defaults': { - 'topic': 'p{background:repeat red;background:red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['red']] + 'topic': function () { + return _optimize('p{background:repeat red;background:red}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 35, undefined]]] + ] ]); } }, 'shorthand then shorthand - with different functions': { - 'topic': 'p{background:linear-gradient();background:-webkit-gradient()}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['linear-gradient()']], - [['background'], ['-webkit-gradient()']] + 'topic': function () { + return _optimize('p{background:linear-gradient();background:-webkit-gradient()}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'linear-gradient()', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 31, undefined]]], + ['property-value', '-webkit-gradient()', [[1, 42, undefined]]] + ] ]); } }, 'shorthand then shorthand - with function then url': { - 'topic': 'p{background:linear-gradient();background:__ESCAPED_URL_CLEAN_CSS0__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']] + 'topic': function () { + return _optimize('p{background:linear-gradient();background:url(image.png)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 42, undefined]]] + ] ]); } }, 'shorthand then shorthand - with url then function': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background:linear-gradient()}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']], - [['background'], ['linear-gradient()']] + 'topic': function () { + return _optimize('p{background:url(image.png);background:linear-gradient()}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 28, undefined]]], + ['property-value', 'linear-gradient()', [[1, 39, undefined]]] + ] ]); } }, 'shorthand then shorthand - important then non-important': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__ no-repeat!important;background:__ESCAPED_URL_CLEAN_CSS1__ repeat red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat!important']] + 'topic': function () { + return _optimize('p{background:url(image.png) no-repeat!important;background:url(image.jpg) repeat red}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]], + ['property-value', 'no-repeat!important', [[1, 28, undefined]]] + ] ]); } }, 'shorthand then shorthand - non-important then important': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__ no-repeat;background:__ESCAPED_URL_CLEAN_CSS1__ repeat red!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS1__'], ['red!important']] + 'topic': function () { + return _optimize('p{background:url(image.png) no-repeat;background:url(image.jpg) repeat red!important}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 38, undefined]]], + ['property-value', 'url(image.jpg)', [[1, 49, undefined]]], + ['property-value', 'red!important', [[1, 71, undefined]]] + ] ]); } }, 'shorthand then shorthand - same value and latter important': { - 'topic': 'a{margin:0;margin:0 !important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['margin'], ['0!important']] + 'topic': function () { + return _optimize('a{margin:0;margin:0 !important}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'margin', [[1, 11, undefined]]], + ['property-value', '0!important', [[1, 18, undefined]]] + ] ]); } }, 'with aggressive off': { - 'topic': 'a{background:white;color:red;background:red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic, null, false), [ - [['background'], ['red']], - [['color'], ['red']] + 'topic': function () { + return _optimize('a{background:white;color:red;background:red}', undefined, false); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 40, undefined]]] + ], + [ + 'property', + ['property-name', 'color', [[1, 19, undefined]]], + ['property-value', 'red', [[1, 25, undefined]]] + ] ]); } } }) .addBatch({ 'border': { - 'topic': 'a{border:1px solid red;border-style:dotted}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border'], ['1px'], ['dotted'], ['red']] + 'topic': function () { + return _optimize('a{border:1px solid red;border-style:dotted}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 9, undefined]]], + ['property-value', 'dotted', [[1, 36, undefined]]], + ['property-value', 'red', [[1, 19, undefined]]] + ] ]); } }, 'border - multivalue righthand': { - 'topic': 'a{border:1px solid red;border-style:dotted solid}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border'], ['1px'], ['solid'], ['red']], - [['border-style'], ['dotted'], ['solid']] + 'topic': function () { + return _optimize('a{border:1px solid red;border-style:dotted solid}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 9, undefined]]], + ['property-value', 'solid', [[1, 13, undefined]]], + ['property-value', 'red', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'border-style', [[1, 23, undefined]]], + ['property-value', 'dotted', [[1, 36, undefined]]], + ['property-value', 'solid', [[1, 43, undefined]]] + ] ]); } }, 'border - important righthand': { - 'topic': 'a{border:1px solid red;border-style:dotted!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border'], ['1px'], ['solid'], ['red']], - [['border-style'], ['dotted!important']] + 'topic': function () { + return _optimize('a{border:1px solid red;border-style:dotted!important}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 9, undefined]]], + ['property-value', 'solid', [[1, 13, undefined]]], + ['property-value', 'red', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'border-style', [[1, 23, undefined]]], + ['property-value', 'dotted!important', [[1, 36, undefined]]], + ] ]); } }, 'border - important lefthand': { - 'topic': 'a{border:1px solid red!important;border-style:dotted}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border'], ['1px'], ['solid'], ['red!important']] + 'topic': function () { + return _optimize('a{border:1px solid red!important;border-style:dotted}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 9, undefined]]], + ['property-value', 'solid', [[1, 13, undefined]]], + ['property-value', 'red!important', [[1, 19, undefined]]] + ] ]); } }, 'border - both important': { - 'topic': 'a{border:1px solid red!important;border-style:dotted!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border'], ['1px'], ['dotted'], ['red!important']] + 'topic': function () { + return _optimize('a{border:1px solid red!important;border-style:dotted!important}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 9, undefined]]], + ['property-value', 'dotted', [[1, 46, undefined]]], + ['property-value', 'red!important', [[1, 19, undefined]]] + ] ]); } }, 'border - hex and rgb colors': { - 'topic': 'a{border:1px solid #000;border-color:rgba(255,0,0,.5)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border'], ['1px'], ['solid'], ['#000']], - [['border-color'], ['rgba(255,0,0,.5)']] + 'topic': function () { + return _optimize('a{border:1px solid #000;border-color:rgba(255,0,0,.5)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border', [[1, 2, undefined]]], + ['property-value', '1px', [[1, 9, undefined]]], + ['property-value', 'solid', [[1, 13, undefined]]], + ['property-value', '#000', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'border-color', [[1, 24, undefined]]], + ['property-value', 'rgba(255,0,0,.5)', [[1, 37, undefined]]], + ] ]); } }, 'border-color - hex then rgb': { - 'topic': 'a{border-color:#000;border-color:rgba(255,0,0,.5)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-color'], ['#000']], - [['border-color'], ['rgba(255,0,0,.5)']] + 'topic': function () { + return _optimize('a{border-color:#000;border-color:rgba(255,0,0,.5)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-color', [[1, 2, undefined]]], + ['property-value', '#000', [[1, 15, undefined]]] + ], + [ + 'property', + ['property-name', 'border-color', [[1, 20, undefined]]], + ['property-value', 'rgba(255,0,0,.5)', [[1, 33, undefined]]], + ] ]); } }, 'border-color - rgb then hex': { - 'topic': 'a{border-color:rgba(255,0,0,.5);border-color:#000}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-color'], ['#000']] + 'topic': function () { + return _optimize('a{border-color:rgba(255,0,0,.5);border-color:#000}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-color', [[1, 2, undefined]]], + ['property-value', '#000', [[1, 45, undefined]]] + ] ]); } }, 'border-color - hex then rgb with multiple values': { - 'topic': 'a{border-color:red;border-color:#000 rgba(255,0,0,.5)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-color'], ['red']], - [['border-color'], ['#000'], ['rgba(255,0,0,.5)']] + 'topic': function () { + return _optimize('a{border-color:red;border-color:#000 rgba(255,0,0,.5)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-color', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 15, undefined]]] + ], + [ + 'property', + ['property-name', 'border-color', [[1, 19, undefined]]], + ['property-value', '#000', [[1, 32, undefined]]], + ['property-value', 'rgba(255,0,0,.5)', [[1, 37, undefined]]], + ] ]); } } }) .addBatch({ 'border radius': { - 'topic': 'a{-moz-border-radius:2px;-moz-border-top-left-radius:3px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['-moz-border-radius'], ['3px'], ['2px'], ['2px']] + 'topic': function () { + return _optimize('a{-moz-border-radius:2px;-moz-border-top-left-radius:3px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', '-moz-border-radius', [[1, 2, undefined]]], + ['property-value', '3px', [[1, 53, undefined]]], + ['property-value', '2px', [[1, 21, undefined]]], + ['property-value', '2px', [[1, 21, undefined]]] + ] ]); } }, 'border radius prefixed and unprefixed': { - 'topic': 'a{-moz-border-radius:2px;border-top-left-radius:3px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['-moz-border-radius'], ['2px']], - [['border-top-left-radius'], ['3px']] + 'topic': function () { + return _optimize('a{-moz-border-radius:2px;border-top-left-radius:3px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', '-moz-border-radius', [[1, 2, undefined]]], + ['property-value', '2px', [[1, 21, undefined]]] + ], + [ + 'property', + ['property-name', 'border-top-left-radius', [[1, 25, undefined]]], + ['property-value', '3px', [[1, 48, undefined]]] + ] ]); } }, 'border width': { - 'topic': 'a{border-width:2px 3px 2px 1px;border-left-width:3px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-width'], ['2px'], ['3px']] + 'topic': function () { + return _optimize('a{border-width:2px 3px 2px 1px;border-left-width:3px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-width', [[1, 2, undefined]]], + ['property-value', '2px', [[1, 15, undefined]]], + ['property-value', '3px', [[1, 19, undefined]]] + ] ]); } }, 'list style': { - 'topic': 'a{list-style:circle inside;list-style-image:__ESCAPED_URL_CLEAN_CSS0__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['list-style'], ['circle'], ['inside'], ['__ESCAPED_URL_CLEAN_CSS0__']] + 'topic': function () { + return _optimize('a{list-style:circle inside;list-style-image:url(image.png)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'list-style', [[1, 2, undefined]]], + ['property-value', 'circle', [[1, 13, undefined]]], + ['property-value', 'inside', [[1, 20, undefined]]], + ['property-value', 'url(image.png)', [[1, 44, undefined]]] + ] ]); } }, 'margin': { - 'topic': 'a{margin:10px 20px;margin-left:25px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['margin'], ['10px'], ['20px'], ['10px'], ['25px']] + 'topic': function () { + return _optimize('a{margin:10px 20px;margin-left:25px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'margin', [[1, 2, undefined]]], + ['property-value', '10px', [[1, 9, undefined]]], + ['property-value', '20px', [[1, 14, undefined]]], + ['property-value', '10px', [[1, 9, undefined]]], + ['property-value', '25px', [[1, 31, undefined]]] + ] ]); } }, 'outline': { - 'topic': 'a{outline:red solid 1px;outline-width:3px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['outline'], ['red'], ['solid'], ['3px']] + 'topic': function () { + return _optimize('a{outline:red solid 1px;outline-width:3px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'outline', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 10, undefined]]], + ['property-value', 'solid', [[1, 14, undefined]]], + ['property-value', '3px', [[1, 38, undefined]]] + ] ]); } }, 'padding': { - 'topic': 'a{padding:10px;padding-right:20px;padding-left:20px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['padding'], ['10px'], ['20px']] + 'topic': function () { + return _optimize('a{padding:10px;padding-right:20px;padding-left:20px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'padding', [[1, 2, undefined]]], + ['property-value', '10px', [[1, 10, undefined]]], + ['property-value', '20px', [[1, 29, undefined]]], + ] ]); } } }) .addBatch({ 'colors with same understandability': { - 'topic': 'a{color:red;color:#fff;color:blue}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['color'], ['blue']] + 'topic': function () { + return _optimize('a{color:red;color:#fff;color:blue}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 23, undefined]]], + ['property-value', 'blue', [[1, 29, undefined]]], + ] ]); } }, 'colors with different understandability': { - 'topic': 'a{color:red;color:#fff;color:blue;color:rgba(1,2,3,.4)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['color'], ['blue']], - [['color'], ['rgba(1,2,3,.4)']] + 'topic': function () { + return _optimize('a{color:red;color:#fff;color:blue;color:rgba(1,2,3,.4)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 23, undefined]]], + ['property-value', 'blue', [[1, 29, undefined]]], + ], + [ + 'property', + ['property-name', 'color', [[1, 34, undefined]]], + ['property-value', 'rgba(1,2,3,.4)', [[1, 40, undefined]]], + ] ]); } }, 'colors with different understandability overridden by high understandability': { - 'topic': 'a{color:red;color:#fff;color:blue;color:rgba(1,2,3,.4);color:red}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['color'], ['red']] + 'topic': function () { + return _optimize('a{color:red;color:#fff;color:blue;color:rgba(1,2,3,.4);color:red}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 55, undefined]]], + ['property-value', 'red', [[1, 61, undefined]]], + ] ]); } }, 'colors with different understandability and importance #1': { - 'topic': 'a{color:#fff!important;color:rgba(1,2,3,.4)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['color'], ['#fff!important']] + 'topic': function () { + return _optimize('a{color:#fff!important;color:rgba(1,2,3,.4)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', '#fff!important', [[1, 8, undefined]]], + ] ]); } }, 'colors with different understandability and importance #2': { - 'topic': 'a{color:#fff;color:rgba(1,2,3,.4)!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['color'], ['#fff']], - [['color'], ['rgba(1,2,3,.4)!important']] + 'topic': function () { + return _optimize('a{color:#fff;color:rgba(1,2,3,.4)!important}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', '#fff', [[1, 8, undefined]]], + ], + [ + 'property', + ['property-name', 'color', [[1, 13, undefined]]], + ['property-value', 'rgba(1,2,3,.4)!important', [[1, 19, undefined]]], + ] ]); } } }) .addBatch({ 'shorthand then shorthand multiplex': { - 'topic': 'p{background:url(one.png);background:url(two.png) center 1px,url(three.png) center 2px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['url(one.png)']], - [['background'], ['url(two.png)'], ['center'], ['1px'], [','], ['url(three.png)'], ['center'], ['2px']] + 'topic': function () { + return _optimize('p{background:url(one.png);background:url(two.png) center 1px,url(three.png) center 2px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(one.png)', [[1, 13, undefined]]], + ], + [ + 'property', + ['property-name', 'background', [[1, 26, undefined]]], + ['property-value', 'url(two.png)', [[1, 37, undefined]]], + ['property-value', 'center', [[1, 50, undefined]]], + ['property-value', '1px', [[1, 57, undefined]]], + ['property-value', ','], + ['property-value', 'url(three.png)', [[1, 61, undefined]]], + ['property-value', 'center', [[1, 76, undefined]]], + ['property-value', '2px', [[1, 83, undefined]]] + ] ]); } }, 'shorthand then longhand multiplex': { - 'topic': 'p{background:top left;background-repeat:no-repeat,no-repeat}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['top'], ['left'], ['no-repeat'], [','], ['top'], ['left'], ['no-repeat']] + 'topic': function () { + return _optimize('p{background:top left;background-repeat:no-repeat,no-repeat}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'top', [[1, 13, undefined]]], + ['property-value', 'left', [[1, 17, undefined]]], + ['property-value', 'no-repeat', [[1, 40, undefined]]], + ['property-value', ','], + ['property-value', 'top', [[1, 13, undefined]]], + ['property-value', 'left', [[1, 17, undefined]]], + ['property-value', 'no-repeat', [[1, 50, undefined]]] + ] ]); } }, 'shorthand multiplex then longhand': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__,__ESCAPED_URL_CLEAN_CSS1__;background-repeat:no-repeat}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat'], [','], ['__ESCAPED_URL_CLEAN_CSS1__'], ['no-repeat']] + 'topic': function () { + return _optimize('p{background:url(image.png),url(image.jpg);background-repeat:no-repeat}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]], + ['property-value', 'no-repeat', [[1, 61, undefined]]], + ['property-value', ','], + ['property-value', 'url(image.jpg)', [[1, 28, undefined]]], + ['property-value', 'no-repeat', [[1, 61, undefined]]] + ] ]); } }, 'longhand then shorthand multiplex': { - 'topic': 'p{background-repeat:no-repeat;background:__ESCAPED_URL_CLEAN_CSS0__,__ESCAPED_URL_CLEAN_CSS1__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], [','], ['__ESCAPED_URL_CLEAN_CSS1__']] + 'topic': function () { + return _optimize('p{background-repeat:no-repeat;background:url(image.png),url(image.jpg)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 30, undefined]]], + ['property-value', 'url(image.png)', [[1, 41, undefined]]], + ['property-value', ','], + ['property-value', 'url(image.jpg)', [[1, 56, undefined]]], + ] ]); } }, 'longhand multiplex then shorthand': { - 'topic': 'p{background-repeat:no-repeat,no-repeat;background:__ESCAPED_URL_CLEAN_CSS0__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']] + 'topic': function () { + return _optimize('p{background-repeat:no-repeat,no-repeat;background:url(image.png)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 40, undefined]]], + ['property-value', 'url(image.png)', [[1, 51, undefined]]], + ] ]); } }, 'multiplex longhand into multiplex shorthand': { - 'topic': 'p{background:no-repeat,no-repeat;background-position:top left,bottom left}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['top'], ['left'], ['no-repeat'], [','], ['bottom'], ['left'], ['no-repeat']] + 'topic': function () { + return _optimize('p{background:no-repeat,no-repeat;background-position:top left,bottom left}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'top', [[1, 53, undefined]]], + ['property-value', 'left', [[1, 57, undefined]]], + ['property-value', 'no-repeat', [[1, 13, undefined]]], + ['property-value', ','], + ['property-value', 'bottom', [[1, 62, undefined]]], + ['property-value', 'left', [[1, 69, undefined]]], + ['property-value', 'no-repeat', [[1, 23, undefined]]] + ] ]); } }, 'two multiplex shorthands with vendor specific functions': { - 'topic': 'p{background:url(1.png),-webkit-linear-gradient();background:url(1.png),linear-gradient()}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['url(1.png)'], [','], ['-webkit-linear-gradient()']], - [['background'], ['url(1.png)'], [','], ['linear-gradient()']] + 'topic': function () { + return _optimize('p{background:url(1.png),-webkit-linear-gradient();background:url(1.png),linear-gradient()}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(1.png)', [[1, 13, undefined]]], + ['property-value', ','], + ['property-value', '-webkit-linear-gradient()', [[1, 24, undefined]]], + ], + [ + 'property', + ['property-name', 'background', [[1, 50, undefined]]], + ['property-value', 'url(1.png)', [[1, 61, undefined]]], + ['property-value', ','], + ['property-value', 'linear-gradient()', [[1, 72, undefined]]], + ] ]); } }, 'not too long into multiplex #1': { - 'topic': 'p{background:top left;background-repeat:no-repeat,no-repeat}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['top'], ['left'], ['no-repeat'], [','], ['top'], ['left'], ['no-repeat']] + 'topic': function () { + return _optimize('p{background:top left;background-repeat:no-repeat,no-repeat}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'top', [[1, 13, undefined]]], + ['property-value', 'left', [[1, 17, undefined]]], + ['property-value', 'no-repeat', [[1, 40, undefined]]], + ['property-value', ','], + ['property-value', 'top', [[1, 13, undefined]]], + ['property-value', 'left', [[1, 17, undefined]]], + ['property-value', 'no-repeat', [[1, 50, undefined]]] + ] ]); } }, 'not too long into multiplex #2': { - 'topic': 'p{background:repeat content-box;background-repeat:no-repeat,no-repeat}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['no-repeat'], ['content-box'], [','], ['no-repeat'], ['content-box']] + 'topic': function () { + return _optimize('p{background:repeat content-box;background-repeat:no-repeat,no-repeat}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'no-repeat', [[1, 50, undefined]]], + ['property-value', 'content-box', [[1, 20, undefined]]], + ['property-value', ','], + ['property-value', 'no-repeat', [[1, 60, undefined]]], + ['property-value', 'content-box', [[1, 20, undefined]]] + ] ]); } }, 'not too long into multiplex - twice': { - 'topic': 'p{background:top left;background-repeat:no-repeat,no-repeat;background-image:__ESCAPED_URL_CLEAN_CSS0__,__ESCAPED_URL_CLEAN_CSS1__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['top'], ['left'], ['no-repeat'], [','], ['__ESCAPED_URL_CLEAN_CSS1__'], ['top'], ['left'], ['no-repeat']] + 'topic': function () { + return _optimize('p{background:top left;background-repeat:no-repeat,no-repeat;background-image:url(image.png),url(image.jpg)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 77, undefined]]], + ['property-value', 'top', [[1, 13, undefined]]], + ['property-value', 'left', [[1, 17, undefined]]], + ['property-value', 'no-repeat', [[1, 40, undefined]]], + ['property-value', ','], + ['property-value', 'url(image.jpg)', [[1, 92, undefined]]], + ['property-value', 'top', [[1, 13, undefined]]], + ['property-value', 'left', [[1, 17, undefined]]], + ['property-value', 'no-repeat', [[1, 50, undefined]]] + ] ]); } }, 'not too long into multiplex - over a property': { - 'topic': 'p{background:top left;background-repeat:no-repeat,no-repeat;background-image:__ESCAPED_URL_CLEAN_CSS0__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['top'], ['left']], - [['background-repeat'], ['no-repeat'], [','], ['no-repeat']] + 'topic': function () { + return _optimize('p{background:top left;background-repeat:no-repeat,no-repeat;background-image:url(image.png)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 77, undefined]]], + ['property-value', 'top', [[1, 13, undefined]]], + ['property-value', 'left', [[1, 17, undefined]]] + ], + [ + 'property', + ['property-name', 'background-repeat', [[1, 22, undefined]]], + ['property-value', 'no-repeat', [[1, 40, undefined]]], + ['property-value', ',', [[1, 49, undefined]]], + ['property-value', 'no-repeat', [[1, 50, undefined]]] + ] ]); } }, 'too long into multiplex #1': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background-repeat:no-repeat,no-repeat}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']], - [['background-repeat'], ['no-repeat'], [','], ['no-repeat']] + 'topic': function () { + return _optimize('p{background:url(/long/image/path.png);background-repeat:no-repeat,no-repeat}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(/long/image/path.png)', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background-repeat', [[1, 39, undefined]]], + ['property-value', 'no-repeat', [[1, 57, undefined]]], + ['property-value', ',', [[1, 66, undefined]]], + ['property-value', 'no-repeat', [[1, 67, undefined]]] + ] ]); } }, 'too long into multiplex #2': { - 'topic': 'p{background:content-box padding-box;background-repeat:no-repeat,no-repeat}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['content-box'], ['padding-box']], - [['background-repeat'], ['no-repeat'], [','], ['no-repeat']] - ]); - } - }, - 'too long into multiplex #3': { - 'topic': 'p{background:top left / 20px 20px;background-repeat:no-repeat,no-repeat}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['top'], ['left'], ['/'], ['20px'], ['20px']], - [['background-repeat'], ['no-repeat'], [','], ['no-repeat']] + 'topic': function () { + return _optimize('p{background:content-box padding-box;background-repeat:no-repeat,no-repeat}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'content-box', [[1, 13, undefined]]], + ['property-value', 'padding-box', [[1, 25, undefined]]] + ], + [ + 'property', + ['property-name', 'background-repeat', [[1, 37, undefined]]], + ['property-value', 'no-repeat', [[1, 55, undefined]]], + ['property-value', ',', [[1, 64, undefined]]], + ['property-value', 'no-repeat', [[1, 65, undefined]]] + ] + ]); + } + }, + 'too long into multiplex #3 - equal size': { + 'topic': function () { + return _optimize('p{background:top left / 20px 20px;background-repeat:no-repeat,no-repeat}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'top', [[1, 13, undefined]]], + ['property-value', 'left', [[1, 17, undefined]]], + ['property-value', '/'], + ['property-value', '20px', [[1, 24, undefined]]], + ['property-value', '20px', [[1, 29, undefined]]] + ], + [ + 'property', + ['property-name', 'background-repeat', [[1, 34, undefined]]], + ['property-value', 'no-repeat', [[1, 52, undefined]]], + ['property-value', ',', [[1, 61, undefined]]], + ['property-value', 'no-repeat', [[1, 62, undefined]]] + ] ]); } }, 'background color into background': { - 'topic': 'p{background:red;background-repeat:__ESCAPED_URL_CLEAN_CSS0__,__ESCAPED_URL_CLEAN_CSS1__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], [','], ['__ESCAPED_URL_CLEAN_CSS1__'], ['red']], + 'topic': function () { + return _optimize('p{background:red;background-image:url(image.png),url(image.jpg)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 34, undefined]]], + ['property-value', ','], + ['property-value', 'url(image.jpg)', [[1, 49, undefined]]], + ['property-value', 'red', [[1, 13, undefined]]] + ] ]); } }, 'background then background - svg hack': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background:__ESCAPED_URL_CLEAN_CSS1__,none}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']], - [['background'], ['__ESCAPED_URL_CLEAN_CSS1__'], [','], ['none']] + 'topic': function () { + return _optimize('p{background:url(image.png);background:url(image.svg),none}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 28, undefined]]], + ['property-value', 'url(image.svg)', [[1, 39, undefined]]], + ['property-value', ','], + ['property-value', 'none', [[1, 54, undefined]]] + ] ]); } }, 'background then background - inverted svg hack': { - 'topic': 'p{background:__ESCAPED_URL_CLEAN_CSS0__;background:none,__ESCAPED_URL_CLEAN_CSS1__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__']], - [['background'], ['0 0'], [','], ['__ESCAPED_URL_CLEAN_CSS1__']] + 'topic': function () { + return _optimize('p{background:url(image.png);background:none,url(image.svg)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 13, undefined]]] + ], + [ + 'property', + ['property-name', 'background', [[1, 28, undefined]]], + ['property-value', '0 0'], + ['property-value', ','], + ['property-value', 'url(image.svg)', [[1, 44, undefined]]] + ] ]); } }, 'background-image then background-image - svg hack': { - 'topic': 'p{background-image:__ESCAPED_URL_CLEAN_CSS0__;background-image: __ESCAPED_URL_CLEAN_CSS1__,none}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-image'], ['__ESCAPED_URL_CLEAN_CSS0__']], - [['background-image'], ['__ESCAPED_URL_CLEAN_CSS1__'], [','], ['none']] + 'topic': function () { + return _optimize('p{background-image:url(image.png);background-image:url(image.svg),none}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-image', [[1, 2, undefined]]], + ['property-value', 'url(image.png)', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'background-image', [[1, 34, undefined]]], + ['property-value', 'url(image.svg)', [[1, 51, undefined]]], + ['property-value', ',', [[1, 65, undefined]]], + ['property-value', 'none', [[1, 66, undefined]]] + ] ]); } } }) .addBatch({ 'padding !important then not !important': { - 'topic': 'a{padding:0!important;padding-left:3px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['padding'], ['0!important']] + 'topic': function () { + return _optimize('a{padding:0!important;padding-left:3px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'padding', [[1, 2, undefined]]], + ['property-value', '0!important', [[1, 10, undefined]]] + ] ]); } } }) .addBatch({ 'overriding !important by a star hack': { - 'topic': 'a{color:red!important;display:block;*color:#fff}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['color'], ['red!important']], - [['display'], ['block']], - [['*color'], ['#fff']] + 'topic': function () { + return _optimize('a{color:red!important;display:block;*color:#fff}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', 'red!important', [[1, 8, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 22, undefined]]], + ['property-value', 'block', [[1, 30, undefined]]] + ], + [ + 'property', + ['property-name', '*color', [[1, 36, undefined]]], + ['property-value', '#fff', [[1, 43, undefined]]] + ] ]); } }, 'overriding !important by an underscore hack': { - 'topic': 'a{color:red!important;display:block;_color:#fff}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['color'], ['red!important']], - [['display'], ['block']], - [['_color'], ['#fff']] + 'topic': function () { + return _optimize('a{color:red!important;display:block;_color:#fff}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', 'red!important', [[1, 8, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 22, undefined]]], + ['property-value', 'block', [[1, 30, undefined]]] + ], + [ + 'property', + ['property-name', '_color', [[1, 36, undefined]]], + ['property-value', '#fff', [[1, 43, undefined]]] + ] ]); } }, 'overriding !important by an backslash hack': { - 'topic': 'a{color:red!important;display:block;color:#fff\\0}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['color'], ['red!important']], - [['display'], ['block']] + 'topic': function () { + return _optimize('a{color:red!important;display:block;color:#fff\\0}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', 'red!important', [[1, 8, undefined]]] + ], + [ + 'property', + ['property-name', 'display', [[1, 22, undefined]]], + ['property-value', 'block', [[1, 30, undefined]]] + ] ]); } } diff --git a/test/properties/populate-components-test.js b/test/properties/populate-components-test.js index dc473699..0e4e6491 100644 --- a/test/properties/populate-components-test.js +++ b/test/properties/populate-components-test.js @@ -8,7 +8,16 @@ vows.describe(populateComponents) .addBatch({ 'shorthand': { 'topic': function () { - var wrapped = wrapForOptimizing([[['margin'], ['0px'], ['1px'], ['2px'], ['3px']]]); + var wrapped = wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'] + ] + ]); populateComponents(wrapped); return wrapped; @@ -27,24 +36,30 @@ vows.describe(populateComponents) }, 'gets a margin-top': function (wrapped) { assert.deepEqual(wrapped[0].components[0].name, 'margin-top'); - assert.deepEqual(wrapped[0].components[0].value, [['0px']]); + assert.deepEqual(wrapped[0].components[0].value, [['property-value', '0px']]); }, 'gets a margin-right': function (wrapped) { assert.deepEqual(wrapped[0].components[1].name, 'margin-right'); - assert.deepEqual(wrapped[0].components[1].value, [['1px']]); + assert.deepEqual(wrapped[0].components[1].value, [['property-value', '1px']]); }, 'gets a margin-bottom': function (wrapped) { assert.deepEqual(wrapped[0].components[2].name, 'margin-bottom'); - assert.deepEqual(wrapped[0].components[2].value, [['2px']]); + assert.deepEqual(wrapped[0].components[2].value, [['property-value', '2px']]); }, 'gets a margin-left': function (wrapped) { assert.deepEqual(wrapped[0].components[3].name, 'margin-left'); - assert.deepEqual(wrapped[0].components[3].value, [['3px']]); + assert.deepEqual(wrapped[0].components[3].value, [['property-value', '3px']]); } }, 'longhand': { 'topic': function () { - var wrapped = wrapForOptimizing([[['margin-top'], ['0px']]]); + var wrapped = wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin-top'], + ['property-value', '0px'] + ] + ]); populateComponents(wrapped); return wrapped; @@ -58,7 +73,12 @@ vows.describe(populateComponents) }, 'no value': { 'topic': function () { - var wrapped = wrapForOptimizing([[['margin']]]); + var wrapped = wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'] + ] + ]); populateComponents(wrapped); return wrapped; diff --git a/test/properties/remove-unused-test.js b/test/properties/remove-unused-test.js index 82ab47cc..ec593857 100644 --- a/test/properties/remove-unused-test.js +++ b/test/properties/remove-unused-test.js @@ -9,8 +9,16 @@ vows.describe(removeUnused) 'it removes unused only': { 'topic': function () { var properties = [ - [['background'], ['none']], - [['color'], ['red']] + [ + 'property', + ['property-name', 'background'], + ['property-value', 'none'] + ], + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red'] + ] ]; var _properties = wrapForOptimizing(properties); _properties[0].unused = true; @@ -20,15 +28,26 @@ vows.describe(removeUnused) }, 'it has one property left': function (properties) { assert.lengthOf(properties, 1); - assert.equal(properties[0][0], 'color'); + assert.equal(properties[0][1][1], 'color'); } }, 'it respects comments': { 'topic': function () { var properties = [ - [['background'], ['none']], - '__ESCAPED_COMMENT_CLEAN_CSS0__', - [['color'], ['red']] + [ + 'property', + ['property-name', 'background'], + ['property-value', 'none'] + ], + [ + 'comment', + ['/* comment */'] + ], + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red'] + ] ]; var _properties = wrapForOptimizing(properties); _properties[1].unused = true; @@ -38,8 +57,8 @@ vows.describe(removeUnused) }, 'it has one property left': function (properties) { assert.lengthOf(properties, 2); - assert.equal(properties[0][0], 'background'); - assert.equal(properties[1], '__ESCAPED_COMMENT_CLEAN_CSS0__'); + assert.equal(properties[0][1][1], 'background'); + assert.equal(properties[1][1][0], '/* comment */'); } } }) diff --git a/test/properties/restore-from-optimizing-test.js b/test/properties/restore-from-optimizing-test.js index 19bb268a..36b04630 100644 --- a/test/properties/restore-from-optimizing-test.js +++ b/test/properties/restore-from-optimizing-test.js @@ -7,163 +7,298 @@ var shallowClone = require('../../lib/properties/clone').shallow; var restoreFromOptimizing = require('../../lib/properties/restore-from-optimizing'); -var Compatibility = require('../../lib/utils/compatibility'); +var compatibility = require('../../lib/utils/compatibility'); var Validator = require('../../lib/properties/validator'); -var validator = new Validator(new Compatibility().toOptions()); +var validator = new Validator(compatibility()); vows.describe(restoreFromOptimizing) .addBatch({ 'without descriptor': { 'topic': function () { - var properties = [[['margin-top'], ['0']]]; - var _properties = wrapForOptimizing(properties); - restoreFromOptimizing(_properties); + var properties = [ + [ + 'property', + ['property-name', 'margin-top'], + ['property-value', '0'] + ] + ]; + var wrapped = wrapForOptimizing(properties); + restoreFromOptimizing(wrapped); return properties; }, 'is same as source': function (properties) { - assert.deepEqual(properties, [[['margin-top'], ['0']]]); + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'margin-top'], + ['property-value', '0'] + ] + ]); } }, 'with changed value but without descriptor': { 'topic': function () { - var properties = [[['margin-top'], ['0']]]; - var _properties = wrapForOptimizing(properties); - _properties[0].value = [['1px']]; - _properties[0].dirty = true; - restoreFromOptimizing(_properties); + var properties = [ + [ + 'property', + ['property-name', 'margin-top'], + ['property-value', '0'] + ] + ]; + var wrapped = wrapForOptimizing(properties); + wrapped[0].value = [['property-value', '1px']]; + wrapped[0].dirty = true; + restoreFromOptimizing(wrapped); return properties; }, 'has right output': function (properties) { - assert.deepEqual(properties, [[['margin-top'], ['1px']]]); + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'margin-top'], + ['property-value', '1px'] + ] + ]); } }, - 'longhands': { + 'with comment': { 'topic': function () { - var properties = ['/*comment */', [['margin-top'], ['0']]]; - var _properties = wrapForOptimizing(properties); - populateComponents(_properties, validator); - restoreFromOptimizing(_properties); + var properties = [ + [ + 'comment', + '/* comment */' + ], + [ + 'property', + ['property-name', 'margin-top'], + ['property-value', '0'] + ] + ]; + var wrapped = wrapForOptimizing(properties); + populateComponents(wrapped, validator); + restoreFromOptimizing(wrapped); return properties; }, 'is same as source': function (properties) { - assert.deepEqual(properties, ['/*comment */', [['margin-top'], ['0']]]); + assert.deepEqual(properties, [ + [ + 'comment', + '/* comment */' + ], + [ + 'property', + ['property-name', 'margin-top'], + ['property-value', '0'] + ] + ]); } }, 'shorthands': { 'topic': function () { - var properties = ['/*comment */', [['background'], ['url(image.png)']]]; - var _properties = wrapForOptimizing(properties); - populateComponents(_properties, validator); + var properties = [ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'] + ] + ]; + var wrapped = wrapForOptimizing(properties); + populateComponents(wrapped, validator); - properties[1].pop(); - _properties[0].dirty = true; + wrapped[0].dirty = true; - restoreFromOptimizing(_properties); + restoreFromOptimizing(wrapped); return properties; }, 'is same as source': function (properties) { - assert.deepEqual(properties, ['/*comment */', [['background'], ['url(image.png)']]]); + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'] + ] + ]); } }, 'shorthands in simple mode': { 'topic': function () { - var properties = [[['margin'], ['1px'], ['2px']]]; - var _properties = wrapForOptimizing(properties); + var properties = [ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '1px'], + ['property-value', '2px'] + ] + ]; + var wrapped = wrapForOptimizing(properties); - _properties[0].dirty = true; + wrapped[0].dirty = true; - restoreFromOptimizing(_properties, true); + restoreFromOptimizing(wrapped, true); return properties; }, 'is same as source': function (properties) { - assert.deepEqual(properties, [[['margin'], ['1px'], ['2px']]]); + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '1px'], + ['property-value', '2px'] + ] + ]); } }, 'values': { 'topic': function () { - var properties = [[['background'], ['url(image.png)']]]; - var _properties = wrapForOptimizing(properties); - populateComponents(_properties, validator); + var properties = [ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'] + ] + ]; + var wrapped = wrapForOptimizing(properties); + populateComponents(wrapped, validator); - _properties[0].value = []; - _properties[0].dirty = true; + wrapped[0].value = []; + wrapped[0].dirty = true; - restoreFromOptimizing(_properties); - return _properties; + restoreFromOptimizing(wrapped); + return properties; }, - 'updates value': function (_properties) { - assert.deepEqual(_properties[0].value, [['url(image.png)']]); + 'updates value': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'] + ] + ]); } }, 'in cloned without reference to `all`': { 'topic': function () { - var properties = [[['background'], ['url(image.png)']]]; - var _properties = wrapForOptimizing(properties); - populateComponents(_properties, validator); + var properties = [ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'] + ] + ]; + var wrapped = wrapForOptimizing(properties); + populateComponents(wrapped, validator); - var cloned = shallowClone(_properties[0]); - cloned.components = _properties[0].components; + var cloned = shallowClone(wrapped[0]); + cloned.components = wrapped[0].components; cloned.dirty = true; restoreFromOptimizing([cloned]); return cloned; }, 'does not fail': function (cloned) { - assert.deepEqual(cloned.value, [['url(image.png)']]); + assert.deepEqual(cloned.value, [['property-value', 'url(image.png)']]); } } }) .addBatch({ 'important': { 'topic': function () { - var properties = [[['color'], ['red!important']]]; - var _properties = wrapForOptimizing(properties); + var properties = [ + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red!important'] + ] + ]; + var wrapped = wrapForOptimizing(properties); - restoreFromOptimizing(_properties, true); + restoreFromOptimizing(wrapped, true); return properties; }, 'restores important': function (properties) { - assert.deepEqual(properties, [[['color'], ['red!important']]]); + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red!important'] + ] + ]); } }, 'underscore hack': { 'topic': function () { - var properties = [[['_color'], ['red']]]; - var _properties = wrapForOptimizing(properties); + var properties = [ + [ + 'property', + ['property-name', '_color'], + ['property-value', 'red'] + ] + ]; + var wrapped = wrapForOptimizing(properties); - restoreFromOptimizing(_properties, true); + restoreFromOptimizing(wrapped, true); return properties; }, 'restores hack': function (properties) { - assert.deepEqual(properties, [[['_color'], ['red']]]); + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', '_color'], + ['property-value', 'red'] + ] + ]); } }, 'star hack': { 'topic': function () { - var properties = [[['*color'], ['red']]]; - var _properties = wrapForOptimizing(properties); + var properties = [ + [ + 'property', + ['property-name', '*color'], + ['property-value', 'red'] + ] + ]; + var wrapped = wrapForOptimizing(properties); - restoreFromOptimizing(_properties, true); + restoreFromOptimizing(wrapped, true); return properties; }, 'restores hack': function (properties) { - assert.deepEqual(properties, [[['*color'], ['red']]]); + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', '*color'], + ['property-value', 'red'] + ] + ]); } }, 'suffix hack': { 'topic': function () { - var properties = [[['color'], ['red\\9']]]; - var _properties = wrapForOptimizing(properties); + var properties = [ + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red\\9'] + ] + ]; + var wrapped = wrapForOptimizing(properties); - restoreFromOptimizing(_properties, true); + restoreFromOptimizing(wrapped, true); return properties; }, 'restores hack': function (properties) { - assert.deepEqual(properties, [[['color'], ['red\\9']]]); + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red\\9'] + ] + ]); } } }) diff --git a/test/properties/restore-test.js b/test/properties/restore-test.js index 38adf332..bf2e8c11 100644 --- a/test/properties/restore-test.js +++ b/test/properties/restore-test.js @@ -3,14 +3,14 @@ var assert = require('assert'); var wrapForOptimizing = require('../../lib/properties/wrap-for-optimizing').single; var compactable = require('../../lib/properties/compactable'); -var Compatibility = require('../../lib/utils/compatibility'); +var compatibility = require('../../lib/utils/compatibility'); var Validator = require('../../lib/properties/validator'); var restore = require('../../lib/properties/restore'); function _breakUp(property) { - var validator = new Validator(new Compatibility().toOptions()); - var descriptor = compactable[property[0][0]]; + var validator = new Validator(compatibility()); + var descriptor = compactable[property[1][1]]; var _property = wrapForOptimizing(property); _property.components = descriptor.breakUp(_property, compactable, validator); _property.multiplex = _property.components[0].multiplex; @@ -27,314 +27,807 @@ vows.describe(restore) 'background': { 'background with some values': { 'topic': function () { - return _restore(_breakUp([['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat'], ['padding-box']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', 'no-repeat'], + ['property-value', 'padding-box'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat'], ['padding-box']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'url(image.png)'], + ['property-value', 'no-repeat'], + ['property-value', 'padding-box'] + ]); } }, 'background with some default values': { 'topic': function () { - return _restore(_breakUp([['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['repeat'], ['padding-box'], ['border-box']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', 'repeat'], + ['property-value', 'padding-box'], + ['property-value', 'border-box'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['__ESCAPED_URL_CLEAN_CSS0__']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'url(image.png)'] + ]); } }, 'background with all default values': { 'topic': function () { - return _restore(_breakUp([['background'], ['transparent'], ['none'], ['repeat'], ['scroll'], ['0'], ['0'], ['padding-box'], ['border-box']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'transparent'], + ['property-value', 'none'], + ['property-value', 'repeat'], + ['property-value', 'scroll'], + ['property-value', '0'], + ['property-value', '0'], + ['property-value', 'padding-box'], + ['property-value', 'border-box'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0 0']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0 0'] + ]); } }, 'background with some double values': { 'topic': function () { - return _restore(_breakUp([['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['repeat'], ['no-repeat'], ['2px'], ['3px'], ['/'], ['auto'], ['padding-box']])); - }, - 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['__ESCAPED_URL_CLEAN_CSS0__'], ['2px'], ['3px'], ['repeat'], ['no-repeat'], ['padding-box']]); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', 'repeat'], + ['property-value', 'no-repeat'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', '/'], + ['property-value', 'auto'], + ['property-value', 'padding-box'] + ]) + ); + }, + 'gives right value back': function (restoredValue) { + assert.deepEqual(restoredValue, [ + ['property-value', 'url(image.png)'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', 'repeat'], + ['property-value', 'no-repeat'], + ['property-value', 'padding-box'] + ]); } }, 'background with default background origin and background clip': { 'topic': function () { - return _restore(_breakUp([['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['padding-box'], ['border-box']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', 'padding-box'], + ['property-value', 'border-box'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['__ESCAPED_URL_CLEAN_CSS0__']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'url(image.png)'] + ]); } }, 'background with same background origin and background clip': { 'topic': function () { - return _restore(_breakUp([['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['padding-box'], ['padding-box']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', 'padding-box'], + ['property-value', 'padding-box'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['__ESCAPED_URL_CLEAN_CSS0__'], ['padding-box']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'url(image.png)'], + ['property-value', 'padding-box'] + ]); } }, 'background with default background position and background size': { 'topic': function () { - return _restore(_breakUp([['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['0'], ['0'], ['/'], ['50%'], ['25%']])); - }, - 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['__ESCAPED_URL_CLEAN_CSS0__'], ['0'], ['0'], ['/'], ['50%'], ['25%']]); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', '0'], + ['property-value', '0'], + ['property-value', '/'], + ['property-value', '50%'], + ['property-value', '25%'] + ]) + ); + }, + 'gives right value back': function (restoredValue) { + assert.deepEqual(restoredValue, [ + ['property-value', 'url(image.png)'], + ['property-value', '0'], + ['property-value', '0'], + ['property-value', '/'], + ['property-value', '50%'], + ['property-value', '25%'] + ]); } }, 'background with default background position and single background size': { 'topic': function () { - return _restore(_breakUp([['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['0'], ['0'], ['/'], ['50%']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', '0'], + ['property-value', '0'], + ['property-value', '/'], + ['property-value', '50%'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['__ESCAPED_URL_CLEAN_CSS0__'], ['0'], ['0'], ['/'], ['50%']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'url(image.png)'], + ['property-value', '0'], + ['property-value', '0'], + ['property-value', '/'], + ['property-value', '50%'] + ]); } }, 'background with default background position and background size differing by 2nd value': { 'topic': function () { - return _restore(_breakUp([['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['0'], ['50px'], ['/'], ['0'], ['30px']])); - }, - 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['__ESCAPED_URL_CLEAN_CSS0__'], ['0'], ['50px'], ['/'], ['0'], ['30px']]); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', '0'], + ['property-value', '50px'], + ['property-value', '/'], + ['property-value', '0'], + ['property-value', '30px'] + ]) + ); + }, + 'gives right value back': function (restoredValue) { + assert.deepEqual(restoredValue, [ + ['property-value', 'url(image.png)'], + ['property-value', '0'], + ['property-value', '50px'], + ['property-value', '/'], + ['property-value', '0'], + ['property-value', '30px'] + ]); } }, 'background 0 to background 0': { 'topic': function () { - return _restore(_breakUp([['background'], ['0']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', '0'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0'] + ]); } }, 'background color in multiplex': { 'topic': function () { - return _restore(_breakUp([['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['blue'], [','], ['__ESCAPED_URL_CLEAN_CSS1__'], ['red']])); - }, - 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['__ESCAPED_URL_CLEAN_CSS0__'], [','], ['__ESCAPED_URL_CLEAN_CSS1__'], ['red']]); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', 'blue'], + ['property-value', ','], + ['property-value', 'url(image.jpg)'], + ['property-value', 'red'] + ]) + ); + }, + 'gives right value back': function (restoredValue) { + assert.deepEqual(restoredValue, [ + ['property-value', 'url(image.png)'], + ['property-value', ','], + ['property-value', 'url(image.jpg)'], + ['property-value', 'red'] + ]); } } }, 'border radius': { '4 values': { 'topic': function () { - return _restore(_breakUp([['border-radius'], ['0px'], ['1px'], ['2px'], ['3px']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border-radius'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px'], ['1px'], ['2px'], ['3px']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'] + ]); } }, '3 values': { 'topic': function () { - return _restore(_breakUp([['border-radius'], ['0px'], ['1px'], ['2px'], ['1px']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border-radius'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '1px'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px'], ['1px'], ['2px']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'] + ]); } }, '2 values': { 'topic': function () { - return _restore(_breakUp([['border-radius'], ['0px'], ['1px'], ['0px'], ['1px']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border-radius'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '0px'], + ['property-value', '1px'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px'], ['1px']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0px'], + ['property-value', '1px'] + ]); } }, '1 value': { 'topic': function () { - return _restore(_breakUp([['border-radius'], ['0px'], ['0px'], ['0px'], ['0px']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border-radius'], + ['property-value', '0px'], + ['property-value', '0px'], + ['property-value', '0px'], + ['property-value', '0px'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0px'] + ]); } }, 'horizontal + vertical - different values': { 'topic': function () { - return _restore(_breakUp([['border-radius'], ['0px'], ['1px'], ['2px'], ['3px'], ['/'], ['2px'], ['1px'], ['2px'], ['1px']])); - }, - 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px'], ['1px'], ['2px'], ['3px'], ['/'], ['2px'], ['1px']]); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border-radius'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', '/'], + ['property-value', '2px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '1px'] + ]) + ); + }, + 'gives right value back': function (restoredValue) { + assert.deepEqual(restoredValue, [ + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', '/'], + ['property-value', '2px'], + ['property-value', '1px'] + ]); } }, 'horizontal + vertical - same values': { 'topic': function () { - return _restore(_breakUp([['border-radius'], ['0px'], ['1px'], ['2px'], ['3px'], ['/'], ['0px'], ['1px'], ['2px'], ['3px']])); - }, - 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px'], ['1px'], ['2px'], ['3px']]); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border-radius'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', '/'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'] + ]) + ); + }, + 'gives right value back': function (restoredValue) { + assert.deepEqual(restoredValue, [ + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'] + ]); } }, 'horizontal + vertical - asymetrical': { 'topic': function () { - return _restore(_breakUp([['border-radius'], ['0px'], ['1px'], ['2px'], ['3px'], ['/'], ['0px'], ['1px']])); - }, - 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px'], ['1px'], ['2px'], ['3px'], ['/'], ['0px'], ['1px']]); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border-radius'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', '/'], + ['property-value', '0px'], + ['property-value', '1px'] + ]) + ); + }, + 'gives right value back': function (restoredValue) { + assert.deepEqual(restoredValue, [ + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'], + ['property-value', '/'], + ['property-value', '0px'], + ['property-value', '1px'] + ]); } }, 'inherit': { 'topic': function () { - return _restore(_breakUp([['border-radius'], ['inherit']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border-radius'], + ['property-value', 'inherit'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['inherit']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'inherit'] + ]); } } }, 'four values': { '4 different': { 'topic': function () { - return _restore(_breakUp([['padding'], ['0px'], ['1px'], ['2px'], ['3px']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'padding'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px'], ['1px'], ['2px'], ['3px']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '3px'] + ]); } }, '3 different': { 'topic': function () { - return _restore(_breakUp([['padding'], ['0px'], ['1px'], ['2px'], ['1px']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'padding'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'], + ['property-value', '1px'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px'], ['1px'], ['2px']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '2px'] + ]); } }, '2 different': { 'topic': function () { - return _restore(_breakUp([['padding'], ['0px'], ['1px'], ['0px'], ['1px']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'padding'], + ['property-value', '0px'], + ['property-value', '1px'], + ['property-value', '0px'], + ['property-value', '1px'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px'], ['1px']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0px'], + ['property-value', '1px'] + ]); } }, 'all same': { 'topic': function () { - return _restore(_breakUp([['padding'], ['0px'], ['0px'], ['0px'], ['0px']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'padding'], + ['property-value', '0px'], + ['property-value', '0px'], + ['property-value', '0px'], + ['property-value', '0px'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0px']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0px'] + ]); } }, 'inherit': { 'topic': function () { - return _restore(_breakUp([['padding'], ['inherit']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'padding'], + ['property-value', 'inherit'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['inherit']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'inherit'] + ]); } } }, 'repeated values': { 'background with some values': { 'topic': function () { - return _restore(_breakUp([['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat'], ['padding-box'], [','], ['repeat'], ['red']])); - }, - 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat'], ['padding-box'], [','], ['red']]); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)'], + ['property-value', 'no-repeat'], + ['property-value', 'padding-box'], + ['property-value', ','], + ['property-value', 'repeat'], + ['property-value', 'red'] + ]) + ); + }, + 'gives right value back': function (restoredValue) { + assert.deepEqual(restoredValue, [ + ['property-value', 'url(image.png)'], + ['property-value', 'no-repeat'], + ['property-value', 'padding-box'], + ['property-value', ','], + ['property-value', 'red'] + ]); } }, 'background with background origin and size': { 'topic': function () { - return _restore(_breakUp([['background'], ['no-repeat'], ['padding-box'], [','], ['repeat'], ['10px'], ['10px'], ['/'], ['auto'], ['red'], [','], ['top'], ['left'], ['/'], ['30%']])); - }, - 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['no-repeat'], ['padding-box'], [','], ['10px'], ['10px'], [','], ['top'], ['left'], ['/'], ['30%']]); + return _restore( + _breakUp([ + 'property', + ['property-name', 'background'], + ['property-value', 'no-repeat'], + ['property-value', 'padding-box'], + ['property-value', ','], + ['property-value', 'repeat'], + ['property-value', '10px'], + ['property-value', '10px'], + ['property-value', '/'], + ['property-value', 'auto'], + ['property-value', 'red'], + ['property-value', ','], + ['property-value', 'top'], + ['property-value', 'left'], + ['property-value', '/'], + ['property-value', '30%'] + ]) + ); + }, + 'gives right value back': function (restoredValue) { + assert.deepEqual(restoredValue, [ + ['property-value', 'no-repeat'], + ['property-value', 'padding-box'], + ['property-value', ','], + ['property-value', '10px'], + ['property-value', '10px'], + ['property-value', ','], + ['property-value', 'top'], + ['property-value', 'left'], + ['property-value', '/'], + ['property-value', '30%'] + ]); } } }, 'without defaults': { 'border with some values': { 'topic': function () { - return _restore(_breakUp([['border'], ['solid']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border'], + ['property-value', 'solid'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['solid']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'solid'] + ]); } }, 'border with all values': { 'topic': function () { - return _restore(_breakUp([['border'], ['1px'], ['solid'], ['red']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border'], + ['property-value', '1px'], + ['property-value', 'solid'], + ['property-value', 'red'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['1px'], ['solid'], ['red']]); + assert.deepEqual(restoredValue, [ + ['property-value', '1px'], + ['property-value', 'solid'], + ['property-value', 'red'] + ]); } }, 'border with all defaults': { 'topic': function () { - return _restore(_breakUp([['border'], ['medium'], ['none'], ['none']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border'], + ['property-value', 'medium'], + ['property-value', 'none'], + ['property-value', 'none'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['none']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'none'] + ]); } }, 'border with inherit': { 'topic': function () { - return _restore(_breakUp([['border'], ['inherit']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'border'], + ['property-value', 'inherit'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['inherit']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'inherit'] + ]); } }, 'list with some values': { 'topic': function () { - return _restore(_breakUp([['list-style'], ['circle']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'list-style'], + ['property-value', 'circle'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['circle']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'circle'] + ]); } }, 'list with all values': { 'topic': function () { - return _restore(_breakUp([['list-style'], ['circle'], ['inside'], ['__ESCAPED_URL_CLEAN_CSS1__']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'list-style'], + ['property-value', 'circle'], + ['property-value', 'inside'], + ['property-value', 'url(image.png)'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['circle'], ['inside'], ['__ESCAPED_URL_CLEAN_CSS1__']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'circle'], + ['property-value', 'inside'], + ['property-value', 'url(image.png)'] + ]); } }, 'list with some defaults': { 'topic': function () { - return _restore(_breakUp([['list-style'], ['circle'], ['outside'], ['__ESCAPED_URL_CLEAN_CSS0__']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'list-style'], + ['property-value', 'circle'], + ['property-value', 'outside'], + ['property-value', 'url(image.png)'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['circle'], ['__ESCAPED_URL_CLEAN_CSS0__']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'circle'], + ['property-value', 'url(image.png)'] + ]); } }, 'list with inherit': { 'topic': function () { - return _restore(_breakUp([['list-style'], ['inherit']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'list-style'], + ['property-value', 'inherit'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['inherit']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'inherit'] + ]); } }, 'outline with some values': { 'topic': function () { - return _restore(_breakUp([['outline'], ['dotted']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'outline'], + ['property-value', 'dotted'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['dotted']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'dotted'] + ]); } }, 'outline with all values': { 'topic': function () { - return _restore(_breakUp([['outline'], ['#fff'], ['dotted'], ['1px']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'outline'], + ['property-value', '#fff'], + ['property-value', 'dotted'], + ['property-value', '1px'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['#fff'], ['dotted'], ['1px']]); + assert.deepEqual(restoredValue, [ + ['property-value', '#fff'], + ['property-value', 'dotted'], + ['property-value', '1px'] + ]); } }, 'outline with all defaults': { 'topic': function () { - return _restore(_breakUp([['outline'], ['invert'], ['none'], ['medium']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'outline'], + ['property-value', 'invert'], + ['property-value', 'none'], + ['property-value', 'medium'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['0']]); + assert.deepEqual(restoredValue, [ + ['property-value', '0'] + ]); } }, 'outline with inherit': { 'topic': function () { - return _restore(_breakUp([['outline'], ['inherit']])); + return _restore( + _breakUp([ + 'property', + ['property-name', 'outline'], + ['property-value', 'inherit'] + ]) + ); }, 'gives right value back': function (restoredValue) { - assert.deepEqual(restoredValue, [['inherit']]); + assert.deepEqual(restoredValue, [ + ['property-value', 'inherit'] + ]); } } } diff --git a/test/properties/shorthand-compacting-source-maps-test.js b/test/properties/shorthand-compacting-source-maps-test.js deleted file mode 100644 index b32306d5..00000000 --- a/test/properties/shorthand-compacting-source-maps-test.js +++ /dev/null @@ -1,57 +0,0 @@ -var vows = require('vows'); -var assert = require('assert'); - -var optimize = require('../../lib/properties/optimizer'); - -var tokenize = require('../../lib/tokenizer/tokenize'); -var SourceTracker = require('../../lib/utils/source-tracker'); -var SourceReader = require('../../lib/utils/source-reader'); -var InputSourceMapTracker = require('../../lib/utils/input-source-map-tracker'); - -var Compatibility = require('../../lib/utils/compatibility'); -var Validator = require('../../lib/properties/validator'); - -function _optimize(source) { - var inputSourceMapTracker = new InputSourceMapTracker({ - options: { inliner: {} }, - errors: {}, - sourceTracker: new SourceTracker() - }); - var tokens = tokenize(source, { - options: { sourceMap: true }, - inputSourceMapTracker: inputSourceMapTracker, - sourceReader: new SourceReader(), - sourceTracker: new SourceTracker(), - warnings: [] - }); - - var compatibility = new Compatibility().toOptions(); - var validator = new Validator(compatibility); - var options = { - aggressiveMerging: true, - compatibility: compatibility, - sourceMap: true, - shorthandCompacting: true - }; - optimize(tokens[0][1], tokens[0][2], false, true, options, { validator: validator }); - - return tokens[0][2]; -} - -vows.describe(optimize) - .addBatch({ - 'with source map': { - topic: 'a{margin-top:10px;margin-bottom:4px;margin-left:5px;margin-right:5px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [ - ['margin', [[1, 2, undefined], [1, 18, undefined], [1, 36, undefined], [1, 52, undefined]]], - [ '10px', [[1, 13, undefined]]], - [ '5px', [[1, 65, undefined]]], - [ '4px', [[1, 32, undefined]]] - ] - ]); - } - } - }) - .export(module); diff --git a/test/properties/shorthand-compacting-test.js b/test/properties/shorthand-compacting-test.js index f66af73f..172e20a9 100644 --- a/test/properties/shorthand-compacting-test.js +++ b/test/properties/shorthand-compacting-test.js @@ -4,25 +4,23 @@ var assert = require('assert'); var optimize = require('../../lib/properties/optimizer'); var tokenize = require('../../lib/tokenizer/tokenize'); -var SourceTracker = require('../../lib/utils/source-tracker'); -var Compatibility = require('../../lib/utils/compatibility'); +var compatibility = require('../../lib/utils/compatibility'); var Validator = require('../../lib/properties/validator'); function _optimize(source) { var tokens = tokenize(source, { options: {}, - sourceTracker: new SourceTracker(), warnings: [] }); - var compatibility = new Compatibility(compatibility).toOptions(); - var validator = new Validator(compatibility); + var compat = compatibility(compat); + var validator = new Validator(compat); var options = { aggressiveMerging: true, - compatibility: compatibility, + compatibility: compat, shorthandCompacting: true }; - optimize(tokens[0][1], tokens[0][2], false, true, options, { validator: validator }); + optimize(tokens[0][1], tokens[0][2], false, true, { options: options, validator: validator }); return tokens[0][2]; } @@ -30,222 +28,503 @@ function _optimize(source) { vows.describe(optimize) .addBatch({ 'shorthand background #1': { - 'topic': 'p{background-color:#111;background-image:__ESCAPED_URL_CLEAN_CSS0__;background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['#111']] + 'topic': function () { + return _optimize('p{background-color:#111;background-image:url(image.png);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)', [[1, 41, undefined]]], + ['property-value', '#111', [[1, 19, undefined]]] + ] ]); } }, 'shorthand background #2': { - 'topic': 'p{background-color:#111;background-image:__ESCAPED_URL_CLEAN_CSS0__;background-repeat:no-repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat'], ['#111']] + 'topic': function () { + return _optimize('p{background-color:#111;background-image:url(image.png);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)', [[1, 41, undefined]]], + ['property-value', 'no-repeat', [[1, 74, undefined]]], + ['property-value', '#111', [[1, 19, undefined]]] + ] ]); } }, 'shorthand important background': { - 'topic': 'p{background-color:#111!important;background-image:__ESCAPED_URL_CLEAN_CSS0__!important;background-repeat:repeat!important;background-position:0 0!important;background-attachment:scroll!important;background-size:auto!important;background-origin:padding-box!important;background-clip:border-box!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['#111!important']] + 'topic': function () { + return _optimize('p{background-color:#111!important;background-image:url(image.png)!important;background-repeat:repeat!important;background-position:0 0!important;background-attachment:scroll!important;background-size:auto!important;background-origin:padding-box!important;background-clip:border-box!important}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background'], + ['property-value', 'url(image.png)', [[1, 51, undefined]]], + ['property-value', '#111!important', [[1, 19, undefined]]] + ] ]); } }, 'shorthand border-width': { - 'topic': 'p{border-top-width:7px;border-bottom-width:7px;border-left-width:4px;border-right-width:4px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-width'], ['7px'], ['4px']] + 'topic': function () { + return _optimize('p{border-top-width:7px;border-bottom-width:7px;border-left-width:4px;border-right-width:4px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-width'], + ['property-value', '7px', [[1, 19, undefined]]], + ['property-value', '4px', [[1, 88, undefined]]] + ] ]); } }, 'shorthand border-color #1': { - 'topic': 'p{border-top-color:#9fce00;border-bottom-color:#9fce00;border-left-color:#9fce00;border-right-color:#9fce00}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-color'], ['#9fce00']] + 'topic': function () { + return _optimize('p{border-top-color:#9fce00;border-bottom-color:#9fce00;border-left-color:#9fce00;border-right-color:#9fce00}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-color'], + ['property-value', '#9fce00', [[1, 19, undefined]]] + ] ]); } }, 'shorthand border-color #2': { - 'topic': 'p{border-right-color:#002;border-bottom-color:#003;border-top-color:#001;border-left-color:#004}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-color'], ['#001'], ['#002'], ['#003'], ['#004']] + 'topic': function () { + return _optimize('p{border-right-color:#002;border-bottom-color:#003;border-top-color:#001;border-left-color:#004}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-color'], + ['property-value', '#001', [[1, 68, undefined]]], + ['property-value', '#002', [[1, 21, undefined]]], + ['property-value', '#003', [[1, 46, undefined]]], + ['property-value', '#004', [[1, 91, undefined]]] + ] ]); } }, 'shorthand border-radius': { - 'topic': 'p{border-top-left-radius:7px;border-bottom-right-radius:6px;border-bottom-left-radius:5px;border-top-right-radius:3px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-radius'], ['7px'], ['3px'], ['6px'], ['5px']] + 'topic': function () { + return _optimize('p{border-top-left-radius:7px;border-bottom-right-radius:6px;border-bottom-left-radius:5px;border-top-right-radius:3px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-radius'], + ['property-value', '7px', [[1, 25, undefined]]], + ['property-value', '3px', [[1, 114, undefined]]], + ['property-value', '6px', [[1, 56, undefined]]], + ['property-value', '5px', [[1, 86, undefined]]] + ] ]); } }, 'shorthand multiplexed border-radius': { - 'topic': 'p{border-radius:7px/3px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-radius'], ['7px'], ['/'], ['3px']] + 'topic': function () { + return _optimize('p{border-radius:7px/3px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-radius', [[1, 2, undefined]]], + ['property-value', '7px', [[1, 16, undefined]]], + ['property-value', '/'], + ['property-value', '3px', [[1, 20, undefined]]] + ] ]); } }, 'shorthand asymmetric border-radius with same values': { - 'topic': 'p{border-top-left-radius:7px 3px;border-top-right-radius:7px 3px;border-bottom-right-radius:7px 3px;border-bottom-left-radius:7px 3px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-radius'], ['7px'], ['/'], ['3px']] + 'topic': function () { + return _optimize('p{border-top-left-radius:7px 3px;border-top-right-radius:7px 3px;border-bottom-right-radius:7px 3px;border-bottom-left-radius:7px 3px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-radius'], + ['property-value', '7px', [[1, 25, undefined]]], + ['property-value', '/'], + ['property-value', '3px', [[1, 29, undefined]]] + ] ]); } }, 'shorthand asymmetric border-radius': { - 'topic': 'p{border-top-left-radius:7px 3px;border-top-right-radius:6px 2px;border-bottom-right-radius:5px 1px;border-bottom-left-radius:4px 0}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-radius'], ['7px'], ['6px'], ['5px'], ['4px'], ['/'], ['3px'], ['2px'], ['1px'], ['0']] + 'topic': function () { + return _optimize('p{border-top-left-radius:7px 3px;border-top-right-radius:6px 2px;border-bottom-right-radius:5px 1px;border-bottom-left-radius:4px 0}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-radius'], + ['property-value', '7px', [[1, 25, undefined]]], + ['property-value', '6px', [[1, 57, undefined]]], + ['property-value', '5px', [[1, 92, undefined]]], + ['property-value', '4px', [[1, 126, undefined]]], + ['property-value', '/'], + ['property-value', '3px', [[1, 29, undefined]]], + ['property-value', '2px', [[1, 61, undefined]]], + ['property-value', '1px', [[1, 96, undefined]]], + ['property-value', '0', [[1, 130, undefined]]] + ] ]); } }, 'shorthand multiple !important': { - 'topic': 'a{border-color:#123 !important;border-top-color: #456 !important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['border-color'], ['#456'], ['#123'], ['#123!important']] + 'topic': function () { + return _optimize('a{border-color:#123 !important;border-top-color: #456 !important}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'border-color', [[1, 2, undefined]]], + ['property-value', '#456', [[1, 49, undefined]]], + ['property-value', '#123', [[1, 15, undefined]]], + ['property-value', '#123!important', [[1, 15, undefined]]] + ] ]); } }, 'shorthand list-style #1': { - 'topic': 'a{list-style-type:circle;list-style-position:outside;list-style-image:__ESCAPED_URL_CLEAN_CSS0__}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['list-style'], ['circle'], ['__ESCAPED_URL_CLEAN_CSS0__']] + 'topic': function () { + return _optimize('a{list-style-type:circle;list-style-position:outside;list-style-image:url(image.png)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'list-style'], + ['property-value', 'circle', [[1, 18, undefined]]], + ['property-value', 'url(image.png)', [[1, 70, undefined]]] + ] ]); } }, 'shorthand list-style #2': { - 'topic': 'a{list-style-image:__ESCAPED_URL_CLEAN_CSS0__;list-style-type:circle;list-style-position:inside}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['list-style'], ['circle'], ['inside'], ['__ESCAPED_URL_CLEAN_CSS0__']] + 'topic': function () { + return _optimize('a{list-style-image:url(image.png);list-style-type:circle;list-style-position:inside}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'list-style'], + ['property-value', 'circle', [[1, 50, undefined]]], + ['property-value', 'inside', [[1, 77, undefined]]], + ['property-value', 'url(image.png)', [[1, 19, undefined]]] + ] ]); } }, 'shorthand margin': { - 'topic': 'a{margin-top:10px;margin-right:5px;margin-bottom:3px;margin-left:2px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['margin'], ['10px'], ['5px'], ['3px'], ['2px']] + 'topic': function () { + return _optimize('a{margin-top:10px;margin-right:5px;margin-bottom:3px;margin-left:2px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '10px', [[1, 13, undefined]]], + ['property-value', '5px', [[1, 31, undefined]]], + ['property-value', '3px', [[1, 49, undefined]]], + ['property-value', '2px', [[1, 65, undefined]]] + ] ]); } }, 'shorthand padding': { - 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:2px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['padding'], ['10px'], ['2px'], ['3px'], ['5px']] + 'topic': function () { + return _optimize('a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:2px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'padding'], + ['property-value', '10px', [[1, 14, undefined]]], + ['property-value', '2px', [[1, 69, undefined]]], + ['property-value', '3px', [[1, 51, undefined]]], + ['property-value', '5px', [[1, 32, undefined]]] + ] ]); } }, 'mixed': { - 'topic': 'a{padding-top:10px;margin-top:3px;padding-left:5px;margin-left:3px;padding-bottom:3px;margin-bottom:3px;padding-right:2px;margin-right:3px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['padding'], ['10px'], ['2px'], ['3px'], ['5px']], - [['margin'], ['3px']] + 'topic': function () { + return _optimize('a{padding-top:10px;margin-top:3px;padding-left:5px;margin-left:3px;padding-bottom:3px;margin-bottom:3px;padding-right:2px;margin-right:3px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'padding'], + ['property-value', '10px', [[1, 14, undefined]]], + ['property-value', '2px', [[1, 118, undefined]]], + ['property-value', '3px', [[1, 82, undefined]]], + ['property-value', '5px', [[1, 47, undefined]]] + ], + [ + 'property', + ['property-name', 'margin'], + ['property-value', '3px', [[1, 30, undefined]]] + ] ]); } }, 'with other properties': { - 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px;color:red;padding-right:2px;width:100px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['color'], ['red']], - [['width'], ['100px']], - [['padding'], ['10px'], ['2px'], ['3px'], ['5px']] + 'topic': function () { + return _optimize('a{padding-top:10px;padding-left:5px;padding-bottom:3px;color:red;padding-right:2px;width:100px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'color', [[1, 55, undefined]]], + ['property-value', 'red', [[1, 61, undefined]]] + ], + [ + 'property', + ['property-name', 'width', [[1, 83, undefined]]], + ['property-value', '100px', [[1, 89, undefined]]] + ], + [ + 'property', + ['property-name', 'padding'], + ['property-value', '10px', [[1, 14, undefined]]], + ['property-value', '2px', [[1, 79, undefined]]], + ['property-value', '3px', [[1, 51, undefined]]], + ['property-value', '5px', [[1, 32, undefined]]] + ] ]); } }, 'with hacks': { - 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px;_padding-right:2px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['padding-top'], ['10px']], - [['padding-left'], ['5px']], - [['padding-bottom'], ['3px']], - [['_padding-right'], ['2px']] + 'topic': function () { + return _optimize('a{padding-top:10px;padding-left:5px;padding-bottom:3px;_padding-right:2px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'padding-top', [[1, 2, undefined]]], + ['property-value', '10px', [[1, 14, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-left', [[1, 19, undefined]]], + ['property-value', '5px', [[1, 32, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-bottom', [[1, 36, undefined]]], + ['property-value', '3px', [[1, 51, undefined]]] + ], + [ + 'property', + ['property-name', '_padding-right', [[1, 55, undefined]]], + ['property-value', '2px', [[1, 70, undefined]]] + ] ]); } }, 'just inherit': { - 'topic': 'a{background:inherit}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background'], ['inherit']] + 'topic': function () { + return _optimize('a{background:inherit}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background', [[1, 2, undefined]]], + ['property-value', 'inherit', [[1, 13, undefined]]] + ] ]); } } }) .addBatch({ 'not enough components': { - 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['padding-top'], ['10px']], - [['padding-left'], ['5px']], - [['padding-bottom'], ['3px']] + 'topic': function () { + return _optimize('a{padding-top:10px;padding-left:5px;padding-bottom:3px}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'padding-top', [[1, 2, undefined]]], + ['property-value', '10px', [[1, 14, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-left', [[1, 19, undefined]]], + ['property-value', '5px', [[1, 32, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-bottom', [[1, 36, undefined]]], + ['property-value', '3px', [[1, 51, undefined]]] + ] ]); } }, 'with inherit - pending #525': { - 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:inherit}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['padding-top'], ['10px']], - [['padding-left'], ['5px']], - [['padding-bottom'], ['3px']], - [['padding-right'], ['inherit']] + 'topic': function () { + return _optimize('a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:inherit}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'padding-top', [[1, 2, undefined]]], + ['property-value', '10px', [[1, 14, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-left', [[1, 19, undefined]]], + ['property-value', '5px', [[1, 32, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-bottom', [[1, 36, undefined]]], + ['property-value', '3px', [[1, 51, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-right', [[1, 55, undefined]]], + ['property-value', 'inherit', [[1, 69, undefined]]] + ] ]); } }, 'mixed importance': { - 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:2px!important}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['padding-top'], ['10px']], - [['padding-left'], ['5px']], - [['padding-bottom'], ['3px']], - [['padding-right'], ['2px!important']] + 'topic': function () { + return _optimize('a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:2px!important}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'padding-top', [[1, 2, undefined]]], + ['property-value', '10px', [[1, 14, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-left', [[1, 19, undefined]]], + ['property-value', '5px', [[1, 32, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-bottom', [[1, 36, undefined]]], + ['property-value', '3px', [[1, 51, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-right', [[1, 55, undefined]]], + ['property-value', '2px!important', [[1, 69, undefined]]] + ] ]); } }, 'mixed understandability of units': { - 'topic': 'a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:calc(100% - 20px)}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['padding-top'], ['10px']], - [['padding-left'], ['5px']], - [['padding-bottom'], ['3px']], - [['padding-right'], ['calc(100% - 20px)']] + 'topic': function () { + return _optimize('a{padding-top:10px;padding-left:5px;padding-bottom:3px;padding-right:calc(100% - 20px)}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'padding-top', [[1, 2, undefined]]], + ['property-value', '10px', [[1, 14, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-left', [[1, 19, undefined]]], + ['property-value', '5px', [[1, 32, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-bottom', [[1, 36, undefined]]], + ['property-value', '3px', [[1, 51, undefined]]] + ], + [ + 'property', + ['property-name', 'padding-right', [[1, 55, undefined]]], + ['property-value', 'calc(100% - 20px)', [[1, 69, undefined]]] + ] ]); } }, 'mixed understandability of images': { - 'topic': 'p{background-color:#111;background-image:linear-gradient(sth);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}', - 'into': function (topic) { - assert.deepEqual(_optimize(topic), [ - [['background-color'], ['#111']], - [['background-image'], ['linear-gradient(sth)']], - [['background-repeat'], ['repeat']], - [['background-position'], ['0'], ['0']], - [['background-attachment'], ['scroll']], - [['background-size'], ['auto']], - [['background-origin'], ['padding-box']], - [['background-clip'], ['border-box']] + 'topic': function () { + return _optimize('p{background-color:#111;background-image:linear-gradient(sth);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto;background-origin:padding-box;background-clip:border-box}'); + }, + 'into': function (properties) { + assert.deepEqual(properties, [ + [ + 'property', + ['property-name', 'background-color', [[1, 2, undefined]]], + ['property-value', '#111', [[1, 19, undefined]]] + ], + [ + 'property', + ['property-name', 'background-image', [[1, 24, undefined]]], + ['property-value', 'linear-gradient(sth)', [[1, 41, undefined]]] + ], + [ + 'property', + ['property-name', 'background-repeat', [[1, 62, undefined]]], + ['property-value', 'repeat', [[1, 80, undefined]]] + ], + [ + 'property', + ['property-name', 'background-position', [[1, 87, undefined]]], + ['property-value', '0', [[1, 107, undefined]]], + ['property-value', '0', [[1, 109, undefined]]] + ], + [ + 'property', + ['property-name', 'background-attachment', [[1, 111, undefined]]], + ['property-value', 'scroll', [[1, 133, undefined]]] + ], + [ + 'property', + ['property-name', 'background-size', [[1, 140, undefined]]], + ['property-value', 'auto', [[1, 156, undefined]]] + ], + [ + 'property', + ['property-name', 'background-origin', [[1, 161, undefined]]], + ['property-value', 'padding-box', [[1, 179, undefined]]] + ], + [ + 'property', + ['property-name', 'background-clip', [[1, 191, undefined]]], + ['property-value', 'border-box', [[1, 207, undefined]]] + ] ]); } - } + } }) .export(module); diff --git a/test/properties/wrap-for-optimizing-test.js b/test/properties/wrap-for-optimizing-test.js index 8c699d28..22e76a5e 100644 --- a/test/properties/wrap-for-optimizing-test.js +++ b/test/properties/wrap-for-optimizing-test.js @@ -7,7 +7,14 @@ vows.describe(wrapForOptimizing) .addBatch({ 'one': { 'topic': function () { - return wrapForOptimizing([[['margin'], ['0'], ['0']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0'], + ['property-value', '0'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); @@ -16,7 +23,7 @@ vows.describe(wrapForOptimizing) assert.deepEqual(wrapped[0].name, 'margin'); }, 'has value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [['0'], ['0']]); + assert.deepEqual(wrapped[0].value, [['property-value', '0'], ['property-value', '0']]); }, 'is not a block': function (wrapped) { assert.isFalse(wrapped[0].block); @@ -45,7 +52,19 @@ vows.describe(wrapForOptimizing) }, 'two': { 'topic': function () { - return wrapForOptimizing([[['margin'], ['0'], ['0']], [['color'], ['red']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0'], + ['property-value', '0'] + ], + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red'] + ] + ]); }, 'has two wraps': function (wrapped) { assert.lengthOf(wrapped, 2); @@ -53,7 +72,17 @@ vows.describe(wrapForOptimizing) }, 'with comments': { 'topic': function () { - return wrapForOptimizing([['/* comment */'], [['color'], ['red']]]); + return wrapForOptimizing([ + [ + 'comment', + ['/* comment */'] + ], + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); @@ -64,7 +93,15 @@ vows.describe(wrapForOptimizing) }, 'longhand': { 'topic': function () { - return wrapForOptimizing([[['border-radius-top-left'], ['1px'], ['/'], ['2px']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'border-radius-top-left'], + ['property-value', '1px'], + ['property-value', '/'], + ['property-value', '2px'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); @@ -73,7 +110,7 @@ vows.describe(wrapForOptimizing) assert.deepEqual(wrapped[0].name, 'border-radius-top-left'); }, 'has value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [['1px'], ['/'], ['2px']]); + assert.deepEqual(wrapped[0].value, [['property-value', '1px'], ['property-value', '/'], ['property-value', '2px']]); }, 'is multiplex': function (wrapped) { assert.isTrue(wrapped[0].multiplex); @@ -81,7 +118,13 @@ vows.describe(wrapForOptimizing) }, 'variable': { 'topic': function () { - return wrapForOptimizing([[['--color'], ['red']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', '--color'], + ['property-value', 'red'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); @@ -89,19 +132,33 @@ vows.describe(wrapForOptimizing) 'has name': function (wrapped) { assert.deepEqual(wrapped[0].name, '--color'); }, - 'has value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [['red']]); - }, 'is not a block': function (wrapped) { assert.isFalse(wrapped[0].block); - }, - 'is variable': function (wrapped) { - assert.isTrue(wrapped[0].variable); } }, 'variable block': { 'topic': function () { - return wrapForOptimizing([[['--color'], [ [['color'], ['red']], [['text-color'], ['red']] ]]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', '--color'], + [ + 'property-block', + [ + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red'] + ], + [ + 'property', + ['property-name', 'text-color'], + ['property-value', 'red'] + ] + ] + ] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); @@ -110,43 +167,143 @@ vows.describe(wrapForOptimizing) assert.deepEqual(wrapped[0].name, '--color'); }, 'has value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [[ [['color'], ['red']], [['text-color'], ['red']] ]]); - }, - 'is not a block': function (wrapped) { + assert.deepEqual(wrapped[0].value, [ + [ + 'property-block', + [ + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red'] + ], + [ + 'property', + ['property-name', 'text-color'], + ['property-value', 'red'] + ] + ] + ] + ]); + }, + 'is a block': function (wrapped) { assert.isTrue(wrapped[0].block); - }, - 'is variable': function (wrapped) { - assert.isTrue(wrapped[0].variable); } }, 'without value': { 'topic': function () { - return wrapForOptimizing([[['margin']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); }, - 'is unused': function (wrapped) { - assert.isTrue(wrapped[0].unused); + 'has value': function (wrapped) { + assert.isUndefined(wrapped.value); + }, + 'unused is not set': function (wrapped) { + assert.isFalse(wrapped[0].unused); } }, 'important': { 'topic': function () { - return wrapForOptimizing([[['margin'], ['0!important']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0!important'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); }, 'has right value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [['0']]); + assert.deepEqual(wrapped[0].value, [['property-value', '0']]); }, - 'is important': function (wrapped) { + 'has important set': function (wrapped) { + assert.isTrue(wrapped[0].important); + } + }, + 'important with prefix space': { + 'topic': function () { + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0'], + ['property-value', '!important'] + ] + ]); + }, + 'has one wrap': function (wrapped) { + assert.lengthOf(wrapped, 1); + }, + 'has right value': function (wrapped) { + assert.deepEqual(wrapped[0].value, [['property-value', '0']]); + }, + 'has important set': function (wrapped) { assert.isTrue(wrapped[0].important); } }, + 'important with suffix space': { + 'topic': function () { + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0!'], + ['property-value', 'important'] + ] + ]); + }, + 'has one wrap': function (wrapped) { + assert.lengthOf(wrapped, 1); + }, + 'has right value': function (wrapped) { + assert.deepEqual(wrapped[0].value, [['property-value', '0']]); + }, + 'has important set': function (wrapped) { + assert.isTrue(wrapped[0].important); + } + }, + 'important with two spaces': { + 'topic': function () { + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0'], + ['property-value', '!'], + ['property-value', 'important'] + ] + ]); + }, + 'has one wrap': function (wrapped) { + assert.lengthOf(wrapped, 1); + }, + 'has right value': function (wrapped) { + assert.deepEqual(wrapped[0].value, [['property-value', '0']]); + }, + 'has important set': function (wrapped) { + assert.isTrue(wrapped[0].important); + }, + 'is not a bang hack': function (wrapped) { + assert.isFalse(wrapped[0].hack); + } + }, 'underscore hack': { 'topic': function () { - return wrapForOptimizing([[['_color'], ['red']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', '_color'], + ['property-value', 'red'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); @@ -160,7 +317,13 @@ vows.describe(wrapForOptimizing) }, 'star hack': { 'topic': function () { - return wrapForOptimizing([[['*color'], ['red']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', '*color'], + ['property-value', 'red'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); @@ -174,13 +337,19 @@ vows.describe(wrapForOptimizing) }, 'backslash hack': { 'topic': function () { - return wrapForOptimizing([[['margin'], ['0\\9']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0\\9'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); }, 'has right value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [['0']]); + assert.deepEqual(wrapped[0].value, [['property-value', '0']]); }, 'is a hack': function (wrapped) { assert.equal(wrapped[0].hack, 'backslash'); @@ -188,13 +357,19 @@ vows.describe(wrapForOptimizing) }, 'backslash hack - single value': { 'topic': function () { - return wrapForOptimizing([[['margin'], ['0']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); }, 'has right value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [['0']]); + assert.deepEqual(wrapped[0].value, [['property-value', '0']]); }, 'is a hack': function (wrapped) { assert.isFalse(wrapped[0].hack); @@ -202,13 +377,20 @@ vows.describe(wrapForOptimizing) }, 'backslash hack - space between values': { 'topic': function () { - return wrapForOptimizing([[['margin'], ['0'], ['\\9']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0'], + ['property-value', '\\9'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); }, 'has right value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [['0']]); + assert.deepEqual(wrapped[0].value, [['property-value', '0']]); }, 'is a hack': function (wrapped) { assert.equal(wrapped[0].hack, 'backslash'); @@ -216,13 +398,42 @@ vows.describe(wrapForOptimizing) }, 'bang hack': { 'topic': function () { - return wrapForOptimizing([[['margin'], ['0'], ['!ie']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0!ie'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); }, 'has right value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [['0']]); + assert.deepEqual(wrapped[0].value, [['property-value', '0']]); + }, + 'is a hack': function (wrapped) { + assert.equal(wrapped[0].hack, 'bang'); + }, + 'is not important': function (wrapped) { + assert.isFalse(wrapped[0].important); + } + }, + 'bang hack with space': { + 'topic': function () { + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0 !ie'] + ] + ]); + }, + 'has one wrap': function (wrapped) { + assert.lengthOf(wrapped, 1); + }, + 'has right value': function (wrapped) { + assert.deepEqual(wrapped[0].value, [['property-value', '0']]); }, 'is a hack': function (wrapped) { assert.equal(wrapped[0].hack, 'bang'); @@ -233,13 +444,20 @@ vows.describe(wrapForOptimizing) }, 'bang hack - space between values': { 'topic': function () { - return wrapForOptimizing([[['margin'], ['0 !ie']]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'margin'], + ['property-value', '0'], + ['property-value', '!ie'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); }, 'has right value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [['0']]); + assert.deepEqual(wrapped[0].value, [['property-value', '0']]); }, 'is a hack': function (wrapped) { assert.equal(wrapped[0].hack, 'bang'); @@ -248,15 +466,21 @@ vows.describe(wrapForOptimizing) assert.isFalse(wrapped[0].important); } }, - 'source map': { + 'two hacks': { 'topic': function () { - return wrapForOptimizing([[['color', 1, 2, undefined], ['red\\9!important', 1, 2, undefined]]]); + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'color'], + ['property-value', 'red\\9!important'] + ] + ]); }, 'has one wrap': function (wrapped) { assert.lengthOf(wrapped, 1); }, 'has right value': function (wrapped) { - assert.deepEqual(wrapped[0].value, [['red', 1, 2, undefined]]); + assert.deepEqual(wrapped[0].value, [['property-value', 'red']]); }, 'is important': function (wrapped) { assert.isTrue(wrapped[0].important); @@ -264,6 +488,23 @@ vows.describe(wrapForOptimizing) 'is a hack': function (wrapped) { assert.equal(wrapped[0].hack, 'backslash'); } + }, + 'source map': { + 'topic': function () { + return wrapForOptimizing([ + [ + 'property', + ['property-name', 'color', [[1, 2, undefined]]], + ['property-value', 'red', [[1, 2, undefined]]] + ] + ]); + }, + 'has one wrap': function (wrapped) { + assert.lengthOf(wrapped, 1); + }, + 'has right value': function (wrapped) { + assert.deepEqual(wrapped[0].value, [['property-value', 'red', [[1, 2, undefined]]]]); + } } }) .export(module); diff --git a/test/selectors/extractor-test.js b/test/selectors/extractor-test.js deleted file mode 100644 index 6d2fd88f..00000000 --- a/test/selectors/extractor-test.js +++ /dev/null @@ -1,152 +0,0 @@ -var vows = require('vows'); -var assert = require('assert'); -var tokenize = require('../../lib/tokenizer/tokenize'); -var extractor = require('../../lib/selectors/extractor'); - -function buildToken(source) { - return tokenize(source, { options: {} })[0]; -} - -vows.describe(extractor) - .addBatch({ - 'no properties': { - 'topic': extractor(buildToken('a{}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, []); - } - }, - 'no valid properties': { - 'topic': extractor(buildToken('a{:red}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, []); - } - }, - 'one property': { - 'topic': extractor(buildToken('a{color:red}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['color', 'red', 'color', [['color'], ['red']], 'color:red', [['a']], true]]); - } - }, - 'one important property': { - 'topic': extractor(buildToken('a{color:red!important}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['color', 'red!important', 'color', [['color'], ['red!important']], 'color:red!important', [['a']], true]]); - } - }, - 'one property - simple selector': { - 'topic': extractor(buildToken('#one span{color:red}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['color', 'red', 'color', [['color'], ['red']], 'color:red', [['#one span']], true]]); - } - }, - 'one property - variable': { - 'topic': extractor(buildToken('#one span{--color:red}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, []); - } - }, - 'one property - block variable': { - 'topic': extractor(buildToken('#one span{--color:{color:red;display:block};}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, []); - } - }, - 'one property - complex selector': { - 'topic': extractor(buildToken('.one{color:red}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['color', 'red', 'color', [['color'], ['red']], 'color:red', [['.one']], false]]); - } - }, - 'two properties': { - 'topic': extractor(buildToken('a{color:red;display:block}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [ - ['color', 'red', 'color', [['color'], ['red']], 'color:red', [['a']], true], - ['display', 'block', 'display', [['display'], ['block']], 'display:block', [['a']], true] - ]); - } - }, - 'from @media': { - 'topic': extractor(buildToken('@media{a{color:red;display:block}p{color:red}}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [ - ['color', 'red', 'color', [['color'], ['red']], 'color:red', [['a']], true], - ['display', 'block', 'display', [['display'], ['block']], 'display:block', [['a']], true], - ['color', 'red', 'color', [['color'], ['red']], 'color:red', [['p']], true] - ]); - } - }, - 'with source map info': { - 'topic': extractor(['selector', [['a', 1, 0, undefined]], [[['color', 1, 3, undefined], ['red', 1, 9, undefined]]]]), - 'has one property': function (tokens) { - assert.deepEqual(tokens, [ - ['color', 'red', 'color', [['color', 1, 3, undefined], ['red', 1, 9, undefined]], 'color:red', [['a', 1, 0, undefined]], true], - ]); - } - } - }) - .addBatch({ - 'name root special cases': { - 'vendor prefix': { - 'topic': extractor(buildToken('a{-moz-transform:none}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['-moz-transform', 'none', 'transform', [['-moz-transform'], ['none']], '-moz-transform:none', [['a']], true]]); - } - }, - 'list-style': { - 'topic': extractor(buildToken('a{list-style:none}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['list-style', 'none', 'list-style', [['list-style'], ['none']], 'list-style:none', [['a']], true]]); - } - }, - 'border-radius': { - 'topic': extractor(buildToken('a{border-top-left-radius:none}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['border-top-left-radius', 'none', 'border-radius', [['border-top-left-radius'], ['none']], 'border-top-left-radius:none', [['a']], true]]); - } - }, - 'vendor prefixed border-radius': { - 'topic': extractor(buildToken('a{-webkit-border-top-left-radius:none}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['-webkit-border-top-left-radius', 'none', 'border-radius', [['-webkit-border-top-left-radius'], ['none']], '-webkit-border-top-left-radius:none', [['a']], true]]); - } - }, - 'border-image-width': { - 'topic': extractor(buildToken('a{border-image-width:2px}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['border-image-width', '2px', 'border-image', [['border-image-width'], ['2px']], 'border-image-width:2px', [['a']], true]]); - } - }, - 'border-color': { - 'topic': extractor(buildToken('a{border-color:red}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['border-color', 'red', 'border', [['border-color'], ['red']], 'border-color:red', [['a']], true]]); - } - }, - 'border-top-style': { - 'topic': extractor(buildToken('a{border-top-style:none}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['border-top-style', 'none', 'border-top', [['border-top-style'], ['none']], 'border-top-style:none', [['a']], true]]); - } - }, - 'border-top': { - 'topic': extractor(buildToken('a{border-top:none}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['border-top', 'none', 'border', [['border-top'], ['none']], 'border-top:none', [['a']], true]]); - } - }, - 'border-collapse': { - 'topic': extractor(buildToken('a{border-collapse:collapse}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['border-collapse', 'collapse', 'border-collapse', [['border-collapse'], ['collapse']], 'border-collapse:collapse', [['a']], true]]); - } - }, - 'text-shadow': { - 'topic': extractor(buildToken('a{text-shadow:none}')), - 'has no properties': function (tokens) { - assert.deepEqual(tokens, [['text-shadow', 'none', 'text-shadow', [['text-shadow'], ['none']], 'text-shadow:none', [['a']], true]]); - } - } - } - }) - .export(module); diff --git a/test/test-helper.js b/test/test-helper.js index 19eaa67f..0a73eb99 100644 --- a/test/test-helper.js +++ b/test/test-helper.js @@ -1,9 +1,6 @@ var assert = require('assert'); var CleanCSS = require('../lib/clean'); -var tokenize = require('../lib/tokenizer/tokenize'); -var simpleOptimize = require('../lib/selectors/simple'); -var Compatibility = require('../lib/utils/compatibility'); function optimizerContext(group, specs, options) { var context = {}; @@ -27,64 +24,6 @@ function optimizerContext(group, specs, options) { return context; } -function selectorContext(group, specs, options) { - var context = {}; - options = options || {}; - options.compatibility = new Compatibility(options.compatibility).toOptions(); - - function optimized(selectors) { - return function (source) { - var tokens = tokenize(source, { options: {} }); - simpleOptimize(tokens, options, {}); - - assert.deepEqual(tokens[0] ? tokens[0][1] : null, selectors); - }; - } - - for (var name in specs) { - context['selector - ' + group + ' - ' + name] = { - topic: specs[name][0], - optimized: optimized(specs[name][1]) - }; - } - - return context; -} - -function propertyContext(group, specs, options) { - var context = {}; - options = options || {}; - options.compatibility = new Compatibility(options.compatibility).toOptions(); - - function optimized(selectors) { - return function (source) { - var tokens = tokenize(source, { options: {} }); - simpleOptimize(tokens, options, {}); - - var value = tokens[0] ? - tokens[0][2].map(function (property) { - return typeof property == 'string' ? - property : - property.map(function (t) { return t[0]; }); - }) : - null; - - assert.deepEqual(value, selectors); - }; - } - - for (var name in specs) { - context['property - ' + group + ' - ' + name] = { - topic: specs[name][0], - optimized: optimized(specs[name][1]) - }; - } - - return context; -} - module.exports = { - optimizerContext: optimizerContext, - selectorContext: selectorContext, - propertyContext: propertyContext + optimizerContext: optimizerContext }; diff --git a/test/utils/compatibility-test.js b/test/utils/compatibility-test.js index 429be441..954f1df8 100644 --- a/test/utils/compatibility-test.js +++ b/test/utils/compatibility-test.js @@ -1,250 +1,250 @@ var vows = require('vows'); var assert = require('assert'); -var Compatibility = require('../../lib/utils/compatibility'); +var compatibility = require('../../lib/utils/compatibility'); -vows.describe(Compatibility) +vows.describe(compatibility) .addBatch({ 'as an empty hash': { 'topic': function () { - return new Compatibility({}).toOptions(); + return compatibility({}); }, - 'gets default options': function (options) { - assert.isTrue(options.colors.opacity); - assert.isTrue(options.properties.colors); - assert.isFalse(options.properties.backgroundClipMerging); - assert.isFalse(options.properties.backgroundOriginMerging); - assert.isFalse(options.properties.backgroundSizeMerging); - assert.isFalse(options.properties.ieBangHack); - assert.isFalse(options.properties.iePrefixHack); - assert.isTrue(options.properties.ieSuffixHack); - assert.isTrue(options.properties.merging); - assert.isFalse(options.properties.shorterLengthUnits); - assert.isTrue(options.properties.spaceAfterClosingBrace); - assert.isFalse(options.properties.urlQuotes); - assert.isTrue(options.properties.zeroUnits); - assert.isFalse(options.selectors.adjacentSpace); - assert.isFalse(options.selectors.ie7Hack); - assert.isTrue(options.units.ch); - assert.isTrue(options.units.in); - assert.isTrue(options.units.pc); - assert.isTrue(options.units.pt); - assert.isTrue(options.units.rem); - assert.isTrue(options.units.vh); - assert.isTrue(options.units.vm); - assert.isTrue(options.units.vmax); - assert.isTrue(options.units.vmin); - assert.isTrue(options.units.vw); + 'gets default compatibility': function (compat) { + assert.isTrue(compat.colors.opacity); + assert.isTrue(compat.properties.colors); + assert.isFalse(compat.properties.backgroundClipMerging); + assert.isFalse(compat.properties.backgroundOriginMerging); + assert.isFalse(compat.properties.backgroundSizeMerging); + assert.isFalse(compat.properties.ieBangHack); + assert.isFalse(compat.properties.iePrefixHack); + assert.isTrue(compat.properties.ieSuffixHack); + assert.isTrue(compat.properties.merging); + assert.isFalse(compat.properties.shorterLengthUnits); + assert.isTrue(compat.properties.spaceAfterClosingBrace); + assert.isFalse(compat.properties.urlQuotes); + assert.isTrue(compat.properties.zeroUnits); + assert.isFalse(compat.selectors.adjacentSpace); + assert.isFalse(compat.selectors.ie7Hack); + assert.isTrue(compat.units.ch); + assert.isTrue(compat.units.in); + assert.isTrue(compat.units.pc); + assert.isTrue(compat.units.pt); + assert.isTrue(compat.units.rem); + assert.isTrue(compat.units.vh); + assert.isTrue(compat.units.vm); + assert.isTrue(compat.units.vmax); + assert.isTrue(compat.units.vmin); + assert.isTrue(compat.units.vw); } }, 'not given': { 'topic': function () { - return new Compatibility().toOptions(); + return compatibility(); }, - 'gets default options': function (options) { - assert.deepEqual(options, new Compatibility({}).toOptions()); + 'gets default compatibility': function (compat) { + assert.deepEqual(compat, compatibility({})); } }, 'as a populated hash': { 'topic': function () { - return new Compatibility({ units: { rem: false, vmax: false }, properties: { prefix: true } }).toOptions(); + return compatibility({ units: { rem: false, vmax: false }, properties: { prefix: true } }); }, - 'gets merged options': function (options) { - assert.isTrue(options.colors.opacity); - assert.isFalse(options.properties.backgroundClipMerging); - assert.isFalse(options.properties.backgroundOriginMerging); - assert.isFalse(options.properties.backgroundSizeMerging); - assert.isTrue(options.properties.colors); - assert.isFalse(options.properties.ieBangHack); - assert.isFalse(options.properties.iePrefixHack); - assert.isTrue(options.properties.ieSuffixHack); - assert.isTrue(options.properties.merging); - assert.isFalse(options.properties.shorterLengthUnits); - assert.isTrue(options.properties.spaceAfterClosingBrace); - assert.isTrue(options.properties.zeroUnits); - assert.isFalse(options.selectors.adjacentSpace); - assert.isFalse(options.selectors.ie7Hack); - assert.isTrue(options.units.ch); - assert.isTrue(options.units.in); - assert.isTrue(options.units.pc); - assert.isTrue(options.units.pt); - assert.isFalse(options.units.rem); - assert.isTrue(options.units.vh); - assert.isTrue(options.units.vm); - assert.isFalse(options.units.vmax); - assert.isTrue(options.units.vmin); - assert.isTrue(options.units.vw); + 'gets merged compatibility': function (compat) { + assert.isTrue(compat.colors.opacity); + assert.isFalse(compat.properties.backgroundClipMerging); + assert.isFalse(compat.properties.backgroundOriginMerging); + assert.isFalse(compat.properties.backgroundSizeMerging); + assert.isTrue(compat.properties.colors); + assert.isFalse(compat.properties.ieBangHack); + assert.isFalse(compat.properties.iePrefixHack); + assert.isTrue(compat.properties.ieSuffixHack); + assert.isTrue(compat.properties.merging); + assert.isFalse(compat.properties.shorterLengthUnits); + assert.isTrue(compat.properties.spaceAfterClosingBrace); + assert.isTrue(compat.properties.zeroUnits); + assert.isFalse(compat.selectors.adjacentSpace); + assert.isFalse(compat.selectors.ie7Hack); + assert.isTrue(compat.units.ch); + assert.isTrue(compat.units.in); + assert.isTrue(compat.units.pc); + assert.isTrue(compat.units.pt); + assert.isFalse(compat.units.rem); + assert.isTrue(compat.units.vh); + assert.isTrue(compat.units.vm); + assert.isFalse(compat.units.vmax); + assert.isTrue(compat.units.vmin); + assert.isTrue(compat.units.vw); } } }) .addBatch({ 'as an ie8 template': { 'topic': function () { - return new Compatibility('ie8').toOptions(); + return compatibility('ie8'); }, - 'gets template options': function (options) { - assert.isFalse(options.colors.opacity); - assert.isFalse(options.properties.backgroundClipMerging); - assert.isFalse(options.properties.backgroundOriginMerging); - assert.isFalse(options.properties.backgroundSizeMerging); - assert.isTrue(options.properties.colors); - assert.isFalse(options.properties.ieBangHack); - assert.isTrue(options.properties.iePrefixHack); - assert.isTrue(options.properties.ieSuffixHack); - assert.isFalse(options.properties.merging); - assert.isFalse(options.properties.shorterLengthUnits); - assert.isTrue(options.properties.spaceAfterClosingBrace); - assert.isFalse(options.properties.urlQuotes); - assert.isTrue(options.properties.zeroUnits); - assert.isFalse(options.selectors.adjacentSpace); - assert.isFalse(options.selectors.ie7Hack); - assert.isFalse(options.units.ch); - assert.isTrue(options.units.in); - assert.isTrue(options.units.pc); - assert.isTrue(options.units.pt); - assert.isFalse(options.units.rem); - assert.isFalse(options.units.vh); - assert.isFalse(options.units.vm); - assert.isFalse(options.units.vmax); - assert.isFalse(options.units.vmin); - assert.isFalse(options.units.vw); + 'gets template compatibility': function (compat) { + assert.isFalse(compat.colors.opacity); + assert.isFalse(compat.properties.backgroundClipMerging); + assert.isFalse(compat.properties.backgroundOriginMerging); + assert.isFalse(compat.properties.backgroundSizeMerging); + assert.isTrue(compat.properties.colors); + assert.isFalse(compat.properties.ieBangHack); + assert.isTrue(compat.properties.iePrefixHack); + assert.isTrue(compat.properties.ieSuffixHack); + assert.isFalse(compat.properties.merging); + assert.isFalse(compat.properties.shorterLengthUnits); + assert.isTrue(compat.properties.spaceAfterClosingBrace); + assert.isFalse(compat.properties.urlQuotes); + assert.isTrue(compat.properties.zeroUnits); + assert.isFalse(compat.selectors.adjacentSpace); + assert.isFalse(compat.selectors.ie7Hack); + assert.isFalse(compat.units.ch); + assert.isTrue(compat.units.in); + assert.isTrue(compat.units.pc); + assert.isTrue(compat.units.pt); + assert.isFalse(compat.units.rem); + assert.isFalse(compat.units.vh); + assert.isFalse(compat.units.vm); + assert.isFalse(compat.units.vmax); + assert.isFalse(compat.units.vmin); + assert.isFalse(compat.units.vw); } }, 'as an ie7 template': { 'topic': function () { - return new Compatibility('ie7').toOptions(); + return compatibility('ie7'); }, - 'gets template options': function (options) { - assert.isFalse(options.colors.opacity); - assert.isFalse(options.properties.backgroundClipMerging); - assert.isFalse(options.properties.backgroundOriginMerging); - assert.isFalse(options.properties.backgroundSizeMerging); - assert.isTrue(options.properties.colors); - assert.isTrue(options.properties.ieBangHack); - assert.isTrue(options.properties.iePrefixHack); - assert.isTrue(options.properties.ieSuffixHack); - assert.isFalse(options.properties.merging); - assert.isFalse(options.properties.shorterLengthUnits); - assert.isTrue(options.properties.spaceAfterClosingBrace); - assert.isFalse(options.properties.urlQuotes); - assert.isTrue(options.properties.zeroUnits); - assert.isFalse(options.selectors.adjacentSpace); - assert.isTrue(options.selectors.ie7Hack); - assert.isFalse(options.units.ch); - assert.isTrue(options.units.in); - assert.isTrue(options.units.pc); - assert.isTrue(options.units.pt); - assert.isFalse(options.units.rem); - assert.isFalse(options.units.vh); - assert.isFalse(options.units.vm); - assert.isFalse(options.units.vmax); - assert.isFalse(options.units.vmin); - assert.isFalse(options.units.vw); + 'gets template compatibility': function (compat) { + assert.isFalse(compat.colors.opacity); + assert.isFalse(compat.properties.backgroundClipMerging); + assert.isFalse(compat.properties.backgroundOriginMerging); + assert.isFalse(compat.properties.backgroundSizeMerging); + assert.isTrue(compat.properties.colors); + assert.isTrue(compat.properties.ieBangHack); + assert.isTrue(compat.properties.iePrefixHack); + assert.isTrue(compat.properties.ieSuffixHack); + assert.isFalse(compat.properties.merging); + assert.isFalse(compat.properties.shorterLengthUnits); + assert.isTrue(compat.properties.spaceAfterClosingBrace); + assert.isFalse(compat.properties.urlQuotes); + assert.isTrue(compat.properties.zeroUnits); + assert.isFalse(compat.selectors.adjacentSpace); + assert.isTrue(compat.selectors.ie7Hack); + assert.isFalse(compat.units.ch); + assert.isTrue(compat.units.in); + assert.isTrue(compat.units.pc); + assert.isTrue(compat.units.pt); + assert.isFalse(compat.units.rem); + assert.isFalse(compat.units.vh); + assert.isFalse(compat.units.vm); + assert.isFalse(compat.units.vmax); + assert.isFalse(compat.units.vmin); + assert.isFalse(compat.units.vw); } }, 'as an unknown template': { 'topic': function () { - return new Compatibility('').toOptions(); + return compatibility(''); }, - 'gets default options': function (options) { - assert.deepEqual(options, new Compatibility({}).toOptions()); + 'gets default compatibility': function (compat) { + assert.deepEqual(compat, compatibility({})); } } }) .addBatch({ 'as a complex string value with group': { 'topic': function () { - return new Compatibility('ie8,-properties.iePrefixHack,+colors.opacity').toOptions(); + return compatibility('ie8,-properties.iePrefixHack,+colors.opacity'); }, - 'gets calculated options': function (options) { - assert.isTrue(options.colors.opacity); - assert.isFalse(options.properties.backgroundClipMerging); - assert.isFalse(options.properties.backgroundOriginMerging); - assert.isFalse(options.properties.backgroundSizeMerging); - assert.isTrue(options.properties.colors); - assert.isFalse(options.properties.ieBangHack); - assert.isFalse(options.properties.iePrefixHack); - assert.isTrue(options.properties.ieSuffixHack); - assert.isFalse(options.properties.merging); - assert.isFalse(options.properties.shorterLengthUnits); - assert.isTrue(options.properties.spaceAfterClosingBrace); - assert.isFalse(options.properties.urlQuotes); - assert.isTrue(options.properties.zeroUnits); - assert.isFalse(options.selectors.adjacentSpace); - assert.isFalse(options.selectors.ie7Hack); - assert.isFalse(options.units.ch); - assert.isTrue(options.units.in); - assert.isTrue(options.units.pc); - assert.isTrue(options.units.pt); - assert.isFalse(options.units.rem); - assert.isFalse(options.units.vh); - assert.isFalse(options.units.vm); - assert.isFalse(options.units.vmax); - assert.isFalse(options.units.vmin); - assert.isFalse(options.units.vw); + 'gets calculated compatibility': function (compat) { + assert.isTrue(compat.colors.opacity); + assert.isFalse(compat.properties.backgroundClipMerging); + assert.isFalse(compat.properties.backgroundOriginMerging); + assert.isFalse(compat.properties.backgroundSizeMerging); + assert.isTrue(compat.properties.colors); + assert.isFalse(compat.properties.ieBangHack); + assert.isFalse(compat.properties.iePrefixHack); + assert.isTrue(compat.properties.ieSuffixHack); + assert.isFalse(compat.properties.merging); + assert.isFalse(compat.properties.shorterLengthUnits); + assert.isTrue(compat.properties.spaceAfterClosingBrace); + assert.isFalse(compat.properties.urlQuotes); + assert.isTrue(compat.properties.zeroUnits); + assert.isFalse(compat.selectors.adjacentSpace); + assert.isFalse(compat.selectors.ie7Hack); + assert.isFalse(compat.units.ch); + assert.isTrue(compat.units.in); + assert.isTrue(compat.units.pc); + assert.isTrue(compat.units.pt); + assert.isFalse(compat.units.rem); + assert.isFalse(compat.units.vh); + assert.isFalse(compat.units.vm); + assert.isFalse(compat.units.vmax); + assert.isFalse(compat.units.vmin); + assert.isFalse(compat.units.vw); } }, 'as a single string value without group': { 'topic': function () { - return new Compatibility('+properties.iePrefixHack').toOptions(); + return compatibility('+properties.iePrefixHack'); }, - 'gets calculated options': function (options) { - assert.isTrue(options.colors.opacity); - assert.isTrue(options.properties.colors); - assert.isFalse(options.properties.backgroundClipMerging); - assert.isFalse(options.properties.backgroundOriginMerging); - assert.isFalse(options.properties.backgroundSizeMerging); - assert.isFalse(options.properties.ieBangHack); - assert.isTrue(options.properties.iePrefixHack); - assert.isTrue(options.properties.ieSuffixHack); - assert.isTrue(options.properties.merging); - assert.isFalse(options.properties.shorterLengthUnits); - assert.isTrue(options.properties.spaceAfterClosingBrace); - assert.isFalse(options.properties.urlQuotes); - assert.isTrue(options.properties.zeroUnits); - assert.isFalse(options.selectors.adjacentSpace); - assert.isFalse(options.selectors.ie7Hack); - assert.isTrue(options.units.ch); - assert.isTrue(options.units.in); - assert.isTrue(options.units.pc); - assert.isTrue(options.units.pt); - assert.isTrue(options.units.rem); - assert.isTrue(options.units.vh); - assert.isTrue(options.units.vm); - assert.isTrue(options.units.vmax); - assert.isTrue(options.units.vmin); - assert.isTrue(options.units.vw); + 'gets calculated compatibility': function (compat) { + assert.isTrue(compat.colors.opacity); + assert.isTrue(compat.properties.colors); + assert.isFalse(compat.properties.backgroundClipMerging); + assert.isFalse(compat.properties.backgroundOriginMerging); + assert.isFalse(compat.properties.backgroundSizeMerging); + assert.isFalse(compat.properties.ieBangHack); + assert.isTrue(compat.properties.iePrefixHack); + assert.isTrue(compat.properties.ieSuffixHack); + assert.isTrue(compat.properties.merging); + assert.isFalse(compat.properties.shorterLengthUnits); + assert.isTrue(compat.properties.spaceAfterClosingBrace); + assert.isFalse(compat.properties.urlQuotes); + assert.isTrue(compat.properties.zeroUnits); + assert.isFalse(compat.selectors.adjacentSpace); + assert.isFalse(compat.selectors.ie7Hack); + assert.isTrue(compat.units.ch); + assert.isTrue(compat.units.in); + assert.isTrue(compat.units.pc); + assert.isTrue(compat.units.pt); + assert.isTrue(compat.units.rem); + assert.isTrue(compat.units.vh); + assert.isTrue(compat.units.vm); + assert.isTrue(compat.units.vmax); + assert.isTrue(compat.units.vmin); + assert.isTrue(compat.units.vw); } }, 'as a complex string value without group': { 'topic': function () { - return new Compatibility('+properties.iePrefixHack,-units.rem').toOptions(); + return compatibility('+properties.iePrefixHack,-units.rem'); }, - 'gets calculated options': function (options) { - assert.isTrue(options.colors.opacity); - assert.isTrue(options.properties.colors); - assert.isFalse(options.properties.backgroundClipMerging); - assert.isFalse(options.properties.backgroundOriginMerging); - assert.isFalse(options.properties.backgroundSizeMerging); - assert.isFalse(options.properties.ieBangHack); - assert.isTrue(options.properties.iePrefixHack); - assert.isTrue(options.properties.ieSuffixHack); - assert.isTrue(options.properties.merging); - assert.isFalse(options.properties.shorterLengthUnits); - assert.isTrue(options.properties.spaceAfterClosingBrace); - assert.isFalse(options.properties.urlQuotes); - assert.isTrue(options.properties.zeroUnits); - assert.isFalse(options.selectors.adjacentSpace); - assert.isFalse(options.selectors.ie7Hack); - assert.isTrue(options.units.ch); - assert.isTrue(options.units.in); - assert.isTrue(options.units.pc); - assert.isTrue(options.units.pt); - assert.isFalse(options.units.rem); - assert.isTrue(options.units.vh); - assert.isTrue(options.units.vm); - assert.isTrue(options.units.vmax); - assert.isTrue(options.units.vmin); - assert.isTrue(options.units.vw); + 'gets calculated compatibility': function (compat) { + assert.isTrue(compat.colors.opacity); + assert.isTrue(compat.properties.colors); + assert.isFalse(compat.properties.backgroundClipMerging); + assert.isFalse(compat.properties.backgroundOriginMerging); + assert.isFalse(compat.properties.backgroundSizeMerging); + assert.isFalse(compat.properties.ieBangHack); + assert.isTrue(compat.properties.iePrefixHack); + assert.isTrue(compat.properties.ieSuffixHack); + assert.isTrue(compat.properties.merging); + assert.isFalse(compat.properties.shorterLengthUnits); + assert.isTrue(compat.properties.spaceAfterClosingBrace); + assert.isFalse(compat.properties.urlQuotes); + assert.isTrue(compat.properties.zeroUnits); + assert.isFalse(compat.selectors.adjacentSpace); + assert.isFalse(compat.selectors.ie7Hack); + assert.isTrue(compat.units.ch); + assert.isTrue(compat.units.in); + assert.isTrue(compat.units.pc); + assert.isTrue(compat.units.pt); + assert.isFalse(compat.units.rem); + assert.isTrue(compat.units.vh); + assert.isTrue(compat.units.vm); + assert.isTrue(compat.units.vmax); + assert.isTrue(compat.units.vmin); + assert.isTrue(compat.units.vw); } } }) diff --git a/test/utils/quote-scanner-test.js b/test/utils/quote-scanner-test.js deleted file mode 100644 index ac809725..00000000 --- a/test/utils/quote-scanner-test.js +++ /dev/null @@ -1,133 +0,0 @@ -var vows = require('vows'); -var assert = require('assert'); -var QuoteScanner = require('../../lib/utils/quote-scanner'); - -vows.describe(QuoteScanner) - .addBatch({ - 'no quotes': { - topic: 'text without quotes', - iterator: function (topic) { - var index = 0; - new QuoteScanner(topic).each(function iterator() { index++; }); - - assert.equal(index, 0); - } - }, - 'one single quote': { - topic: 'text with \'one quote\'!', - iterator: function (topic) { - var index = 0; - new QuoteScanner(topic).each(function iterator(match, tokensSoFar, nextStart) { - index++; - - assert.equal(match, '\'one quote\''); - assert.deepEqual(tokensSoFar, ['text with ']); - assert.equal(nextStart, 10); - }); - - assert.equal(index, 1); - } - }, - 'one double quote': { - topic: 'text with "one quote"!', - iterator: function (topic) { - var index = 0; - new QuoteScanner(topic).each(function iterator(match, tokensSoFar, nextStart) { - index++; - - assert.equal(match, '"one quote"'); - assert.deepEqual(tokensSoFar, ['text with ']); - assert.equal(nextStart, 10); - }); - - assert.equal(index, 1); - } - }, - 'mixed quotes': { - topic: 'text with "one \'quote\'"!', - iterator: function (topic) { - var index = 0; - new QuoteScanner(topic).each(function iterator(match, tokensSoFar, nextStart) { - index++; - - assert.equal(match, '"one \'quote\'"'); - assert.deepEqual(tokensSoFar, ['text with ']); - assert.equal(nextStart, 10); - }); - - assert.equal(index, 1); - } - }, - 'escaped quotes': { - topic: 'text with "one \\"quote"!', - iterator: function (topic) { - var index = 0; - new QuoteScanner(topic).each(function iterator(match, tokensSoFar, nextStart) { - index++; - - assert.equal(match, '"one \\"quote"'); - assert.deepEqual(tokensSoFar, ['text with ']); - assert.equal(nextStart, 10); - }); - - assert.equal(index, 1); - } - }, - 'one open-ended quote': { - topic: '.this-class\\\'s-got-an-apostrophe {}', - iterator: function (topic) { - var index = 0; - new QuoteScanner(topic).each(function iterator() { - index++; - }); - - assert.equal(index, 0); - } - }, - 'many open-ended quotes': { - topic: '.this-class\\\'s-got-many\\\"-apostrophes\\\' {}', - iterator: function (topic) { - var index = 0; - new QuoteScanner(topic).each(function iterator() { - index++; - }); - - assert.equal(index, 0); - } - }, - 'two quotes': { - topic: 'text with "one \\"quote" and \'another one\'!', - iterator: function (topic) { - var index = 0; - new QuoteScanner(topic).each(function iterator(match, tokensSoFar, nextStart) { - index++; - - if (index == 1) { - assert.equal(match, '"one \\"quote"'); - assert.deepEqual(tokensSoFar, ['text with ']); - assert.equal(nextStart, 10); - } else { - assert.equal(match, '\'another one\''); - assert.deepEqual(tokensSoFar, ['text with ', ' and ']); - assert.equal(nextStart, 28); - } - }); - - assert.equal(index, 2); - } - }, - 'between comments': { - topic: '/*! comment */*{box-sizing:border-box}div:before{content:" "}/*! @comment */', - iterator: function (topic) { - var index = 0; - new QuoteScanner(topic).each(function iterator(match) { - index++; - - assert.equal(match, '" "'); - }); - - assert.equal(index, 1); - } - }, - }) - .export(module);