From da45a94c9f62a957c5a9baf940ba2299967b8632 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowicz Date: Thu, 8 Dec 2016 08:04:31 +0100 Subject: [PATCH] Simplifies URL rebasing. ** WARNING ** - this is a truly breaking change. There is now a single option called `rebaseTo`, which denotes a path all relative URLs are rebased to. Absolute URLs are kept intact as it's assumed user knows what he/she does when using them, however absolute @imports are still inlined relative to the current working directory. This commit also re-introduces ability to pass arrays to CleanCSS `minify` method. ** IMPORTANT ** - it'd probably be wise to give users an option to use a function as `rebaseTo` so they can restore some of old functionality if needed. Why: * The old system with three options (`relativeTo`, `root`, and `target`) was too hard to understand and work with reliably. --- History.md | 1 + README.md | 23 +- bin/cleancss | 48 ++-- lib/clean.js | 17 +- lib/optimizer/basic.js | 7 - lib/urls/rebase-config.js | 31 -- lib/urls/{rewrite-url.js => rewrite.js} | 2 +- lib/utils/read-sources.js | 124 ++++---- test/batch-test.js | 21 +- test/bench.js | 6 +- test/binary-test.js | 106 ++----- test/fixtures/blueprint-min.css | 2 +- test/fixtures/bootstrap-min.css | 2 +- test/fixtures/font-awesome-min.css | 2 +- test/fixtures/issue-198-min.css | 4 +- test/fixtures/issue-232-min.css | 2 +- test/fixtures/issue-304-2-min.css | 4 +- test/fixtures/issue-304-min.css | 2 +- test/fixtures/issue-312-min.css | 2 +- test/fixtures/issue-466-min.css | 2 +- test/fixtures/issue-490-min.css | 2 +- test/fixtures/issue-543-min.css | 2 +- .../line-breaks-in-attributes-min.css | 4 +- test/fixtures/partials-absolute/extra/sub.css | 4 +- test/integration-test.js | 166 ++--------- test/module-test.js | 265 +++++++++--------- 26 files changed, 310 insertions(+), 541 deletions(-) delete mode 100644 lib/urls/rebase-config.js rename lib/urls/{rewrite-url.js => rewrite.js} (98%) diff --git a/History.md b/History.md index bd1c42e2..c6c77cf4 100644 --- a/History.md +++ b/History.md @@ -6,6 +6,7 @@ * Removes `debug` API switch as stats are always gathered and available under `stats` property. * Replaces the old tokenizer with a new one which doesn't use any escaping. * Replaces the old `@import` inlining with one on top of the new tokenizer. +* Simplifies URL rebasing with a single `rebaseTo` option in API or inferred from `--output` in CLI. [3.4.22 / 2016-12-12](https://github.com/jakubpawlowicz/clean-css/compare/v3.4.21...v3.4.22) ================== diff --git a/README.md b/README.md index 2f26cda0..085b19dd 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,6 @@ cleancss [options] source-file, [source-file, ...] -c, --compatibility [ie7|ie8] Force compatibility mode (see Readme for advanced examples) -d, --debug Shows debug information (minification time & compression efficiency) -o, --output [output-file] Use [output-file] as output instead of STDOUT --r, --root [root-path] Set a root path to which resolve absolute @import rules -s, --skip-import Disable @import processing -t, --timeout [seconds] Per connection timeout when fetching remote @imports (defaults to 5 seconds) --rounding-precision [n] Rounds pixel values to `N` decimal places. Defaults to 2. -1 disables rounding @@ -122,9 +121,8 @@ CleanCSS constructor accepts a hash as a parameter, i.e., * `processImport` - whether to process `@import` rules * `processImportFrom` - a list of `@import` rules, can be `['all']` (default), `['local']`, `['remote']`, or a blacklisted path e.g. `['!fonts.googleapis.com']` * `rebase` - set to false to skip URL rebasing -* `relativeTo` - path to **resolve** relative `@import` rules and URLs +* `rebaseTo` - a directory to which all URLs are rebased (most likely the directory under which the output file will live), defaults to the current directory * `restructuring` - set to false to disable restructuring in advanced optimizations -* `root` - path to **resolve** absolute `@import` rules and **rebase** relative URLs * `roundingPrecision` - rounding precision; defaults to `2`; `-1` disables rounding * `semanticMerging` - set to true to enable semantic merging mode which assumes BEM-like content (default is false as it's highly likely this will break your stylesheets - **use with caution**!) * `shorthandCompacting` - set to false to skip shorthand compacting (default is true unless sourceMap is set when it's false) @@ -132,7 +130,6 @@ CleanCSS constructor accepts a hash as a parameter, i.e., If input styles are a product of CSS preprocessor (Less, Sass) an input source map can be passed as a string. * `sourceMapInlineSources` - set to true to inline sources inside a source map's `sourcesContent` field (defaults to false) It is also required to process inlined sources from input source maps. -* `target` - path to a folder or an output file to which **rebase** all URLs The output of `minify` method (or the 2nd argument to passed callback) is a hash containing the following fields: @@ -205,16 +202,10 @@ Use the `/*!` notation instead of the standard one `/*`: ### How to rebase relative image URLs? -Clean-css will handle it automatically for you (since version 1.1) in the following cases: +Clean-css will handle it automatically for you in the following cases: -* When using the CLI: - 1. Use an output path via `-o`/`--output` to rebase URLs as relative to the output file. - 2. Use a root path via `-r`/`--root` to rebase URLs as absolute from the given root path. - 3. If you specify both then `-r`/`--root` takes precedence. -* When using clean-css as a library: - 1. Use a combination of `relativeTo` and `target` options for relative rebase (same as 1 in CLI). - 2. Use a combination of `relativeTo` and `root` options for absolute rebase (same as 2 in CLI). - 3. `root` takes precedence over `target` as in CLI. +* When using the CLI specify output path via `-o`/`--output` to rebase URLs as relative to the output file +* When using the API use `rebaseTo` to rebase URLs to the given path (same as with CLI) ### How to generate source maps? @@ -239,7 +230,7 @@ Name of the output file is required, so a map file, named by adding `.map` suffi To generate a source map, use `sourceMap: true` option, e.g.: ```js -new CleanCSS({ sourceMap: true, target: pathToOutputDirectory }) +new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory }) .minify(source, function (error, minified) { // access minified.sourceMap for SourceMapGenerator object // see https://github.com/mozilla/source-map/#sourcemapgenerator for more details @@ -250,7 +241,7 @@ new CleanCSS({ sourceMap: true, target: pathToOutputDirectory }) Using API you can also pass an input source map directly: ```js -new CleanCSS({ sourceMap: inputSourceMapAsString, target: pathToOutputDirectory }) +new CleanCSS({ sourceMap: inputSourceMapAsString, rebaseTo: pathToOutputDirectory }) .minify(source, function (error, minified) { // access minified.sourceMap to access SourceMapGenerator object // see https://github.com/mozilla/source-map/#sourcemapgenerator for more details @@ -261,7 +252,7 @@ new CleanCSS({ sourceMap: inputSourceMapAsString, target: pathToOutputDirectory Or even multiple input source maps at once (available since version 3.1): ```js -new CleanCSS({ sourceMap: true, target: pathToOutputDirectory }).minify({ +new CleanCSS({ sourceMap: true, rebaseTo: pathToOutputDirectory }).minify({ 'path/to/source/1': { styles: '...styles...', sourceMap: '...source-map...' diff --git a/bin/cleancss b/bin/cleancss index d51a5455..5f764d64 100755 --- a/bin/cleancss +++ b/bin/cleancss @@ -19,7 +19,6 @@ commands .option('-c, --compatibility [ie7|ie8]', 'Force compatibility mode (see Readme for advanced examples)') .option('-d, --debug', 'Shows debug information (minification time & compression efficiency)') .option('-o, --output [output-file]', 'Use [output-file] as output instead of STDOUT') - .option('-r, --root [root-path]', 'Set a root path to which resolve absolute @import rules') .option('-s, --skip-import', 'Disable @import processing') .option('-t, --timeout [seconds]', 'Per connection timeout when fetching remote @imports (defaults to 5 seconds)') .option('--rounding-precision [n]', 'Rounds pixel values to `N` decimal places. Defaults to 2. -1 disables rounding') @@ -69,34 +68,20 @@ var options = { keepBreaks: !!commands.keepLineBreaks, keepSpecialComments: commands.s0 ? 0 : (commands.s1 ? 1 : '*'), mediaMerging: commands.skipMediaMerging ? false : true, + output: commands.output, processImport: commands.skipImport ? false : true, processImportFrom: processImportFrom(commands.skipImportFrom), rebase: commands.skipRebase ? false : true, + rebaseTo: ('output' in commands) && commands.output.length > 0 ? path.dirname(path.resolve(commands.output)) : process.cwd(), restructuring: commands.skipRestructuring ? false : true, - root: commands.root, roundingPrecision: commands.roundingPrecision, semanticMerging: commands.semanticMerging ? true : false, shorthandCompacting: commands.skipShorthandCompacting ? false : true, sourceMap: commands.sourceMap, - sourceMapInlineSources: commands.sourceMapInlineSources, - target: commands.output + sourceMapInlineSources: commands.sourceMapInlineSources }; -if (options.root || commands.args.length > 0) { - var relativeTo = options.root || commands.args[0]; - - if (isRemote(relativeTo)) { - options.relativeTo = relativeTo; - } else { - var resolvedRelativeTo = path.resolve(relativeTo); - - options.relativeTo = fs.statSync(resolvedRelativeTo).isFile() ? - path.dirname(resolvedRelativeTo) : - resolvedRelativeTo; - } -} - -if (options.sourceMap && !options.target) { +if (options.sourceMap && !options.output) { outputFeedback(['Source maps will not be built because you have not specified an output file.'], true); options.sourceMap = false; } @@ -116,10 +101,6 @@ if (commands.args.length > 0) { }); } -function isRemote(path) { - return /^https?:\/\//.test(path) || /^\/\//.test(path); -} - function processImportFrom(rules) { if (rules.length === 0) { return ['all']; @@ -127,12 +108,13 @@ function processImportFrom(rules) { return []; } else { return rules.map(function (rule) { - if (rule == 'local') + if (rule == 'local') { return 'remote'; - else if (rule == 'remote') + } else if (rule == 'remote') { return 'local'; - else + } else { return '!' + rule; + } }); } } @@ -149,11 +131,12 @@ function minify(data) { outputFeedback(minified.errors, true); outputFeedback(minified.warnings); - if (minified.errors.length > 0) + if (minified.errors.length > 0) { process.exit(1); + } if (minified.sourceMap) { - var mapFilename = path.basename(options.target) + '.map'; + var mapFilename = path.basename(options.output) + '.map'; output(minified.styles + '/*# sourceMappingURL=' + mapFilename + ' */'); outputMap(minified.sourceMap, mapFilename); } else { @@ -163,14 +146,15 @@ function minify(data) { } function output(minified) { - if (options.target) - fs.writeFileSync(options.target, minified, 'utf8'); - else + if (options.output) { + fs.writeFileSync(options.output, minified, 'utf8'); + } else { process.stdout.write(minified); + } } function outputMap(sourceMap, mapFilename) { - var mapPath = path.join(path.dirname(options.target), mapFilename); + var mapPath = path.join(path.dirname(options.output), mapFilename); fs.writeFileSync(mapPath, sourceMap.toString(), 'utf-8'); } diff --git a/lib/clean.js b/lib/clean.js index 7fdbe384..de987a11 100644 --- a/lib/clean.js +++ b/lib/clean.js @@ -5,7 +5,6 @@ * Copyright (C) 2016 JakubPawlowicz.com */ -var fs = require('fs'); var path = require('path'); var url = require('url'); @@ -28,8 +27,6 @@ var CleanCSS = module.exports = function CleanCSS(options) { aggressiveMerging: undefined === options.aggressiveMerging ? true : !!options.aggressiveMerging, benchmark: options.benchmark, compatibility: compatibility(options.compatibility), - explicitRoot: !!options.root, - explicitTarget: !!options.target, inliner: options.inliner || {}, keepBreaks: options.keepBreaks || false, keepSpecialComments: 'keepSpecialComments' in options ? options.keepSpecialComments : '*', @@ -37,15 +34,13 @@ var CleanCSS = module.exports = function CleanCSS(options) { processImport: undefined === options.processImport ? true : !!options.processImport, processImportFrom: importOptionsFrom(options.processImportFrom), rebase: undefined === options.rebase ? true : !!options.rebase, - relativeTo: options.relativeTo, + rebaseTo: ('rebaseTo' in options) ? path.resolve(options.rebaseTo) : process.cwd(), restructuring: undefined === options.restructuring ? true : !!options.restructuring, - root: options.root || process.cwd(), roundingPrecision: options.roundingPrecision, semanticMerging: undefined === options.semanticMerging ? false : !!options.semanticMerging, shorthandCompacting: undefined === options.shorthandCompacting ? true : !!options.shorthandCompacting, sourceMap: options.sourceMap, - sourceMapInlineSources: !!options.sourceMapInlineSources, - target: !options.target || missingDirectory(options.target) || presentDirectory(options.target) ? options.target : path.dirname(options.target) + sourceMapInlineSources: !!options.sourceMapInlineSources }; this.options.inliner.timeout = this.options.inliner.timeout || DEFAULT_TIMEOUT; @@ -60,14 +55,6 @@ function importOptionsFrom(rules) { return undefined === rules ? ['all'] : rules; } -function missingDirectory(filepath) { - return !fs.existsSync(filepath) && !/\.css$/.test(filepath); -} - -function presentDirectory(filepath) { - return fs.existsSync(filepath) && fs.statSync(filepath).isDirectory(); -} - function proxyOptionsFrom(httpProxy) { return httpProxy ? { diff --git a/lib/optimizer/basic.js b/lib/optimizer/basic.js index c4e6830f..0e2dc208 100644 --- a/lib/optimizer/basic.js +++ b/lib/optimizer/basic.js @@ -16,9 +16,6 @@ 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'); @@ -387,9 +384,6 @@ function optimizeBody(properties, context) { 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 { @@ -527,7 +521,6 @@ function basicOptimize(tokens, context) { 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]; diff --git a/lib/urls/rebase-config.js b/lib/urls/rebase-config.js deleted file mode 100644 index 9c1a5e70..00000000 --- a/lib/urls/rebase-config.js +++ /dev/null @@ -1,31 +0,0 @@ -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/rewrite-url.js b/lib/urls/rewrite.js similarity index 98% rename from lib/urls/rewrite-url.js rename to lib/urls/rewrite.js index 04e4ae48..daced3d5 100644 --- a/lib/urls/rewrite-url.js +++ b/lib/urls/rewrite.js @@ -9,7 +9,7 @@ var URL_SUFFIX = ')'; var QUOTE_PREFIX_PATTERN = /^["']/; var QUOTE_SUFFIX_PATTERN = /["']$/; var ROUND_BRACKETS_PATTERN = /[\(\)]/; -var URL_PREFIX_PATTERN = /^url\(/; +var URL_PREFIX_PATTERN = /^url\(/i; var URL_SUFFIX_PATTERN = /\)$/; var WHITESPACE_PATTERN = /\s/; diff --git a/lib/utils/read-sources.js b/lib/utils/read-sources.js index 925af0bf..30b35d61 100644 --- a/lib/utils/read-sources.js +++ b/lib/utils/read-sources.js @@ -7,7 +7,7 @@ var url = require('url'); var tokenize = require('../tokenizer/tokenize'); var Token = require('../tokenizer/token'); -var rewriteUrl = require('../urls/rewrite-url'); +var rewriteUrl = require('../urls/rewrite'); var override = require('../utils/override'); var split = require('../utils/split'); @@ -31,64 +31,78 @@ function readSources(input, context, callback) { return fromString(input, context, {}, callback); } else if (Buffer.isBuffer(input)) { return fromString(input.toString(), context, {}, callback); + } else if (Array.isArray(input)) { + return fromArray(input, context, {}, callback); } else if (typeof input == 'object') { return fromHash(input, context, {}, callback); } } function fromString(input, context, parentInlinerContext, callback) { - var tokens = tokenize(input, context); + var inputAsHash = {}; - context.stats.originalSize += input.length; + inputAsHash[false] = { + styles: input + }; - return context.options.processImport ? - inlineImports(tokens, context, parentInlinerContext, callback) : - callback(tokens); + return fromHash(inputAsHash, context, parentInlinerContext, callback); +} + +function fromArray(input, context, parentInlinerContext, callback) { + var inputAsHash = input.reduce(function (accumulator, uri) { + var absolutePath = uri[0] == '/' ? + uri : + path.resolve(uri); + + if (!fs.existsSync(absolutePath) || !fs.statSync(absolutePath).isFile()) { + context.errors.push('Ignoring "' + uri + '" as resource is missing.'); + } else { + accumulator[uri] = { + styles: fs.readFileSync(absolutePath, 'utf-8') + }; + } + + return accumulator; + }, {}); + + return fromHash(inputAsHash, context, parentInlinerContext, callback); } function fromHash(input, context, parentInlinerContext, callback) { var tokens = []; var sourcePath; var source; - var baseRelativeTo = context.options.relativeTo || context.options.root; - var relativeTo; - var fullPath; - var config; + var rebaseFrom; + var rebaseTo; + var rebaseConfig; for (sourcePath in input) { source = input[sourcePath]; if (isRemote(sourcePath)) { - config = { - relative: true, - fromBase: sourcePath, - toBase: sourcePath - }; + rebaseFrom = sourcePath; + rebaseTo = sourcePath; + } else if (isAbsolute(sourcePath)) { + rebaseFrom = path.dirname(sourcePath); + rebaseTo = context.options.rebaseTo; } else { - relativeTo = sourcePath[0] == '/' ? - context.options.root : - baseRelativeTo; - - fullPath = path.resolve( - path.join( - relativeTo, - sourcePath - ) - ); - - config = { - relative: true, - fromBase: path.dirname(fullPath), - toBase: baseRelativeTo - }; + rebaseFrom = sourcePath ? + path.dirname(path.resolve(sourcePath)) : + path.resolve(sourcePath); + rebaseTo = context.options.rebaseTo; } + rebaseConfig = { + fromBase: rebaseFrom, + toBase: rebaseTo + }; + tokens = tokens.concat( rebase( tokenize(source.styles, context), context.options.rebase, context.validator, - config + rebaseConfig ) ); @@ -100,13 +114,17 @@ function fromHash(input, context, parentInlinerContext, callback) { callback(tokens); } -function rebase(tokens, rebaseAll, validator, config) { +function isAbsolute(uri) { + return uri && uri[0] == '/'; +} + +function rebase(tokens, rebaseAll, validator, rebaseConfig) { return rebaseAll ? - rebaseEverything(tokens, validator, config) : - rebaseAtRules(tokens, validator, config); + rebaseEverything(tokens, validator, rebaseConfig) : + rebaseAtRules(tokens, validator, rebaseConfig); } -function rebaseEverything(tokens, validator, config) { +function rebaseEverything(tokens, validator, rebaseConfig) { var token; var i, l; @@ -115,19 +133,19 @@ function rebaseEverything(tokens, validator, config) { switch (token[0]) { case Token.AT_RULE: - rebaseAtRule(token, validator, config); + rebaseAtRule(token, validator, rebaseConfig); break; case Token.AT_RULE_BLOCK: // break; case Token.BLOCK: - rebaseEverything(token[2], validator, config); + rebaseEverything(token[2], validator, rebaseConfig); break; case Token.PROPERTY: // break; case Token.RULE: - rebaseProperties(token[2], validator, config); + rebaseProperties(token[2], validator, rebaseConfig); break; } } @@ -135,7 +153,7 @@ function rebaseEverything(tokens, validator, config) { return tokens; } -function rebaseAtRules(tokens, validator, config) { +function rebaseAtRules(tokens, validator, rebaseConfig) { var token; var i, l; @@ -144,7 +162,7 @@ function rebaseAtRules(tokens, validator, config) { switch (token[0]) { case Token.AT_RULE: - rebaseAtRule(token, validator, config); + rebaseAtRule(token, validator, rebaseConfig); break; } } @@ -152,9 +170,13 @@ function rebaseAtRules(tokens, validator, config) { return tokens; } -function rebaseAtRule(token, validator, config) { +function rebaseAtRule(token, validator, rebaseConfig) { + if (!IMPORT_PREFIX_PATTERN.test(token[1])) { + return; + } + var uriAndMediaQuery = extractUrlAndMedia(token[1]); - var newUrl = rewriteUrl(uriAndMediaQuery[0], config); + var newUrl = rewriteUrl(uriAndMediaQuery[0], rebaseConfig); var mediaQuery = uriAndMediaQuery[1]; token[1] = restoreImport(newUrl, mediaQuery); @@ -164,7 +186,7 @@ function restoreImport(uri, mediaQuery) { return ('@import ' + uri + ' ' + mediaQuery).trim(); } -function rebaseProperties(properties, validator, config) { +function rebaseProperties(properties, validator, rebaseConfig) { var property; var value; var i, l; @@ -177,7 +199,7 @@ function rebaseProperties(properties, validator, config) { value = property[j][1]; if (validator.isValidUrl(value)) { - property[j][1] = rewriteUrl(value, config); + property[j][1] = rewriteUrl(value, rebaseConfig); } } } @@ -254,7 +276,7 @@ function extractUrlAndMedia(atRuleValue) { } function isRemote(uri) { - return REMOTE_RESOURCE_PATTERN.test(uri); + return uri && REMOTE_RESOURCE_PATTERN.test(uri); } function allowedResource(uri, isRemote, rules) { @@ -406,11 +428,9 @@ function inlineRemoteStylesheet(uri, mediaQuery, inlinerContext) { } function inlineLocalStylesheet(uri, mediaQuery, inlinerContext) { - var relativeTo = uri[0] == '/' ? - inlinerContext.externalContext.options.root : - inlinerContext.externalContext.options.relativeTo || inlinerContext.externalContext.options.root; - var absolutePath = path.join(relativeTo, uri); - var resolvedPath = path.resolve(absolutePath); + var resolvedPath = uri[0] == '/' ? + path.resolve(path.resolve(''), uri.substring(1)) : + path.resolve(inlinerContext.externalContext.options.rebaseTo, uri); var importedStyles; var importedTokens; var isAllowed = allowedResource(uri, false, inlinerContext.externalContext.options.processImportFrom); @@ -431,7 +451,7 @@ function inlineLocalStylesheet(uri, mediaQuery, inlinerContext) { importedStyles = fs.readFileSync(resolvedPath, 'utf-8'); inlinerContext.imported.push(resolvedPath); - sourceHash[uri] = { + sourceHash[resolvedPath] = { styles: importedStyles }; importedTokens = fromHash(sourceHash, inlinerContext.externalContext, inlinerContext, function (tokens) { return tokens; }); diff --git a/test/batch-test.js b/test/batch-test.js index 9ed68f16..f651ac6d 100644 --- a/test/batch-test.js +++ b/test/batch-test.js @@ -19,13 +19,12 @@ var batchContexts = function () { context[testName] = { topic: function () { - var plainPath = path.join(__dirname, 'fixtures', testName + '.css'); + var plainPath = path.join('test', 'fixtures', testName + '.css'); var minPath = path.join(__dirname, 'fixtures', testName + '-min.css'); return { - plain: fs.readFileSync(plainPath, 'utf-8'), - preminified: fs.readFileSync(minPath, 'utf-8'), - root: path.dirname(plainPath) + plain: '@import "' + plainPath + '";', + preminified: fs.readFileSync(minPath, 'utf8') }; }, 'minifying': { @@ -33,18 +32,17 @@ var batchContexts = function () { var self = this; new CleanCSS({ - keepBreaks: true, - root: data.root + keepBreaks: true }).minify(data.plain, function (errors, minified) { self.callback(errors, minified.styles, data); }); }, 'should output right content': function (errors, minified, data) { - var minifiedTokens = minified.split(lineBreak); - var preminifiedTokens = data.preminified.split(lineBreak); + var minifiedRules = minified.split(lineBreak); + var preminifiedRules = data.preminified.split(lineBreak); - minifiedTokens.forEach(function (line, i) { - assert.equal(line, preminifiedTokens[i]); + minifiedRules.forEach(function (line, i) { + assert.equal(line, preminifiedRules[i]); }); } }, @@ -54,8 +52,7 @@ var batchContexts = function () { new CleanCSS({ keepBreaks: true, - sourceMap: true, - root: data.root + sourceMap: true }).minify(data.plain, function (errors, minified) { self.callback(errors, minified.styles, data); }); diff --git a/test/bench.js b/test/bench.js index 2acabd5c..c17dff12 100644 --- a/test/bench.js +++ b/test/bench.js @@ -1,13 +1,11 @@ var CleanCSS = require('../index'); -var path = require('path'); -var benchDir = path.join(__dirname, 'fixtures', 'bench'); -var cssData = require('fs').readFileSync(path.join(benchDir, 'complex.css'), 'utf8'); +var input = '@import url(test/fixtures/bench/complex.css);'; var total = 0; for (var i = 1; i <= 10; i++) { var start = process.hrtime(); - new CleanCSS({ benchmark: i == 10, root: benchDir }).minify(cssData); + new CleanCSS({ benchmark: i == 10 }).minify(input); var itTook = process.hrtime(start); total += 1000 * itTook[0] + itTook[1] / 1000000; diff --git a/test/binary-test.js b/test/binary-test.js index 9ed866c4..d7fe3fd0 100644 --- a/test/binary-test.js +++ b/test/binary-test.js @@ -122,9 +122,9 @@ vows.describe('./bin/cleancss') .addBatch({ 'piped with correct debug info on inlining': pipedContext('@import url(test/fixtures/imports.css);', '-d', { 'should output correct info': function (error, stdout, stderr) { - assert.include(stderr, 'Original: 120 bytes'); + assert.include(stderr, 'Original: 339 bytes'); assert.include(stderr, 'Minified: 86 bytes'); - assert.include(stderr, 'Efficiency: 28.33%'); + assert.include(stderr, 'Efficiency: 74.63%'); } }) }) @@ -162,7 +162,7 @@ vows.describe('./bin/cleancss') }) }) .addBatch({ - 'no relative to path': binaryContext('./test/fixtures/partials-absolute/base.css', { + 'no relative to path': binaryContext('./fixtures/partials-absolute/base.css', { 'should not be able to resolve it fully': function (error, stdout, stderr) { assert.isEmpty(stdout); assert.notEqual(error, null); @@ -170,13 +170,6 @@ vows.describe('./bin/cleancss') } }) }) - .addBatch({ - 'relative to path': binaryContext('-r ./test/fixtures ./test/fixtures/partials-absolute/base.css', { - 'should be able to resolve it': function (error, stdout) { - assert.equal(stdout, '.base2{border-width:0}.sub{padding:0}.base{margin:0}'); - } - }) - }) .addBatch({ 'from source': binaryContext('./test/fixtures/reset.css', { 'should minimize': function (error, stdout) { @@ -210,7 +203,7 @@ vows.describe('./bin/cleancss') .addBatch({ 'disable @import': binaryContext('-s ./test/fixtures/imports.css', { 'should disable the import processing': function (error, stdout) { - assert.equal(stdout, '@import url(./partials/one.css);@import url(./partials/two.css);.imports{color:#000}'); + assert.equal(stdout, '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/two.css);.imports{color:#000}'); } }) }) @@ -233,17 +226,12 @@ vows.describe('./bin/cleancss') }) .addBatch({ 'relative image paths': { - 'no root & output': binaryContext('./test/fixtures/partials-relative/base.css', { + 'no output': binaryContext('./test/fixtures/partials-relative/base.css', { 'should leave paths': function (error, stdout) { - assert.equal(stdout, 'a{background:url(../partials/extra/down.gif) no-repeat}'); + assert.equal(stdout, 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'); } }), - 'root but no output': binaryContext('-r ./test ./test/fixtures/partials-relative/base.css', { - 'should rewrite path relative to ./test': function (error, stdout) { - assert.equal(stdout, 'a{background:url(/fixtures/partials/extra/down.gif) no-repeat}'); - } - }), - 'no root but output': binaryContext('-o ./base1-min.css ./test/fixtures/partials-relative/base.css', { + 'output': binaryContext('-o ./base1-min.css ./test/fixtures/partials-relative/base.css', { 'should rewrite path relative to current path': function () { var minimized = readFile('./base1-min.css'); assert.equal(minimized, 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}'); @@ -252,15 +240,6 @@ vows.describe('./bin/cleancss') deleteFile('./base1-min.css'); } }), - 'root and output': binaryContext('-r ./test/fixtures -o ./base2-min.css ./test/fixtures/partials-relative/base.css', { - 'should rewrite path relative to ./test/fixtures/': function () { - var minimized = readFile('./base2-min.css'); - assert.equal(minimized, 'a{background:url(/partials/extra/down.gif) no-repeat}'); - }, - teardown: function () { - deleteFile('./base2-min.css'); - } - }), 'piped with output': pipedContext('a{background:url(test/fixtures/partials/extra/down.gif)}', '-o base3-min.css', { 'should keep paths as they are': function () { var minimized = readFile('base3-min.css'); @@ -275,37 +254,36 @@ vows.describe('./bin/cleancss') .addBatch({ 'import rebasing': binaryContext('test/fixtures/partials/quoted-svg.css', { 'should keep quoting intact': function (error, stdout) { - assert.include(stdout, 'div{background:url(\'data:image'); - assert.include(stdout, 'svg%3E\')}'); + assert.include(stdout, 'div{background:url("data:image'); + assert.include(stdout, 'svg%3E")}'); } }) }) .addBatch({ 'complex import and url rebasing': { - 'absolute': binaryContext('-r ./test/fixtures/129-assets ./test/fixtures/129-assets/assets/ui.css', { + 'absolute': binaryContext('./test/fixtures/129-assets/assets/ui.css', { 'should rebase urls correctly': function (error, stdout) { - assert.isNull(error); - assert.include(stdout, 'url(/components/bootstrap/images/glyphs.gif)'); - assert.include(stdout, 'url(/components/jquery-ui/images/prev.gif)'); - assert.include(stdout, 'url(/components/jquery-ui/images/next.gif)'); + assert.include(stdout, 'url(test/fixtures/129-assets/components/bootstrap/images/glyphs.gif)'); + assert.include(stdout, 'url(test/fixtures/129-assets/components/jquery-ui/images/prev.gif)'); + assert.include(stdout, 'url(test/fixtures/129-assets/components/jquery-ui/images/next.gif)'); } }), - 'relative': binaryContext('-o ui.bundled.css ./test/fixtures/129-assets/assets/ui.css', { + 'relative': binaryContext('-o test/ui.bundled.css ./test/fixtures/129-assets/assets/ui.css', { 'should rebase urls correctly': function () { - var minimized = readFile('ui.bundled.css'); - assert.include(minimized, 'url(test/fixtures/129-assets/components/bootstrap/images/glyphs.gif)'); - assert.include(minimized, 'url(test/fixtures/129-assets/components/jquery-ui/images/prev.gif)'); - assert.include(minimized, 'url(test/fixtures/129-assets/components/jquery-ui/images/next.gif)'); + var minimized = readFile('test/ui.bundled.css'); + assert.include(minimized, 'url(fixtures/129-assets/components/bootstrap/images/glyphs.gif)'); + assert.include(minimized, 'url(fixtures/129-assets/components/jquery-ui/images/prev.gif)'); + assert.include(minimized, 'url(fixtures/129-assets/components/jquery-ui/images/next.gif)'); }, teardown: function () { - deleteFile('ui.bundled.css'); + deleteFile('test/ui.bundled.css'); } }) } }) .addBatch({ 'complex import and skipped url rebasing': { - 'absolute': binaryContext('-r ./test/fixtures/129-assets --skip-rebase ./test/fixtures/129-assets/assets/ui.css', { + 'absolute': binaryContext('--skip-rebase ./test/fixtures/129-assets/assets/ui.css', { 'should rebase urls correctly': function (error, stdout) { assert.isNull(error); assert.include(stdout, 'url(../images/glyphs.gif)'); @@ -315,20 +293,6 @@ vows.describe('./bin/cleancss') }) } }) - .addBatch({ - 'relative import with just a filename': pipedContext('@import "one.css";', '-r ./test/fixtures/partials', { - 'imports sources correctly': function(error, stdout) { - assert.equal(error, null); - assert.include(stdout, '.one{color:red}'); - } - }), - 'relative import with ./': pipedContext('@import "./one.css";', '-r ./test/fixtures/partials', { - 'imports sources correctly': function(error, stdout) { - assert.equal(error, null); - assert.include(stdout, '.one{color:red}'); - } - }) - }) .addBatch({ 'remote import': { topic: function () { @@ -467,7 +431,7 @@ vows.describe('./bin/cleancss') } }) .addBatch({ - '@media merging': pipedContext('@media screen{a{color:red}}@media screen{a{display:block}}', '--skip-media-merging', { + '@media merging ': pipedContext('@media screen{a{color:red}}@media screen{a{display:block}}', '--skip-media-merging', { 'gets right result': function (error, stdout) { assert.equal(stdout, '@media screen{a{color:red}}@media screen{a{display:block}}'); } @@ -586,32 +550,6 @@ vows.describe('./bin/cleancss') } }) }) - .addBatch({ - 'source maps - output file with root path': binaryContext('--source-map -o ./reset-root.min.css -r ./test ./test/fixtures/reset.css', { - 'includes map in minified file': function () { - assert.include(readFile('./reset-root.min.css'), '/*# sourceMappingURL=reset-root.min.css.map */'); - }, - 'creates a map file': function () { - assert.isTrue(fs.existsSync('./reset-root.min.css.map')); - }, - 'includes right content in map file': function () { - var sourceMap = new SourceMapConsumer(readFile('./reset-root.min.css.map')); - assert.deepEqual( - sourceMap.originalPositionFor({ line: 1, column: 1 }), - { - source: 'fixtures/reset.css', - line: 4, - column: 0, - name: null - } - ); - }, - 'teardown': function () { - deleteFile('reset-root.min.css'); - deleteFile('reset-root.min.css.map'); - } - }) - }) .addBatch({ 'source maps - with input source map': binaryContext('--source-map -o ./import.min.css ./test/fixtures/source-maps/import.css', { 'includes map in minified file': function () { @@ -631,7 +569,7 @@ vows.describe('./bin/cleancss') }) }) .addBatch({ - 'source maps - with input source map and source 1inlining': binaryContext('--source-map --source-map-inline-sources -o ./import-inline.min.css ./test/fixtures/source-maps/import.css', { + 'source maps - with input source map and source inlining': binaryContext('--source-map --source-map-inline-sources -o ./import-inline.min.css ./test/fixtures/source-maps/import.css', { 'includes map in minified file': function () { assert.include(readFile('./import-inline.min.css'), '/*# sourceMappingURL=import-inline.min.css.map */'); }, diff --git a/test/fixtures/blueprint-min.css b/test/fixtures/blueprint-min.css index 71e99f05..bea9c198 100644 --- a/test/fixtures/blueprint-min.css +++ b/test/fixtures/blueprint-min.css @@ -80,7 +80,7 @@ form.inline p{margin-bottom:0} .success a{color:#264409} .info a{color:#205791} .container{width:950px;margin:0 auto} -.showgrid{background:url(src/grid.png)} +.showgrid{background:url(test/fixtures/src/grid.png)} .column,.span-1,.span-10,.span-11,.span-12,.span-13,.span-14,.span-15,.span-16,.span-17,.span-18,.span-19,.span-2,.span-20,.span-21,.span-22,.span-23,.span-24,.span-3,.span-4,.span-5,.span-6,.span-7,.span-8,.span-9{float:left;margin-right:10px} .last,.span-24{margin-right:0} .span-1{width:30px} diff --git a/test/fixtures/bootstrap-min.css b/test/fixtures/bootstrap-min.css index db9db193..111cfbf8 100644 --- a/test/fixtures/bootstrap-min.css +++ b/test/fixtures/bootstrap-min.css @@ -56,7 +56,7 @@ select{background:#fff!important} .dropdown-menu,.modal-content{-webkit-background-clip:padding-box} .btn,.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-warning.active,.btn-warning:active,.btn.active,.btn:active,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.form-control,.navbar-toggle,.open>.dropdown-toggle.btn-danger,.open>.dropdown-toggle.btn-default,.open>.dropdown-toggle.btn-info,.open>.dropdown-toggle.btn-primary,.open>.dropdown-toggle.btn-warning{background-image:none} .img-thumbnail,body{background-color:#fff} -@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')} +@font-face{font-family:'Glyphicons Halflings';src:url(test/fonts/glyphicons-halflings-regular.eot);src:url(test/fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(test/fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(test/fonts/glyphicons-halflings-regular.woff) format('woff'),url(test/fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(test/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')} .glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale} .glyphicon-asterisk:before{content:"\2a"} .glyphicon-plus:before{content:"\2b"} diff --git a/test/fixtures/font-awesome-min.css b/test/fixtures/font-awesome-min.css index b8d5cd05..a67f0f55 100644 --- a/test/fixtures/font-awesome-min.css +++ b/test/fixtures/font-awesome-min.css @@ -20,7 +20,7 @@ * Twitter: http://twitter.com/fortaweso_me * Work: Lead Product Designer @ http://kyruus.com */ -@font-face{font-family:FontAwesome;src:url(../font/fontawesome-webfont.eot?v=3.0.1);src:url(../font/fontawesome-webfont.eot?#iefix&v=3.0.1) format('embedded-opentype'),url(../font/fontawesome-webfont.woff?v=3.0.1) format('woff'),url(../font/fontawesome-webfont.ttf?v=3.0.1) format('truetype');font-weight:400;font-style:normal} +@font-face{font-family:FontAwesome;src:url(test/font/fontawesome-webfont.eot?v=3.0.1);src:url(test/font/fontawesome-webfont.eot?#iefix&v=3.0.1) format('embedded-opentype'),url(test/font/fontawesome-webfont.woff?v=3.0.1) format('woff'),url(test/font/fontawesome-webfont.ttf?v=3.0.1) format('truetype');font-weight:400;font-style:normal} [class*=" icon-"],[class^=icon-]{font-family:FontAwesome;font-weight:400;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0 0;background-repeat:repeat;margin-top:0} .btn [class*=" icon-"].icon-large,.btn [class^=icon-].icon-large,.nav [class*=" icon-"].icon-large,.nav [class^=icon-].icon-large,.nav-pills [class*=" icon-"],.nav-pills [class*=" icon-"].icon-large,.nav-pills [class^=icon-],.nav-pills [class^=icon-].icon-large,.nav-tabs [class*=" icon-"],.nav-tabs [class*=" icon-"].icon-large,.nav-tabs [class^=icon-],.nav-tabs [class^=icon-].icon-large{line-height:.9em} .dropdown-menu>.active>a>[class*=" icon-"],.dropdown-menu>.active>a>[class^=icon-],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^=icon-],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^=icon-],.icon-white,.nav-list>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^=icon-],.nav-pills>.active>a>[class*=" icon-"],.nav-pills>.active>a>[class^=icon-],.navbar-inverse .nav>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^=icon-]{background-image:none} diff --git a/test/fixtures/issue-198-min.css b/test/fixtures/issue-198-min.css index 78b32f50..e8da7d1b 100644 --- a/test/fixtures/issue-198-min.css +++ b/test/fixtures/issue-198-min.css @@ -1,3 +1,3 @@ .one{color:red} -.three{background-image:url(partials/extra/down.gif)} -.imports-with-comment{color:#999} +.three{background-image:url(test/fixtures/partials/extra/down.gif)} +.imports-with-comment{color:#999} \ No newline at end of file diff --git a/test/fixtures/issue-232-min.css b/test/fixtures/issue-232-min.css index da28adf5..a939a914 100644 --- a/test/fixtures/issue-232-min.css +++ b/test/fixtures/issue-232-min.css @@ -1,2 +1,2 @@ .bar{padding:0} -.bug-selector,.bug-selector1{background:url(images/b-toolbar.gif) #000;background:linear-gradient(#5e6081,#353340)} \ No newline at end of file +.bug-selector,.bug-selector1{background:url(test/fixtures/images/b-toolbar.gif) #000;background:linear-gradient(#5e6081,#353340)} \ No newline at end of file diff --git a/test/fixtures/issue-304-2-min.css b/test/fixtures/issue-304-2-min.css index 97b7cc8c..b79cb03f 100644 --- a/test/fixtures/issue-304-2-min.css +++ b/test/fixtures/issue-304-2-min.css @@ -1,2 +1,2 @@ -.one{background:url(one.png) right 10px top 10px no-repeat,linear-gradient(0deg,#efefef 0,#fff 100%)} -.two{background:url(two.png) right 9px top 15px/9px 7px no-repeat,linear-gradient(-179deg,#FFF 0,#F9F9F9 100%)} \ No newline at end of file +.one{background:url(test/fixtures/one.png) right 10px top 10px no-repeat,linear-gradient(0deg,#efefef 0,#fff 100%)} +.two{background:url(test/fixtures/two.png) right 9px top 15px/9px 7px no-repeat,linear-gradient(-179deg,#FFF 0,#F9F9F9 100%)} \ No newline at end of file diff --git a/test/fixtures/issue-304-min.css b/test/fixtures/issue-304-min.css index 4f8eeca0..6be63bf0 100644 --- a/test/fixtures/issue-304-min.css +++ b/test/fixtures/issue-304-min.css @@ -1 +1 @@ -.test{background:url(top.png) left 0 top -12px no-repeat,url(bottom.png) left 0 bottom -12px no-repeat,url(middle.png) left 0 top 0 no-repeat} \ No newline at end of file +.test{background:url(test/fixtures/top.png) left 0 top -12px no-repeat,url(test/fixtures/bottom.png) left 0 bottom -12px no-repeat,url(test/fixtures/middle.png) left 0 top 0 no-repeat} \ No newline at end of file diff --git a/test/fixtures/issue-312-min.css b/test/fixtures/issue-312-min.css index 84699e19..fdb5ff4b 100644 --- a/test/fixtures/issue-312-min.css +++ b/test/fixtures/issue-312-min.css @@ -1 +1 @@ -.envelope{background:url(one.png) top center repeat-x,url(one.png) bottom center repeat-x,url(two.png) 110% 10px no-repeat #eee;background-size:35px 4px,35px 4px,101px 61px} \ No newline at end of file +.envelope{background:url(test/fixtures/one.png) top center repeat-x,url(test/fixtures/one.png) bottom center repeat-x,url(test/fixtures/two.png) 110% 10px no-repeat #eee;background-size:35px 4px,35px 4px,101px 61px} \ No newline at end of file diff --git a/test/fixtures/issue-466-min.css b/test/fixtures/issue-466-min.css index d0ad7ba9..21cae29d 100644 --- a/test/fixtures/issue-466-min.css +++ b/test/fixtures/issue-466-min.css @@ -1 +1 @@ -div{background:url(image.png);background-image:linear-gradient(rgba(0,0,0,.1),rgba(0,0,0,.5)),url(image.png)} +div{background:url(test/fixtures/image.png);background-image:linear-gradient(rgba(0,0,0,.1),rgba(0,0,0,.5)),url(test/fixtures/image.png)} \ No newline at end of file diff --git a/test/fixtures/issue-490-min.css b/test/fixtures/issue-490-min.css index f503dd04..34de1143 100644 --- a/test/fixtures/issue-490-min.css +++ b/test/fixtures/issue-490-min.css @@ -1 +1 @@ -div{background:url(image.png),-webkit-linear-gradient(160.57deg,#4393b8 0,#346aa9 100%);background:url(image.png),-moz-linear-gradient(83.68% 67.94% 160.57deg,#4393b8 0,#346aa9 100%);background:url(image.png),linear-gradient(160.57deg,#4393b8 0,#346aa9 100%);background-repeat:no-repeat;background-position:25% 60%;z-index:1;background-size:100%;height:auto;min-height:820px} \ No newline at end of file +div{background:url(test/fixtures/image.png),-webkit-linear-gradient(160.57deg,#4393b8 0,#346aa9 100%);background:url(test/fixtures/image.png),-moz-linear-gradient(83.68% 67.94% 160.57deg,#4393b8 0,#346aa9 100%);background:url(test/fixtures/image.png),linear-gradient(160.57deg,#4393b8 0,#346aa9 100%);background-repeat:no-repeat;background-position:25% 60%;z-index:1;background-size:100%;height:auto;min-height:820px} \ No newline at end of file diff --git a/test/fixtures/issue-543-min.css b/test/fixtures/issue-543-min.css index 21def463..24162a60 100644 --- a/test/fixtures/issue-543-min.css +++ b/test/fixtures/issue-543-min.css @@ -1 +1 @@ -@font-face{src:url(../font/myfont.eot);/*! IE9 *//*! IE6-IE8 *//*! chrome, firefox *//*! chrome, firefox, opera, Safari, Android, iOS 4.2+ */src:url(../font/myfont.eot?#iefix) format("embedded-opentype"),url(../font/myfont.woff) format("woff"),url(../font/myfont.ttf) format("truetype"),url(../font/myfont.svg#myfont) format("svg");font-style:normal;font-weight:400} \ No newline at end of file +@font-face{src:url(test/font/myfont.eot);/*! IE9 */src:url(test/font/myfont.eot?#iefix) format("embedded-opentype"),url(test/font/myfont.woff) format("woff"),url(test/font/myfont.ttf) format("truetype"),url(test/font/myfont.svg#myfont) format("svg");/*! IE6-IE8 *//*! chrome, firefox *//*! chrome, firefox, opera, Safari, Android, iOS 4.2+ */font-style:normal;font-weight:400} \ No newline at end of file diff --git a/test/fixtures/line-breaks-in-attributes-min.css b/test/fixtures/line-breaks-in-attributes-min.css index d0ac4c0f..1161524a 100644 --- a/test/fixtures/line-breaks-in-attributes-min.css +++ b/test/fixtures/line-breaks-in-attributes-min.css @@ -1,2 +1,2 @@ -.test[title="my very long title"]{background-image:url(very/long/path)} -.test[title=my_very_long_title]{background-image:url(my/very/long/path)} \ No newline at end of file +.test[title="my very long title"]{background-image:url(test/fixtures/very/long/path)} +.test[title=my_very_long_title]{background-image:url(test/fixtures/my/very/long/path)} \ No newline at end of file diff --git a/test/fixtures/partials-absolute/extra/sub.css b/test/fixtures/partials-absolute/extra/sub.css index ddf9baf9..a86fd6cc 100644 --- a/test/fixtures/partials-absolute/extra/sub.css +++ b/test/fixtures/partials-absolute/extra/sub.css @@ -1,3 +1,3 @@ -@import url(/partials-absolute/base2.css); +@import url(/test/fixtures/partials-absolute/base2.css); -.sub { padding:0px } \ No newline at end of file +.sub { padding:0px } diff --git a/test/integration-test.js b/test/integration-test.js index 199c87a7..f8932920 100644 --- a/test/integration-test.js +++ b/test/integration-test.js @@ -1342,7 +1342,7 @@ vows.describe('integration tests') 'a{background:url(git+ssh2://abc.png)}', 'a{background:url(git+ssh2://abc.png)}' ] - }, { root: process.cwd(), relativeTo: process.cwd() }) + }) ) .addBatch( optimizerContext('urls whitespace in compatibility mode', { @@ -1394,7 +1394,7 @@ vows.describe('integration tests') 'a{background:url(\'data:image/svg+xml,%3csvg%20xmlns%3d"http://www.w3.org/2000/svg"/%3e\')}', 'a{background:url(\'data:image/svg+xml,%3csvg%20xmlns%3d"http://www.w3.org/2000/svg"/%3e\')}' ] - }, { root: process.cwd(), relativeTo: process.cwd() }) + }) ) .addBatch( optimizerContext('urls quotes in compatibility mode', { @@ -1417,22 +1417,22 @@ vows.describe('integration tests') }, { compatibility: { properties: { urlQuotes: true } } }) ) .addBatch( - optimizerContext('urls rewriting - no root or target', { + optimizerContext('urls rewriting - rebaseTo', { 'no @import': [ 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}', - 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}' + 'a{background:url(partials/extra/down.gif) no-repeat}' ], 'relative @import': [ '@import url(test/fixtures/partials-relative/base.css);', - 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}' + 'a{background:url(partials/extra/down.gif) no-repeat}' ], 'relative @import twice': [ '@import url(test/fixtures/partials-relative/extra/included.css);', - 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}' + 'a{background:url(partials/extra/down.gif) no-repeat}' ], 'absolute @import': [ '@import url(/test/fixtures/partials-relative/base.css);', - 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}' + 'a{background:url(partials/extra/down.gif) no-repeat}' ], 'document-local reference': [ 'svg{marker-end:url(#arrow)}', @@ -1442,149 +1442,31 @@ vows.describe('integration tests') 'a{background-image:url("chrome-extension://__MSG_@@extension_id__/someFile.png")}', 'a{background-image:url(chrome-extension://__MSG_@@extension_id__/someFile.png)}' ] - }) + }, { rebaseTo: path.join('test', 'fixtures') }) ) .addBatch( - optimizerContext('urls rewriting - root but no target', { - 'no @import': [ - 'a{background:url(../partials/extra/down.gif) no-repeat}', - 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'relative @import': [ - '@import url(base.css);', - 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'absolute @import': [ - '@import url(/test/fixtures/partials-relative/base.css);', - 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'SVG': [ - 'a{background-image:url("data:image/svg+xml,")}', - 'a{background-image:url("data:image/svg+xml,")}' - ], - 'document-local reference': [ - 'svg{marker-end:url(#arrow)}', - 'svg{marker-end:url(#arrow)}' - ], - 'internal page': [ - 'a{background:url(about:blank)}', - 'a{background:url(about:blank)}' - ], - 'chrome extension': [ - 'a{background-image:url("chrome-extension://__MSG_@@extension_id__/someFile.png")}', - 'a{background-image:url(chrome-extension://__MSG_@@extension_id__/someFile.png)}' - ] - }, { - root: process.cwd(), - relativeTo: path.join('test', 'fixtures', 'partials-relative') - }) - ) - .addBatch( - optimizerContext('urls rewriting - no root but target as file', { - 'no @import': [ - 'a{background:url(../partials/extra/down.gif) no-repeat}', - 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'relative @import': [ - '@import url(base.css);', - 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'absolute @import': [ - '@import url(/test/fixtures/partials-relative/base.css);', - 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'document-local reference': [ - 'svg{marker-end:url(#arrow)}', - 'svg{marker-end:url(#arrow)}' - ] - }, { - target: path.join(process.cwd(), 'test.css'), - relativeTo: path.join('test', 'fixtures', 'partials-relative') - }) - ) - .addBatch( - optimizerContext('urls rewriting - no root but target as a directory', { - 'no @import': [ - 'a{background:url(../partials/extra/down.gif) no-repeat}', - 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'relative @import': [ - '@import url(base.css);', - 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'absolute @import': [ - '@import url(/test/fixtures/partials-relative/base.css);', - 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'document-local reference': [ - 'svg{marker-end:url(#arrow)}', - 'svg{marker-end:url(#arrow)}' - ], - 'quoting URLs #1': [ - 'div{background:url("data:image/svg+xml;base64,==")}li:nth-child(odd){color:red}', - 'div{background:url(data:image/svg+xml;base64,==)}li:nth-child(odd){color:red}' - ], - 'quoting URLs #2': [ - 'div{background:url("data:image/svg+xml;base64,==");border-image:url(1.png)}li:nth-child(odd){color:red}', - 'div{background:url(data:image/svg+xml;base64,==);border-image:url(test/fixtures/partials-relative/1.png)}li:nth-child(odd){color:red}' - ] - }, { - target: process.cwd(), - relativeTo: path.join('test', 'fixtures', 'partials-relative') - }) - ) - .addBatch( - optimizerContext('urls rewriting - no root but target as a missing directory', { + optimizerContext('urls rewriting - rebaseTo as a missing directory', { 'url': [ - 'a{background:url(../partials/extra/down.gif) no-repeat}', - 'a{background:url(../fixtures/partials/extra/down.gif) no-repeat}' + 'a{background:url(test/partials/extra/down.gif) no-repeat}', + 'a{background:url(../partials/extra/down.gif) no-repeat}' ], 'relative @import': [ - '@import url(base.css);', + '@import url(test/fixtures/partials-relative/base.css);', 'a{background:url(../fixtures/partials/extra/down.gif) no-repeat}' ], 'absolute @import': [ '@import url(/test/fixtures/partials-relative/base.css);', 'a{background:url(../fixtures/partials/extra/down.gif) no-repeat}' ] - }, { - target: path.join('test', 'fixtures2'), - relativeTo: path.join('test', 'fixtures', 'partials-relative') - }) - ) - .addBatch( - optimizerContext('urls rewriting - root and target', { - 'no @import': [ - 'a{background:url(../partials/extra/down.gif) no-repeat}', - 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'relative @import': [ - '@import url(base.css);', - 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'absolute @import': [ - '@import url(/test/fixtures/partials-relative/base.css);', - 'a{background:url(/test/fixtures/partials/extra/down.gif) no-repeat}' - ], - 'document-local reference': [ - 'svg{marker-end:url(#arrow)}', - 'svg{marker-end:url(#arrow)}' - ] - }, { - root: process.cwd(), - target: path.join(process.cwd(), 'test.css'), - relativeTo: path.join('test', 'fixtures', 'partials-relative') - }) + }, { rebaseTo: path.join('test', 'fixtures2') }) ) .addBatch( optimizerContext('urls rewriting - rebase off', { 'keeps urls the same': [ - '@import url(base.css);', + '@import url(test/fixtures/partials-relative/base.css);', 'a{background:url(../partials/extra/down.gif) no-repeat}' ] }, { - target: path.join(process.cwd(), 'test.css'), - relativeTo: path.join('test', 'fixtures', 'partials-relative'), rebase: false }) ) @@ -2119,7 +2001,7 @@ vows.describe('integration tests') generateComments(30000) + '@import url(fonts.google.com/some.css);', '' ] - }, { root: process.cwd() }) + }) ) .addBatch( optimizerContext('malformed but still valid @import', { @@ -2167,7 +2049,7 @@ vows.describe('integration tests') '@import url(\'test/fixtures/partials/one.css \');', '.one{color:red}' ] - }, { root: process.cwd() }) + }) ) .addBatch( optimizerContext('@import with absolute paths', { @@ -2176,26 +2058,26 @@ vows.describe('integration tests') '' ], 'of a real file': [ - '@import url(/partials/one.css);', + '@import url(/test/fixtures/partials/one.css);', '.one{color:red}' ], 'of a real file with quoted paths': [ - '@import url("/partials/one.css");', + '@import url("/test/fixtures/partials/one.css");', '.one{color:red}' ], 'of two files with mixed paths': [ - '@import url(/partials/one.css);@import url(partials/extra/three.css);a{display:block}', + '@import url(/test/fixtures/partials/one.css);@import url(/test/fixtures/partials/extra/three.css);a{display:block}', '.one{color:red}.three{color:#0f0}a{display:block}' ], 'of a multi-level, circular dependency file': [ - '@import url(/partials/two.css);', + '@import url(/test/fixtures/partials/two.css);', '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}' ], 'of a multi-level, circular dependency file with mixed paths': [ - '@import url(/partials-absolute/base.css);', + '@import url(/test/fixtures/partials-absolute/base.css);', '.base2{border-width:0}.sub{padding:0}.base{margin:0}' ] - }, { root: path.join(process.cwd(), 'test', 'fixtures') }) + }) ) .addBatch( optimizerContext('@import with option processImport', { @@ -2209,7 +2091,7 @@ vows.describe('integration tests') ], 'of comment chars within import url': [ '@import \'necolas/normalize.css@*/normalize.css\';', - '@import \'necolas/normalize.css@*/normalize.css\';' + '@import url(necolas/normalize.css@*/normalize.css);' ] }, { processImport: false }) ) @@ -2231,7 +2113,7 @@ vows.describe('integration tests') '@import url(test.css);@font-face{font-family:"icomoon"}', '@import url(test.css);@font-face{font-family:icomoon}' ] - }, { processImport: false, root: process.cwd(), relativeTo: process.cwd() }) + }, { processImport: false }) ) .addBatch( optimizerContext('body at-rules', { diff --git a/test/module-test.js b/test/module-test.js index 0ac7f2e0..47953394 100644 --- a/test/module-test.js +++ b/test/module-test.js @@ -10,6 +10,7 @@ function sourcesAsHash(sources, resolve) { sources.forEach(function (source) { source = resolve ? path.resolve(source) : source; + inputHash[source] = { styles: fs.readFileSync(source, 'utf-8') }; @@ -99,18 +100,6 @@ vows.describe('module tests').addBatch({ assert.isEmpty(minified.warnings); } }, - 'warnings': { - 'topic': function () { - return new CleanCSS({ root: 'test/fixtures', target: 'custom-warnings.css' }).minify('a{color:red}'); - }, - 'are an array': function (error, minified) { - assert.isArray(minified.warnings); - }, - 'if both root and output used reasons given': function (error, minified) { - assert.lengthOf(minified.warnings, 1); - assert.match(minified.warnings[0], /Both 'root' and output file given/); - } - }, 'warnings on extra closing brace': { 'topic': function () { return new CleanCSS().minify('a{display:block}}'); @@ -185,7 +174,7 @@ vows.describe('module tests').addBatch({ 'topic': function () { return new CleanCSS(); }, - 'if both root and output used reasons given': function (minifier) { + 'if a file is missing': function (minifier) { assert.doesNotThrow(function () { minifier.minify('@import url(/some/fake/file);', function (errors) { assert.isArray(errors); @@ -199,7 +188,7 @@ vows.describe('module tests').addBatch({ 'topic': function () { return new CleanCSS(); }, - 'if both root and output used reasons given': function (minifier) { + 'if file is missing': function (minifier) { minifier.minify('@import url(/some/fake/file);'); minifier.minify('@import url(/some/fake/file);', function (errors) { assert.lengthOf(errors, 1); @@ -328,10 +317,10 @@ vows.describe('module tests').addBatch({ }, 'rebase': { 'topic': function () { - return new CleanCSS({ rebase: true, relativeTo: path.join(process.cwd(), 'test', 'fixtures'), root: process.cwd() }).minify('div{background:url(./dummy.png)}'); + return new CleanCSS({ rebase: true, rebaseTo: path.join('test') }).minify('div{background:url(dummy.png)}'); }, 'gets right output': function (minified) { - assert.include(minified.styles, 'url(/test/fixtures/dummy.png)'); + assert.include(minified.styles, 'url(../dummy.png)'); } }, 'restructuring - on': { @@ -379,57 +368,73 @@ vows.describe('module tests').addBatch({ } }, 'accepts a list of source files as array': { - 'rebased to the current dir': { - 'relative': { + 'relative': { + 'with rebase to the current directory': { 'topic': function () { - return new CleanCSS().minify(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css']); + return new CleanCSS().minify([ + 'test/fixtures/partials/one.css', + 'test/fixtures/partials/three.css' + ]); }, 'should give right output': function (minified) { assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/fixtures/partials/extra/down.gif)}'); } }, - 'absolute': { - 'topic': function () { - return new CleanCSS({ relativeTo: process.cwd() }).minify([path.resolve('test/fixtures/partials/one.css'), path.resolve('test/fixtures/partials/three.css')]); - }, - 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/fixtures/partials/extra/down.gif)}'); - } - } - }, - 'rebased to a path': { - 'relative': { + 'with rebase to a custom directory': { 'topic': function () { - return new CleanCSS({ relativeTo: 'test/fixtures' }).minify(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css']); + return new CleanCSS({ rebaseTo: path.join('test', 'fixtures') }).minify([ + 'test/fixtures/partials/one.css', + 'test/fixtures/partials/three.css' + ]); }, 'should give right output': function (minified) { assert.equal(minified.styles, '.one{color:red}.three{background-image:url(partials/extra/down.gif)}'); } }, - 'absolute': { + 'without rebase': { 'topic': function () { - return new CleanCSS({ relativeTo: 'test/fixtures' }).minify([path.resolve('test/fixtures/partials/one.css'), path.resolve('test/fixtures/partials/three.css')]); + return new CleanCSS({ rebase: false }).minify([ + 'test/fixtures/partials/one.css', + 'test/fixtures/partials/three.css' + ]); }, 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{background-image:url(partials/extra/down.gif)}'); + assert.equal(minified.styles, '.one{color:red}.three{background-image:url(extra/down.gif)}'); } } }, - 'rebased to root': { - 'relative': { + 'absolute': { + 'with rebase to the current directory': { 'topic': function () { - return new CleanCSS({ root: 'test/fixtures', relativeTo: 'test/fixtures' }).minify(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css']); + return new CleanCSS().minify([ + path.resolve('test/fixtures/partials/one.css'), + path.resolve('test/fixtures/partials/three.css') + ]); }, 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{background-image:url(/partials/extra/down.gif)}'); + assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/fixtures/partials/extra/down.gif)}'); } }, - 'absolute': { + 'with rebase to a custom directory': { + 'topic': function () { + return new CleanCSS({ rebaseTo: path.join('test', 'fixtures') }).minify([ + path.resolve('test/fixtures/partials/one.css'), + path.resolve('test/fixtures/partials/three.css') + ]); + }, + 'should give right output': function (minified) { + assert.equal(minified.styles, '.one{color:red}.three{background-image:url(partials/extra/down.gif)}'); + } + }, + 'without rebase': { 'topic': function () { - return new CleanCSS({ root: 'test/fixtures', relativeTo: 'test/fixtures' }).minify([path.resolve('test/fixtures/partials/one.css'), path.resolve('test/fixtures/partials/three.css')]); + return new CleanCSS({ rebase: false }).minify([ + path.resolve('test/fixtures/partials/one.css'), + path.resolve('test/fixtures/partials/three.css') + ]); }, 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{background-image:url(/partials/extra/down.gif)}'); + assert.equal(minified.styles, '.one{color:red}.three{background-image:url(extra/down.gif)}'); } } }, @@ -439,78 +444,96 @@ vows.describe('module tests').addBatch({ return new CleanCSS({ processImport: false }).minify(['./test/fixtures/partials/two.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}'); + assert.equal(minified.styles, '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/extra/three.css);@import url(test/fixtures/partials/extra/four.css);.two{color:#fff}'); } - } - } - }, - 'accepts a list of source files as hash': { - 'rebased to the current dir': { - 'with relative paths': { + }, + 'off and rebase off': { 'topic': function () { - return new CleanCSS().minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'])); + return new CleanCSS({ processImport: false, rebase: false }).minify(['./test/fixtures/partials/two.css']); }, 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/fixtures/partials/extra/down.gif)}'); + assert.equal(minified.styles, '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/extra/three.css);@import url(test/fixtures/partials/extra/four.css);.two{color:#fff}'); } }, - 'with absolute paths': { + } + }, + 'accepts a list of source files as hash': { + 'relative': { + 'with rebase to the current directory': { 'topic': function () { - return new CleanCSS().minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'], true)); + return new CleanCSS().minify( + sourcesAsHash([ + 'test/fixtures/partials/one.css', + 'test/fixtures/partials/three.css' + ]) + ); }, 'should give right output': function (minified) { assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/fixtures/partials/extra/down.gif)}'); } - } - }, - 'rebased to a relative path': { - 'with relative paths': { + }, + 'with rebase to a custom directory': { 'topic': function () { - return new CleanCSS({ target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'])); + return new CleanCSS({ rebaseTo: path.join('test', 'fixtures') }).minify( + sourcesAsHash([ + 'test/fixtures/partials/one.css', + 'test/fixtures/partials/three.css' + ]) + ); }, 'should give right output': function (minified) { assert.equal(minified.styles, '.one{color:red}.three{background-image:url(partials/extra/down.gif)}'); } }, - 'with absolute paths': { + 'without rebase': { 'topic': function () { - return new CleanCSS({ target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'], true)); + return new CleanCSS({ rebase: false }).minify( + sourcesAsHash([ + 'test/fixtures/partials/one.css', + 'test/fixtures/partials/three.css' + ]) + ); }, 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{background-image:url(partials/extra/down.gif)}'); + assert.equal(minified.styles, '.one{color:red}.three{background-image:url(extra/down.gif)}'); } } }, - 'rebased to an absolute root': { - 'with relative paths': { + 'absolute': { + 'with rebase to the current directory': { 'topic': function () { - return new CleanCSS({ root: 'test/fixtures', target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'])); + return new CleanCSS().minify( + sourcesAsHash([ + 'test/fixtures/partials/one.css', + 'test/fixtures/partials/three.css' + ], true) + ); }, 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{background-image:url(/partials/extra/down.gif)}'); + assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/fixtures/partials/extra/down.gif)}'); } }, - 'with absolute paths': { - 'topic': function () { - return new CleanCSS({ root: 'test/fixtures', target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'], true)); - }, - 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{background-image:url(/partials/extra/down.gif)}'); - } - } - }, - 'with rebasing off': { - 'with relative paths': { + 'with rebase to a custom directory': { 'topic': function () { - return new CleanCSS({ rebase: false }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'])); + return new CleanCSS({ rebaseTo: path.join('test', 'fixtures') }).minify( + sourcesAsHash([ + 'test/fixtures/partials/one.css', + 'test/fixtures/partials/three.css' + ], true) + ); }, 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{background-image:url(extra/down.gif)}'); + assert.equal(minified.styles, '.one{color:red}.three{background-image:url(partials/extra/down.gif)}'); } }, - 'with absolute paths': { + 'without rebase': { 'topic': function () { - return new CleanCSS({ rebase: false }).minify(sourcesAsHash(['test/fixtures/partials/one.css', 'test/fixtures/partials/three.css'], true)); + return new CleanCSS({ rebase: false }).minify( + sourcesAsHash([ + 'test/fixtures/partials/one.css', + 'test/fixtures/partials/three.css' + ], true) + ); }, 'should give right output': function (minified) { assert.equal(minified.styles, '.one{color:red}.three{background-image:url(extra/down.gif)}'); @@ -519,7 +542,11 @@ vows.describe('module tests').addBatch({ }, 'with other imports': { 'topic': function () { - return new CleanCSS().minify(sourcesAsHash(['test/fixtures/partials/two.css'])); + return new CleanCSS().minify( + sourcesAsHash([ + 'test/fixtures/partials/two.css' + ]) + ); }, 'should give right output': function (minified) { assert.equal(minified.styles, '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}'); @@ -527,74 +554,56 @@ vows.describe('module tests').addBatch({ }, 'with other imports and rebasing off': { 'topic': function () { - return new CleanCSS({ rebase: false }).minify(sourcesAsHash(['test/fixtures/partials/two.css'])); + return new CleanCSS({ rebase: false }).minify( + sourcesAsHash([ + 'test/fixtures/partials/two.css' + ]) + ); }, 'should give right output': function (minified) { assert.equal(minified.styles, '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}'); } }, 'with other imports and processing imports off': { - 'relative to current path': { + 'relative': { 'topic': function () { - return new CleanCSS({ processImport: false }).minify(sourcesAsHash(['test/fixtures/partials/two.css'])); + return new CleanCSS({ processImport: false }).minify( + sourcesAsHash([ + 'test/fixtures/partials/two.css' + ]) + ); }, 'should give right output': function (minified) { assert.equal(minified.styles, '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/extra/three.css);@import url(test/fixtures/partials/extra/four.css);.two{color:#fff}'); } }, - 'relative to different path': { - 'topic': function () { - return new CleanCSS({ processImport: false, target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/two.css'])); - }, - 'should give right output': function (minified) { - assert.equal(minified.styles, '@import url(partials/one.css);@import url(partials/extra/three.css);@import url(partials/extra/four.css);.two{color:#fff}'); - } - }, 'absolute': { 'topic': function () { - return new CleanCSS({ processImport: false, root: 'test/fixtures', target: 'test/fixtures' }).minify(sourcesAsHash(['test/fixtures/partials/two.css'])); - }, - 'should give right output': function (minified) { - assert.equal(minified.styles, '@import url(/partials/one.css);@import url(/partials/extra/three.css);@import url(/partials/extra/four.css);.two{color:#fff}'); - } - }, - 'with import URL as a string': { - 'topic': function () { - var source = 'test/fixtures/partials/two.css'; - var asHash = sourcesAsHash([source]); - asHash[source].styles = asHash[source].styles.replace(/url\(|\)/g, ''); - return new CleanCSS().minify(asHash); - }, - 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}'); - } - }, - 'with import URL as an uppercase string': { - 'topic': function () { - var source = 'test/fixtures/partials/two.css'; - var asHash = sourcesAsHash([source]); - asHash[source].styles = asHash[source].styles.replace(/url\(|\)/g, '').replace('@import', '@IMPORT'); - return new CleanCSS().minify(asHash); + return new CleanCSS({ processImport: false }).minify( + sourcesAsHash([ + 'test/fixtures/partials/two.css' + ], true) + ); }, 'should give right output': function (minified) { - assert.equal(minified.styles, '.one{color:red}.three{color:#0f0}.four{color:#00f}.two{color:#fff}'); - } - }, - 'with two import URLs when one is a string plus a callback': { - 'topic': function () { - new CleanCSS().minify({ - 'main.css': { - styles: '@import "test/fixtures/partials/one.css";\n@import url(test/fixtures/partials/three.css);' - } - }, this.callback); - }, - 'should give right output': function (error, minified) { - assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/fixtures/partials/extra/down.gif)}'); + assert.equal(minified.styles, '@import url(test/fixtures/partials/one.css);@import url(test/fixtures/partials/extra/three.css);@import url(test/fixtures/partials/extra/four.css);.two{color:#fff}'); } } }, + 'with a callback': { + 'topic': function () { + new CleanCSS().minify({ + 'main.css': { + styles: '@import url(test/fixtures/partials/one.css);\n@import url(test/fixtures/partials/three.css);' + } + }, this.callback); + }, + 'should give right output': function (error, minified) { + assert.equal(minified.styles, '.one{color:red}.three{background-image:url(test/fixtures/partials/extra/down.gif)}'); + } + }, 'with remote paths': { - 'topic': new CleanCSS({ sourceMap: true, target: process.cwd() }).minify({ + 'topic': new CleanCSS({ sourceMap: true }).minify({ 'http://127.0.0.1/styles.css': { styles: 'div{background-image:url(image.png)}' } -- 2.34.1