Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2045)

Unified Diff: node_modules/vulcanize/lib/vulcan.js

Issue 800513006: Added vulcanize under third_party/npm_modules (Closed) Base URL: https://chromium.googlesource.com/infra/third_party/npm_modules.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « node_modules/vulcanize/lib/utils.js ('k') | node_modules/vulcanize/node_modules/.bin/nopt » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: node_modules/vulcanize/lib/vulcan.js
diff --git a/node_modules/vulcanize/lib/vulcan.js b/node_modules/vulcanize/lib/vulcan.js
new file mode 100644
index 0000000000000000000000000000000000000000..0d7e230add04c5c206444bfe6264e4081cdbedcf
--- /dev/null
+++ b/node_modules/vulcanize/lib/vulcan.js
@@ -0,0 +1,356 @@
+/**
+ * @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 cssom = require('cssom');
+var fs = require('fs');
+var path = require('path');
+var uglify = require('uglify-js');
+var url = require('url');
+var whacko = require('whacko');
+
+var constants = require('./constants.js');
+var optparser = require('./optparser.js');
+var pathresolver = require('./pathresolver');
+var utils = require('./utils');
+var setTextContent = utils.setTextContent;
+var getTextContent = utils.getTextContent;
+var searchAll = utils.searchAll;
+
+var read = {};
+var options = {};
+
+// validate options with boolean return
+function setOptions(optHash, callback) {
+ optparser.processOptions(optHash, function(err, o) {
+ if (err) {
+ return callback(err);
+ }
+ options = o;
+ callback();
+ });
+}
+
+function exclude(regexes, href) {
+ return regexes.some(function(r) {
+ return r.test(href);
+ });
+}
+
+function excludeImport(href) {
+ return exclude(options.excludes.imports, href);
+}
+
+function excludeScript(href) {
+ return exclude(options.excludes.scripts, href);
+}
+
+function excludeStyle(href) {
+ return exclude(options.excludes.styles, href);
+}
+
+function readFile(file) {
+ var content = fs.readFileSync(file, 'utf8');
+ return content.replace(/^\uFEFF/, '');
+}
+
+// inline relative linked stylesheets into <style> tags
+function inlineSheets($, inputPath, outputPath) {
+ searchAll($, 'link[rel="stylesheet"]').each(function() {
+ var el = $(this);
+ var href = el.attr('href');
+ if (href && !excludeStyle(href)) {
+
+ var rel = href;
+ var inputPath = path.dirname(options.input);
+ if (constants.ABS_URL.test(rel)) {
+ var abs = path.resolve(inputPath, path.join(options.abspath, rel));
+ rel = path.relative(options.outputDir, abs);
+ }
+
+ var filepath = path.resolve(options.outputDir, rel);
+ // fix up paths in the stylesheet to be relative to the location of the style
+ var content = pathresolver.rewriteURL(path.dirname(filepath), outputPath, readFile(filepath));
+ var styleEl = whacko('<style>' + content + '</style>');
+ // clone attributes
+ styleEl.attr(el.attr());
+ // don't set href or rel on the <style>
+ styleEl.attr('href', null);
+ styleEl.attr('rel', null);
+ el.replaceWith(whacko.html(styleEl));
+ }
+ });
+}
+
+function inlineScripts($, dir) {
+ searchAll($, constants.JS_SRC).each(function() {
+ var el = $(this);
+ var src = el.attr('src');
+ if (src && !excludeScript(src)) {
+
+ var rel = src;
+ var inputPath = path.dirname(options.input);
+ if (constants.ABS_URL.test(rel)) {
+ var abs = path.resolve(inputPath, path.join(options.abspath, rel));
+ rel = path.relative(options.outputDir, abs);
+ }
+
+ var filepath = path.resolve(dir, rel);
+ var content = readFile(filepath);
+ // NOTE: reusing UglifyJS's inline script printer (not exported from OutputStream :/)
+ content = content.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
+ el.replaceWith('<script>' + content + '</script>');
+ }
+ });
+}
+
+function concat(filename) {
+ if (!read[filename]) {
+ read[filename] = true;
+ var $ = whacko.load(readFile(filename));
+ var dir = path.dirname(filename);
+ pathresolver.resolvePaths($, dir, options.outputDir, options.abspath);
+ processImports($);
+ inlineSheets($, dir, options.outputDir);
+ return $;
+ } else if (options.verbose) {
+ console.log('Dependency deduplicated');
+ }
+}
+
+function processImports($, mainDoc) {
+ var bodyContent = [];
+ searchAll($, constants.IMPORTS).each(function() {
+ var el = $(this);
+ var href = el.attr('href');
+ if (!excludeImport(href)) {
+ var rel = href;
+ var inputPath = path.dirname(options.input);
+ if (constants.ABS_URL.test(rel)) {
+ var abs = path.resolve(inputPath, path.join(options.abspath, rel));
+ rel = path.relative(options.outputDir, abs);
+ }
+ var $$ = concat(path.resolve(options.outputDir, rel));
+ if (!$$) {
+ // remove import link
+ el.remove();
+ return;
+ }
+ // append import document head to main document head
+ el.replaceWith($$('head').html());
+ var bodyHTML = $$('body').html();
+ // keep the ordering of the import body in main document, before main document's body
+ bodyContent.push(bodyHTML);
+ } else if (!options.keepExcludes) {
+ // if the path is excluded for being absolute, then the import link must remain
+ var absexclude = options.abspath ? constants.REMOTE_ABS_URL : constants.ABS_URL;
+ if (!absexclude.test(href)) {
+ el.remove();
+ }
+ }
+ });
+ // prepend the import document body contents to the main document, in order
+ var content = bodyContent.join('\n');
+ // hide import body content in the main document
+ if (mainDoc && content) {
+ content = '<div hidden>' + content + '</div>';
+ }
+ $('body').prepend(content);
+}
+
+function findScriptLocation($) {
+ var pos = $('body').last();
+ if (!pos.length) {
+ pos = $.root();
+ }
+ return pos;
+}
+
+function isCommentOrEmptyTextNode(node) {
+ if (node.type === 'comment'){
+ return true;
+ } else if (node.type === 'text') {
+ // return true if the node is only whitespace
+ return !((/\S/).test(node.data));
+ }
+}
+
+function compressJS(content, inline) {
+ try {
+ var ast = uglify.parse(content);
+ return ast.print_to_string({inline_script: inline});
+ } catch (e) {
+ // return a useful error
+ var js_err = new Error('Compress JS Error');
+ js_err.detail = e.message + ' at line: ' + e.line + ' col: ' + e.col;
+ js_err.content = content;
+ js_err.toString = function() {
+ return this.message + '\n' + this.detail + '\n' + this.content;
+ };
+ throw js_err;
+ }
+}
+
+function compressCSS(content) {
+ var out;
+ try {
+ var ast = cssom.parse(content);
+ out = ast.toString();
+ } catch (e) {
+ if (options.verbose) {
+ console.log('Error parsing CSS:', e.toString());
+ console.log('Falling back to removing newlines only');
+ }
+ out = content;
+ } finally {
+ return out.replace(/[\r\n]/g, '');
+ }
+}
+
+function removeCommentsAndWhitespace($) {
+ function walk(node) {
+ var content, c;
+ if (!node) {
+ return;
+ } else if (isCommentOrEmptyTextNode(node)) {
+ $(node).remove();
+ return true;
+ } else if (node.type == 'script') {
+ // only run uglify on inline javascript scripts
+ if (!node.attribs.src && (!node.attribs.type || node.attribs.type == "text/javascript")) {
+ content = getTextContent(node);
+ setTextContent(node, compressJS(content, true));
+ }
+ } else if (node.type == 'style') {
+ content = getTextContent(node);
+ setTextContent(node, compressCSS(content));
+ } else if ((c = node.children)) {
+ for (var i = 0; i < c.length; i++) {
+ // since .remove() will modify this array, decrement `i` on successful comment removal
+ if (walk(c[i])) {
+ i--;
+ }
+ }
+ }
+ }
+
+ // walk the whole AST from root
+ walk($.root().get(0));
+}
+
+function writeFileSync(filename, data, eop) {
+ if (!options.outputHandler) {
+ fs.writeFileSync(filename, data, 'utf8');
+ } else {
+ options.outputHandler(filename, data, eop);
+ }
+}
+
+function handleMainDocument() {
+ // reset shared buffers
+ read = {};
+ var content = options.inputSrc ? options.inputSrc.toString() : readFile(options.input);
+ var $ = whacko.load(content);
+ var dir = path.dirname(options.input);
+ pathresolver.resolvePaths($, dir, options.outputDir, options.abspath);
+ processImports($, true);
+ if (options.inline) {
+ inlineSheets($, dir, options.outputDir);
+ }
+
+ if (options.inline) {
+ inlineScripts($, options.outputDir);
+ }
+
+ searchAll($, constants.JS_INLINE).each(function() {
+ var el = $(this);
+ var content = getTextContent(el);
+ // find ancestor polymer-element node
+ var parentElement = el.closest('polymer-element').get(0);
+ if (parentElement) {
+ var match = constants.POLYMER_INVOCATION.exec(content);
+ var elementName = $(parentElement).attr('name');
+ if (match) {
+ var invocation = utils.processPolymerInvocation(elementName, match);
+ content = content.replace(match[0], invocation);
+ setTextContent(el, content);
+ }
+ }
+ });
+
+ // strip noscript from elements, and instead inject explicit Polymer() invocation
+ // script, so registration order is preserved
+ searchAll($, constants.ELEMENTS_NOSCRIPT).each(function() {
+ var el = $(this);
+ var name = el.attr('name');
+ if (options.verbose) {
+ console.log('Injecting explicit Polymer invocation for noscript element "' + name + '"');
+ }
+ el.append('<script>Polymer(\'' + name + '\');</script>');
+ el.attr('noscript', null);
+ });
+
+ // strip scripts into a separate file
+ if (options.csp) {
+ if (options.verbose) {
+ console.log('Separating scripts into separate file');
+ }
+
+ // CSPify main page by removing inline scripts
+ var scripts = [];
+ searchAll($, constants.JS_INLINE).each(function() {
+ var el = $(this);
+ var content = getTextContent(el);
+ scripts.push(content);
+ el.remove();
+ });
+
+ // join scripts with ';' to prevent breakages due to EOF semicolon insertion
+ var scriptName = path.basename(options.output, '.html') + '.js';
+ var scriptContent = scripts.join(';' + constants.EOL);
+ if (options.strip) {
+ scriptContent = compressJS(scriptContent, false);
+ }
+
+ writeFileSync(path.resolve(options.outputDir, scriptName), scriptContent);
+ // insert out-of-lined script into document
+ findScriptLocation($).append('<script charset="utf-8" src="' + scriptName + '"></script>');
+ }
+
+ deduplicateImports($);
+
+ if (options.strip) {
+ removeCommentsAndWhitespace($);
+ }
+
+ writeFileSync(options.output, $.html(), true);
+}
+
+function deduplicateImports($) {
+ var imports = {};
+ searchAll($, constants.IMPORTS).each(function() {
+ var el = $(this);
+ var href = el.attr('href');
+ // TODO(dfreedm): allow a user defined base url?
+ var abs = url.resolve('http://', href);
+ if (!imports[abs]) {
+ imports[abs] = true;
+ } else {
+ if(options.verbose) {
+ console.log('Import Dependency deduplicated');
+ }
+ el.remove();
+ }
+ });
+}
+
+exports.processDocument = handleMainDocument;
+exports.setOptions = setOptions;
« no previous file with comments | « node_modules/vulcanize/lib/utils.js ('k') | node_modules/vulcanize/node_modules/.bin/nopt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698