UNPKG

hydrolysis

Version:
193 lines (192 loc) 8.11 kB
/** * @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'; var estraverse = require('estraverse'); var esutil = require('./esutil'); var declaration_property_handlers_1 = require('./declaration-property-handlers'); var docs = require('./docs'); 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 = { classDetected: false, enterClassDeclaration: function enterClassDeclaration(node, parent) { this.classDetected = true; element = { type: 'element', desc: esutil.getAttachedComment(node), events: esutil.getEventComments(node).map(function (event) { return { desc: event }; }), properties: [], behaviors: [], observers: [] }; propertyHandlers = declaration_property_handlers_1.declarationPropertyHandlers(element); }, leaveClassDeclaration: function leaveClassDeclaration(node, parent) { element.properties.map(function (property) { return docs.annotate(property); }); if (element) { elements.push(element); element = null; propertyHandlers = null; } this.classDetected = false; }, enterAssignmentExpression: function enterAssignmentExpression(node, parent) { if (!element) { return; } var left = node.left; if (left && left.object && left.object.type !== 'ThisExpression') { return; } var prop = left.property; if (prop && prop.name) { var name = prop.name; if (name in propertyHandlers) { propertyHandlers[name](node.right); } } }, enterMethodDefinition: function enterMethodDefinition(node, parent) { if (!element) { return; } var prop = { key: node.key, value: node.value, kind: node.kind, method: true, leadingComments: node.leadingComments, shorthand: false, computed: false, type: 'Property' }; var propDesc = docs.annotate(esutil.toPropertyDescriptor(prop)); if (prop && prop.kind === 'get' && (propDesc.name === 'behaviors' || propDesc.name === 'observers')) { var returnStatement = node.value.body.body[0]; var argument = returnStatement.argument; if (argument.elements) { if (propDesc.name === 'behaviors') { argument.elements.forEach(function (elementObject) { element.behaviors.push(elementObject.name); }); } else { argument.elements.forEach(function (elementObject) { element.observers.push({ javascriptNode: elementObject, expression: elementObject.raw }); }); } } } else { element.properties.push(propDesc); } }, enterCallExpression: function enterCallExpression(node, parent) { // When dealing with a class, enterCallExpression is called after the parsing actually starts if (this.classDetected) { return estraverse.VisitorOption.Skip; } var callee = node.callee; if (callee.type == 'Identifier') { var ident = callee; if (ident.name == 'Polymer') { element = { type: 'element', desc: esutil.getAttachedComment(parent), events: esutil.getEventComments(parent).map(function (event) { return { desc: event }; }) }; propertyHandlers = declaration_property_handlers_1.declarationPropertyHandlers(element); } } }, leaveCallExpression: function leaveCallExpression(node, parent) { var callee = node.callee; var args = node.arguments; if (callee.type == 'Identifier' && args.length === 1 && args[0].type === 'ObjectExpression') { var ident = callee; if (ident.name == 'Polymer') { if (element) { elements.push(element); element = null; propertyHandlers = null; } } } }, enterObjectExpression: function enterObjectExpression(node, parent) { // When dealing with a class, there is no single object that we can parse to retrieve all properties if (this.classDetected) { return estraverse.VisitorOption.Skip; } 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(prop); }); return estraverse.VisitorOption.Skip; } } }; return { visitors: visitors, elements: elements }; } exports.elementFinder = elementFinder; ;