hydrolysis
Version:
Breaks polymers into monomers
162 lines (160 loc) • 5.65 kB
JavaScript
/**
* @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
*/
;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var estraverse = require("estraverse");
var escodegen = require('escodegen');
/**
* 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 {ESTree.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);
if (expression.property.type !== 'Identifier') {
return;
}
var property = expression.property;
// Unravel backwards, make sure properties match each step of the way.
if (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;
}
exports.matchesCallExpression = matchesCallExpression;
/**
* @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.toString();
}
if (key.type == 'MemberExpression') {
var mEx = key;
return objectKeyToString(mEx.object) + '.' + objectKeyToString(mEx.property);
}
}
exports.objectKeyToString = objectKeyToString;
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') {
var ident = node;
return CLOSURE_CONSTRUCTOR_MAP[ident.name] || ident.name;
} else {
throw {
message: 'Unknown Closure type for node: ' + node.type,
location: node.loc.start
};
}
}
exports.closureType = closureType;
function getAttachedComment(node) {
var comments = getLeadingComments(node) || getLeadingComments(node['key']);
if (!comments) {
return;
}
return comments[comments.length - 1];
}
exports.getAttachedComment = getAttachedComment;
/**
* Returns all comments from a tree defined with @event.
*/
function getEventComments(node) {
var eventComments = [];
estraverse.traverse(node, {
enter: function enter(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);
},
keys: {
Super: []
}
});
// dedup
return eventComments.filter(function (el, index, array) {
return array.indexOf(el) === index;
});
}
exports.getEventComments = getEventComments;
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 estree Property AST node into its Hydrolysis representation.
*/
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') {
var value = node.value;
result.params = (value.params || []).map(function (param) {
// With ES6 we can have a variety of param patterns. Best to leave the
// formatting to escodegen.
return { name: escodegen.generate(param) };
});
}
return result;
}
exports.toPropertyDescriptor = toPropertyDescriptor;