UNPKG

esprima-ast-utils

Version:

collection for AST query/manipulation/transformation

228 lines (195 loc) 6.45 kB
'use strict'; module.exports = { setIdentifier: setIdentifier, renameProperty: renameProperty, renameVariable: renameVariable, renameFunction: renameFunction, toProgram: toProgram }; var traverse = require("./walk.js").traverse, getRoot = require("./walk.js").getRoot, parentize = require("./walk.js").parentize, idze = require("./walk.js").idze, clone = require("./walk.js").clone, getToken = require("./tokens.js").getToken, getTokens = require("./tokens.js").getTokens, pushTokens = require("./tokens.js").pushTokens, growTokens = require("./tokens.js").growTokens, isVarDeclared = require("./query.js").isVarDeclared, isFunctionDefined = require("./query.js").isFunctionDefined, getCode = require("./query.js").getCode, replaceCodeRange = require("./tokens.js").replaceCodeRange; /** * rename `Identifier` * * @param {Object} node * @param {String} new_name */ function setIdentifier(node, new_name) { if (node.type !== "Identifier") { throw new Error("node must be an Identifier"); } var root = getRoot(node), diff = (new_name.length - node.name.length), token = getToken(root, node.range[0], node.range[1]); if (!token) { console.log(node); console.log(root.tokens); throw new Error("token cannot be found"); } token.value = new_name; token.range[1] += diff; replaceCodeRange(root, node.range, new_name); pushTokens(root, node.range[1], diff); growTokens(root, node.range[0], node.range[1], diff); node.name = new_name; } /** * `traverse` and apply given `replacements` * * @param {Object} node * @param {Object} replacements * * @example * renameProperty(node, {"old_var": "new_var", "much_older": "shinnig_new"}) */ function renameProperty(node, replacements) { if (node.$parent === undefined) { throw new Error("parentize is required"); } if (node.$id === undefined) { throw new Error("idze is required"); } traverse(node, function(node) { if (node.type == "Identifier" && replacements[node.name] && ( "Property" === node.$parent.type || ( "MemberExpression" === node.$parent.type && node.$parent.property === node ) ) ) { setIdentifier(node, replacements[node.name]); } }); } /** * `traverse` and apply given `replacements` * * @param {Object} node * @param {Object} replacements * * @example * renameVariable(node, {"old_var": "new_var", "much_older": "shinnig_new"}) */ function renameVariable(node, replacements) { if (node.$parent === undefined) { throw new Error("parentize is required"); } if (node.$id === undefined) { throw new Error("idze is required"); } var root = getRoot(node); traverse(node, function(node) { //if (node.type == "Identifier") //console.log("*", node.type, node.$parent.type, node.$parent); if (node.type == "Identifier" && replacements[node.name] && ( ["VariableDeclarator", "AssignmentExpression", "ReturnStatement"] .indexOf(node.$parent.type) !== -1 || ( "Property" === node.$parent.type && node.$parent.value.$id === node.$id && isVarDeclared(node, replacements[node.name]) ) ) ) { setIdentifier(node, replacements[node.name]); } }); } /** * traverse and apply given `replacements` * * @param {Object} node * @param {Object} replacements * * @example * renameFunction(node, {"old_var": "new_var", "much_older": "shinnig_new"}) */ function renameFunction(node, replacements) { if (node.$parent === undefined) { throw new Error("parentize is required"); } if (node.$id === undefined) { throw new Error("idze is required"); } traverse(node, function(node) { if (node.type == "Identifier" && replacements[node.name]) { if ( ["FunctionDeclaration", "CallExpression"].indexOf(node.$parent.type) !== -1 || ( "Property" === node.$parent.type && node.$parent.value.$id === node.$id && !isVarDeclared(node, replacements[node.name]) && ( isFunctionDefined(node, replacements[node.name]) || // could be below isFunctionDefined(node, node.name) ) ) ) { setIdentifier(node, replacements[node.name]); } } }); } /** * Clone given node(s) and extract tokens & code from root to given you a Program-like attachable node * * @param {Object|Array} node * if array is provided will add all nodes to program.body */ function toProgram(node) { var root, program_range, tokens, program, i; if (Array.isArray(node)) { root = getRoot(node[0]); program_range = [Infinity, -Infinity]; for(i = 0; i < node.length; ++i) { program_range[0] = Math.min(program_range[0], node[i].range[0]); program_range[1] = Math.max(program_range[1], node[i].range[1]); } } else { root = getRoot(node); program_range = node.range; } tokens = getTokens(root, program_range[0], program_range[1]); program = { type: "Program", body: null, range: [program_range[0], program_range[1]], tokens: tokens, comments: [], $code: null }; if (Array.isArray(node)) { program.$code = getCode({$parent: root, range: program_range}); // fake program.body = node.slice().map(clone); // clone! } else { program.$code = getCode(node); program.body = [ clone(node) ]; } parentize(program); idze(program); pushTokens(program, 0, -program_range[0]); return program; }