package com.crawljax.plugins.jsmodify; import org.mozilla.javascript.CompilerEnvirons; import org.mozilla.javascript.Parser; import org.mozilla.javascript.ast.AstNode; import org.mozilla.javascript.ast.AstRoot; import org.mozilla.javascript.ast.Block; import org.mozilla.javascript.ast.ForLoop; import org.mozilla.javascript.ast.FunctionNode; import org.mozilla.javascript.ast.IfStatement; import org.mozilla.javascript.ast.Name; import org.mozilla.javascript.ast.NodeVisitor; import org.mozilla.javascript.ast.WhileLoop; /** * Abstract class that is used to define the interface and some functionality for the NodeVisitors * that modify JavaScript. * */ public abstract class JSASTModifier implements NodeVisitor { /** * This is used by the JavaScript node creation functions that follow. */ private CompilerEnvirons compilerEnvirons = new CompilerEnvirons(); /** * Contains the scopename of the AST we are visiting. Generally this will be the filename */ private String scopeName = null; /** * @param scopeName * the scopeName to set */ public void setScopeName(String scopeName) { this.scopeName = scopeName; } /** * @return the scopeName */ public String getScopeName() { return scopeName; } /** * Abstract constructor to initialize the mapper variable. */ public JSASTModifier() { } /** * Parse some JavaScript to a simple AST. * * @param code * The JavaScript source code to parse. * @return The AST node. */ public AstNode parse(String code) { Parser p = new Parser(compilerEnvirons, null); return p.parse(code, null, 0); } /** * Find out the function name of a certain node and return "anonymous" if it's an anonymous * function. * * @param f * The function node. * @return The function name. */ protected String getFunctionName(FunctionNode f) { Name functionName = f.getFunctionName(); if (functionName == null) { return "anonymous" + f.getLineno(); } else { return functionName.toSource(); } } /** * Creates a node that can be inserted at a certain point in function. * * @param function * The function that will enclose the node. * * @param lineNo * Linenumber where the node will be inserted. * @return The new node. */ public abstract AstNode createNodeInFunction(FunctionNode function, int lineNo); public abstract AstNode createNode(AstNode... node); /** * * * @param shouldLog * The variable that should be logged (for example jQuery('#test').attr('style')) * @param lineNo * The line number where this will be inserted. * @return The new node. */ public abstract AstNode createPointNode(String shouldLog, int lineNo); /** * Create a new block node with two children. * * @param node * The child. * @return The new block. */ private Block createBlockWithNode(AstNode node) { Block b = new Block(); b.addChild(node); return b; } /** * @param node * The node we want to have wrapped. * @return The (new) node parent (the block probably) */ public AstNode makeSureBlockExistsAround(AstNode node) { AstNode parent = node.getParent(); if (parent instanceof IfStatement) { /* the parent is an if and there are no braces, so we should make a new block */ IfStatement i = (IfStatement) parent; /* replace the if or the then, depending on what the current node is */ if (i.getThenPart().equals(node)) { i.setThenPart(createBlockWithNode(node)); } else { i.setElsePart(createBlockWithNode(node)); } } else if (parent instanceof WhileLoop) { /* the parent is a while and there are no braces, so we should make a new block */ /* I don't think you can find this in the real world, but just to be sure */ WhileLoop w = (WhileLoop) parent; w.setBody(createBlockWithNode(node)); } else if (parent instanceof ForLoop) { /* the parent is a for and there are no braces, so we should make a new block */ /* I don't think you can find this in the real world, but just to be sure */ ForLoop f = (ForLoop) parent; f.setBody(createBlockWithNode(node)); } return node.getParent(); } /** * Actual visiting method. * * @param node * The node that is currently visited. * @return Whether to visit the children. */ @Override public abstract boolean visit(AstNode node); /** * This method is called when the complete AST has been traversed. * * @param node * The AST root node. */ public abstract void finish(AstRoot node); /** * This method is called before the AST is going to be traversed. */ public abstract void start(); }