From: Jakub Pawlowicz Date: Sun, 19 Apr 2015 15:56:42 +0000 (+0100) Subject: Fixes #436 - refactors URI rewriting. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=bda97f52e80fc1b3482fce7c06fab5d865b5eeb0;p=clean-css.git Fixes #436 - refactors URI rewriting. Now it's way easier to understand. --- diff --git a/History.md b/History.md index 745c18bd..6adba11d 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,8 @@ +[3.3.0 / 2015-xx-xx](https://github.com/jakubpawlowicz/clean-css/compare/v3.2.0...HEAD) +================== + +* Fixed issue [#436](https://github.com/jakubpawlowicz/clean-css/issues/436) - refactors URI rewriting. + [3.2.0 / 2015-04-19](https://github.com/jakubpawlowicz/clean-css/compare/v3.1.9...v3.2.0) ================== diff --git a/lib/images/rewrite-urls.js b/lib/images/rewrite-urls.js new file mode 100644 index 00000000..bae44d10 --- /dev/null +++ b/lib/images/rewrite-urls.js @@ -0,0 +1,74 @@ +var path = require('path'); +var url = require('url'); + +var UrlScanner = require('../utils/url-scanner'); + +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 isRemote(uri) { + return uri.indexOf('http://') === 0 || uri.indexOf('https://') === 0; +} + +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)) + 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 url.resolve(options.toBase, uri); + + return options.absolute ? + normalize(absolute(uri, options)) : + normalize(relative(uri, options)); +} + +function rewriteUrls(data, options, context) { + return new UrlScanner(data, context).reduce(function (url, tempData) { + url = url.replace(/^url\(\s*['"]?|['"]?\s*\)$/g, ''); + tempData.push('url(' + rebase(url, options) + ')'); + }); +} + +module.exports = rewriteUrls; diff --git a/lib/images/url-rebase.js b/lib/images/url-rebase.js index aa8cc0b9..193c7e9d 100644 --- a/lib/images/url-rebase.js +++ b/lib/images/url-rebase.js @@ -1,6 +1,6 @@ var path = require('path'); -var UrlRewriter = require('./url-rewriter'); +var rewriteUrls = require('./rewrite-urls'); function UrlRebase(outerContext) { this.outerContext = outerContext; @@ -30,7 +30,7 @@ UrlRebase.prototype.process = function (data) { if (!rebaseOpts.fromBase || !rebaseOpts.toBase) return data; - return new UrlRewriter(rebaseOpts).process(data); + return rewriteUrls(data, rebaseOpts, this.outerContext); }; module.exports = UrlRebase; diff --git a/lib/images/url-rewriter.js b/lib/images/url-rewriter.js deleted file mode 100644 index be4a5eba..00000000 --- a/lib/images/url-rewriter.js +++ /dev/null @@ -1,58 +0,0 @@ -var path = require('path'); -var url = require('url'); - -var UrlScanner = require('../utils/url-scanner'); - -function UrlRewriter(options, context) { - this.options = options; - this.context = context; -} - -UrlRewriter.prototype.process = function (data) { - var self = this; - - return new UrlScanner(data, this.context).reduce(function (url, tempData) { - url = url.replace(/^url\(\s*['"]?|['"]?\s*\)$/g, ''); - tempData.push('url(' + rebase(url, self.options) + ')'); - }); -}; - -function rebase(resource, options) { - // TODO: this is getting insane now - pending refactor in #436 - var importUrl = resource.substring(resource.length - 4) == '.css'; - var dataUri = resource.indexOf('data:') === 0; - var specialUrl = resource[0] == '/' || - resource[0] == '#' || - (!options.imports && importUrl) || - dataUri || - /^https?:\/\//.exec(resource) !== null || - /__\w+__/.exec(resource) !== null; - var rebased; - - if (false === options.urls) { - if (options.imports && importUrl) - specialUrl = false; - else - specialUrl = true; - } - - if (specialUrl) - return dataUri ? '\'' + resource + '\'' : resource; - - if (/https?:\/\//.test(options.toBase)) - return url.resolve(options.toBase, resource); - - if (options.absolute) { - rebased = path - .resolve(path.join(options.fromBase, resource)) - .replace(options.toBase, ''); - } else { - rebased = path.relative(options.toBase, path.join(options.fromBase, resource)); - } - - return process.platform == 'win32' ? - rebased.replace(/\\/g, '/') : - rebased; -} - -module.exports = UrlRewriter; diff --git a/lib/imports/inliner.js b/lib/imports/inliner.js index 553a8477..8f774b9a 100644 --- a/lib/imports/inliner.js +++ b/lib/imports/inliner.js @@ -4,7 +4,7 @@ var http = require('http'); var https = require('https'); var url = require('url'); -var UrlRewriter = require('../images/url-rewriter'); +var rewriteUrls = require('../images/rewrite-urls'); var Splitter = require('../utils/splitter.js'); var override = require('../utils/object.js').override; @@ -263,7 +263,7 @@ function inlineRemoteResource(importedFile, mediaQuery, context) { res.on('end', function() { var importedData = chunks.join(''); if (context.rebase) - importedData = new UrlRewriter({ toBase: importedUrl }, context).process(importedData); + importedData = rewriteUrls(importedData, { toBase: importedUrl }, context); context.sourceReader.trackSource(importedUrl, importedData); importedData = context.sourceTracker.store(importedUrl, importedData); importedData = rebaseMap(importedData, importedUrl); @@ -314,12 +314,12 @@ function inlineLocalResource(importedFile, mediaQuery, context) { var importRelativeTo = path.dirname(fullPath); var importedData = fs.readFileSync(fullPath, 'utf8'); if (context.rebase) { - var rewriter = new UrlRewriter({ + var rewriteOptions = { relative: true, fromBase: importRelativeTo, toBase: context.baseRelativeTo - }, context); - importedData = rewriter.process(importedData); + }; + importedData = rewriteUrls(importedData, rewriteOptions, context); } var relativePath = path.relative(context.root, fullPath); diff --git a/lib/utils/source-reader.js b/lib/utils/source-reader.js index 9393157c..89a24061 100644 --- a/lib/utils/source-reader.js +++ b/lib/utils/source-reader.js @@ -1,5 +1,5 @@ var path = require('path'); -var UrlRewriter = require('../images/url-rewriter'); +var rewriteUrls = require('../images/rewrite-urls'); var REMOTE_RESOURCE = /^(https?:)?\/\//; @@ -68,15 +68,15 @@ function fromHash(self) { var absoluteSource = isRemote ? source : path.resolve(source); var absoluteSourcePath = path.dirname(absoluteSource); - var rewriter = new UrlRewriter({ + var rewriteOptions = { absolute: self.outerContext.options.explicitRoot, relative: !self.outerContext.options.explicitRoot, imports: true, - urls: self.outerContext.options.rebase, + rebase: self.outerContext.options.rebase, fromBase: absoluteSourcePath, toBase: isRemote ? absoluteSourcePath : toBase - }, self.outerContext); - styles = rewriter.process(styles); + }; + styles = rewriteUrls(styles, rewriteOptions, self.outerContext); self.trackSource(source, styles);