playwright/utils/ESTreeWalker.js
2019-11-19 10:58:15 -08:00

137 lines
4.2 KiB
JavaScript

// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @unrestricted
*/
class ESTreeWalker {
/**
* @param {function(!ESTree.Node):(!Object|undefined)} beforeVisit
* @param {function(!ESTree.Node)=} afterVisit
*/
constructor(beforeVisit, afterVisit) {
this._beforeVisit = beforeVisit;
this._afterVisit = afterVisit || new Function();
}
/**
* @param {!ESTree.Node} ast
*/
walk(ast) {
this._innerWalk(ast, null);
}
/**
* @param {!ESTree.Node} node
* @param {?ESTree.Node} parent
*/
_innerWalk(node, parent) {
if (!node)
return;
node.parent = parent;
if (this._beforeVisit.call(null, node) === ESTreeWalker.SkipSubtree) {
this._afterVisit.call(null, node);
return;
}
const walkOrder = ESTreeWalker._walkOrder[node.type];
if (!walkOrder)
return;
if (node.type === 'TemplateLiteral') {
const templateLiteral = /** @type {!ESTree.TemplateLiteralNode} */ (node);
const expressionsLength = templateLiteral.expressions.length;
for (let i = 0; i < expressionsLength; ++i) {
this._innerWalk(templateLiteral.quasis[i], templateLiteral);
this._innerWalk(templateLiteral.expressions[i], templateLiteral);
}
this._innerWalk(templateLiteral.quasis[expressionsLength], templateLiteral);
} else {
for (let i = 0; i < walkOrder.length; ++i) {
const entity = node[walkOrder[i]];
if (Array.isArray(entity))
this._walkArray(entity, node);
else
this._innerWalk(entity, node);
}
}
this._afterVisit.call(null, node);
}
/**
* @param {!Array.<!ESTree.Node>} nodeArray
* @param {?ESTree.Node} parentNode
*/
_walkArray(nodeArray, parentNode) {
for (let i = 0; i < nodeArray.length; ++i)
this._innerWalk(nodeArray[i], parentNode);
}
}
/** @typedef {!Object} ESTreeWalker.SkipSubtree */
ESTreeWalker.SkipSubtree = {};
/** @enum {!Array.<string>} */
ESTreeWalker._walkOrder = {
'AwaitExpression': ['argument'],
'ArrayExpression': ['elements'],
'ArrowFunctionExpression': ['params', 'body'],
'AssignmentExpression': ['left', 'right'],
'AssignmentPattern': ['left', 'right'],
'BinaryExpression': ['left', 'right'],
'BlockStatement': ['body'],
'BreakStatement': ['label'],
'CallExpression': ['callee', 'arguments'],
'CatchClause': ['param', 'body'],
'ClassBody': ['body'],
'ClassDeclaration': ['id', 'superClass', 'body'],
'ClassExpression': ['id', 'superClass', 'body'],
'ConditionalExpression': ['test', 'consequent', 'alternate'],
'ContinueStatement': ['label'],
'DebuggerStatement': [],
'DoWhileStatement': ['body', 'test'],
'EmptyStatement': [],
'ExpressionStatement': ['expression'],
'ForInStatement': ['left', 'right', 'body'],
'ForOfStatement': ['left', 'right', 'body'],
'ForStatement': ['init', 'test', 'update', 'body'],
'FunctionDeclaration': ['id', 'params', 'body'],
'FunctionExpression': ['id', 'params', 'body'],
'Identifier': [],
'IfStatement': ['test', 'consequent', 'alternate'],
'LabeledStatement': ['label', 'body'],
'Literal': [],
'LogicalExpression': ['left', 'right'],
'MemberExpression': ['object', 'property'],
'MethodDefinition': ['key', 'value'],
'NewExpression': ['callee', 'arguments'],
'ObjectExpression': ['properties'],
'ObjectPattern': ['properties'],
'ParenthesizedExpression': ['expression'],
'Program': ['body'],
'Property': ['key', 'value'],
'ReturnStatement': ['argument'],
'SequenceExpression': ['expressions'],
'Super': [],
'SwitchCase': ['test', 'consequent'],
'SwitchStatement': ['discriminant', 'cases'],
'TaggedTemplateExpression': ['tag', 'quasi'],
'TemplateElement': [],
'TemplateLiteral': ['quasis', 'expressions'],
'ThisExpression': [],
'ThrowStatement': ['argument'],
'TryStatement': ['block', 'handler', 'finalizer'],
'UnaryExpression': ['argument'],
'UpdateExpression': ['argument'],
'VariableDeclaration': ['declarations'],
'VariableDeclarator': ['id', 'init'],
'WhileStatement': ['test', 'body'],
'WithStatement': ['object', 'body'],
'YieldExpression': ['argument']
};
module.exports = ESTreeWalker;