UNPKG

@openui5/sap.ui.demokit

Version:

OpenUI5 UI Library sap.ui.demokit

189 lines (165 loc) 5.8 kB
/*! * OpenUI5 * (c) Copyright 2009-2019 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ // Provides implementation of sap.ui.demokit.util.jsanalyzer.ASTUtils sap.ui.define(['jquery.sap.global', 'sap/ui/demokit/js/esprima'], function(jQuery, esprima_) { "use strict"; /*global esprima */ var Syntax = esprima.Syntax; function unlend(node) { if ( node.type == Syntax.AssignmentExpression && node.left.type == Syntax.Identifier && node.right.type == Syntax.ObjectExpression ) { //console.log("lends found, skipped to " + node.type); return node.right; } return node; } /** * Creates a map of property values from an AST 'object literal' node. * * The values in the map are again AST 'property' nodes (representing key/value pairs). * It would be more convenient to just return the values, but the property node is needed * to find the corresponding (preceding) documentation comment. * * If a defaultKey is given, then a simple literal value instead of an object literal is also accepted. * It will be interpreted as the value of a property with the name specified as defaultKey. * <pre> * "value" * </pre> * is a shorthand notation of * <pre> * { * 'defaultKey': "value" * } * </pre> * @param {object} node Esprima compatible node of a syntax tree * @param {string} defaultKey When no object is given but only a literla, then the literal is assumed to be the value of the defaultKey * @returns {Map<string,Property>} Map of "Property" objects keyed by the property key */ function createPropertyMap(node, defaultKey) { var result; if ( node != null ) { //if ( node.type === Syntax.Property ) { // node = node.value; // //console.log("property found, skipped to " + node.type); //} // special handling of the synthetic ___ = {} assignments that JSDoc3 creates for @lends statements -> reduce them to the object literal (right hand side of assignment) node = unlend(node); // if, instead of an object literal only a literal is given and there is a defaultKey, then wrap the literal in a map if ( node.type === Syntax.Literal && defaultKey != null ) { result = {}; result[defaultKey] = { type: Syntax.Property, value: node }; return result; } if ( node.type != Syntax.ObjectExpression ) { // something went wrong, it's not an object literal jQuery.sap.log.error("not an object literal:" + node.type + ":" + node.value); // console.log(node.toSource()); return; } // invariant: node.type == Syntax.ObjectExpression result = {}; for (var i = 0; i < node.properties.length; i++) { var prop = node.properties[i]; var name; //console.log("objectproperty " + prop.type); if ( prop.key.type === Syntax.Identifier ) { name = prop.key.name; } else if ( prop.key.type === Syntax.Literal ) { name = String(prop.key.value); } else { name = prop.key.toSource(); } //console.log("objectproperty " + prop.type + ":" + name); result[name] = prop; } } return result; } var astNodeInfos = { AssignmentExpression: [ 'left', 'right' ], ArrayExpression: [ 'elements' ], BlockStatement: [ 'body' ], BinaryExpression: [ 'left', 'right' ], BreakStatement: [], CallExpression: [ 'callee', 'arguments' ], CatchClause: [], ConditionalExpression: [ 'test', 'consequent', 'alternate' ], ContinueStatement: [], DoWhileStatement: [ 'body', 'test' ], DebuggerStatement: [], EmptyStatement: [], ExpressionStatement: [ 'expression' ], ForStatement: [ 'init', 'test', 'update', 'body' ], ForInStatement: [ 'left', 'right', 'body' ], FunctionDeclaration: [ 'id', 'params', 'body' ], FunctionExpression: [ 'id', 'params', 'body' ], Identifier: [], IfStatement: [ 'test', 'consequent', 'alternate' ], Literal: [], LabeledStatement: [ 'body' ], LogicalExpression: [ 'left', 'right' ], MemberExpression: [ 'object', 'property' ], NewExpression: [ 'callee', 'arguments' ], ObjectExpression: [ 'properties' ], Program: [ 'body' ], Property: [ 'key', 'value' ], ReturnStatement: [ 'argument' ], SequenceExpression: [ 'expressions' ], SwitchStatement: [ 'discriminant', 'cases' ], SwitchCase: [ 'test', 'consequent' ], ThisExpression: [], ThrowStatement: [ 'argument' ], TryStatement: [ '' ], // TODO UnaryExpression: [ 'argument' ], UpdateExpression: [ 'argument' ], VariableDeclaration: [ 'declarations' ], VariableDeclarator: [ 'id', 'init' ], WhileStatement: [ 'test', 'body' ], WithStatement: [ 'object', 'body' ] }; function visit(root, delegate, args) { function _visit(node) { // call the delegate before the children if ( delegate["*"] ) { delegate["*"].call(delegate, node, args); } if ( delegate[node.type] ) { delegate[node.type].call(delegate, node, args); } // visit children var aChildNames = astNodeInfos[node.type]; if ( aChildNames ) { for (var i = 0; i < aChildNames.length; i++) { var aChildNodes = node[aChildNames[i]]; if ( jQuery.isArray(aChildNodes) ) { for ( var j = 0; j < aChildNodes.length; j++) { if ( aChildNodes[j] ) { _visit(aChildNodes[j]); } } } else if ( aChildNodes ) { _visit(aChildNodes); } } } else { jQuery.sap.log.warning("don't know how to handle " + node.type); } // call the delegate if ( delegate["after:" + node.type] ) { delegate["after:" + node.type].call(delegate, node, args); } if ( delegate["after:*"] ) { delegate["after:*"].call(delegate, node, args); } } _visit(root); } return { createPropertyMap: createPropertyMap, unlend: unlend, visit : visit }; }, /* export= */ true);