first commit
This commit is contained in:
773
build/node_modules/hydrolysis/lib/analyzer.js
generated
vendored
Normal file
773
build/node_modules/hydrolysis/lib/analyzer.js
generated
vendored
Normal file
@@ -0,0 +1,773 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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';
|
||||
// jshint -W079
|
||||
var Promise = global.Promise || require('es6-promise').Promise;
|
||||
// jshint +W079
|
||||
|
||||
var dom5 = require('dom5');
|
||||
var url = require('url');
|
||||
|
||||
var docs = require('./ast-utils/docs');
|
||||
var FileLoader = require('./loader/file-loader');
|
||||
var importParse = require('./ast-utils/import-parse');
|
||||
var jsParse = require('./ast-utils/js-parse');
|
||||
var NoopResolver = require('./loader/noop-resolver');
|
||||
var StringResolver = require('./loader/string-resolver');
|
||||
|
||||
function reduceMetadata(m1, m2) {
|
||||
return {
|
||||
elements: m1.elements.concat(m2.elements),
|
||||
features: m1.features.concat(m2.features),
|
||||
behaviors: m1.behaviors.concat(m2.behaviors),
|
||||
};
|
||||
}
|
||||
|
||||
var EMPTY_METADATA = {elements: [], features: [], behaviors: []};
|
||||
|
||||
/**
|
||||
* Parse5's representation of a parsed html document
|
||||
* @typedef {Object} DocumentAST
|
||||
* @memberof hydrolysis
|
||||
*/
|
||||
|
||||
/**
|
||||
* espree's representation of a parsed html document
|
||||
* @typedef {Object} JSAST
|
||||
* @memberof hydrolysis
|
||||
*/
|
||||
|
||||
/**
|
||||
* Package of a parsed JS script
|
||||
* @typedef {Object} ParsedJS
|
||||
* @property {JSAST} ast The script's AST
|
||||
* @property {DocumentAST} scriptElement If inline, the script's containing tag.
|
||||
* @memberof hydrolysis
|
||||
*/
|
||||
|
||||
/**
|
||||
* The metadata for a single polymer element
|
||||
* @typedef {Object} ElementDescriptor
|
||||
* @memberof hydrolysis
|
||||
*/
|
||||
|
||||
/**
|
||||
* The metadata for a Polymer feature.
|
||||
* @typedef {Object} FeatureDescriptor
|
||||
* @memberof hydrolysis
|
||||
*/
|
||||
|
||||
/**
|
||||
* The metadata for a Polymer behavior mixin.
|
||||
* @typedef {Object} BehaviorDescriptor
|
||||
* @memberof hydrolysis
|
||||
*/
|
||||
|
||||
/**
|
||||
* The metadata for all features and elements defined in one document
|
||||
* @typedef {Object} DocumentDescriptor
|
||||
* @memberof hydrolysis
|
||||
* @property {Array<ElementDescriptor>} elements The elements from the document
|
||||
* @property {Array<FeatureDescriptor>} features The features from the document
|
||||
* @property {Array<FeatureDescriptor>} behaviors The behaviors from the document
|
||||
*/
|
||||
|
||||
/**
|
||||
* The metadata of an entire HTML document, in promises.
|
||||
* @typedef {Object} AnalyzedDocument
|
||||
* @memberof hydrolysis
|
||||
* @property {string} href The url of the document.
|
||||
* @property {Promise<ParsedImport>} htmlLoaded The parsed representation of
|
||||
* the doc. Use the `ast` property to get the full `parse5` ast
|
||||
*
|
||||
* @property {Promise<Array<string>>} depsLoaded Resolves to the list of this
|
||||
* Document's transitive import dependencies
|
||||
*
|
||||
* @property {Array<string>} depHrefs The direct dependencies of the document.
|
||||
*
|
||||
* @property {Promise<DocumentDescriptor>} metadataLoaded Resolves to the list of
|
||||
* this Document's import dependencies
|
||||
*/
|
||||
|
||||
/**
|
||||
* A database of Polymer metadata defined in HTML
|
||||
*
|
||||
* @constructor
|
||||
* @memberOf hydrolysis
|
||||
* @param {boolean} attachAST If true, attach a parse5 compliant AST
|
||||
* @param {FileLoader=} loader An optional `FileLoader` used to load external
|
||||
* resources
|
||||
*/
|
||||
var Analyzer = function Analyzer(attachAST,
|
||||
loader) {
|
||||
this.loader = loader;
|
||||
|
||||
/**
|
||||
* A list of all elements the `Analyzer` has metadata for.
|
||||
* @member {Array.<ElementDescriptor>}
|
||||
*/
|
||||
this.elements = [];
|
||||
|
||||
/**
|
||||
* A view into `elements`, keyed by tag name.
|
||||
* @member {Object.<string,ElementDescriptor>}
|
||||
*/
|
||||
this.elementsByTagName = {};
|
||||
|
||||
/**
|
||||
* A list of API features added to `Polymer.Base` encountered by the
|
||||
* analyzer.
|
||||
* @member {Array<FeatureDescriptor>}
|
||||
*/
|
||||
this.features = [];
|
||||
|
||||
/**
|
||||
* The behaviors collected by the analysis pass.
|
||||
*
|
||||
* @member {Array<BehaviorDescriptor>}
|
||||
*/
|
||||
this.behaviors = [];
|
||||
|
||||
/**
|
||||
* The behaviors collected by the analysis pass by name.
|
||||
*
|
||||
* @member {Object<string,BehaviorDescriptor>}
|
||||
*/
|
||||
this.behaviorsByName = {};
|
||||
|
||||
/**
|
||||
* A map, keyed by absolute path, of Document metadata.
|
||||
* @member {Object<string,AnalyzedDocument>}
|
||||
*/
|
||||
this.html = {};
|
||||
|
||||
/**
|
||||
* A map, keyed by path, of HTML document ASTs.
|
||||
* @type {Object}
|
||||
*/
|
||||
this.parsedDocuments = {};
|
||||
|
||||
/**
|
||||
* A map, keyed by path, of JS script ASTs.
|
||||
*
|
||||
* If the path is an HTML file with multiple scripts, the entry will be an array of scripts.
|
||||
*
|
||||
* @type {Object<string,Array<ParsedJS>>}
|
||||
*/
|
||||
this.parsedScripts = {};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A map, keyed by path, of document content.
|
||||
* @type {Object}
|
||||
*/
|
||||
this._content = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Options for `Analyzer.analzye`
|
||||
* @typedef {Object} LoadOptions
|
||||
* @memberof hydrolysis
|
||||
* @property {boolean} noAnnotations Whether `annotate()` should be skipped.
|
||||
* @property {String=} content Content to resolve `href` to instead of loading
|
||||
* from the file system.
|
||||
* @property {boolean} clean Whether the generated descriptors should be cleaned
|
||||
* of redundant data.
|
||||
* @property {string=} resolver.
|
||||
* `xhr` to use XMLHttpRequest
|
||||
* `fs` to use the local filesystem.
|
||||
* `permissive` to use the local filesystem and return empty files when a
|
||||
* path can't be found.
|
||||
* Default is `fs` in node and `xhr` in the browser.
|
||||
* @property {function(string): boolean} filter A predicate function that
|
||||
* indicates which files should be ignored by the loader. By default all
|
||||
* files not located under the dirname of `href` will be ignored.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Shorthand for transitively loading and processing all imports beginning at
|
||||
* `href`.
|
||||
*
|
||||
* In order to properly filter paths, `href` _must_ be an absolute URI.
|
||||
*
|
||||
* @param {string} href The root import to begin loading from.
|
||||
* @param {LoadOptions=} options Any additional options for the load.
|
||||
* @return {Promise<Analyzer>} A promise that will resolve once `href` and its
|
||||
* dependencies have been loaded and analyzed.
|
||||
*/
|
||||
Analyzer.analyze = function analyze(href, options) {
|
||||
options = options || {};
|
||||
options.filter = options.filter || _defaultFilter(href);
|
||||
|
||||
var loader = new FileLoader();
|
||||
|
||||
var resolver = options.resolver;
|
||||
if (resolver === undefined) {
|
||||
if (typeof window === 'undefined') {
|
||||
resolver = 'fs';
|
||||
} else {
|
||||
resolver = 'xhr';
|
||||
}
|
||||
}
|
||||
var PrimaryResolver;
|
||||
if (resolver === 'fs') {
|
||||
PrimaryResolver = require('./loader/fs-resolver');
|
||||
} else if (resolver === 'xhr') {
|
||||
PrimaryResolver = require('./loader/xhr-resolver');
|
||||
} else if (resolver === 'permissive') {
|
||||
PrimaryResolver = require('./loader/error-swallowing-fs-resolver');
|
||||
} else {
|
||||
throw new Error("Resolver must be one of 'fs' or 'xhr'");
|
||||
}
|
||||
|
||||
loader.addResolver(new PrimaryResolver(options));
|
||||
if (options.content) {
|
||||
loader.addResolver(new StringResolver({url: href, content: options.content}));
|
||||
}
|
||||
loader.addResolver(new NoopResolver({test: options.filter}));
|
||||
|
||||
var analyzer = new this(null, loader);
|
||||
return analyzer.metadataTree(href).then(function(root) {
|
||||
if (!options.noAnnotations) {
|
||||
analyzer.annotate();
|
||||
}
|
||||
if (options.clean) {
|
||||
analyzer.clean();
|
||||
}
|
||||
return Promise.resolve(analyzer);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} href
|
||||
* @return {function(string): boolean}
|
||||
*/
|
||||
function _defaultFilter(href) {
|
||||
// Everything up to the last `/` or `\`.
|
||||
var base = href.match(/^(.*?)[^\/\\]*$/)[1];
|
||||
return function(uri) {
|
||||
return uri.indexOf(base) !== 0;
|
||||
};
|
||||
}
|
||||
|
||||
Analyzer.prototype.load = function load(href) {
|
||||
return this.loader.request(href).then(function(content) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
setTimeout(function() {
|
||||
this._content[href] = content;
|
||||
resolve(this._parseHTML(content, href));
|
||||
}.bind(this), 0);
|
||||
}.bind(this)).catch(function(err){
|
||||
console.error("Error processing document at " + href);
|
||||
throw err;
|
||||
});
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an `AnalyzedDocument` representing the provided document
|
||||
* @private
|
||||
* @param {string} htmlImport Raw text of an HTML document
|
||||
* @param {string} href The document's URL.
|
||||
* @return {AnalyzedDocument} An `AnalyzedDocument`
|
||||
*/
|
||||
Analyzer.prototype._parseHTML = function _parseHTML(htmlImport,
|
||||
href) {
|
||||
if (href in this.html) {
|
||||
return this.html[href];
|
||||
}
|
||||
var depsLoaded = [];
|
||||
var depHrefs = [];
|
||||
var metadataLoaded = Promise.resolve(EMPTY_METADATA);
|
||||
var parsed;
|
||||
try {
|
||||
parsed = importParse(htmlImport, href);
|
||||
} catch (err) {
|
||||
console.error('Error parsing!');
|
||||
throw err;
|
||||
}
|
||||
var htmlLoaded = Promise.resolve(parsed);
|
||||
if (parsed.script) {
|
||||
metadataLoaded = this._processScripts(parsed.script, href);
|
||||
}
|
||||
var commentText = parsed.comment.map(function(comment){
|
||||
return dom5.getTextContent(comment);
|
||||
});
|
||||
var pseudoElements = docs.parsePseudoElements(commentText);
|
||||
pseudoElements.forEach(function(element){
|
||||
element.contentHref = href;
|
||||
this.elements.push(element);
|
||||
this.elementsByTagName[element.is] = element;
|
||||
}.bind(this));
|
||||
metadataLoaded = metadataLoaded.then(function(metadata){
|
||||
var metadataEntry = {
|
||||
elements: pseudoElements,
|
||||
features: [],
|
||||
behaviors: []
|
||||
};
|
||||
return [metadata, metadataEntry].reduce(reduceMetadata);
|
||||
});
|
||||
depsLoaded.push(metadataLoaded);
|
||||
|
||||
|
||||
if (this.loader) {
|
||||
var baseUri = href;
|
||||
if (parsed.base.length > 1) {
|
||||
console.error("Only one base tag per document!");
|
||||
throw "Multiple base tags in " + href;
|
||||
} else if (parsed.base.length == 1) {
|
||||
var baseHref = dom5.getAttribute(parsed.base[0], "href");
|
||||
if (baseHref) {
|
||||
baseHref = baseHref + "/";
|
||||
baseUri = url.resolve(baseUri, baseHref);
|
||||
}
|
||||
}
|
||||
parsed.import.forEach(function(link) {
|
||||
var linkurl = dom5.getAttribute(link, 'href');
|
||||
if (linkurl) {
|
||||
var resolvedUrl = url.resolve(baseUri, linkurl);
|
||||
depHrefs.push(resolvedUrl);
|
||||
depsLoaded.push(this._dependenciesLoadedFor(resolvedUrl, href));
|
||||
}
|
||||
}.bind(this));
|
||||
parsed.style.forEach(function(styleElement) {
|
||||
if (polymerExternalStyle(styleElement)) {
|
||||
var styleHref = dom5.getAttribute(styleElement, 'href');
|
||||
if (href) {
|
||||
styleHref = url.resolve(baseUri, styleHref);
|
||||
depsLoaded.push(this.loader.request(styleHref).then(function(content){
|
||||
this._content[styleHref] = content;
|
||||
}.bind(this)));
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
depsLoaded = Promise.all(depsLoaded)
|
||||
.then(function() {return depHrefs;})
|
||||
.catch(function(err) {throw err;});
|
||||
this.parsedDocuments[href] = parsed.ast;
|
||||
this.html[href] = {
|
||||
href: href,
|
||||
htmlLoaded: htmlLoaded,
|
||||
metadataLoaded: metadataLoaded,
|
||||
depHrefs: depHrefs,
|
||||
depsLoaded: depsLoaded
|
||||
};
|
||||
return this.html[href];
|
||||
};
|
||||
|
||||
Analyzer.prototype._processScripts = function _processScripts(scripts, href) {
|
||||
var scriptPromises = [];
|
||||
scripts.forEach(function(script) {
|
||||
scriptPromises.push(this._processScript(script, href));
|
||||
}.bind(this));
|
||||
return Promise.all(scriptPromises).then(function(metadataList) {
|
||||
return metadataList.reduce(reduceMetadata, EMPTY_METADATA);
|
||||
});
|
||||
};
|
||||
|
||||
Analyzer.prototype._processScript = function _processScript(script, href) {
|
||||
var src = dom5.getAttribute(script, 'src');
|
||||
var parsedJs;
|
||||
if (!src) {
|
||||
try {
|
||||
parsedJs = jsParse((script.childNodes.length) ? script.childNodes[0].value : '');
|
||||
} catch (err) {
|
||||
// Figure out the correct line number for the error.
|
||||
var line = 0;
|
||||
var col = 0;
|
||||
if (script.__ownerDocument && script.__ownerDocument == href) {
|
||||
line = script.__locationDetail.line - 1;
|
||||
col = script.__locationDetail.column - 1;
|
||||
}
|
||||
line += err.lineNumber;
|
||||
col += err.column;
|
||||
var message = "Error parsing script in " + href + " at " + line + ":" + col;
|
||||
message += "\n" + err.stack;
|
||||
var fixedErr = new Error(message);
|
||||
fixedErr.location = {line: line, column: col};
|
||||
fixedErr.ownerDocument = script.__ownerDocument;
|
||||
return Promise.reject(fixedErr);
|
||||
}
|
||||
if (parsedJs.elements) {
|
||||
parsedJs.elements.forEach(function(element) {
|
||||
element.scriptElement = script;
|
||||
element.contentHref = href;
|
||||
this.elements.push(element);
|
||||
if (element.is in this.elementsByTagName) {
|
||||
console.warn('Ignoring duplicate element definition: ' + element.is);
|
||||
} else {
|
||||
this.elementsByTagName[element.is] = element;
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
if (parsedJs.features) {
|
||||
parsedJs.features.forEach(function(feature){
|
||||
feature.contentHref = href;
|
||||
feature.scriptElement = script;
|
||||
});
|
||||
this.features = this.features.concat(parsedJs.features);
|
||||
}
|
||||
if (parsedJs.behaviors) {
|
||||
parsedJs.behaviors.forEach(function(behavior){
|
||||
behavior.contentHref = href;
|
||||
this.behaviorsByName[behavior.is] = behavior;
|
||||
this.behaviorsByName[behavior.symbol] = behavior;
|
||||
}.bind(this));
|
||||
this.behaviors = this.behaviors.concat(parsedJs.behaviors);
|
||||
}
|
||||
if (!Object.hasOwnProperty.call(this.parsedScripts, href)) {
|
||||
this.parsedScripts[href] = [];
|
||||
}
|
||||
var scriptElement;
|
||||
if (script.__ownerDocument && script.__ownerDocument == href) {
|
||||
scriptElement = script;
|
||||
}
|
||||
this.parsedScripts[href].push({
|
||||
ast: parsedJs.parsedScript,
|
||||
scriptElement: scriptElement
|
||||
});
|
||||
return parsedJs;
|
||||
}
|
||||
if (this.loader) {
|
||||
var resolvedSrc = url.resolve(href, src);
|
||||
return this.loader.request(resolvedSrc).then(function(content) {
|
||||
this._content[resolvedSrc] = content;
|
||||
var resolvedScript = Object.create(script);
|
||||
resolvedScript.childNodes = [{value: content}];
|
||||
resolvedScript.attrs = resolvedScript.attrs.slice();
|
||||
dom5.removeAttribute(resolvedScript, 'src');
|
||||
return this._processScript(resolvedScript, resolvedSrc);
|
||||
}.bind(this)).catch(function(err) {throw err;});
|
||||
} else {
|
||||
return Promise.resolve(EMPTY_METADATA);
|
||||
}
|
||||
};
|
||||
|
||||
Analyzer.prototype._dependenciesLoadedFor = function _dependenciesLoadedFor(href, root) {
|
||||
var found = {};
|
||||
if (root !== undefined) {
|
||||
found[root] = true;
|
||||
}
|
||||
return this._getDependencies(href, found).then(function(deps) {
|
||||
var depMetadataLoaded = [];
|
||||
var depPromises = deps.map(function(depHref){
|
||||
return this.load(depHref).then(function(htmlMonomer) {
|
||||
return htmlMonomer.metadataLoaded;
|
||||
});
|
||||
}.bind(this));
|
||||
return Promise.all(depPromises);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* List all the html dependencies for the document at `href`.
|
||||
* @param {string} href The href to get dependencies for.
|
||||
* @param {Object.<string,boolean>=} found An object keyed by URL of the
|
||||
* already resolved dependencies.
|
||||
* @param {boolean=} transitive Whether to load transitive
|
||||
* dependencies. Defaults to true.
|
||||
* @return {Array.<string>} A list of all the html dependencies.
|
||||
*/
|
||||
Analyzer.prototype._getDependencies = function _getDependencies(href, found, transitive) {
|
||||
if (found === undefined) {
|
||||
found = {};
|
||||
found[href] = true;
|
||||
}
|
||||
if (transitive === undefined) {
|
||||
transitive = true;
|
||||
}
|
||||
var deps = [];
|
||||
return this.load(href).then(function(htmlMonomer) {
|
||||
var transitiveDeps = [];
|
||||
htmlMonomer.depHrefs.forEach(function(depHref){
|
||||
if (found[depHref]) {
|
||||
return;
|
||||
}
|
||||
deps.push(depHref);
|
||||
found[depHref] = true;
|
||||
if (transitive) {
|
||||
transitiveDeps.push(this._getDependencies(depHref, found));
|
||||
}
|
||||
}.bind(this));
|
||||
return Promise.all(transitiveDeps);
|
||||
}.bind(this)).then(function(transitiveDeps) {
|
||||
var alldeps = transitiveDeps.reduce(function(a, b) {
|
||||
return a.concat(b);
|
||||
}, []).concat(deps);
|
||||
return alldeps;
|
||||
});
|
||||
};
|
||||
|
||||
function matchesDocumentFolder(descriptor, href) {
|
||||
if (!descriptor.contentHref) {
|
||||
return false;
|
||||
}
|
||||
var descriptorDoc = url.parse(descriptor.contentHref);
|
||||
if (!descriptorDoc || !descriptorDoc.pathname) {
|
||||
return false;
|
||||
}
|
||||
var searchDoc = url.parse(href);
|
||||
if (!searchDoc || !searchDoc.pathname) {
|
||||
return false;
|
||||
}
|
||||
var searchPath = searchDoc.pathname;
|
||||
var lastSlash = searchPath.lastIndexOf("/");
|
||||
if (lastSlash > 0) {
|
||||
searchPath = searchPath.slice(0, lastSlash);
|
||||
}
|
||||
return descriptorDoc.pathname.indexOf(searchPath) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the elements defined in the folder containing `href`.
|
||||
* @param {string} href path to search.
|
||||
* @return {Array.<ElementDescriptor>}
|
||||
*/
|
||||
Analyzer.prototype.elementsForFolder = function elementsForFolder(href) {
|
||||
return this.elements.filter(function(element){
|
||||
return matchesDocumentFolder(element, href);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the behaviors defined in the folder containing `href`.
|
||||
* @param {string} href path to search.
|
||||
* @return {Array.<BehaviorDescriptor>}
|
||||
*/
|
||||
Analyzer.prototype.behaviorsForFolder = function behaviorsForFolder(href) {
|
||||
return this.behaviors.filter(function(behavior){
|
||||
return matchesDocumentFolder(behavior, href);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a promise that resolves to a POJO representation of the import
|
||||
* tree, in a format that maintains the ordering of the HTML imports spec.
|
||||
* @param {string} href the import to get metadata for.
|
||||
* @return {Promise}
|
||||
*/
|
||||
Analyzer.prototype.metadataTree = function metadataTree(href) {
|
||||
return this.load(href).then(function(monomer){
|
||||
var loadedHrefs = {};
|
||||
loadedHrefs[href] = true;
|
||||
return this._metadataTree(monomer, loadedHrefs);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Analyzer.prototype._metadataTree = function _metadataTree(htmlMonomer,
|
||||
loadedHrefs) {
|
||||
if (loadedHrefs === undefined) {
|
||||
loadedHrefs = {};
|
||||
}
|
||||
return htmlMonomer.metadataLoaded.then(function(metadata) {
|
||||
metadata = {
|
||||
elements: metadata.elements,
|
||||
features: metadata.features,
|
||||
href: htmlMonomer.href
|
||||
};
|
||||
return htmlMonomer.depsLoaded.then(function(hrefs) {
|
||||
var depMetadata = [];
|
||||
hrefs.forEach(function(href) {
|
||||
var metadataPromise = Promise.resolve(true);
|
||||
if (depMetadata.length > 0) {
|
||||
metadataPromise = depMetadata[depMetadata.length - 1];
|
||||
}
|
||||
metadataPromise = metadataPromise.then(function() {
|
||||
if (!loadedHrefs[href]) {
|
||||
loadedHrefs[href] = true;
|
||||
return this._metadataTree(this.html[href], loadedHrefs);
|
||||
} else {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
}.bind(this));
|
||||
depMetadata.push(metadataPromise);
|
||||
}.bind(this));
|
||||
return Promise.all(depMetadata).then(function(importMetadata) {
|
||||
metadata.imports = importMetadata;
|
||||
return htmlMonomer.htmlLoaded.then(function(parsedHtml) {
|
||||
metadata.html = parsedHtml;
|
||||
if (metadata.elements) {
|
||||
metadata.elements.forEach(function(element) {
|
||||
attachDomModule(parsedHtml, element);
|
||||
});
|
||||
}
|
||||
return metadata;
|
||||
});
|
||||
});
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
function matchingImport(importElement) {
|
||||
var matchesTag = dom5.predicates.hasTagName(importElement.tagName);
|
||||
var matchesHref = dom5.predicates.hasAttrValue('href', dom5.getAttribute(importElement, 'href'));
|
||||
var matchesRel = dom5.predicates.hasAttrValue('rel', dom5.getAttribute(importElement, 'rel'));
|
||||
return dom5.predicates.AND(matchesTag, matchesHref, matchesRel);
|
||||
}
|
||||
|
||||
// TODO(ajo): Refactor out of vulcanize into dom5.
|
||||
var polymerExternalStyle = dom5.predicates.AND(
|
||||
dom5.predicates.hasTagName('link'),
|
||||
dom5.predicates.hasAttrValue('rel', 'import'),
|
||||
dom5.predicates.hasAttrValue('type', 'css')
|
||||
);
|
||||
|
||||
var externalScript = dom5.predicates.AND(
|
||||
dom5.predicates.hasTagName('script'),
|
||||
dom5.predicates.hasAttr('src')
|
||||
);
|
||||
|
||||
var isHtmlImportNode = dom5.predicates.AND(
|
||||
dom5.predicates.hasTagName('link'),
|
||||
dom5.predicates.hasAttrValue('rel', 'import'),
|
||||
dom5.predicates.NOT(
|
||||
dom5.predicates.hasAttrValue('type', 'css')
|
||||
)
|
||||
);
|
||||
|
||||
Analyzer.prototype._inlineStyles = function _inlineStyles(ast, href) {
|
||||
var cssLinks = dom5.queryAll(ast, polymerExternalStyle);
|
||||
cssLinks.forEach(function(link) {
|
||||
var linkHref = dom5.getAttribute(link, 'href');
|
||||
var uri = url.resolve(href, linkHref);
|
||||
var content = this._content[uri];
|
||||
var style = dom5.constructors.element('style');
|
||||
dom5.setTextContent(style, '\n' + content + '\n');
|
||||
dom5.replace(link, style);
|
||||
}.bind(this));
|
||||
return cssLinks.length > 0;
|
||||
};
|
||||
|
||||
Analyzer.prototype._inlineScripts = function _inlineScripts(ast, href) {
|
||||
var scripts = dom5.queryAll(ast, externalScript);
|
||||
scripts.forEach(function(script) {
|
||||
var scriptHref = dom5.getAttribute(script, 'src');
|
||||
var uri = url.resolve(href, scriptHref);
|
||||
var content = this._content[uri];
|
||||
var inlined = dom5.constructors.element('script');
|
||||
dom5.setTextContent(inlined, '\n' + content + '\n');
|
||||
dom5.replace(script, inlined);
|
||||
}.bind(this));
|
||||
return scripts.length > 0;
|
||||
};
|
||||
|
||||
Analyzer.prototype._inlineImports = function _inlineImports(ast, href, loaded) {
|
||||
var imports = dom5.queryAll(ast, isHtmlImportNode);
|
||||
imports.forEach(function(htmlImport) {
|
||||
var importHref = dom5.getAttribute(htmlImport, 'href');
|
||||
var uri = url.resolve(href, importHref);
|
||||
if (loaded[uri]) {
|
||||
dom5.remove(htmlImport);
|
||||
return;
|
||||
}
|
||||
var content = this.getLoadedAst(uri, loaded);
|
||||
dom5.replace(htmlImport, content);
|
||||
}.bind(this));
|
||||
return imports.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a promise resolving to a form of the AST with all links replaced
|
||||
* with the document they link to. .css and .script files become <style> and
|
||||
* <script>, respectively.
|
||||
*
|
||||
* The elements in the loaded document are unmodified from their original
|
||||
* documents.
|
||||
*
|
||||
* @param {string} href The document to load.
|
||||
* @param {Object.<string,boolean>=} loaded An object keyed by already loaded documents.
|
||||
* @return {Promise.<DocumentAST>}
|
||||
*/
|
||||
Analyzer.prototype.getLoadedAst = function getLoadedAst(href, loaded) {
|
||||
if (!loaded) {
|
||||
loaded = {};
|
||||
}
|
||||
loaded[href] = true;
|
||||
var parsedDocument = this.parsedDocuments[href];
|
||||
var analyzedDocument = this.html[href];
|
||||
var astCopy = dom5.parse(dom5.serialize(parsedDocument));
|
||||
// Whenever we inline something, reset inlined to true to know that anoather
|
||||
// inlining pass is needed;
|
||||
this._inlineStyles(astCopy, href);
|
||||
this._inlineScripts(astCopy, href);
|
||||
this._inlineImports(astCopy, href, loaded);
|
||||
return astCopy;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls `dom5.nodeWalkAll` on each document that `Anayzler` has laoded.
|
||||
* @param {Object} predicate A dom5 predicate.
|
||||
* @return {Object}
|
||||
*/
|
||||
Analyzer.prototype.nodeWalkDocuments = function nodeWalkDocuments(predicate) {
|
||||
for (var href in this.parsedDocuments) {
|
||||
var match = dom5.nodeWalk(this.parsedDocuments[href], predicate);
|
||||
if (match) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls `dom5.nodeWalkAll` on each document that `Anayzler` has laoded.
|
||||
* @param {Object} predicate A dom5 predicate.
|
||||
* @return {Object}
|
||||
*/
|
||||
Analyzer.prototype.nodeWalkAllDocuments = function nodeWalkDocuments(predicate) {
|
||||
var results = [];
|
||||
for (var href in this.parsedDocuments) {
|
||||
var newNodes = dom5.nodeWalkAll(this.parsedDocuments[href], predicate);
|
||||
results = results.concat(newNodes);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
/** Annotates all loaded metadata with its documentation. */
|
||||
Analyzer.prototype.annotate = function annotate() {
|
||||
if (this.features.length > 0) {
|
||||
var featureEl = docs.featureElement(this.features);
|
||||
this.elements.unshift(featureEl);
|
||||
this.elementsByTagName[featureEl.is] = featureEl;
|
||||
}
|
||||
var behaviorsByName = this.behaviorsByName;
|
||||
var elementHelper = function(descriptor){
|
||||
docs.annotateElement(descriptor, behaviorsByName);
|
||||
};
|
||||
this.elements.forEach(elementHelper);
|
||||
this.behaviors.forEach(elementHelper); // Same shape.
|
||||
this.behaviors.forEach(function(behavior){
|
||||
if (behavior.is !== behavior.symbol && behavior.symbol) {
|
||||
this.behaviorsByName[behavior.symbol] = undefined;
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
function attachDomModule(parsedImport, element) {
|
||||
var domModules = parsedImport['dom-module'];
|
||||
for (var i = 0, domModule; i < domModules.length; i++) {
|
||||
domModule = domModules[i];
|
||||
if (dom5.getAttribute(domModule, 'id') === element.is) {
|
||||
element.domModule = domModule;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes redundant properties from the collected descriptors. */
|
||||
Analyzer.prototype.clean = function clean() {
|
||||
this.elements.forEach(docs.cleanElement);
|
||||
};
|
||||
|
||||
module.exports = Analyzer;
|
||||
107
build/node_modules/hydrolysis/lib/ast-utils/analyze-properties.js
generated
vendored
Normal file
107
build/node_modules/hydrolysis/lib/ast-utils/analyze-properties.js
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 esutil = require('./esutil');
|
||||
var astValue = require('./ast-value');
|
||||
|
||||
var analyzeProperties = function(node) {
|
||||
|
||||
var analyzedProps = [];
|
||||
|
||||
if (node.type != 'ObjectExpression') {
|
||||
return analyzedProps;
|
||||
}
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
var property = node.properties[i];
|
||||
var prop = esutil.toPropertyDescriptor(property);
|
||||
prop.published = true;
|
||||
|
||||
if (property.value.type == 'ObjectExpression') {
|
||||
/**
|
||||
* Parse the expression inside a property object block.
|
||||
* property: {
|
||||
* key: {
|
||||
* type: String,
|
||||
* notify: true,
|
||||
* value: -1,
|
||||
* readOnly: true,
|
||||
* reflectToAttribute: true
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
for (var j = 0; j < property.value.properties.length; j++) {
|
||||
var propertyArg = property.value.properties[j];
|
||||
var propertyKey = esutil.objectKeyToString(propertyArg.key);
|
||||
|
||||
switch(propertyKey) {
|
||||
case 'type': {
|
||||
prop.type = esutil.objectKeyToString(propertyArg.value);
|
||||
if (prop.type === undefined) {
|
||||
throw {
|
||||
message: 'Invalid type in property object.',
|
||||
location: propertyArg.loc.start
|
||||
};
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'notify': {
|
||||
prop.notify = astValue.expressionToValue(propertyArg.value);
|
||||
if (prop.notify === undefined)
|
||||
prop.notify = astValue.CANT_CONVERT;
|
||||
}
|
||||
break;
|
||||
case 'observer': {
|
||||
prop.observer = astValue.expressionToValue(propertyArg.value);
|
||||
prop.observerNode = propertyArg.value;
|
||||
if (prop.observer === undefined)
|
||||
prop.observer = astValue.CANT_CONVERT;
|
||||
}
|
||||
break;
|
||||
case 'readOnly': {
|
||||
prop.readOnly = astValue.expressionToValue(propertyArg.value);
|
||||
if (prop.readOnly === undefined)
|
||||
prop.readOnly = astValue.CANT_CONVERT;
|
||||
}
|
||||
break;
|
||||
case 'reflectToAttribute': {
|
||||
prop.reflectToAttribute = astValue.expressionToValue(propertyArg);
|
||||
if (prop.reflectToAttribute === undefined)
|
||||
prop.reflectToAttribute = astValue.CANT_CONVERT;
|
||||
}
|
||||
break;
|
||||
case 'value': {
|
||||
prop.default = astValue.expressionToValue(propertyArg.value);
|
||||
if (prop.default === undefined)
|
||||
prop.default = astValue.CANT_CONVERT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!prop.type) {
|
||||
throw {
|
||||
message: 'Unable to determine name for property key.',
|
||||
location: node.loc.start
|
||||
};
|
||||
}
|
||||
|
||||
analyzedProps.push(prop);
|
||||
}
|
||||
return analyzedProps;
|
||||
};
|
||||
|
||||
|
||||
module.exports = analyzeProperties;
|
||||
|
||||
160
build/node_modules/hydrolysis/lib/ast-utils/ast-value.js
generated
vendored
Normal file
160
build/node_modules/hydrolysis/lib/ast-utils/ast-value.js
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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';
|
||||
|
||||
// useful tool to visualize AST: http://esprima.org/demo/parse.html
|
||||
|
||||
/**
|
||||
* converts literal: {"type": "Literal", "value": 5, "raw": "5" }
|
||||
* to string
|
||||
*/
|
||||
function literalToValue(literal) {
|
||||
return literal.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts unary to string
|
||||
* unary: { type: 'UnaryExpression', operator: '-', argument: { ... } }
|
||||
*/
|
||||
function unaryToValue(unary) {
|
||||
var argValue = expressionToValue(unary.argument);
|
||||
if (argValue === undefined)
|
||||
return;
|
||||
return unary.operator + argValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* converts identifier to its value
|
||||
* identifier { "type": "Identifier", "name": "Number }
|
||||
*/
|
||||
function identifierToValue(identifier) {
|
||||
return identifier.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function is a block statement.
|
||||
*/
|
||||
function functionDeclarationToValue(fn) {
|
||||
if (fn.body.type == "BlockStatement")
|
||||
return blockStatementToValue(fn.body);
|
||||
}
|
||||
|
||||
function functionExpressionToValue(fn) {
|
||||
if (fn.body.type == "BlockStatement")
|
||||
return blockStatementToValue(fn.body);
|
||||
}
|
||||
/**
|
||||
* Block statement: find last return statement, and return its value
|
||||
*/
|
||||
function blockStatementToValue(block) {
|
||||
for (var i=block.body.length - 1; i>= 0; i--) {
|
||||
if (block.body[i].type === "ReturnStatement")
|
||||
return returnStatementToValue(block.body[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates return's argument
|
||||
*/
|
||||
function returnStatementToValue(ret) {
|
||||
return expressionToValue(ret.argument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enclose containing values in []
|
||||
*/
|
||||
function arrayExpressionToValue(arry) {
|
||||
var value = '[';
|
||||
for (var i=0; i<arry.elements.length; i++) {
|
||||
var v = expressionToValue(arry.elements[i]);
|
||||
if (v === undefined)
|
||||
continue;
|
||||
if (i !== 0)
|
||||
value += ', ';
|
||||
value += v;
|
||||
}
|
||||
value += ']';
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make it look like an object
|
||||
*/
|
||||
function objectExpressionToValue(obj) {
|
||||
var value = '{';
|
||||
for (var i=0; i<obj.properties.length; i++) {
|
||||
var k = expressionToValue(obj.properties[i].key);
|
||||
var v = expressionToValue(obj.properties[i].value);
|
||||
if (v === undefined)
|
||||
continue;
|
||||
if (i !== 0)
|
||||
value += ', ';
|
||||
value += '"' + k + '": ' + v;
|
||||
}
|
||||
value += '}';
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* BinaryExpressions are of the form "literal" + "literal"
|
||||
*/
|
||||
function binaryExpressionToValue(member) {
|
||||
if (member.operator == "+") {
|
||||
return expressionToValue(member.left) + expressionToValue(member.right);
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* MemberExpression references a variable with name
|
||||
*/
|
||||
function memberExpressionToValue(member) {
|
||||
return expressionToValue(member.object) + "." + expressionToValue(member.property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to get a value from expression. Handles Literal, UnaryExpression
|
||||
* returns undefined on failure
|
||||
* valueExpression example:
|
||||
* { type: "Literal",
|
||||
*/
|
||||
function expressionToValue(valueExpression) {
|
||||
switch(valueExpression.type) {
|
||||
case 'Literal':
|
||||
return literalToValue(valueExpression);
|
||||
case 'UnaryExpression':
|
||||
return unaryToValue(valueExpression);
|
||||
case 'Identifier':
|
||||
return identifierToValue(valueExpression);
|
||||
case 'FunctionDeclaration':
|
||||
return functionDeclarationToValue(valueExpression);
|
||||
case 'FunctionExpression':
|
||||
return functionExpressionToValue(valueExpression);
|
||||
case 'ArrayExpression':
|
||||
return arrayExpressionToValue(valueExpression);
|
||||
case 'ObjectExpression':
|
||||
return objectExpressionToValue(valueExpression);
|
||||
case 'Identifier':
|
||||
return identifierToValue(valueExpression);
|
||||
case 'MemberExpression':
|
||||
return memberExpressionToValue(valueExpression);
|
||||
case 'BinaryExpression':
|
||||
return binaryExpressionToValue(valueExpression);
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var CANT_CONVERT = 'UNKNOWN';
|
||||
module.exports = {
|
||||
CANT_CONVERT: CANT_CONVERT,
|
||||
expressionToValue: expressionToValue
|
||||
};
|
||||
225
build/node_modules/hydrolysis/lib/ast-utils/behavior-finder.js
generated
vendored
Normal file
225
build/node_modules/hydrolysis/lib/ast-utils/behavior-finder.js
generated
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 estraverse = require('estraverse');
|
||||
|
||||
var docs = require('./docs');
|
||||
var esutil = require('./esutil');
|
||||
var jsdoc = require('./jsdoc');
|
||||
var analyzeProperties = require('./analyze-properties');
|
||||
var astValue = require('./ast-value.js');
|
||||
var declarationPropertyHandlers = require('./declaration-property-handlers');
|
||||
|
||||
module.exports = function behaviorFinder() {
|
||||
/** @type {!Array<BehaviorDescriptor>} The behaviors we've found. */
|
||||
var behaviors = [];
|
||||
|
||||
var currentBehavior = null;
|
||||
var propertyHandlers = null;
|
||||
|
||||
/**
|
||||
* merges behavior with preexisting behavior with the same name.
|
||||
* here to support multiple @polymerBehavior tags referring
|
||||
* to same behavior. See iron-multi-selectable for example.
|
||||
*/
|
||||
function mergeBehavior(newBehavior) {
|
||||
var isBehaviorImpl = function(b) { // filter out BehaviorImpl
|
||||
return b.indexOf(newBehavior.is) === -1;
|
||||
};
|
||||
for (var i=0; i<behaviors.length; i++) {
|
||||
if (newBehavior.is !== behaviors[i].is)
|
||||
continue;
|
||||
// merge desc, longest desc wins
|
||||
if (newBehavior.desc) {
|
||||
if (behaviors[i].desc) {
|
||||
if (newBehavior.desc.length > behaviors[i].desc.length)
|
||||
behaviors[i].desc = newBehavior.desc;
|
||||
}
|
||||
else {
|
||||
behaviors[i].desc = newBehavior.desc;
|
||||
}
|
||||
}
|
||||
// merge demos
|
||||
behaviors[i].demos = (behaviors[i].demos || []).concat(newBehavior.demos || []);
|
||||
// merge events,
|
||||
behaviors[i].events = (behaviors[i].events || []).concat(newBehavior.events || []);
|
||||
// merge properties
|
||||
behaviors[i].properties = (behaviors[i].properties || []).concat(newBehavior.properties || []);
|
||||
// merge observers
|
||||
behaviors[i].observers = (behaviors[i].observers || []).concat(newBehavior.observers || []);
|
||||
// merge behaviors
|
||||
behaviors[i].behaviors =
|
||||
(behaviors[i].behaviors || []).concat(newBehavior.behaviors || [])
|
||||
.filter(isBehaviorImpl);
|
||||
return behaviors[i];
|
||||
}
|
||||
return newBehavior;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the expression representing a behavior from a node.
|
||||
*/
|
||||
function behaviorExpression(node) {
|
||||
switch(node.type) {
|
||||
case 'ExpressionStatement':
|
||||
return node.expression.right;
|
||||
case 'VariableDeclaration':
|
||||
return node.declarations.length > 0 ? node.declarations[0].init : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether an expression is a simple array containing only member
|
||||
* expressions or identifiers.
|
||||
*/
|
||||
function isSimpleBehaviorArray(expression) {
|
||||
if (!expression || expression.type !== 'ArrayExpression') return false;
|
||||
for (var i=0; i < expression.elements.length; i++) {
|
||||
if (expression.elements[i].type !== 'MemberExpression' &&
|
||||
expression.elements[i].type !== 'Identifier') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var templatizer = "Polymer.Templatizer";
|
||||
|
||||
var visitors = {
|
||||
|
||||
/**
|
||||
* Look for object declarations with @behavior in the docs.
|
||||
*/
|
||||
enterVariableDeclaration: function(node, parent) {
|
||||
if (node.declarations.length !== 1) return; // Ambiguous.
|
||||
this._initBehavior(node, function () {
|
||||
return esutil.objectKeyToString(node.declarations[0].id);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Look for object assignments with @polymerBehavior in the docs.
|
||||
*/
|
||||
enterAssignmentExpression: function(node, parent) {
|
||||
this._initBehavior(parent, function () {
|
||||
return esutil.objectKeyToString(node.left);
|
||||
});
|
||||
},
|
||||
|
||||
_parseChainedBehaviors: function(node) {
|
||||
// if current behavior is part of an array, it gets extended by other behaviors
|
||||
// inside the array. Ex:
|
||||
// Polymer.IronMultiSelectableBehavior = [ {....}, Polymer.IronSelectableBehavior]
|
||||
// We add these to behaviors array
|
||||
var expression = behaviorExpression(node);
|
||||
var chained = [];
|
||||
if (expression && expression.type === 'ArrayExpression') {
|
||||
for (var i=0; i < expression.elements.length; i++) {
|
||||
if (expression.elements[i].type === 'MemberExpression' ||
|
||||
expression.elements[i].type === 'Identifier') {
|
||||
chained.push(astValue.expressionToValue(expression.elements[i]));
|
||||
}
|
||||
}
|
||||
if (chained.length > 0)
|
||||
currentBehavior.behaviors = chained;
|
||||
}
|
||||
},
|
||||
|
||||
_initBehavior: function(node, getName) {
|
||||
var comment = esutil.getAttachedComment(node);
|
||||
var symbol = getName();
|
||||
// Quickly filter down to potential candidates.
|
||||
if (!comment || comment.indexOf('@polymerBehavior') === -1) {
|
||||
if (symbol !== templatizer) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
currentBehavior = {
|
||||
type: 'behavior',
|
||||
desc: comment,
|
||||
events: esutil.getEventComments(node).map( function(event) {
|
||||
return { desc: event};
|
||||
})
|
||||
};
|
||||
propertyHandlers = declarationPropertyHandlers(currentBehavior);
|
||||
|
||||
docs.annotateBehavior(currentBehavior);
|
||||
// Make sure that we actually parsed a behavior tag!
|
||||
if (!jsdoc.hasTag(currentBehavior.jsdoc, 'polymerBehavior') &&
|
||||
symbol !== templatizer) {
|
||||
currentBehavior = null;
|
||||
propertyHandlers = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var name = jsdoc.getTag(currentBehavior.jsdoc, 'polymerBehavior', 'name');
|
||||
currentBehavior.symbol = symbol;
|
||||
if (!name) {
|
||||
name = currentBehavior.symbol;
|
||||
}
|
||||
if (!name) {
|
||||
console.warn('Unable to determine name for @polymerBehavior:', comment);
|
||||
}
|
||||
currentBehavior.is = name;
|
||||
|
||||
this._parseChainedBehaviors(node);
|
||||
|
||||
currentBehavior = mergeBehavior(currentBehavior);
|
||||
propertyHandlers = declarationPropertyHandlers(currentBehavior);
|
||||
|
||||
// Some behaviors are just lists of other behaviors. If this is one then
|
||||
// add it to behaviors right away.
|
||||
if (isSimpleBehaviorArray(behaviorExpression(node))) {
|
||||
// TODO(ajo): Add a test to confirm the presence of `properties`
|
||||
if (!currentBehavior.observers) currentBehavior.observers = [];
|
||||
if (!currentBehavior.properties) currentBehavior.properties = [];
|
||||
if (behaviors.indexOf(currentBehavior) === -1)
|
||||
behaviors.push(currentBehavior);
|
||||
currentBehavior = null;
|
||||
propertyHandlers = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* We assume that the object expression after such an assignment is the
|
||||
* behavior's declaration. Seems to be a decent assumption for now.
|
||||
*/
|
||||
enterObjectExpression: function(node, parent) {
|
||||
if (!currentBehavior || currentBehavior.properties) return;
|
||||
|
||||
currentBehavior.properties = currentBehavior.properties || [];
|
||||
currentBehavior.observers = currentBehavior.observers || [];
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
var prop = node.properties[i];
|
||||
var name = esutil.objectKeyToString(prop.key);
|
||||
if (!name) {
|
||||
throw {
|
||||
message: 'Cant determine name for property key.',
|
||||
location: node.loc.start
|
||||
};
|
||||
}
|
||||
if (name in propertyHandlers) {
|
||||
propertyHandlers[name](prop.value);
|
||||
}
|
||||
else {
|
||||
currentBehavior.properties.push(esutil.toPropertyDescriptor(prop));
|
||||
}
|
||||
}
|
||||
behaviors.push(currentBehavior);
|
||||
currentBehavior = null;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
return {visitors: visitors, behaviors: behaviors};
|
||||
};
|
||||
68
build/node_modules/hydrolysis/lib/ast-utils/declaration-property-handlers.js
generated
vendored
Normal file
68
build/node_modules/hydrolysis/lib/ast-utils/declaration-property-handlers.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 astValue = require('./ast-value');
|
||||
var analyzeProperties = require('./analyze-properties');
|
||||
|
||||
/**
|
||||
* Returns an object containing functions that will annotate `declaration` with
|
||||
* the polymer-specificmeaning of the value nodes for the named properties.
|
||||
*
|
||||
* @param {ElementDescriptor} declaration The descriptor to annotate.
|
||||
* @return {object.<string,function>} An object containing property
|
||||
* handlers.
|
||||
*/
|
||||
function declarationPropertyHandlers(declaration) {
|
||||
return {
|
||||
is: function(node) {
|
||||
if (node.type == 'Literal') {
|
||||
declaration.is = node.value;
|
||||
}
|
||||
},
|
||||
properties: function(node) {
|
||||
|
||||
var props = analyzeProperties(node);
|
||||
|
||||
for (var i=0; i<props.length; i++) {
|
||||
declaration.properties.push(props[i]);
|
||||
}
|
||||
},
|
||||
behaviors: function(node) {
|
||||
if (node.type != 'ArrayExpression') {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i=0; i<node.elements.length; i++) {
|
||||
var v = astValue.expressionToValue(node.elements[i]);
|
||||
if (v === undefined)
|
||||
v = astValue.CANT_CONVERT;
|
||||
declaration.behaviors.push(v);
|
||||
}
|
||||
},
|
||||
observers: function(node) {
|
||||
if (node.type != 'ArrayExpression') {
|
||||
return;
|
||||
}
|
||||
for (var i=0; i<node.elements.length; i++) {
|
||||
var v = astValue.expressionToValue(node.elements[i]);
|
||||
if (v === undefined)
|
||||
v = astValue.CANT_CONVERT;
|
||||
declaration.observers.push({
|
||||
javascriptNode: node.elements[i],
|
||||
expression: v
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = declarationPropertyHandlers;
|
||||
485
build/node_modules/hydrolysis/lib/ast-utils/docs.js
generated
vendored
Normal file
485
build/node_modules/hydrolysis/lib/ast-utils/docs.js
generated
vendored
Normal file
@@ -0,0 +1,485 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// jshint node:true
|
||||
|
||||
var jsdoc = require('./jsdoc');
|
||||
|
||||
var dom5 = require('dom5');
|
||||
|
||||
/** Properties on element prototypes that are purely configuration. */
|
||||
var ELEMENT_CONFIGURATION = [
|
||||
'attached',
|
||||
'attributeChanged',
|
||||
'configure',
|
||||
'constructor',
|
||||
'created',
|
||||
'detached',
|
||||
'enableCustomStyleProperties',
|
||||
'extends',
|
||||
'hostAttributes',
|
||||
'is',
|
||||
'listeners',
|
||||
'mixins',
|
||||
'properties',
|
||||
'ready',
|
||||
'registered'
|
||||
];
|
||||
|
||||
/** Tags understood by the annotation process, to be removed during `clean`. */
|
||||
var HANDLED_TAGS = [
|
||||
'param',
|
||||
'return',
|
||||
'type',
|
||||
];
|
||||
|
||||
/**
|
||||
* Annotates Hydrolysis descriptors, processing any `desc` properties as JSDoc.
|
||||
*
|
||||
* You probably want to use a more specialized version of this, such as
|
||||
* `annotateElement`.
|
||||
*
|
||||
* Processed JSDoc values will be made available via the `jsdoc` property on a
|
||||
* descriptor node.
|
||||
*
|
||||
* @param {Object} descriptor The descriptor node to process.
|
||||
* @return {Object} The descriptor that was given.
|
||||
*/
|
||||
function annotate(descriptor) {
|
||||
if (!descriptor || descriptor.jsdoc) return descriptor;
|
||||
|
||||
if (typeof descriptor.desc === 'string') {
|
||||
descriptor.jsdoc = jsdoc.parseJsdoc(descriptor.desc);
|
||||
// We want to present the normalized form of a descriptor.
|
||||
descriptor.jsdoc.orig = descriptor.desc;
|
||||
descriptor.desc = descriptor.jsdoc.description;
|
||||
}
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotates @event, @hero, & @demo tags
|
||||
*/
|
||||
function annotateElementHeader(descriptor) {
|
||||
if (descriptor.events) {
|
||||
descriptor.events.forEach(function(event) {
|
||||
_annotateEvent(event);
|
||||
});
|
||||
descriptor.events.sort( function(a,b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
}
|
||||
descriptor.demos = [];
|
||||
if (descriptor.jsdoc && descriptor.jsdoc.tags) {
|
||||
descriptor.jsdoc.tags.forEach( function(tag) {
|
||||
switch(tag.tag) {
|
||||
case 'hero':
|
||||
descriptor.hero = tag.name || 'hero.png';
|
||||
break;
|
||||
case 'demo':
|
||||
descriptor.demos.push({
|
||||
desc: tag.description || 'demo',
|
||||
path: tag.name || 'demo/index.html'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function matchByName(propa, propb) {
|
||||
return propa.name == propb.name;
|
||||
}
|
||||
|
||||
function copyProperties(from, to, behaviorsByName) {
|
||||
if (from.properties) {
|
||||
from.properties.forEach(function(fromProp){
|
||||
for (var toProp, i = 0; i < to.properties.length; i++) {
|
||||
toProp = to.properties[i];
|
||||
if (fromProp.name === toProp.name) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
var newProp = {__fromBehavior: from.is};
|
||||
if (fromProp.__fromBehavior) {
|
||||
return;
|
||||
}
|
||||
Object.keys(fromProp).forEach(function(propertyField){
|
||||
newProp[propertyField] = fromProp[propertyField];
|
||||
});
|
||||
to.properties.push(newProp);
|
||||
});
|
||||
from.events.forEach(function(fromEvent){
|
||||
for (var toEvent, i = 0; i < to.events.length; i++) {
|
||||
toEvent = to.events[i];
|
||||
if (fromEvent.name === toEvent.name) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (fromEvent.__fromBehavior) {
|
||||
return;
|
||||
}
|
||||
var newEvent = Object.create(fromEvent);
|
||||
newEvent.__fromBehavior = from.is;
|
||||
to.events.push(newEvent);
|
||||
});
|
||||
}
|
||||
if (!from.behaviors) {
|
||||
return;
|
||||
}
|
||||
for (var i = from.behaviors.length - 1; i >= 0; i--) {
|
||||
var behavior = from.behaviors[i];
|
||||
var definedBehavior = behaviorsByName[behavior] || behaviorsByName[behavior.symbol];
|
||||
if (!definedBehavior) {
|
||||
console.warn("Behavior " + behavior + " not found when mixing " +
|
||||
"properties into " + to.is + "!");
|
||||
return;
|
||||
}
|
||||
copyProperties(definedBehavior, to, behaviorsByName);
|
||||
}
|
||||
}
|
||||
|
||||
function mixinBehaviors(descriptor, behaviorsByName) {
|
||||
if (descriptor.behaviors) {
|
||||
for (var i = descriptor.behaviors.length - 1; i >= 0; i--) {
|
||||
var behavior = descriptor.behaviors[i];
|
||||
if (!behaviorsByName[behavior]) {
|
||||
console.warn("Behavior " + behavior + " not found when mixing " +
|
||||
"properties into " + descriptor.is + "!");
|
||||
break;
|
||||
}
|
||||
var definedBehavior = behaviorsByName[behavior];
|
||||
copyProperties(definedBehavior, descriptor, behaviorsByName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotates documentation found within a Hydrolysis element descriptor. Also
|
||||
* supports behaviors.
|
||||
*
|
||||
* If the element was processed via `hydrolize`, the element's documentation
|
||||
* will also be extracted via its <dom-module>.
|
||||
*
|
||||
* @param {Object} descriptor The element descriptor.
|
||||
* @return {Object} The descriptor that was given.
|
||||
*/
|
||||
function annotateElement(descriptor, behaviorsByName) {
|
||||
if (!descriptor.desc && descriptor.type === 'element') {
|
||||
descriptor.desc = _findElementDocs(descriptor.is,
|
||||
descriptor.domModule,
|
||||
descriptor.scriptElement);
|
||||
}
|
||||
annotate(descriptor);
|
||||
|
||||
// The `<dom-module>` is too low level for most needs, and it is _not_
|
||||
// serializable. So we drop it now that we've extracted all the useful bits
|
||||
// from it.
|
||||
// TODO: Don't worry about serializability here, provide an API to get JSON.
|
||||
delete descriptor.domModule;
|
||||
|
||||
mixinBehaviors(descriptor, behaviorsByName);
|
||||
|
||||
// Descriptors that should have their `desc` properties parsed as JSDoc.
|
||||
descriptor.properties.forEach(function(property) {
|
||||
// Feature properties are special, configuration is really just a matter of
|
||||
// inheritance...
|
||||
annotateProperty(property, descriptor.abstract);
|
||||
});
|
||||
|
||||
// It may seem like overkill to always sort, but we have an assumption that
|
||||
// these properties are typically being consumed by user-visible tooling.
|
||||
// As such, it's good to have consistent output/ordering to aid the user.
|
||||
descriptor.properties.sort(function(a, b) {
|
||||
// Private properties are always last.
|
||||
if (a.private && !b.private) {
|
||||
return 1;
|
||||
} else if (!a.private && b.private) {
|
||||
return -1;
|
||||
// Otherwise, we're just sorting alphabetically.
|
||||
} else {
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
});
|
||||
|
||||
annotateElementHeader(descriptor);
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotates behavior descriptor.
|
||||
* @param {Object} descriptor behavior descriptor
|
||||
* @return {Object} descriptor passed in as param
|
||||
*/
|
||||
function annotateBehavior(descriptor, behaviorsByName) {
|
||||
annotate(descriptor);
|
||||
annotateElementHeader(descriptor);
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotates event documentation
|
||||
*/
|
||||
function _annotateEvent(descriptor) {
|
||||
annotate(descriptor);
|
||||
// process @event
|
||||
var eventTag = jsdoc.getTag(descriptor.jsdoc, 'event');
|
||||
descriptor.name = eventTag ? eventTag.description : "N/A";
|
||||
|
||||
// process @params
|
||||
descriptor.params = (descriptor.jsdoc.tags || [])
|
||||
.filter( function(tag) {
|
||||
return tag.tag === 'param';
|
||||
})
|
||||
.map( function(tag) {
|
||||
return {
|
||||
type: tag.type || "N/A",
|
||||
desc: tag.description,
|
||||
name: tag.name || "N/A"
|
||||
};
|
||||
});
|
||||
// process @params
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotates documentation found about a Hydrolysis property descriptor.
|
||||
*
|
||||
* @param {Object} descriptor The property descriptor.
|
||||
* @param {boolean} ignoreConfiguration If true, `configuration` is not set.
|
||||
* @return {Object} The descriptior that was given.
|
||||
*/
|
||||
function annotateProperty(descriptor, ignoreConfiguration) {
|
||||
annotate(descriptor);
|
||||
if (descriptor.name[0] === '_' || jsdoc.hasTag(descriptor.jsdoc, 'private')) {
|
||||
descriptor.private = true;
|
||||
}
|
||||
|
||||
if (!ignoreConfiguration && ELEMENT_CONFIGURATION.indexOf(descriptor.name) !== -1) {
|
||||
descriptor.private = true;
|
||||
descriptor.configuration = true;
|
||||
}
|
||||
|
||||
// @type JSDoc wins
|
||||
descriptor.type = jsdoc.getTag(descriptor.jsdoc, 'type', 'type') || descriptor.type;
|
||||
|
||||
if (descriptor.type.match(/^function/i)) {
|
||||
_annotateFunctionProperty(descriptor);
|
||||
}
|
||||
|
||||
// @default JSDoc wins
|
||||
var defaultTag = jsdoc.getTag(descriptor.jsdoc, 'default');
|
||||
if (defaultTag !== null) {
|
||||
var newDefault = (defaultTag.name || '') + (defaultTag.description || '');
|
||||
if (newDefault !== '') {
|
||||
descriptor.default = newDefault;
|
||||
}
|
||||
}
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/** @param {Object} descriptor */
|
||||
function _annotateFunctionProperty(descriptor) {
|
||||
descriptor.function = true;
|
||||
|
||||
var returnTag = jsdoc.getTag(descriptor.jsdoc, 'return');
|
||||
if (returnTag) {
|
||||
descriptor.return = {
|
||||
type: returnTag.type,
|
||||
desc: returnTag.description,
|
||||
};
|
||||
}
|
||||
|
||||
var paramsByName = {};
|
||||
(descriptor.params || []).forEach(function(param) {
|
||||
paramsByName[param.name] = param;
|
||||
});
|
||||
(descriptor.jsdoc && descriptor.jsdoc.tags || []).forEach(function(tag) {
|
||||
if (tag.tag !== 'param') return;
|
||||
var param = paramsByName[tag.name];
|
||||
if (!param) {
|
||||
return;
|
||||
}
|
||||
|
||||
param.type = tag.type || param.type;
|
||||
param.desc = tag.description;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts raw features into an abstract `Polymer.Base` element.
|
||||
*
|
||||
* Note that docs on this element _are not processed_. You must call
|
||||
* `annotateElement` on it yourself if you wish that.
|
||||
*
|
||||
* @param {Array<FeatureDescriptor>} features
|
||||
* @return {ElementDescriptor}
|
||||
*/
|
||||
function featureElement(features) {
|
||||
var properties = features.reduce(function(result, feature) {
|
||||
return result.concat(feature.properties);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
type: 'element',
|
||||
is: 'Polymer.Base',
|
||||
abstract: true,
|
||||
properties: properties,
|
||||
desc: '`Polymer.Base` acts as a base prototype for all Polymer ' +
|
||||
'elements. It is composed via various calls to ' +
|
||||
'`Polymer.Base._addFeature()`.\n' +
|
||||
'\n' +
|
||||
'The properties reflected here are the combined view of all ' +
|
||||
'features found in this library. There may be more properties ' +
|
||||
'added via other libraries, as well.',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans redundant properties from a descriptor, assuming that you have already
|
||||
* called `annotate`.
|
||||
*
|
||||
* @param {Object} descriptor
|
||||
*/
|
||||
function clean(descriptor) {
|
||||
if (!descriptor.jsdoc) return;
|
||||
// The doctext was written to `descriptor.desc`
|
||||
delete descriptor.jsdoc.description;
|
||||
delete descriptor.jsdoc.orig;
|
||||
|
||||
var cleanTags = [];
|
||||
(descriptor.jsdoc.tags || []).forEach(function(tag) {
|
||||
// Drop any tags we've consumed.
|
||||
if (HANDLED_TAGS.indexOf(tag.tag) !== -1) return;
|
||||
cleanTags.push(tag);
|
||||
});
|
||||
|
||||
if (cleanTags.length === 0) {
|
||||
// No tags? no docs left!
|
||||
delete descriptor.jsdoc;
|
||||
} else {
|
||||
descriptor.jsdoc.tags = cleanTags;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans redundant properties from an element, assuming that you have already
|
||||
* called `annotateElement`.
|
||||
*
|
||||
* @param {ElementDescriptor|BehaviorDescriptor} element
|
||||
*/
|
||||
function cleanElement(element) {
|
||||
clean(element);
|
||||
element.properties.forEach(cleanProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans redundant properties from a property, assuming that you have already
|
||||
* called `annotateProperty`.
|
||||
*
|
||||
* @param {PropertyDescriptor} property
|
||||
*/
|
||||
function cleanProperty(property) {
|
||||
clean(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse elements defined only in comments.
|
||||
* @param {comments} Array<string> A list of comments to parse.
|
||||
* @return {ElementDescriptor} A list of pseudo-elements.
|
||||
*/
|
||||
function parsePseudoElements(comments) {
|
||||
var elements = [];
|
||||
comments.forEach(function(comment) {
|
||||
var parsed = jsdoc.parseJsdoc(comment);
|
||||
var pseudoTag = jsdoc.getTag(parsed, 'pseudoElement', 'name');
|
||||
if (pseudoTag) {
|
||||
parsed.is = pseudoTag;
|
||||
parsed.jsdoc = {description: parsed.description, tags: parsed.tags};
|
||||
parsed.properties = [];
|
||||
parsed.desc = parsed.description;
|
||||
parsed.description = undefined;
|
||||
parsed.tags = undefined;
|
||||
annotateElementHeader(parsed);
|
||||
elements.push(parsed);
|
||||
}
|
||||
});
|
||||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} elementId
|
||||
* @param {DocumentAST} domModule
|
||||
* @param {DocumentAST} scriptElement The script that the element was defined in.
|
||||
*/
|
||||
function _findElementDocs(elementId, domModule, scriptElement) {
|
||||
// Note that we concatenate docs from all sources if we find them.
|
||||
// element can be defined in:
|
||||
// html comment right before dom-module
|
||||
// html commnet right before script defining the module, if dom-module is empty
|
||||
|
||||
var found = [];
|
||||
|
||||
// Do we have a HTML comment on the `<dom-module>` or `<script>`?
|
||||
//
|
||||
// Confusingly, with our current style, the comment will be attached to
|
||||
// `<head>`, rather than being a sibling to the `<dom-module>`
|
||||
var searchRoot = domModule || scriptElement;
|
||||
var parents = dom5.nodeWalkAllPrior(searchRoot, dom5.isCommentNode);
|
||||
var comment = parents.length > 0 ? parents[0] : null;
|
||||
if (comment && comment.data) {
|
||||
found.push(comment.data);
|
||||
}
|
||||
if (found.length === 0) return null;
|
||||
return found
|
||||
.filter(function(comment) {
|
||||
// skip @license comments
|
||||
if (comment && comment.indexOf('@license' === -1)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.map(jsdoc.unindent).join('\n');
|
||||
}
|
||||
|
||||
function _findLastChildNamed(name, parent) {
|
||||
var children = parent.childNodes;
|
||||
for (var i = children.length - 1, child; i >= 0; i--) {
|
||||
child = children[i];
|
||||
if (child.nodeName === name) return child;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO(nevir): parse5-utils!
|
||||
function _getNodeAttribute(node, name) {
|
||||
for (var i = 0, attr; i < node.attrs.length; i++) {
|
||||
attr = node.attrs[i];
|
||||
if (attr.name === name) {
|
||||
return attr.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
annotate: annotate,
|
||||
annotateElement: annotateElement,
|
||||
annotateBehavior: annotateBehavior,
|
||||
clean: clean,
|
||||
cleanElement: cleanElement,
|
||||
featureElement: featureElement,
|
||||
parsePseudoElements: parsePseudoElements
|
||||
};
|
||||
115
build/node_modules/hydrolysis/lib/ast-utils/element-finder.js
generated
vendored
Normal file
115
build/node_modules/hydrolysis/lib/ast-utils/element-finder.js
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 estraverse = require('estraverse');
|
||||
|
||||
var esutil = require('./esutil');
|
||||
var findAlias = require('./find-alias');
|
||||
var analyzeProperties = require('./analyze-properties');
|
||||
var astValue = require('./ast-value');
|
||||
var declarationPropertyHandlers = require('./declaration-property-handlers');
|
||||
|
||||
var elementFinder = function elementFinder() {
|
||||
/**
|
||||
* The list of elements exported by each traversed script.
|
||||
*/
|
||||
var elements = [];
|
||||
|
||||
/**
|
||||
* The element being built during a traversal;
|
||||
*/
|
||||
var element = null;
|
||||
var propertyHandlers = null;
|
||||
|
||||
var visitors = {
|
||||
enterCallExpression: function enterCallExpression(node, parent) {
|
||||
var callee = node.callee;
|
||||
if (callee.type == 'Identifier') {
|
||||
|
||||
if (callee.name == 'Polymer') {
|
||||
element = {
|
||||
type: 'element',
|
||||
desc: esutil.getAttachedComment(parent),
|
||||
events: esutil.getEventComments(parent).map( function(event) {
|
||||
return {desc: event};
|
||||
})
|
||||
};
|
||||
propertyHandlers = declarationPropertyHandlers(element);
|
||||
}
|
||||
}
|
||||
},
|
||||
leaveCallExpression: function leaveCallExpression(node, parent) {
|
||||
var callee = node.callee;
|
||||
if (callee.type == 'Identifier') {
|
||||
if (callee.name == 'Polymer') {
|
||||
if (element) {
|
||||
elements.push(element);
|
||||
element = null;
|
||||
propertyHandlers = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
enterObjectExpression: function enterObjectExpression(node, parent) {
|
||||
if (element && !element.properties) {
|
||||
element.properties = [];
|
||||
element.behaviors = [];
|
||||
element.observers = [];
|
||||
var getters = {};
|
||||
var setters = {};
|
||||
var definedProperties = {};
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
var prop = node.properties[i];
|
||||
var name = esutil.objectKeyToString(prop.key);
|
||||
if (!name) {
|
||||
throw {
|
||||
message: 'Cant determine name for property key.',
|
||||
location: node.loc.start
|
||||
};
|
||||
}
|
||||
|
||||
if (name in propertyHandlers) {
|
||||
propertyHandlers[name](prop.value);
|
||||
continue;
|
||||
}
|
||||
var descriptor = esutil.toPropertyDescriptor(prop);
|
||||
if (descriptor.getter) {
|
||||
getters[descriptor.name] = descriptor;
|
||||
} else if (descriptor.setter) {
|
||||
setters[descriptor.name] = descriptor;
|
||||
} else {
|
||||
element.properties.push(esutil.toPropertyDescriptor(prop));
|
||||
}
|
||||
}
|
||||
Object.keys(getters).forEach(function(getter) {
|
||||
var get = getters[getter];
|
||||
definedProperties[get.name] = get;
|
||||
});
|
||||
Object.keys(setters).forEach(function(setter) {
|
||||
var set = setters[setter];
|
||||
if (!(set.name in definedProperties)) {
|
||||
definedProperties[set.name] = set;
|
||||
} else {
|
||||
definedProperties[set.name].setter = true;
|
||||
}
|
||||
});
|
||||
Object.keys(definedProperties).forEach(function(p){
|
||||
var prop = definedProperties[p];
|
||||
element.properties.push(p);
|
||||
});
|
||||
return estraverse.VisitorOption.Skip;
|
||||
}
|
||||
}
|
||||
};
|
||||
return {visitors: visitors, elements: elements};
|
||||
};
|
||||
|
||||
module.exports = elementFinder;
|
||||
178
build/node_modules/hydrolysis/lib/ast-utils/esutil.js
generated
vendored
Normal file
178
build/node_modules/hydrolysis/lib/ast-utils/esutil.js
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 estraverse = require("estraverse");
|
||||
|
||||
/**
|
||||
* Returns whether an Espree node matches a particular object path.
|
||||
*
|
||||
* e.g. you have a MemberExpression node, and want to see whether it represents
|
||||
* `Foo.Bar.Baz`:
|
||||
*
|
||||
* matchesCallExpression(node, ['Foo', 'Bar', 'Baz'])
|
||||
*
|
||||
* @param {Node} expression The Espree node to match against.
|
||||
* @param {Array<string>} path The path to look for.
|
||||
*/
|
||||
function matchesCallExpression(expression, path) {
|
||||
if (!expression.property || !expression.object) return;
|
||||
console.assert(path.length >= 2);
|
||||
|
||||
// Unravel backwards, make sure properties match each step of the way.
|
||||
if (expression.property.name !== path[path.length - 1]) return false;
|
||||
// We've got ourselves a final member expression.
|
||||
if (path.length == 2 && expression.object.type === 'Identifier') {
|
||||
return expression.object.name === path[0];
|
||||
}
|
||||
// Nested expressions.
|
||||
if (path.length > 2 && expression.object.type == 'MemberExpression') {
|
||||
return matchesCallExpression(expression.object, path.slice(0, path.length - 1));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} key The node representing an object key or expression.
|
||||
* @return {string} The name of that key.
|
||||
*/
|
||||
function objectKeyToString(key) {
|
||||
if (key.type == 'Identifier') {
|
||||
return key.name;
|
||||
}
|
||||
if (key.type == 'Literal') {
|
||||
return key.value;
|
||||
}
|
||||
if (key.type == 'MemberExpression') {
|
||||
return objectKeyToString(key.object) + '.' + objectKeyToString(key.property);
|
||||
}
|
||||
}
|
||||
|
||||
var CLOSURE_CONSTRUCTOR_MAP = {
|
||||
'Boolean': 'boolean',
|
||||
'Number': 'number',
|
||||
'String': 'string',
|
||||
};
|
||||
|
||||
/**
|
||||
* AST expression -> Closure type.
|
||||
*
|
||||
* Accepts literal values, and native constructors.
|
||||
*
|
||||
* @param {Node} node An Espree expression node.
|
||||
* @return {string} The type of that expression, in Closure terms.
|
||||
*/
|
||||
function closureType(node) {
|
||||
if (node.type.match(/Expression$/)) {
|
||||
return node.type.substr(0, node.type.length - 10);
|
||||
} else if (node.type === 'Literal') {
|
||||
return typeof node.value;
|
||||
} else if (node.type === 'Identifier') {
|
||||
return CLOSURE_CONSTRUCTOR_MAP[node.name] || node.name;
|
||||
} else {
|
||||
throw {
|
||||
message: 'Unknown Closure type for node: ' + node.type,
|
||||
location: node.loc.start,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @return {?string}
|
||||
*/
|
||||
function getAttachedComment(node) {
|
||||
var comments = getLeadingComments(node) || getLeadingComments(node.key);
|
||||
if (!comments) {
|
||||
return;
|
||||
}
|
||||
return comments[comments.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all comments from a tree defined with @event.
|
||||
* @param {Node} node [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
function getEventComments(node) {
|
||||
var eventComments = [];
|
||||
estraverse.traverse(node, {
|
||||
enter: function (node) {
|
||||
var comments = (node.leadingComments || []).concat(node.trailingComments || [])
|
||||
.map( function(commentAST) {
|
||||
return commentAST.value;
|
||||
})
|
||||
.filter( function(comment) {
|
||||
return comment.indexOf("@event") != -1;
|
||||
});
|
||||
eventComments = eventComments.concat(comments);
|
||||
}
|
||||
});
|
||||
// dedup
|
||||
return eventComments.filter( function(el, index, array) {
|
||||
return array.indexOf(el) === index;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @param
|
||||
* @return {Array.<string>}
|
||||
*/
|
||||
function getLeadingComments(node) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
var comments = node.leadingComments;
|
||||
if (!comments || comments.length === 0) return;
|
||||
return comments.map(function(comment) {
|
||||
return comment.value;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a parse5 Property AST node into its Hydrolysis representation.
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {PropertyDescriptor}
|
||||
*/
|
||||
function toPropertyDescriptor(node) {
|
||||
var type = closureType(node.value);
|
||||
if (type == "Function") {
|
||||
if (node.kind === "get" || node.kind === "set") {
|
||||
type = '';
|
||||
node[node.kind+"ter"] = true;
|
||||
}
|
||||
}
|
||||
var result = {
|
||||
name: objectKeyToString(node.key),
|
||||
type: type,
|
||||
desc: getAttachedComment(node),
|
||||
javascriptNode: node
|
||||
};
|
||||
|
||||
if (type === 'Function') {
|
||||
result.params = (node.value.params || []).map(function(param) {
|
||||
return {name: param.name};
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
closureType: closureType,
|
||||
getAttachedComment: getAttachedComment,
|
||||
getEventComments: getEventComments,
|
||||
matchesCallExpression: matchesCallExpression,
|
||||
objectKeyToString: objectKeyToString,
|
||||
toPropertyDescriptor: toPropertyDescriptor,
|
||||
};
|
||||
56
build/node_modules/hydrolysis/lib/ast-utils/feature-finder.js
generated
vendored
Normal file
56
build/node_modules/hydrolysis/lib/ast-utils/feature-finder.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 estraverse = require('estraverse');
|
||||
|
||||
var esutil = require('./esutil');
|
||||
|
||||
var numFeatures = 0;
|
||||
|
||||
module.exports = function featureFinder() {
|
||||
/** @type {!Array<FeatureDescriptor>} The features we've found. */
|
||||
var features = [];
|
||||
|
||||
var visitors = {
|
||||
|
||||
enterCallExpression: function enterCallExpression(node, parent) {
|
||||
if (!esutil.matchesCallExpression(node.callee, ['Polymer', 'Base', '_addFeature'])) {
|
||||
return;
|
||||
}
|
||||
/** @type {!FeatureDescriptor} */
|
||||
var feature = {};
|
||||
this._extractDesc(feature, node, parent);
|
||||
this._extractProperties(feature, node, parent);
|
||||
|
||||
features.push(feature);
|
||||
},
|
||||
|
||||
_extractDesc: function _extractDesc(feature, node, parent) {
|
||||
feature.desc = esutil.getAttachedComment(parent);
|
||||
},
|
||||
|
||||
_extractProperties: function _extractProperties(feature, node, parent) {
|
||||
var featureNode = node.arguments[0];
|
||||
if (featureNode.type !== 'ObjectExpression') {
|
||||
console.warn(
|
||||
'Expected first argument to Polymer.Base._addFeature to be an object.',
|
||||
'Got', featureNode.type, 'instead.');
|
||||
return;
|
||||
}
|
||||
if (!featureNode.properties) return;
|
||||
|
||||
feature.properties = featureNode.properties.map(esutil.toPropertyDescriptor);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
return {visitors: visitors, features: features};
|
||||
};
|
||||
19
build/node_modules/hydrolysis/lib/ast-utils/find-alias.js
generated
vendored
Normal file
19
build/node_modules/hydrolysis/lib/ast-utils/find-alias.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 findAlias = function findAlias(names, aliases, name) {
|
||||
if (!names) {
|
||||
return null;
|
||||
}
|
||||
return aliases[names.indexOf(name)];
|
||||
};
|
||||
|
||||
module.exports = findAlias;
|
||||
141
build/node_modules/hydrolysis/lib/ast-utils/import-parse.js
generated
vendored
Normal file
141
build/node_modules/hydrolysis/lib/ast-utils/import-parse.js
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 dom5 = require('dom5');
|
||||
|
||||
var p = dom5.predicates;
|
||||
|
||||
var isHtmlImportNode = p.AND(
|
||||
p.hasTagName('link'),
|
||||
p.hasAttrValue('rel', 'import'),
|
||||
p.NOT(
|
||||
p.hasAttrValue('type', 'css')
|
||||
)
|
||||
);
|
||||
|
||||
var isStyleNode = p.OR(
|
||||
// inline style
|
||||
p.hasTagName('style'),
|
||||
// external stylesheet
|
||||
p.AND(
|
||||
p.hasTagName('link'),
|
||||
p.hasAttrValue('rel', 'stylesheet')
|
||||
),
|
||||
// polymer specific external stylesheet
|
||||
p.AND(
|
||||
p.hasTagName('link'),
|
||||
p.hasAttrValue('rel', 'import'),
|
||||
p.hasAttrValue('type', 'css')
|
||||
)
|
||||
);
|
||||
|
||||
var isJSScriptNode = p.AND(
|
||||
p.hasTagName('script'),
|
||||
p.OR(
|
||||
p.NOT(p.hasAttr('type')),
|
||||
p.hasAttrValue('type', 'text/javascript'),
|
||||
p.hasAttrValue('type', 'application/javascript')
|
||||
)
|
||||
);
|
||||
|
||||
function addNode(node, registry) {
|
||||
if (isHtmlImportNode(node)) {
|
||||
registry.import.push(node);
|
||||
} else if (isStyleNode(node)) {
|
||||
registry.style.push(node);
|
||||
} else if (isJSScriptNode(node)) {
|
||||
registry.script.push(node);
|
||||
} else if (node.tagName === 'base') {
|
||||
registry.base.push(node);
|
||||
} else if (node.tagName === 'template') {
|
||||
registry.template.push(node);
|
||||
} else if (node.tagName === 'dom-module') {
|
||||
registry['dom-module'].push(node);
|
||||
} else if (dom5.isCommentNode(node)) {
|
||||
registry.comment.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
function getLineAndColumn(string, charNumber) {
|
||||
if (charNumber > string.length) {
|
||||
return undefined;
|
||||
}
|
||||
// TODO(ajo): Caching the line lengths of each document could be much faster.
|
||||
var sliced = string.slice(0,charNumber+1);
|
||||
var split = sliced.split('\n');
|
||||
var line = split.length;
|
||||
var column = split[split.length - 1].length;
|
||||
return {line: line, column: column};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse5's representation of a parsed html document.
|
||||
* @typedef {Object} DocumentAST
|
||||
*/
|
||||
|
||||
/**
|
||||
* The ASTs of the HTML elements needed to represent Polymer elements.
|
||||
* @typedef {Object} ParsedImport
|
||||
* @property {Array<DocumentAST>} template The entry points to the AST at each outermost template tag.
|
||||
* @property {Array<DocumentAST>} script The entry points to the AST at each script tag not inside a template.
|
||||
* @property {Array<DocumentAST>} style The entry points to the AST at style tag outside a template.
|
||||
* @property {Array<DocumentAST>} dom-module The entry points to the AST at each outermost dom-module element.
|
||||
* @property {DocumentAST} ast The full parse5 ast for the document.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parse html into ASTs.
|
||||
* @param {string} htmlString A utf8, html5 document containing polymer element or module definitons.
|
||||
* @param {string} href The path of the document.
|
||||
* @return {ParsedImport}
|
||||
*/
|
||||
var importParse = function importParse(htmlString, href) {
|
||||
var doc;
|
||||
try {
|
||||
doc = dom5.parse(htmlString, {locationInfo: true});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add line/column information
|
||||
dom5.treeMap(doc, function(node) {
|
||||
if (node.__location && node.__location.start >= 0) {
|
||||
node.__locationDetail = getLineAndColumn(htmlString, node.__location.start);
|
||||
if (href) {
|
||||
node.__ownerDocument = href;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var registry = {
|
||||
base: [],
|
||||
template: [],
|
||||
script: [],
|
||||
style: [],
|
||||
import: [],
|
||||
'dom-module': [],
|
||||
comment: []};
|
||||
|
||||
var queue = [].concat(doc.childNodes);
|
||||
var nextNode;
|
||||
while (queue.length > 0) {
|
||||
nextNode = queue.shift();
|
||||
if (nextNode) {
|
||||
queue = queue.concat(nextNode.childNodes);
|
||||
addNode(nextNode, registry);
|
||||
}
|
||||
}
|
||||
registry.ast = doc;
|
||||
return registry;
|
||||
};
|
||||
|
||||
module.exports = importParse;
|
||||
95
build/node_modules/hydrolysis/lib/ast-utils/js-parse.js
generated
vendored
Normal file
95
build/node_modules/hydrolysis/lib/ast-utils/js-parse.js
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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
|
||||
*/
|
||||
/**
|
||||
* Finds and annotates the Polymer() and modulate() calls in javascript.
|
||||
*/
|
||||
// jshint node: true
|
||||
'use strict';
|
||||
var espree = require('espree');
|
||||
var estraverse = require('estraverse');
|
||||
|
||||
var behaviorFinder = require('./behavior-finder');
|
||||
var elementFinder = require('./element-finder');
|
||||
var featureFinder = require('./feature-finder');
|
||||
|
||||
function traverse(visitorRegistries) {
|
||||
var visitor;
|
||||
function applyVisitors(name, node, parent) {
|
||||
var returnVal;
|
||||
for (var i = 0; i < visitorRegistries.length; i++) {
|
||||
if (name in visitorRegistries[i]) {
|
||||
returnVal = visitorRegistries[i][name](node, parent);
|
||||
if (returnVal) {
|
||||
return returnVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
enter: function(node, parent) {
|
||||
visitor = 'enter' + node.type;
|
||||
return applyVisitors(visitor, node, parent);
|
||||
},
|
||||
leave: function(node, parent) {
|
||||
visitor = 'leave' + node.type;
|
||||
return applyVisitors(visitor, node, parent);
|
||||
},
|
||||
fallback: 'iteration',
|
||||
};
|
||||
}
|
||||
|
||||
var jsParse = function jsParse(jsString) {
|
||||
var script = espree.parse(jsString, {
|
||||
attachComment: true,
|
||||
comment: true,
|
||||
loc: true,
|
||||
ecmaFeatures: {
|
||||
arrowFunctions: true,
|
||||
blockBindings: true,
|
||||
destructuring: true,
|
||||
regexYFlag: true,
|
||||
regexUFlag: true,
|
||||
templateStrings: true,
|
||||
binaryLiterals: true,
|
||||
unicodeCodePointEscapes: true,
|
||||
defaultParams: true,
|
||||
restParams: true,
|
||||
forOf: true,
|
||||
objectLiteralComputedProperties: true,
|
||||
objectLiteralShorthandMethods: true,
|
||||
objectLiteralShorthandProperties: true,
|
||||
objectLiteralDuplicateProperties: true,
|
||||
generators: true,
|
||||
spread: true,
|
||||
classes: true,
|
||||
modules: true,
|
||||
jsx: true,
|
||||
globalReturn: true,
|
||||
}
|
||||
});
|
||||
|
||||
var featureInfo = featureFinder();
|
||||
var behaviorInfo = behaviorFinder();
|
||||
var elementInfo = elementFinder();
|
||||
|
||||
var visitors = [featureInfo, behaviorInfo, elementInfo].map(function(info) {
|
||||
return info.visitors;
|
||||
});
|
||||
estraverse.traverse(script, traverse(visitors));
|
||||
|
||||
return {
|
||||
behaviors: behaviorInfo.behaviors,
|
||||
elements: elementInfo.elements,
|
||||
features: featureInfo.features,
|
||||
parsedScript: script
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = jsParse;
|
||||
223
build/node_modules/hydrolysis/lib/ast-utils/jsdoc.js
generated
vendored
Normal file
223
build/node_modules/hydrolysis/lib/ast-utils/jsdoc.js
generated
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 doctrine = require('doctrine');
|
||||
|
||||
/**
|
||||
* An annotated JSDoc block tag, all fields are optionally processed except for
|
||||
* the tag:
|
||||
*
|
||||
* @TAG {TYPE} NAME DESC
|
||||
*
|
||||
* `line` and `col` indicate the position of the first character of text that
|
||||
* the tag was extracted from - relative to the first character of the comment
|
||||
* contents (e.g. the value of `desc` on a descriptor node). Lines are
|
||||
* 1-indexed.
|
||||
*
|
||||
* @typedef {{
|
||||
* tag: string,
|
||||
* type: ?string,
|
||||
* name: ?string,
|
||||
* description: ?string,
|
||||
* }}
|
||||
*/
|
||||
var JsdocTag;
|
||||
|
||||
/**
|
||||
* The parsed representation of a JSDoc comment.
|
||||
*
|
||||
* @typedef {{
|
||||
* description: ?string,
|
||||
* tags: Array<JsdocTag>,
|
||||
* }}
|
||||
*/
|
||||
var JsdocAnnotation;
|
||||
|
||||
/**
|
||||
* doctrine configuration,
|
||||
* CURRENTLY UNUSED BECAUSE PRIVATE
|
||||
*/
|
||||
// function configureDoctrine() {
|
||||
|
||||
// // @hero [path/to/image]
|
||||
// doctrine.Rules['hero'] = ['parseNamePathOptional', 'ensureEnd'];
|
||||
|
||||
// // // @demo [path/to/demo] [Demo title]
|
||||
// doctrine.Rules['demo'] = ['parseNamePathOptional', 'parseDescription', 'ensureEnd'];
|
||||
|
||||
// // // @polymerBehavior [Polymer.BehaviorName]
|
||||
// doctrine.Rules['polymerBehavior'] = ['parseNamePathOptional', 'ensureEnd'];
|
||||
// }
|
||||
// configureDoctrine();
|
||||
|
||||
// @demo [path] [title]
|
||||
function parseDemo(tag) {
|
||||
var match = (tag.description || "").match(/^\s*(\S*)\s*(.*)$/);
|
||||
return {
|
||||
tag: 'demo',
|
||||
type: null,
|
||||
name: match ? match[1] : null,
|
||||
description: match ? match[2] : null
|
||||
};
|
||||
}
|
||||
|
||||
// @hero [path]
|
||||
function parseHero(tag) {
|
||||
return {
|
||||
tag: tag.title,
|
||||
type: null,
|
||||
name: tag.description,
|
||||
description: null
|
||||
};
|
||||
}
|
||||
|
||||
// @polymerBehavior [name]
|
||||
function parsePolymerBehavior(tag) {
|
||||
return {
|
||||
tag: tag.title,
|
||||
type: null,
|
||||
name: tag.description,
|
||||
description: null
|
||||
};
|
||||
}
|
||||
|
||||
// @pseudoElement name
|
||||
function parsePseudoElement(tag) {
|
||||
return {
|
||||
tag: tag.title,
|
||||
type: null,
|
||||
name: tag.description,
|
||||
description: null
|
||||
};
|
||||
}
|
||||
|
||||
var CUSTOM_TAGS = {
|
||||
demo: parseDemo,
|
||||
hero: parseHero,
|
||||
polymerBehavior: parsePolymerBehavior,
|
||||
pseudoElement: parsePseudoElement
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert doctrine tags to hydrolysis tag format
|
||||
*/
|
||||
function _tagsToHydroTags(tags) {
|
||||
if (!tags)
|
||||
return null;
|
||||
return tags.map( function(tag) {
|
||||
if (tag.title in CUSTOM_TAGS) {
|
||||
return CUSTOM_TAGS[tag.title](tag);
|
||||
}
|
||||
else {
|
||||
return {
|
||||
tag: tag.title,
|
||||
type: tag.type ? doctrine.type.stringify(tag.type) : null,
|
||||
name: tag.name,
|
||||
description: tag.description,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* removes leading *, and any space before it
|
||||
* @param {string} description -- js doc description
|
||||
*/
|
||||
function _removeLeadingAsterisks(description) {
|
||||
if ((typeof description) !== 'string')
|
||||
return description;
|
||||
|
||||
return description
|
||||
.split('\n')
|
||||
.map( function(line) {
|
||||
// remove leading '\s*' from each line
|
||||
var match = line.match(/^[\s]*\*\s?(.*)$/);
|
||||
return match ? match[1] : line;
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a JSDoc string (minus opening/closing comment delimiters), extract its
|
||||
* description and tags.
|
||||
*
|
||||
* @param {string} docs
|
||||
* @return {?JsdocAnnotation}
|
||||
*/
|
||||
function parseJsdoc(docs) {
|
||||
docs = _removeLeadingAsterisks(docs);
|
||||
var d = doctrine.parse(docs, {
|
||||
unwrap: false,
|
||||
lineNumber: true,
|
||||
preserveWhitespace: true
|
||||
});
|
||||
return {
|
||||
description: d.description,
|
||||
tags: _tagsToHydroTags(d.tags)
|
||||
};
|
||||
}
|
||||
|
||||
// Utility
|
||||
|
||||
/**
|
||||
* @param {JsdocAnnotation} jsdoc
|
||||
* @param {string} tagName
|
||||
* @return {boolean}
|
||||
*/
|
||||
function hasTag(jsdoc, tagName) {
|
||||
if (!jsdoc || !jsdoc.tags) return false;
|
||||
return jsdoc.tags.some(function(tag) { return tag.tag === tagName; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first JSDoc tag matching `name` and returns its value at `key`.
|
||||
*
|
||||
* @param {JsdocAnnotation} jsdoc
|
||||
* @param {string} tagName
|
||||
* @param {string=} key If omitted, the entire tag object is returned.
|
||||
* @return {?string|Object}
|
||||
*/
|
||||
function getTag(jsdoc, tagName, key) {
|
||||
if (!jsdoc || !jsdoc.tags) return false;
|
||||
for (var i = 0; i < jsdoc.tags.length; i++) {
|
||||
var tag = jsdoc.tags[i];
|
||||
if (tag.tag === tagName) {
|
||||
return key ? tag[key] : tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?string} text
|
||||
* @return {?string}
|
||||
*/
|
||||
function unindent(text) {
|
||||
if (!text) return text;
|
||||
var lines = text.replace(/\t/g, ' ').split('\n');
|
||||
var indent = lines.reduce(function(prev, line) {
|
||||
if (/^\s*$/.test(line)) return prev; // Completely ignore blank lines.
|
||||
|
||||
var lineIndent = line.match(/^(\s*)/)[0].length;
|
||||
if (prev === null) return lineIndent;
|
||||
return lineIndent < prev ? lineIndent : prev;
|
||||
}, null);
|
||||
|
||||
return lines.map(function(l) { return l.substr(indent); }).join('\n');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getTag: getTag,
|
||||
hasTag: hasTag,
|
||||
parseJsdoc: parseJsdoc,
|
||||
unindent: unindent
|
||||
};
|
||||
30
build/node_modules/hydrolysis/lib/loader/error-swallowing-fs-resolver.js
generated
vendored
Normal file
30
build/node_modules/hydrolysis/lib/loader/error-swallowing-fs-resolver.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 FSResolver = require('./fs-resolver');
|
||||
|
||||
function ErrorSwallowingFSResolver(config) {
|
||||
FSResolver.call(this, config);
|
||||
}
|
||||
|
||||
ErrorSwallowingFSResolver.prototype = Object.create(FSResolver.prototype);
|
||||
|
||||
ErrorSwallowingFSResolver.prototype.accept = function(uri, deferred) {
|
||||
var reject = deferred.reject;
|
||||
deferred.reject = function(arg) {
|
||||
deferred.resolve("");
|
||||
};
|
||||
return FSResolver.prototype.accept.call(this, uri, deferred);
|
||||
};
|
||||
|
||||
module.exports = ErrorSwallowingFSResolver;
|
||||
99
build/node_modules/hydrolysis/lib/loader/file-loader.js
generated
vendored
Normal file
99
build/node_modules/hydrolysis/lib/loader/file-loader.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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';
|
||||
|
||||
// jshint -W079
|
||||
// Promise polyfill
|
||||
var Promise = global.Promise || require('es6-promise').Promise;
|
||||
// jshint +W079
|
||||
|
||||
function Deferred() {
|
||||
var self = this;
|
||||
this.promise = new Promise(function(resolve, reject) {
|
||||
self.resolve = resolve;
|
||||
self.reject = reject;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that knows how to resolve resources.
|
||||
* @typedef {Object} Resolver
|
||||
* @memberof hydrolysis
|
||||
* @property {function(string, Deferred): boolean} accept Attempt to resolve
|
||||
* `deferred` with the contents the specified URL. Returns false if the
|
||||
* Resolver is unable to resolve the URL.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* A FileLoader lets you resolve URLs with a set of potential resolvers.
|
||||
* @constructor
|
||||
* @memberof hydrolysis
|
||||
*/
|
||||
function FileLoader() {
|
||||
this.resolvers = [];
|
||||
// map url -> Deferred
|
||||
this.requests = {};
|
||||
}
|
||||
FileLoader.prototype = {
|
||||
|
||||
/**
|
||||
* Add an instance of a Resolver class to the list of url resolvers
|
||||
*
|
||||
* Ordering of resolvers is most to least recently added
|
||||
* The first resolver to "accept" the url wins.
|
||||
* @param {Resolver} resolver The resolver to add.
|
||||
*/
|
||||
addResolver: function(resolver) {
|
||||
this.resolvers.push(resolver);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a promise for an absolute url
|
||||
*
|
||||
* Url requests are deduplicated by the loader, returning the same Promise for
|
||||
* identical urls
|
||||
*
|
||||
* @param {string} url The absolute url to request.
|
||||
* @return {Promise.<string>} A promise that resolves to the contents of the URL.
|
||||
*/
|
||||
request: function(uri) {
|
||||
var promise;
|
||||
|
||||
if (!(uri in this.requests)) {
|
||||
var handled = false;
|
||||
var deferred = new Deferred();
|
||||
this.requests[uri] = deferred;
|
||||
|
||||
// loop backwards through resolvers until one "accepts" the request
|
||||
for (var i = this.resolvers.length - 1, r; i >= 0; i--) {
|
||||
r = this.resolvers[i];
|
||||
if (r.accept(uri, deferred)) {
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
deferred.reject(new Error('no resolver found for ' + uri));
|
||||
}
|
||||
|
||||
promise = deferred.promise;
|
||||
} else {
|
||||
promise = this.requests[uri].promise;
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = FileLoader;
|
||||
110
build/node_modules/hydrolysis/lib/loader/fs-resolver.js
generated
vendored
Normal file
110
build/node_modules/hydrolysis/lib/loader/fs-resolver.js
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 fs = require('fs');
|
||||
var path = require('path');
|
||||
var pathIsAbsolute = require('path-is-absolute');
|
||||
var url = require('url');
|
||||
|
||||
function getFile(filePath, deferred, secondPath) {
|
||||
fs.readFile(filePath, 'utf-8', function(err, content) {
|
||||
if (err) {
|
||||
if (secondPath) {
|
||||
getFile(secondPath, deferred);
|
||||
} else {
|
||||
console.log("ERROR finding " + filePath);
|
||||
deferred.reject(err);
|
||||
}
|
||||
} else {
|
||||
deferred.resolve(content);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if `patha` is a sibling or aunt of `pathb`.
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isSiblingOrAunt(patha, pathb) {
|
||||
var parent = path.dirname(patha);
|
||||
if (pathb.indexOf(patha) === -1 && pathb.indexOf(parent) === 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change `localPath` from a sibling of `basePath` to be a child of
|
||||
* `basePath` joined with `redirect`.
|
||||
* @return {string}
|
||||
*/
|
||||
function redirectSibling(basePath, localPath, redirect) {
|
||||
var parent = path.dirname(basePath);
|
||||
var redirected = path.join(basePath, redirect, localPath.slice(parent.length));
|
||||
return redirected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves requests via the file system.
|
||||
* @constructor
|
||||
* @memberof hydrolysis
|
||||
* @param {Object} config configuration options.
|
||||
* @param {string} config.host Hostname to match for absolute urls.
|
||||
* Matches "/" by default
|
||||
* @param {string} config.basePath Prefix directory for components in url.
|
||||
* Defaults to "/".
|
||||
* @param {string} config.root Filesystem root to search. Defaults to the
|
||||
* current working directory.
|
||||
* @param {string} config.redirect Where to redirect lookups to siblings.
|
||||
*/
|
||||
function FSResolver(config) {
|
||||
this.config = config || {};
|
||||
}
|
||||
FSResolver.prototype = {
|
||||
accept: function(uri, deferred) {
|
||||
var parsed = url.parse(uri);
|
||||
var host = this.config.host;
|
||||
var base = this.config.basePath && decodeURIComponent(this.config.basePath);
|
||||
var root = this.config.root && path.normalize(this.config.root);
|
||||
var redirect = this.config.redirect;
|
||||
|
||||
var local;
|
||||
|
||||
if (!parsed.hostname || parsed.hostname === host) {
|
||||
local = parsed.pathname;
|
||||
}
|
||||
if (local) {
|
||||
// un-escape HTML escapes
|
||||
local = decodeURIComponent(local);
|
||||
|
||||
if (base) {
|
||||
local = path.relative(base, local);
|
||||
}
|
||||
if (root) {
|
||||
local = path.join(root, local);
|
||||
}
|
||||
|
||||
var backup;
|
||||
if (redirect && isSiblingOrAunt(root, local)) {
|
||||
backup = redirectSibling(root, local, redirect);
|
||||
}
|
||||
|
||||
getFile(local, deferred, backup);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = FSResolver;
|
||||
44
build/node_modules/hydrolysis/lib/loader/noop-resolver.js
generated
vendored
Normal file
44
build/node_modules/hydrolysis/lib/loader/noop-resolver.js
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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';
|
||||
|
||||
/**
|
||||
* A resolver that resolves to null any uri matching config.
|
||||
* @constructor
|
||||
* @memberof hydrolysis
|
||||
* @param {string} config The url to `accept`.
|
||||
*/
|
||||
function NoopResolver(config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
NoopResolver.prototype = {
|
||||
|
||||
/**
|
||||
* @param {string} uri The absolute URI being requested.
|
||||
* @param {!Deferred} deferred The deferred promise that should be resolved if
|
||||
* this resolver handles the URI.
|
||||
* @return {boolean} Whether the URI is handled by this resolver.
|
||||
*/
|
||||
accept: function(uri, deferred) {
|
||||
if (!this.config.test) {
|
||||
if (uri.search(this.config) == -1) {
|
||||
return false;
|
||||
}
|
||||
} else if (!this.config.test(uri)) return false;
|
||||
|
||||
deferred.resolve('');
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = NoopResolver;
|
||||
106
build/node_modules/hydrolysis/lib/loader/redirect-resolver.js
generated
vendored
Normal file
106
build/node_modules/hydrolysis/lib/loader/redirect-resolver.js
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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 fs = require('fs');
|
||||
var path = require('path');
|
||||
var url = require('url');
|
||||
|
||||
var FSResolver = require('./fs-resolver');
|
||||
|
||||
/**
|
||||
* A single redirect configuration
|
||||
* @param {Object} config The configuration object
|
||||
* @param {string} config.protocol The protocol this redirect matches.
|
||||
* @param {string} config.hostname The host name this redirect matches.
|
||||
* @param {string} config.path The part of the path to match and
|
||||
* replace with 'redirectPath'
|
||||
* @param {string} config.redirectPath The local filesystem path that should
|
||||
* replace "protocol://hosname/path/"
|
||||
*/
|
||||
function ProtocolRedirect(config){
|
||||
this.protocol = config.protocol;
|
||||
this.hostname = config.hostname;
|
||||
this.path = config.path;
|
||||
this.redirectPath = config.redirectPath;
|
||||
}
|
||||
|
||||
ProtocolRedirect.prototype = {
|
||||
/**
|
||||
* The protocol this redirect matches.
|
||||
* @type {string}
|
||||
*/
|
||||
protocol: null,
|
||||
/**
|
||||
* The host name this redirect matches.
|
||||
* @type {string}
|
||||
*/
|
||||
hostname: null,
|
||||
|
||||
/**
|
||||
* The part of the path to match and replace with 'redirectPath'
|
||||
* @type {string}
|
||||
*/
|
||||
path: null,
|
||||
|
||||
/**
|
||||
* The local filesystem path that should replace "protocol://hosname/path/"
|
||||
* @type {string}
|
||||
*/
|
||||
redirectPath: null,
|
||||
|
||||
redirect: function redirect(uri) {
|
||||
var parsed = url.parse(uri);
|
||||
if (this.protocol !== parsed.protocol) {
|
||||
return null;
|
||||
} else if (this.hostname !== parsed.hostname) {
|
||||
return null;
|
||||
} else if (parsed.pathname.indexOf(this.path) !== 0) {
|
||||
return null;
|
||||
}
|
||||
return path.join(this.redirectPath,
|
||||
parsed.pathname.slice(this.path.length));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves protocol://hostname/path to the local filesystem.
|
||||
* @constructor
|
||||
* @memberof hydrolysis
|
||||
* @param {Object} config configuration options.
|
||||
* @param {string} config.root Filesystem root to search. Defaults to the
|
||||
* current working directory.
|
||||
* @param {Array.<ProtocolRedirect>} redirects A list of protocol redirects
|
||||
* for the resolver. They are checked for matching first-to-last.
|
||||
*/
|
||||
function RedirectResolver(config) {
|
||||
FSResolver.call(this, config);
|
||||
this.redirects = config.redirects || [];
|
||||
}
|
||||
|
||||
RedirectResolver.prototype = Object.create(FSResolver.prototype);
|
||||
|
||||
RedirectResolver.prototype.accept = function(uri, deferred) {
|
||||
for (var i = 0; i < this.redirects.length; i++) {
|
||||
var redirected = this.redirects[i].redirect(uri);
|
||||
if (redirected) {
|
||||
return FSResolver.prototype.accept.call(this, redirected, deferred);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
RedirectResolver.prototype.constructor = RedirectResolver;
|
||||
RedirectResolver.ProtocolRedirect = ProtocolRedirect;
|
||||
|
||||
|
||||
module.exports = RedirectResolver;
|
||||
54
build/node_modules/hydrolysis/lib/loader/string-resolver.js
generated
vendored
Normal file
54
build/node_modules/hydrolysis/lib/loader/string-resolver.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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';
|
||||
|
||||
/**
|
||||
* A resolver that resolves to `config.content` any uri matching config.
|
||||
* @constructor
|
||||
* @memberof hydrolysis
|
||||
* @param {string|RegExp} config.url The url or rejex to accept.
|
||||
* @param {string} config.content The content to serve for `url`.
|
||||
*/
|
||||
function StringResolver(config) {
|
||||
this.url = config.url;
|
||||
this.content = config.content;
|
||||
if (!this.url || !this.content) {
|
||||
throw new Error("Must provide a url and content to the string resolver.");
|
||||
}
|
||||
}
|
||||
|
||||
StringResolver.prototype = {
|
||||
|
||||
/**
|
||||
* @param {string} uri The absolute URI being requested.
|
||||
* @param {!Deferred} deferred The deferred promise that should be resolved if
|
||||
* this resolver handles the URI.
|
||||
* @return {boolean} Whether the URI is handled by this resolver.
|
||||
*/
|
||||
accept: function(uri, deferred) {
|
||||
if (this.url.test) {
|
||||
// this.url is a regex
|
||||
if (!this.url.test(uri)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// this.url is a string
|
||||
if (uri.search(this.url) == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
deferred.resolve(this.content);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = StringResolver;
|
||||
53
build/node_modules/hydrolysis/lib/loader/xhr-resolver.js
generated
vendored
Normal file
53
build/node_modules/hydrolysis/lib/loader/xhr-resolver.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2015 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';
|
||||
|
||||
function getFile(url, deferred, config) {
|
||||
/* global XMLHttpRequest:false */
|
||||
var x = new XMLHttpRequest();
|
||||
x.onload = function() {
|
||||
var status = x.status || 0;
|
||||
if (status >= 200 && status < 300) {
|
||||
deferred.resolve(x.response);
|
||||
} else {
|
||||
deferred.reject('xhr status: ' + status);
|
||||
}
|
||||
};
|
||||
x.onerror = function(e) {
|
||||
deferred.reject(e);
|
||||
};
|
||||
x.open('GET', url, true);
|
||||
if (config && config.responseType) {
|
||||
x.responseType = config.responseType;
|
||||
}
|
||||
x.send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a resolver that requests resources over XHR.
|
||||
* @constructor
|
||||
* @memberof hydrolysis
|
||||
* @param {Object} config configuration arguments.
|
||||
* @param {string} config.responseType Type of object to be returned by the
|
||||
* XHR. Defaults to 'text', accepts 'document', 'arraybuffer', and 'json'.
|
||||
*/
|
||||
function XHRResolver(config) {
|
||||
this.config = config;
|
||||
}
|
||||
XHRResolver.prototype = {
|
||||
accept: function(uri, deferred) {
|
||||
getFile(uri, deferred, this.config);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = XHRResolver;
|
||||
Reference in New Issue
Block a user