vulcanize
Version:
Process Web Components into one output file
166 lines (152 loc) • 5.81 kB
JavaScript
/**
* @license
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
// jshint node:true
;
var path = require('path');
// use path.posix on Node > 0.12+, path-posix on 0.10
var pathPosix = path.posix || require('path-posix');
var url = require('url');
var dom5 = require('dom5');
var matchers = require('./matchers');
var constants = require('./constants');
var PathResolver = function PathResolver(abspath) {
if (abspath) {
this.abspath = abspath;
}
};
PathResolver.prototype = {
isTemplatedUrl: function isTemplatedUrl(href) {
return href.search(constants.URL_TEMPLATE) >= 0;
},
resolvePaths: function resolvePaths(importDoc, importUrl, mainDocUrl, polymer2) {
// rewrite URLs in element attributes
var nodes = dom5.queryAll(importDoc, matchers.urlAttrs);
var attrValue;
for (var i = 0, node; i < nodes.length; i++) {
node = nodes[i];
for (var j = 0, attr; j < constants.URL_ATTR.length; j++) {
attr = constants.URL_ATTR[j];
attrValue = dom5.getAttribute(node, attr);
// When the path is an empty string value the intent is to represent
// in URL-speak "the same path that the current document is at".
// We'll set it to '.' which better represents this intent to the
// rewrite methods.
if (attrValue === '') {
attrValue = '.';
}
if (attrValue && !this.isTemplatedUrl(attrValue)) {
var relUrl;
if (attr === 'style') {
relUrl = this.rewriteURL(importUrl, mainDocUrl, attrValue);
} else {
relUrl = this.rewriteRelPath(importUrl, mainDocUrl, attrValue);
if (attr === 'assetpath' && relUrl.length > 0 && relUrl.slice(-1) !== '/') {
relUrl += '/';
}
}
dom5.setAttribute(node, attr, relUrl);
}
}
}
// rewrite URLs in stylesheets unless they're inside a <dom-module>
var styleNodes = polymer2 ?
dom5.queryAll(importDoc,
dom5.predicates.AND(
dom5.predicates.NOT(
dom5.predicates.parentMatches(
dom5.predicates.hasTagName('dom-module'))),
matchers.CSS)) :
dom5.queryAll(importDoc, matchers.CSS);
for (i = 0, node; i < styleNodes.length; i++) {
node = styleNodes[i];
var styleText = dom5.getTextContent(node);
styleText = this.rewriteURL(importUrl, mainDocUrl, styleText);
dom5.setTextContent(node, styleText);
}
// add assetpath to dom-modules in importDoc
var domModules = dom5.queryAll(importDoc, matchers.domModule);
for (i = 0, node; i < domModules.length; i++) {
node = domModules[i];
var assetPathUrl = this.rewriteRelPath(importUrl, mainDocUrl, '');
assetPathUrl = pathPosix.dirname(assetPathUrl) + '/';
dom5.setAttribute(node, 'assetpath', assetPathUrl);
}
},
isAbsoluteUrl: function isAbsoluteUrl(href) {
return constants.ABS_URL.test(href);
},
rewriteRelPath: function rewriteRelPath(importUrl, mainDocUrl, relUrl) {
if (this.isAbsoluteUrl(relUrl)) {
return relUrl;
}
var absUrl = url.resolve(importUrl, relUrl);
if (this.abspath) {
return url.resolve('/', absUrl);
}
var parsedFrom = url.parse(mainDocUrl);
var parsedTo = url.parse(absUrl);
if (parsedFrom.protocol === parsedTo.protocol && parsedFrom.host === parsedTo.host) {
var pathname = pathPosix.relative(pathPosix.dirname(parsedFrom.pathname), parsedTo.pathname);
return url.format({
pathname: pathname,
search: parsedTo.search,
hash: parsedTo.hash
});
}
return absUrl;
},
rewriteURL: function rewriteURL(importUrl, mainDocUrl, cssText) {
return cssText.replace(constants.URL, function(match) {
var path = match.replace(/["']/g, "").slice(4, -1);
path = this.rewriteRelPath(importUrl, mainDocUrl, path);
return 'url("' + path + '")';
}.bind(this));
},
// remove effects of <base>
acid: function acid(doc, docUrl, polymer2) {
var base = dom5.query(doc, matchers.base);
if (base) {
var baseUrl = dom5.getAttribute(base, 'href');
var baseTarget = dom5.getAttribute(base, 'target');
dom5.remove(base);
if (baseUrl) {
if (baseUrl.slice(-1) === '/') {
baseUrl = baseUrl.slice(0, -1);
}
var docBaseUrl = url.resolve(docUrl, baseUrl + '/.index.html');
this.resolvePaths(doc, docBaseUrl, docUrl, polymer2);
}
if (baseTarget) {
var elementsNeedTarget = dom5.queryAll(doc, matchers.targetMatcher);
elementsNeedTarget.forEach(function(el) {
dom5.setAttribute(el, 'target', baseTarget);
});
}
}
},
pathToUrl: function pathToUrl(filePath) {
var absolutePath = path.resolve(filePath);
if (process.platform === 'win32') {
// encode C:\foo\ as C:/foo/
return absolutePath.split('\\').join('/');
} else {
return absolutePath;
}
},
urlToPath: function urlToPath(uri) {
var parsed = url.parse(uri);
if (process.platform === 'win32') {
return parsed.protocol + parsed.pathname.split('/').join('\\');
} else {
return (parsed.protocol || '') + parsed.pathname;
}
}
};
module.exports = PathResolver;