first commit
This commit is contained in:
26
build/node_modules/vulcanize/lib/comment-map.js
generated
vendored
Normal file
26
build/node_modules/vulcanize/lib/comment-map.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
function CommentMap() {
|
||||
this.commentMap = Object.create(null);
|
||||
}
|
||||
|
||||
CommentMap.prototype = {
|
||||
get: function(comment) {
|
||||
return this.commentMap[comment];
|
||||
},
|
||||
set: function(comment, value) {
|
||||
this.commentMap[comment] = value;
|
||||
},
|
||||
keys: function() {
|
||||
return Object.keys(this.commentMap);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = CommentMap;
|
||||
18
build/node_modules/vulcanize/lib/constants.js
generated
vendored
Normal file
18
build/node_modules/vulcanize/lib/constants.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
EXTERNAL_URL: /^(?:https?:)?\/\//,
|
||||
ABS_URL: /(^\/)|(^#)|(^[\w-\d]*:)/,
|
||||
URL: /url\([^)]*\)/g,
|
||||
URL_ATTR: ['href', 'src', 'action', 'style', 'assetpath'],
|
||||
URL_TEMPLATE: '{{.*}}|\\[\\[.*\\]\\]',
|
||||
OLD_POLYMER: 'This version of vulcanize is not compatible with Polymer < 0.8. Please use vulcanize 0.7.x.'
|
||||
};
|
||||
100
build/node_modules/vulcanize/lib/matchers.js
generated
vendored
Normal file
100
build/node_modules/vulcanize/lib/matchers.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @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
|
||||
'use strict';
|
||||
|
||||
var constants = require('./constants');
|
||||
var dom5 = require('dom5');
|
||||
var p = dom5.predicates;
|
||||
|
||||
var urlAttrMatchers = constants.URL_ATTR.map(function(attr) {
|
||||
return p.hasAttr(attr);
|
||||
});
|
||||
|
||||
var urlAttrs = p.OR.apply(null, urlAttrMatchers);
|
||||
|
||||
var jsMatcher = p.AND(
|
||||
p.hasTagName('script'),
|
||||
p.OR(
|
||||
p.NOT(
|
||||
p.hasAttr('type')
|
||||
),
|
||||
p.hasAttrValue('type', 'text/javascript'),
|
||||
p.hasAttrValue('type', 'application/javascript')
|
||||
)
|
||||
);
|
||||
|
||||
var externalStyle = p.AND(
|
||||
p.hasTagName('link'),
|
||||
p.hasAttrValue('rel', 'stylesheet')
|
||||
);
|
||||
// polymer specific external stylesheet
|
||||
var polymerExternalStyle = p.AND(
|
||||
p.hasTagName('link'),
|
||||
p.hasAttrValue('rel', 'import'),
|
||||
p.hasAttrValue('type', 'css')
|
||||
);
|
||||
|
||||
var htmlImport = p.AND(
|
||||
p.hasTagName('link'),
|
||||
p.hasAttrValue('rel', 'import'),
|
||||
p.OR(
|
||||
p.NOT(p.hasAttr('type')),
|
||||
p.hasAttrValue('type', 'text/html')
|
||||
)
|
||||
);
|
||||
|
||||
var styleMatcher = p.AND(
|
||||
p.hasTagName('style'),
|
||||
p.OR(
|
||||
p.NOT(
|
||||
p.hasAttr('type')
|
||||
),
|
||||
p.hasAttrValue('type', 'text/css')
|
||||
)
|
||||
);
|
||||
|
||||
var targetMatcher = p.AND(
|
||||
p.OR(
|
||||
p.hasTagName('a'),
|
||||
p.hasTagName('form')
|
||||
),
|
||||
p.NOT(p.hasAttr('target'))
|
||||
);
|
||||
|
||||
module.exports = {
|
||||
head: p.hasTagName('head'),
|
||||
body: p.hasTagName('body'),
|
||||
base: p.hasTagName('base'),
|
||||
domModule: p.AND(
|
||||
p.hasTagName('dom-module'),
|
||||
p.hasAttr('id'),
|
||||
p.NOT(
|
||||
p.hasAttr('assetpath')
|
||||
)
|
||||
),
|
||||
meta: p.AND(
|
||||
p.hasTagName('meta'),
|
||||
p.hasAttr('charset')
|
||||
),
|
||||
polymerElement: p.hasTagName('polymer-element'),
|
||||
urlAttrs: urlAttrs,
|
||||
targetMatcher: targetMatcher,
|
||||
polymerExternalStyle: polymerExternalStyle,
|
||||
htmlImport: htmlImport,
|
||||
JS: jsMatcher,
|
||||
CSS: styleMatcher,
|
||||
CSS_LINK: externalStyle,
|
||||
POLY_CSS_LINK: polymerExternalStyle,
|
||||
ALL_CSS_LINK: p.OR(externalStyle, polymerExternalStyle),
|
||||
JS_SRC: p.AND(p.hasAttr('src'), jsMatcher),
|
||||
JS_INLINE: p.AND(p.NOT(p.hasAttr('src')), jsMatcher)
|
||||
};
|
||||
165
build/node_modules/vulcanize/lib/pathresolver.js
generated
vendored
Normal file
165
build/node_modules/vulcanize/lib/pathresolver.js
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* @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
|
||||
'use strict';
|
||||
|
||||
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;
|
||||
565
build/node_modules/vulcanize/lib/vulcan.js
generated
vendored
Normal file
565
build/node_modules/vulcanize/lib/vulcan.js
generated
vendored
Normal file
@@ -0,0 +1,565 @@
|
||||
/**
|
||||
* @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
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var url = require('url');
|
||||
var pathPosix = path.posix || require('path-posix');
|
||||
var hyd = require('hydrolysis');
|
||||
var dom5 = require('dom5');
|
||||
var CommentMap = require('./comment-map');
|
||||
var constants = require('./constants');
|
||||
var matchers = require('./matchers');
|
||||
var PathResolver = require('./pathresolver');
|
||||
var encodeString = require('../third_party/UglifyJS2/output');
|
||||
|
||||
var Promise = global.Promise || require('es6-promise').Promise;
|
||||
|
||||
/**
|
||||
* This is the copy of vulcanize we keep to simulate the setOptions api.
|
||||
*
|
||||
* TODO(garlicnation): deprecate and remove setOptions API in favor of constructor.
|
||||
*/
|
||||
var singleton;
|
||||
|
||||
function buildLoader(config) {
|
||||
var abspath = config.abspath;
|
||||
var excludes = config.excludes;
|
||||
var fsResolver = config.fsResolver;
|
||||
var redirects = config.redirects;
|
||||
var loader = new hyd.Loader();
|
||||
if (fsResolver) {
|
||||
loader.addResolver(fsResolver);
|
||||
} else {
|
||||
var fsOptions = {};
|
||||
if (abspath) {
|
||||
fsOptions.root = path.resolve(abspath);
|
||||
fsOptions.basePath = '/';
|
||||
}
|
||||
loader.addResolver(new hyd.FSResolver(fsOptions));
|
||||
}
|
||||
// build null HTTPS? resolver to skip external scripts
|
||||
loader.addResolver(new hyd.NoopResolver(constants.EXTERNAL_URL));
|
||||
var redirectOptions = {};
|
||||
if (abspath) {
|
||||
redirectOptions.root = path.resolve(abspath);
|
||||
redirectOptions.basePath = '/';
|
||||
}
|
||||
var redirectConfigs = [];
|
||||
for (var i = 0; i < redirects.length; i++) {
|
||||
var split = redirects[i].split('|');
|
||||
var uri = url.parse(split[0]);
|
||||
var replacement = split[1];
|
||||
if (!uri || !replacement) {
|
||||
throw new Error("Invalid redirect config: " + redirects[i]);
|
||||
}
|
||||
var redirectConfig = new hyd.RedirectResolver.ProtocolRedirect({
|
||||
protocol: uri.protocol,
|
||||
hostname: uri.hostname,
|
||||
path: uri.pathname,
|
||||
redirectPath: replacement
|
||||
});
|
||||
redirectConfigs.push(redirectConfig);
|
||||
}
|
||||
if (redirectConfigs.length > 0) {
|
||||
redirectOptions.redirects = redirectConfigs;
|
||||
loader.addResolver(new hyd.RedirectResolver(redirectOptions));
|
||||
}
|
||||
if (excludes) {
|
||||
excludes.forEach(function(r) {
|
||||
loader.addResolver(new hyd.NoopResolver(r));
|
||||
});
|
||||
}
|
||||
return loader;
|
||||
}
|
||||
|
||||
function nextSibling(node) {
|
||||
var parentNode = node.parentNode;
|
||||
if (!parentNode) {
|
||||
return null;
|
||||
}
|
||||
var idx = parentNode.childNodes.indexOf(node);
|
||||
return parentNode.childNodes[idx + 1] || null;
|
||||
}
|
||||
|
||||
var Vulcan = function Vulcan(opts) {
|
||||
// implicitStrip should be true by default
|
||||
this.implicitStrip = opts.implicitStrip === undefined ? true : Boolean(opts.implicitStrip);
|
||||
this.abspath = (String(opts.abspath) === opts.abspath && String(opts.abspath).trim() !== '') ? path.resolve(opts.abspath) : null;
|
||||
this.pathResolver = new PathResolver(this.abspath);
|
||||
this.addedImports = Array.isArray(opts.addedImports) ? opts.addedImports : [];
|
||||
this.excludes = Array.isArray(opts.excludes) ? opts.excludes : [];
|
||||
this.stripExcludes = Array.isArray(opts.stripExcludes) ? opts.stripExcludes : [];
|
||||
this.stripComments = Boolean(opts.stripComments);
|
||||
this.enableCssInlining = Boolean(opts.inlineCss);
|
||||
this.enableScriptInlining = Boolean(opts.inlineScripts);
|
||||
this.inputUrl = String(opts.inputUrl) === opts.inputUrl ? opts.inputUrl : '';
|
||||
this.fsResolver = opts.fsResolver;
|
||||
this.redirects = Array.isArray(opts.redirects) ? opts.redirects : [];
|
||||
this.polymer2 = opts.polymer2;
|
||||
if (opts.loader) {
|
||||
this.loader = opts.loader;
|
||||
} else {
|
||||
this.loader = buildLoader({
|
||||
abspath: this.abspath,
|
||||
fsResolver: this.fsResolver,
|
||||
excludes: this.excludes,
|
||||
redirects: this.redirects
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Vulcan.prototype = {
|
||||
isDuplicateImport: function isDuplicateImport(importMeta) {
|
||||
return !importMeta.href;
|
||||
},
|
||||
|
||||
reparent: function reparent(newParent) {
|
||||
return function(node) {
|
||||
node.parentNode = newParent;
|
||||
};
|
||||
},
|
||||
|
||||
isExcludedImport: function isExcludedImport(importMeta) {
|
||||
return this.isExcludedHref(importMeta.href);
|
||||
},
|
||||
|
||||
isExcludedHref: function isExcludedHref(href) {
|
||||
if (constants.EXTERNAL_URL.test(href)) {
|
||||
return true;
|
||||
}
|
||||
if (!this.excludes) {
|
||||
return false;
|
||||
}
|
||||
return this.excludes.some(function(r) {
|
||||
return href.search(r) >= 0;
|
||||
});
|
||||
},
|
||||
|
||||
isStrippedImport: function isStrippedImport(importMeta) {
|
||||
if (!this.stripExcludes.length) {
|
||||
return false;
|
||||
}
|
||||
var href = importMeta.href;
|
||||
return this.stripExcludes.some(function(r) {
|
||||
return href.search(r) >= 0;
|
||||
});
|
||||
},
|
||||
|
||||
isBlankTextNode: function isBlankTextNode(node) {
|
||||
return node && dom5.isTextNode(node) && !/\S/.test(dom5.getTextContent(node));
|
||||
},
|
||||
|
||||
hasOldPolymer: function hasOldPolymer(doc) {
|
||||
return Boolean(dom5.query(doc, matchers.polymerElement));
|
||||
},
|
||||
|
||||
removeElementAndNewline: function removeElementAndNewline(node, replacement) {
|
||||
// when removing nodes, remove the newline after it as well
|
||||
var parent = node.parentNode;
|
||||
var nextIdx = parent.childNodes.indexOf(node) + 1;
|
||||
var next = parent.childNodes[nextIdx];
|
||||
// remove next node if it is blank text
|
||||
if (this.isBlankTextNode(next)) {
|
||||
dom5.remove(next);
|
||||
}
|
||||
if (replacement) {
|
||||
dom5.replace(node, replacement);
|
||||
} else {
|
||||
dom5.remove(node);
|
||||
}
|
||||
},
|
||||
|
||||
isLicenseComment: function(node) {
|
||||
if (dom5.isCommentNode(node)) {
|
||||
return dom5.getTextContent(node).indexOf('@license') > -1;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
moveToBodyMatcher: dom5.predicates.AND(
|
||||
dom5.predicates.NOT(
|
||||
dom5.predicates.parentMatches(
|
||||
dom5.predicates.hasTagName('template'))),
|
||||
dom5.predicates.OR(
|
||||
dom5.predicates.hasTagName('script'),
|
||||
dom5.predicates.hasTagName('link'),
|
||||
matchers.CSS
|
||||
),
|
||||
dom5.predicates.NOT(
|
||||
dom5.predicates.OR(
|
||||
matchers.polymerExternalStyle,
|
||||
dom5.predicates.hasAttrValue('rel', 'dns-prefetch'),
|
||||
dom5.predicates.hasAttrValue('rel', 'icon'),
|
||||
dom5.predicates.hasAttrValue('rel', 'manifest'),
|
||||
dom5.predicates.hasAttrValue('rel', 'preconnect'),
|
||||
dom5.predicates.hasAttrValue('rel', 'prefetch'),
|
||||
dom5.predicates.hasAttrValue('rel', 'preload'),
|
||||
dom5.predicates.hasAttrValue('rel', 'prerender')
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
ancestorWalk: function(node, target) {
|
||||
while(node) {
|
||||
if (node === target) {
|
||||
return true;
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
isTemplated: function(node) {
|
||||
while(node) {
|
||||
if (dom5.isDocumentFragment(node)) {
|
||||
return true;
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
isInsideTemplate: dom5.predicates.parentMatches(
|
||||
dom5.predicates.hasTagName('template')),
|
||||
|
||||
flatten: function flatten(tree, mainDocUrl) {
|
||||
var isMainDoc = (mainDocUrl === undefined);
|
||||
if (isMainDoc) {
|
||||
mainDocUrl = tree.href;
|
||||
}
|
||||
var doc = tree.html.ast;
|
||||
var imports = tree.imports;
|
||||
var head = dom5.query(doc, matchers.head);
|
||||
var body = dom5.query(doc, matchers.body);
|
||||
var importNodes = tree.html.import;
|
||||
// early check for old polymer versions
|
||||
if (this.hasOldPolymer(doc)) {
|
||||
throw new Error(constants.OLD_POLYMER + ' File: ' + this.pathResolver.urlToPath(tree.href));
|
||||
}
|
||||
this.fixFakeExternalScripts(doc);
|
||||
this.pathResolver.acid(doc, tree.href, this.polymer2);
|
||||
var moveTarget;
|
||||
if (isMainDoc) {
|
||||
// hide bodies of imports from rendering in main document
|
||||
moveTarget = dom5.constructors.element('div');
|
||||
dom5.setAttribute(moveTarget, 'hidden', '');
|
||||
dom5.setAttribute(moveTarget, 'by-vulcanize', '');
|
||||
} else {
|
||||
moveTarget = dom5.constructors.fragment();
|
||||
}
|
||||
var htmlImportEncountered = false;
|
||||
|
||||
// Once we encounter an html import, we need to move things into the body,
|
||||
// because html imports contain things that can't be in document
|
||||
// head.
|
||||
dom5.queryAll(head, this.moveToBodyMatcher).forEach(function(n) {
|
||||
if (!htmlImportEncountered && matchers.htmlImport(n)) {
|
||||
htmlImportEncountered = true;
|
||||
}
|
||||
if (htmlImportEncountered) {
|
||||
this.removeElementAndNewline(n);
|
||||
dom5.append(moveTarget, n);
|
||||
}
|
||||
}, this);
|
||||
this.prepend(body, moveTarget);
|
||||
if (imports) {
|
||||
for (var i = 0, im, thisImport; i < imports.length; i++) {
|
||||
im = imports[i];
|
||||
thisImport = importNodes[i];
|
||||
if (this.isInsideTemplate(thisImport)) {
|
||||
continue;
|
||||
}
|
||||
if (this.isDuplicateImport(im) || this.isStrippedImport(im)) {
|
||||
this.removeElementAndNewline(thisImport);
|
||||
continue;
|
||||
}
|
||||
if (this.isExcludedImport(im)) {
|
||||
continue;
|
||||
}
|
||||
if (this.isTemplated(thisImport)) {
|
||||
continue;
|
||||
}
|
||||
var bodyFragment = dom5.constructors.fragment();
|
||||
var importDoc = this.flatten(im, mainDocUrl);
|
||||
// rewrite urls
|
||||
this.pathResolver.resolvePaths(importDoc, im.href, tree.href, this.polymer2);
|
||||
var importHead = dom5.query(importDoc, matchers.head);
|
||||
var importBody = dom5.query(importDoc, matchers.body);
|
||||
// merge head and body tags for imports into main document
|
||||
var importHeadChildren = importHead.childNodes;
|
||||
var importBodyChildren = importBody.childNodes;
|
||||
// make sure @license comments from import document make it into the import
|
||||
var importHtml = importHead.parentNode;
|
||||
var licenseComments = importDoc.childNodes.concat(importHtml.childNodes).filter(this.isLicenseComment);
|
||||
// move children of <head> and <body> into importer's <body>
|
||||
var reparentFn = this.reparent(bodyFragment);
|
||||
importHeadChildren.forEach(reparentFn);
|
||||
importBodyChildren.forEach(reparentFn);
|
||||
bodyFragment.childNodes = bodyFragment.childNodes.concat(
|
||||
licenseComments,
|
||||
importHeadChildren,
|
||||
importBodyChildren
|
||||
);
|
||||
// hide imports in main document, unless already hidden
|
||||
if (isMainDoc && !this.ancestorWalk(thisImport, moveTarget)) {
|
||||
this.hide(thisImport);
|
||||
}
|
||||
this.removeElementAndNewline(thisImport, bodyFragment);
|
||||
}
|
||||
}
|
||||
// If hidden node is empty, remove it
|
||||
if (isMainDoc && moveTarget.childNodes.length === 0) {
|
||||
dom5.remove(moveTarget);
|
||||
}
|
||||
return doc;
|
||||
},
|
||||
|
||||
hide: function(node) {
|
||||
var hidden = dom5.constructors.element('div');
|
||||
dom5.setAttribute(hidden, 'hidden', '');
|
||||
dom5.setAttribute(hidden, 'by-vulcanize', '');
|
||||
this.removeElementAndNewline(node, hidden);
|
||||
dom5.append(hidden, node);
|
||||
},
|
||||
|
||||
prepend: function prepend(parent, node) {
|
||||
if (parent.childNodes.length) {
|
||||
dom5.insertBefore(parent, parent.childNodes[0], node);
|
||||
} else {
|
||||
dom5.append(parent, node);
|
||||
}
|
||||
},
|
||||
|
||||
fixFakeExternalScripts: function fixFakeExternalScripts(doc) {
|
||||
var scripts = dom5.queryAll(doc, matchers.JS_INLINE);
|
||||
scripts.forEach(function(script) {
|
||||
if (script.__hydrolysisInlined) {
|
||||
dom5.setAttribute(script, 'src', script.__hydrolysisInlined);
|
||||
dom5.setTextContent(script, '');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// inline scripts into document, returns a promise resolving to document.
|
||||
inlineScripts: function inlineScripts(doc, href) {
|
||||
var scripts = dom5.queryAll(doc, matchers.JS_SRC);
|
||||
var scriptPromises = scripts.map(function(script) {
|
||||
var src = dom5.getAttribute(script, 'src');
|
||||
var uri = url.resolve(href, src);
|
||||
// let the loader handle the requests
|
||||
if (this.isExcludedHref(src)) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
return this.loader.request(uri).then(function(content) {
|
||||
if (content) {
|
||||
content = encodeString(content);
|
||||
dom5.removeAttribute(script, 'src');
|
||||
dom5.setTextContent(script, content);
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
// When all scripts are read, return the document
|
||||
return Promise.all(scriptPromises).then(function(){ return {doc: doc, href: href}; });
|
||||
},
|
||||
|
||||
|
||||
// inline scripts into document, returns a promise resolving to document.
|
||||
inlineCss: function inlineCss(doc, href) {
|
||||
var lastPolymerExternalStyle = null;
|
||||
var css_links = dom5.queryAll(doc, matchers.ALL_CSS_LINK);
|
||||
var cssPromises = css_links.map(function(link) {
|
||||
var tag = link;
|
||||
var src = dom5.getAttribute(tag, 'href');
|
||||
var media = dom5.getAttribute(tag, 'media');
|
||||
var uri = url.resolve(href, src);
|
||||
var isPolymerExternalStyle = matchers.polymerExternalStyle(tag);
|
||||
var polymer2 = this.polymer2;
|
||||
// let the loader handle the requests
|
||||
if (this.isExcludedHref(src)) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
// let the loader handle the requests
|
||||
return this.loader.request(uri).then(function(content) {
|
||||
if (content) {
|
||||
if (media) {
|
||||
content = '@media ' + media + ' {' + content + '}';
|
||||
}
|
||||
var style = dom5.constructors.element('style');
|
||||
|
||||
if (isPolymerExternalStyle) {
|
||||
// a polymer expternal style <link type="css" rel="import"> must be
|
||||
// in a <dom-module> to be processed
|
||||
var ownerDomModule = dom5.nodeWalkPrior(tag, dom5.predicates.hasTagName('dom-module'));
|
||||
if (ownerDomModule) {
|
||||
var domTemplate = dom5.query(ownerDomModule, dom5.predicates.hasTagName('template'));
|
||||
if (polymer2) {
|
||||
var assetpath = dom5.getAttribute(ownerDomModule, 'assetpath') || '';
|
||||
content = this.pathResolver.rewriteURL(uri, url.resolve(href, assetpath), content);
|
||||
} else {
|
||||
content = this.pathResolver.rewriteURL(uri, href, content);
|
||||
}
|
||||
if (!domTemplate) {
|
||||
// create a <template>, which has a fragment as childNodes[0]
|
||||
domTemplate = dom5.constructors.element('template');
|
||||
domTemplate.childNodes.push(dom5.constructors.fragment());
|
||||
dom5.append(ownerDomModule, domTemplate);
|
||||
}
|
||||
dom5.remove(tag);
|
||||
if (!lastPolymerExternalStyle) {
|
||||
// put the style at the top of the dom-module's template
|
||||
this.prepend(domTemplate.childNodes[0], style);
|
||||
} else {
|
||||
// put this style behind the last polymer external style
|
||||
dom5.insertBefore(domTemplate.childNodes[0], nextSibling(lastPolymerExternalStyle), style);
|
||||
}
|
||||
lastPolymerExternalStyle = style;
|
||||
}
|
||||
} else {
|
||||
content = this.pathResolver.rewriteURL(uri, href, content);
|
||||
dom5.replace(tag, style);
|
||||
}
|
||||
dom5.setTextContent(style, '\n' + content + '\n');
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
// When all style imports are read, return the document
|
||||
return Promise.all(cssPromises).then(function(){ return {doc: doc, href: href}; });
|
||||
},
|
||||
|
||||
getImplicitExcludes: function getImplicitExcludes(excludes) {
|
||||
// Build a loader that doesn't have to stop at our HTML excludes, since we
|
||||
// need them. JS excludes should still be excluded.
|
||||
var loader = buildLoader({
|
||||
abspath: this.abspath,
|
||||
fsResolver: this.fsResolver,
|
||||
redirects: this.redirects,
|
||||
excludes: excludes.filter(function(e) { return e.match(/.js$/i); })
|
||||
});
|
||||
var analyzer = new hyd.Analyzer(true, loader);
|
||||
var analyzedExcludes = [];
|
||||
excludes.forEach(function(exclude) {
|
||||
if (exclude.match(/.js$/i)) {
|
||||
return;
|
||||
}
|
||||
if (exclude.match(/.css$/i)) {
|
||||
return;
|
||||
}
|
||||
if (exclude.slice(-1) === '/') {
|
||||
return;
|
||||
}
|
||||
var depPromise = analyzer._getDependencies(exclude);
|
||||
depPromise.catch(function(err) {
|
||||
// include that this was an excluded url in the error message.
|
||||
err.message += '. Could not read dependencies for excluded URL: ' + exclude;
|
||||
});
|
||||
analyzedExcludes.push(depPromise);
|
||||
});
|
||||
return Promise.all(analyzedExcludes).then(function(strippedExcludes) {
|
||||
var dedupe = {};
|
||||
strippedExcludes.forEach(function(excludeList){
|
||||
excludeList.forEach(function(exclude) {
|
||||
dedupe[exclude] = true;
|
||||
});
|
||||
});
|
||||
return Object.keys(dedupe);
|
||||
});
|
||||
},
|
||||
|
||||
_process: function _process(target, cb) {
|
||||
var chain = Promise.resolve(true);
|
||||
if (this.implicitStrip && this.excludes) {
|
||||
chain = this.getImplicitExcludes(this.excludes).then(function(implicitExcludes) {
|
||||
implicitExcludes.forEach(function(strippedExclude) {
|
||||
this.stripExcludes.push(strippedExclude);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
var analyzer = new hyd.Analyzer(true, this.loader);
|
||||
chain = chain.then(function(){
|
||||
return analyzer.metadataTree(target);
|
||||
}).then(function(tree) {
|
||||
var flatDoc = this.flatten(tree);
|
||||
// make sure there's a <meta charset> in the page to force UTF-8
|
||||
var meta = dom5.query(flatDoc, matchers.meta);
|
||||
var head = dom5.query(flatDoc, matchers.head);
|
||||
for (var i = 0; i < this.addedImports.length; i++) {
|
||||
var newImport = dom5.constructors.element('link');
|
||||
dom5.setAttribute(newImport, 'rel', 'import');
|
||||
dom5.setAttribute(newImport, 'href', this.addedImports[i]);
|
||||
this.prepend(head, newImport);
|
||||
}
|
||||
if (!meta) {
|
||||
meta = dom5.constructors.element('meta');
|
||||
dom5.setAttribute(meta, 'charset', 'UTF-8');
|
||||
this.prepend(head, meta);
|
||||
}
|
||||
return {doc: flatDoc, href: tree.href};
|
||||
}.bind(this));
|
||||
if (this.enableScriptInlining) {
|
||||
chain = chain.then(function(docObj) {
|
||||
return this.inlineScripts(docObj.doc, docObj.href);
|
||||
}.bind(this));
|
||||
}
|
||||
if (this.enableCssInlining) {
|
||||
chain = chain.then(function(docObj) {
|
||||
return this.inlineCss(docObj.doc, docObj.href);
|
||||
}.bind(this));
|
||||
}
|
||||
if (this.stripComments) {
|
||||
chain = chain.then(function(docObj) {
|
||||
var comments = new CommentMap();
|
||||
var doc = docObj.doc;
|
||||
var head = dom5.query(doc, matchers.head);
|
||||
// remove all comments
|
||||
dom5.nodeWalkAll(doc, dom5.isCommentNode).forEach(function(comment) {
|
||||
comments.set(comment.data, comment);
|
||||
dom5.remove(comment);
|
||||
});
|
||||
// Deduplicate license comments
|
||||
comments.keys().forEach(function (commentData) {
|
||||
if (commentData.indexOf("@license") == -1) {
|
||||
return;
|
||||
}
|
||||
this.prepend(head, comments.get(commentData));
|
||||
}, this);
|
||||
return docObj;
|
||||
}.bind(this));
|
||||
}
|
||||
chain.then(function(docObj) {
|
||||
cb(null, dom5.serialize(docObj.doc));
|
||||
}).catch(cb);
|
||||
},
|
||||
|
||||
process: function process(target, cb) {
|
||||
if (this.inputUrl) {
|
||||
this._process(this.inputUrl, cb);
|
||||
} else {
|
||||
if (this.abspath) {
|
||||
target = pathPosix.resolve('/', target);
|
||||
} else {
|
||||
target = this.pathResolver.pathToUrl(path.resolve(target));
|
||||
}
|
||||
this._process(target, cb);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Vulcan.process = function process(target, cb) {
|
||||
singleton.process(target, cb);
|
||||
};
|
||||
|
||||
Vulcan.setOptions = function setOptions(opts) {
|
||||
singleton = new Vulcan(opts);
|
||||
};
|
||||
|
||||
module.exports = Vulcan;
|
||||
Reference in New Issue
Block a user