//ast节点名称定义 class AstNode { static File = "File" static Program = "Program"; static Identifier = "Identifier"; static BlockStatement = "BlockStatement"; static IfStatement = "IfStatement"; static ForStatement = "ForStatement"; static ForInStatement = "ForInStatement"; static ForStatement = "ForOfStatement"; static WhileStatement = "WhileStatement"; static DoWhileStatement = "DoWhileStatement"; static SwitchStatement = "SwitchStatement"; static LabeledStatement = "LabeledStatement"; static ClassDeclaration = "ClassDeclaration"; static ClassBody = "ClassBody"; static ClassMethod = "ClassMethod"; static ClassProperty = "ClassProperty"; static VariableDeclaration = "VariableDeclaration"; static VariableDeclarator = "VariableDeclarator"; static FunctionDeclaration = "FunctionDeclaration"; static ExpressionStatement = "ExpressionStatement"; static ArrowFunctionExpression = "ArrowFunctionExpression"; static FunctionExpression = "FunctionExpression"; static AssignmentExpression = "AssignmentExpression"; static AssignmentPattern = "AssignmentPattern"; static MemberExpression = "MemberExpression"; static ObjectProperty = "ObjectProperty" static CallExpression = "CallExpression"; static ReturnStatement = "ReturnStatement"; static CatchClause = "CatchClause"; static TryStatement = "TryStatement"; static BinaryExpression = "BinaryExpression"; static ConditionalExpression = "ConditionalExpression"; static LogicalExpression = "LogicalExpression"; static ThisExpression = "ThisExpression"; static TemplateLiteral = "TemplateLiteral"; static NumericLiteral = "NumericLiteral"; static AwaitExpression = "AwaitExpression"; static StringLiteral = "StringLiteral"; static ObjectExpression = "ObjectExpression"; static BooleanLiteral = "BooleanLiteral"; static ArrayExpression = "ArrayExpression"; static NewExpression = "NewExpression"; } //ast节点辅助处理函数 class AstHelper { //所有块类型集合定义 if{} for{} while{} switch{} class{} try{} ()=>{} function(){} static M_BlockStatements = new Map([[AstNode.IfStatement, null], [AstNode.ForStatement, null], [AstNode.ForInStatement, null], [AstNode.ForOfStatement, null], [AstNode.WhileStatement, null], [AstNode.DoWhileStatement, null], [AstNode.SwitchStatement, null], [AstNode.ClassBody, null], [AstNode.TryStatement, null], [AstNode.FunctionDeclaration, null], [AstNode.ArrowFunctionExpression, null], [AstNode.FunctionExpression, null]]); //循环块集合定义 static M_LoopBlockStatements = new Map([[AstNode.ForInStatement, null], [AstNode.ForOfStatement, null], [AstNode.ForStatement, null], [AstNode.WhileStatement, null], [AstNode.DoWhileStatement, null]]); //类成员集合定义 static M_ClassMember = new Map([[AstNode.ClassMethod, null], [AstNode.ClassProperty, null]]); //函数定义-函数表达式,箭头函数,函数定义 static M_FuncExpression = new Map([[AstNode.FunctionExpression, null], [AstNode.ArrowFunctionExpression, null], [AstNode.FunctionDeclaration, null]]); //window的变量定义 static M_GlobalVar = new Map([["name", null], ["status", null], ["closed", null], ["length", null], ["origin", null], ["innerWidth", null], ["innerHeight", null], ["scrollX", null], ["pageXOffset", null], ["scrollY", null], ["pageYOffset", null], ["screenX", null], ["screenY", null], ["outerWidth", null], ["outerHeight", null], ["devicePixelRatio", null], ["event", null], ["screenLeft", null], ["screenTop", null], ["isSecureContext", null], ["crossOriginIsolated", null], ["originAgentCluster", null], ["credentialless", null]]); //事的定义方式 static M_Event = new Map([["change", null], ["click", null], ["dblclick", null], ["mousedown", null], ["mouseup", null], ["mouseenter", null], ["mouseout", null], ["mouseleave", null], ["mouseover", null], ["mousemove", null], ["focus", null], ["keydown", null], ["keyup", null], ["blur", null], ["keypress", null], ["load", null], ["unload", null], ["resize", null], ["scroll", null], ["drag", null], ["dragstart", null], ["dragend", null], ["dragover", null], ["drop", null], ["error", null], ["wheel", null]]); //风险代码定义 //static RiskCodes = ["eval","html","Function","outerHTML","innerHTML"]; //获取变量值类型 static AssignmentTypeConvert(curNode, rightNode) { if (!rightNode) return ""; let assignmentType = rightNode.type; switch (assignmentType) { case AstNode.StringLiteral: { return "string"; } case AstNode.NumericLiteral: { return "number"; } case AstNode.ObjectExpression: { return "object"; } case AstNode.ArrowFunctionExpression: case AstNode.FunctionExpression: { return "function"; } case AstNode.BooleanLiteral: { return "boolean"; } case AstNode.ArrayExpression: { return "array"; } case AstNode.NewExpression: { return rightNode.callee?.name; } default: { return ""; } } } //查找指定类型的父级节点 static FindParentNode(node, type, abortNode) { let curNode = node; if (node.nodeRel?.[type]) return node.nodeRel[type]; while (curNode) { if (curNode.root) return null; if (curNode.type == type) { //缓存查找到的节点类型 if (!node.nodeRel) node.nodeRel = {}; node.nodeRel[type] = curNode; return curNode; } if (abortNode && abortNode == curNode) return null; curNode = curNode.parent; } return null; } //根据多个节点类型遍历父级节点 static FindParentNodeByTypes(node, types, abortNode) { let curNode = node; while (curNode) { if (curNode.root) return null; //if (types.indexOf(curNode.type) >= 0) return curNode; if (types.has(curNode.type)) return curNode; if (abortNode && abortNode == curNode) return null; curNode = curNode.parent; } return null; } //根据identifierName查找子节点 static FindSubNodeByIdentifierName(node, identifierName) { if (!node) return null; let findNode = null; let option = { identifier: [(ast, pName, curNode, parent, des, depth) => { if (!findNode && curNode.name == identifierName) { findNode = curNode; } }] } AstHelper.TraverseNode(node, node, null, option, 0, false); return findNode; } //获取顶层调用节点,如$("#xx").children().get(0).on("click", ...)则获取$("#xx")所在的定义节点 static GetTopCallNode(callNode) { while (callNode) { if (callNode.type == AstNode.MemberExpression) { callNode = callNode.object; } else if (callNode.type == AstNode.CallExpression) { callNode = callNode.callee; } if (callNode.type == AstNode.identifier) return callNode.parent; } return null; } //获取指定节点的层级深度 static GetNodeDepth(node, depth) { if (!node) return depth; let keys = Object.keys(node); let retDepth = 0; keys.forEach((k) => { if (node[k] && typeof node[k] == "object" && k != "parent" && k != "loc" && k != "nodeRel" && k != "errors" && k != "directives" && k != "interpreter" && k != "comments" && k != "leadingComments" && k != "trailingComments" && k != "bufferNodes" ) { let curDepth = depth; if (node[k].type == AstNode.BlockStatement) { //每增加一层块语句{},则节点层级加一 curDepth = AstHelper.GetNodeDepth(node[k], depth + 1); } else { curDepth = AstHelper.GetNodeDepth(node[k], depth); } if (curDepth > retDepth) retDepth = curDepth; } }); return (retDepth > depth) ? retDepth : depth; } static _count = 0; //重置分析节点 static ResetAnalyzeNode(ast) { ast.bufferNodes = { ProgramNode: [], ExpressionStatementNode: [], CallExpressionNode: [], FunctionExpressionNode: [], BlockStatementNode: [], FunctionDeclarationNode: [], IdentifierNode: [], ReturnStatementNode: [], CatchClauseNode: [], } } static TraverseNode(ast, curNode, parent, option, depth, useBuffer) { //AstHelper._count = 0; if (useBuffer && ast.bufferNodes) { AstHelper.TraverseBufferNode(ast, curNode, parent, option, depth); } else { if (useBuffer) AstHelper.ResetAnalyzeNode(ast); AstHelper.RecursiveNode(ast, curNode, parent, option, depth, useBuffer); } } //从缓存读取节点进行解析 static TraverseBufferNode(ast, curNode, parent, option, depth) { let bufNodes = ast.bufferNodes; let nodeProcess = function (func, k, node, ptNode, des, depth) { if (!func) return; //if (Array.isArray(func)) { for (let f of func) f(ast, k, node, ptNode, des, depth); //} //else { // func(ast, k, node, ptNode, des, depth); //} } if (option.program) { for (pNode of bufNodes.ProgramNode) { nodeProcess(option.program, pNode.key, pNode.node, pNode.parentNode, pNode.des, pNode.depth); } } if (option.expression) { for (let pNode of bufNodes.ExpressionStatementNode) { nodeProcess(option.expression, pNode.key, pNode.node, pNode.parentNode, pNode.des, pNode.depth); } } if (option.callExp) { for (let pNode of bufNodes.CallExpressionNode) { nodeProcess(option.callExp, pNode.key, pNode.node, pNode.parentNode, pNode.des, pNode.depth); } } if (option.funcExp) { for (let pNode of bufNodes.FunctionExpressionNode) { nodeProcess(option.funcExp, pNode.key, pNode.node, pNode.parentNode, pNode.des, pNode.depth); } } if (option.block) { for (let pNode of bufNodes.BlockStatementNode) { nodeProcess(option.block, pNode.key, pNode.node, pNode.parentNode, pNode.des, pNode.depth); } } if (option.funcDec) { for (let pNode of bufNodes.FunctionDeclarationNode) { nodeProcess(option.funcDec, pNode.key, pNode.node, pNode.parentNode, pNode.des, pNode.depth); } } if (option.identifier) { for (let pNode of bufNodes.IdentifierNode) { nodeProcess(option.identifier, pNode.key, pNode.node, pNode.parentNode, pNode.des, pNode.depth); } } if (option.returnstatement) { for (let pNode of bufNodes.ReturnStatementNode) { nodeProcess(option.returnstatement, pNode.key, pNode.node, pNode.parentNode, pNode.des, pNode.depth); } } if (option.catchclause) { for (let pNode of bufNodes.CatchClauseNode) { nodeProcess(option.catchclause, pNode.key, pNode.node, pNode.parentNode, pNode.des, pNode.depth); } } } //遍历节点 static RecursiveNode(ast, curNode, parent, option, depth, useBuffer) { if (!curNode) return; if (!depth) depth = 0; let keys = Object.keys(curNode); let insertBufNode = function (aryNode, k, node, ptNode, des, depth) { aryNode.push({ node: node, ast: ast, parentNode: ptNode, des: des, depth: depth, key: k, }); } keys.forEach((k) => { let keyNode = curNode[k]; if (keyNode && typeof keyNode == "object" && k != "parent" && k != "loc" && k != "nodeRel" && k != "errors" && k != "interpreter" && k != "comments" && k != "leadingComments" && k != "trailingComments" && k != "bufferNodes" ) { let ptNode = curNode; if (!ptNode.parent) { ptNode.parent = parent; //ptNode.propertyName = k; } keyNode.parent = ptNode; if (!keyNode.iid && !Array.isArray(keyNode)) { keyNode.iid = `n_${AstHelper._count}`; AstHelper._count = AstHelper._count + 1; } switch (keyNode.type) { case AstNode.Program: { if (option.program) for (let f of option.program) f(ast, k, keyNode, ptNode, "", depth); if (useBuffer) insertBufNode(ast.bufferNodes.ProgramNode, k, keyNode, ptNode, "", depth); break; } case AstNode.ExpressionStatement: { if (option.expression) for (let f of option.expression) f(ast, k, keyNode, ptNode, "", depth); if (useBuffer) insertBufNode(ast.bufferNodes.ExpressionStatementNode, k, keyNode, ptNode, "", depth); break; } case AstNode.CallExpression: { if (option.callExp) for (let f of option.callExp) f(ast, k, keyNode, ptNode, "", depth); if (useBuffer) insertBufNode(ast.bufferNodes.CallExpressionNode, k, keyNode, ptNode, "", depth); break; } case AstNode.FunctionExpression: { if (option.funcExp) for (let f of option.funcExp) f(ast, k, keyNode, ptNode, "", depth); if (useBuffer) insertBufNode(ast.bufferNodes.FunctionExpressionNode, k, keyNode, ptNode, "", depth); break; } case AstNode.BlockStatement: { if (option.block) for (let f of option.block) f(ast, k, keyNode, ptNode, "", depth); if (useBuffer) insertBufNode(ast.bufferNodes.BlockStatementNode, k, keyNode, ptNode, "", depth); break; } case AstNode.FunctionDeclaration: { if (option.funcDec) for (let f of option.funcDec) f(ast, k, keyNode, ptNode, "", depth); if (useBuffer) insertBufNode(ast.bufferNodes.FunctionDeclarationNode, k, keyNode, ptNode, "", depth); break; } case AstNode.Identifier: { if (option.identifier) for (let f of option.identifier) f(ast, k, keyNode, ptNode, "", depth); if (useBuffer) insertBufNode(ast.bufferNodes.IdentifierNode, k, keyNode, ptNode, "", depth); break; } case AstNode.ReturnStatement: { if (option.returnstatement) for (let f of option.returnstatement) f(ast, k, keyNode, ptNode, "", depth); if (useBuffer) insertBufNode(ast.bufferNodes.ReturnStatementNode, k, keyNode, ptNode, "", depth); break; } case AstNode.CatchClause: { if (option.catchclause) for (let f of option.catchclause) f(ast, k, keyNode, ptNode, "", depth); if (useBuffer) insertBufNode(ast.bufferNodes.CatchClauseNode, k, keyNode, ptNode, "", depth); break; } } //节点深度 AstHelper.RecursiveNode(ast, keyNode, ptNode, option, depth + 1, useBuffer); } }); } //获取父级路径 static GetParentPath(ast, node) { if (!node) return ""; let path = ""; let pNode = node.parent; let info; let curCallLink = ""; while (pNode) { info = null; curCallLink = ""; if (pNode.root) break; if (pNode.type == AstNode.FunctionDeclaration) { //if (path) path = "/" + path; //path = pNode.id?.name + path; info = AstHelper.GetCurNodeCallInfoByFuncDeclaration(ast, pNode, pNode.parent); if (info) { curCallLink = info.name + (info.member ? "." + info.member : ""); } } else if (pNode.type == AstNode.CallExpression) { curCallLink = AstHelper.GetCallLinkInfo(pNode, pNode.parent); } else if (pNode.type == AstNode.VariableDeclarator) { info = AstHelper.GetCurNodeCallInfoByVariableDeclarator(ast, pNode, pNode.parent); if (info) { curCallLink = info.name + (info.member ? "." + info.member : ""); } } else if (pNode.type == AstNode.AssignmentExpression) { info = AstHelper.GetCurNodeCallInfoByAssigmentExpress(ast, pNode, pNode.parent); if (info) { curCallLink = info.name + (info.member ? "." + info.member : ""); } } else if (pNode.type == AstNode.ArrowFunctionExpression) { //info = AstHelper.GetCurNodeCallInfoByArrowFunc(ast, pNode, pNode.parent); } else if (pNode.type == AstNode.FunctionExpression) { info = AstHelper.GetCurNodeCallInfoByFuncExpression(ast, pNode, pNode.parent); if (info) { curCallLink = info.name + (info.member ? "." + info.member : ""); } } else if (pNode.type == AstNode.ObjectProperty) { info = AstHelper.GetCurNodeCallInfoByObjectProperty(ast, pNode, pNode.parent); if (info) { curCallLink = info.name + (info.member ? "." + info.member : ""); } } else if (pNode.type == AstNode.ClassProperty || pNode.type == AstNode.ClassMethod) { info = AstHelper.GetCurNodeCallInfoByClassMember(ast, pNode, pNode.parent); if (info) { curCallLink = info.name + (info.member ? "." + info.member : ""); } } else { if (pNode.type && pNode.type != AstNode.BlockStatement && pNode.type != AstNode.ExpressionStatement && pNode.type != AstNode.IfStatement && pNode.type != AstNode.Program && pNode.type != AstNode.File) { console.log("获取父级信息找到了未知的节点类型:" + pNode?.type); } } if (curCallLink) { if (path) path = "/" + path; path = curCallLink + path; } if (pNode.parent?.root) { pNode = null; } else { if (info) { pNode = info.node?.parent; } else { pNode = pNode.parent; } } } return "/" + path; } //获取变量节点描述 static GetVarNodeDes(node) { let des = ""; if (!des) { node.trailingComments?.forEach((d) => { if (d.loc.start.line == node.loc.start.line) des = d.value; }); } return des; } //获取函数节点描述 static GetFuncNodeDes(node) { let des = ""; if (node) { node.leadingComments?.forEach((d) => { des = d.value + des; //des = des + "\r\n" + x.value; }); } return des; } //是否在对应的作用域节点内,即pNode是否domainNode的子节点 static IsInDomainNode(pNode, domainNode, abortNode) { //获取函数定义节点 while (pNode) { if (pNode == domainNode) return true; if (pNode.parent == abortNode) return false; pNode = pNode.parent; } return false; } //是否在参数节点中定义 static IsInParasNode(pNode, abortNode) { let args = null; while (pNode) { args = pNode.parent?.arguments ?? pNode.parent?.parent?.arguments; if (args) { for (let arg of args) { if (pNode == arg) return true; } } if (pNode == abortNode) return; pNode = pNode.parent; } return false; } //是否数组的元素节点,如xx[node] static IsArrayEleNode(pNode, abortNode) { while (pNode) { if (pNode.parent.computed) return true; if (pNode == abortNode) return; pNode = pNode.parent; } return false; } //获取模板字符串的定义信息 static GetTemplateLiteral(templateNode) { if (!templateNode) return ""; let ret = ""; let quasis = templateNode.quasis; let express = templateNode.expressions; for (let i = 0; i <= quasis.length - 1; i++) { ret = ret + quasis[i].value.raw; let curExpress = express[i]; switch (curExpress?.type) { case AstNode.Identifier: { ret = ret + "${" + curExpress.name + "}" break; } case AstNode.BinaryExpression: { ret = ret + "${" + AstHelper.GetExpressLinkInfo(curExpress) + "}" break; } case AstNode.CallExpression: case AstNode.MemberExpression: { ret = ret + "${" + AstHelper.GetCallLinkInfo(curExpress) + "}" break; } } } return "`" + ret + "`"; } //获取调用链信息,如a().b().c().d() static GetCallLinkInfo(callNode, parent) { //aa().bb().cc().ee("xxx"); /** * $(f.aa()); $(f.c); $(f); $("f"); $("f" + a); $("f" + a + c()); $("f" + a + c().e()); $("f" + a + c().e().f); $(a()); $(a().b()); $(a().b().c); $(a() + "b"); $(a() + b); $(a().b + b); $(a().b() + b); $(a().b.c() + b); */ if (!callNode) return; let stackInfo = ""; while (callNode) { if (callNode.type == AstNode.CallExpression) { parent = callNode; callNode = callNode.callee; } else if (callNode.type == AstNode.MemberExpression) { //aa.bb.xx[1].zlPring = {xx:function(){$("aaa")}} if (parent?.type == AstNode.MemberExpression && parent.computed) { //数组则不加点 } else { if (stackInfo) stackInfo = "." + stackInfo; } if (parent?.type == AstNode.CallExpression) { stackInfo = callNode.property.name + "()" + stackInfo; } else { if (callNode.property.type == AstNode.Identifier) { if (callNode.computed == true) { stackInfo = "[" + callNode.property.name + "]" + stackInfo; } else { stackInfo = callNode.property.name + stackInfo; } } else if (callNode.property.type == AstNode.CallExpression) { if (callNode.computed == true) { stackInfo = "[" + AstHelper.GetCallLinkInfo(callNode.property) + "]" + stackInfo; } else { stackInfo = AstHelper.GetCallLinkInfo(callNode.property) + stackInfo; } } else { if (callNode.computed == true) { stackInfo = "[" + callNode.property.value + "]" + stackInfo; } else { stackInfo = callNode.property.value + stackInfo; } } } parent = callNode; callNode = callNode.object; } else if (callNode.type == AstNode.BinaryExpression) { stackInfo = "(" + AstHelper.GetExpressLinkInfo(callNode) + ")" + stackInfo; callNode = null; } else if (callNode.type == AstNode.Identifier) { if (parent.type == AstNode.MemberExpression && parent.computed == true) { //成员数组不做处理 } else { //避免data[1]中间出现data.[1] if (stackInfo) stackInfo = "." + stackInfo; } if (parent?.type == AstNode.CallExpression) { stackInfo = callNode.name + "()" + stackInfo; } else { stackInfo = callNode.name + stackInfo; } callNode = null; } else if (callNode.type == AstNode.ThisExpression) { if (stackInfo) stackInfo = "." + stackInfo; stackInfo = "this" + stackInfo; callNode = null; } else { debugger; console.error("GetCallLinkInfo中发现未能识别的调用类型:" + callNode.type); callNode = null; } } return stackInfo; } //获取表达式堆栈 static GetExpressLinkInfo(expNode) { if (!expNode) return ""; let selectorPar = ""; //二元 //$(aa + bb + "ee" + cc + " tbody tr" + dd + "bb").css(""); if (expNode.type == AstNode.BinaryExpression) { while (expNode) { if (expNode.right.type == AstNode.Identifier) { //变量 selectorPar = expNode.operator + expNode.right.name + selectorPar; } else if (expNode.right.type == AstNode.CallExpression) { //函数 selectorPar = expNode.operator + AstHelper.GetCallLinkInfo(expNode.right) + selectorPar; } else if (expNode.right.type == AstNode.MemberExpression) { //成员 selectorPar = expNode.operator + AstHelper.GetCallLinkInfo(expNode.right, expNode) + selectorPar; } else if (expNode.right.type == AstNode.TemplateLiteral) { //模版字符串 selectorPar = AstHelper.GetTemplateLiteral(expNode.right) + selectorPar; } else { //值 if (expNode.right.type == AstNode.NumericLiteral) { selectorPar = expNode.operator + expNode.right.value + selectorPar; } else { selectorPar = expNode.operator + "'" + expNode.right.value + "'" + selectorPar; } } if (expNode.left.type == AstNode.BinaryExpression) { expNode = expNode.left; } else if (expNode.left.type == AstNode.Identifier) { selectorPar = expNode.left.name + selectorPar; expNode = null; } else if (expNode.left.type == AstNode.CallExpression) { selectorPar = AstHelper.GetCallLinkInfo(expNode.left) + selectorPar; expNode = null; } else if (expNode.left.type == AstNode.MemberExpression) { selectorPar = AstHelper.GetCallLinkInfo(expNode.left, expNode) + selectorPar; expNode = null; } else if (expNode.left.type == AstNode.TemplateLiteral) { //模版字符串 selectorPar = AstHelper.GetTemplateLiteral(expNode.left) + selectorPar; expNode = null; } else { selectorPar = "'" + expNode.left.value + "'" + selectorPar; expNode = null; } } } //三元 if (!selectorPar && expNode.type == AstNode.ConditionalExpression) { console.error("GetExpressLinkInfo调用中尚未处理三元表达式"); } return selectorPar; } //获取参数节点的内容信息 static GetParasString(parNode) { if (!parNode) return {}; let parType = ""; let selectorPar = ""; if (parNode.type == AstNode.CallExpression) { //参数是函数 selectorPar = AstHelper.GetCallLinkInfo(parNode); parType = "调用" } else if (parNode.type == AstNode.MemberExpression) { selectorPar = AstHelper.GetCallLinkInfo(parNode); parType = "成员" } else if (parNode.type == AstNode.TemplateLiteral) { selectorPar = AstHelper.GetTemplateLiteral(parNode); parType = "模板字符" } else if (parNode.type == AstNode.ThisExpression) { selectorPar = "this"; parType = "变量" } else if (parNode.type == AstNode.BinaryExpression) { selectorPar = AstHelper.GetExpressLinkInfo(parNode); parType = "表达式" } else { if (parNode.type == AstNode.Identifier) { //参数是变量 selectorPar = parNode.name; parType = "变量"; } else { //参数是值 //if (parNode.type != AstNode.NumericLiteral) { selectorPar = "'" + parNode.value + "'"; parType = "值"; //} //else { // selectorPar = parNode.value; // parType = "值"; //} } } return { parContext: selectorPar, parType: parType, } } //获取当前节函数定义节点所在的函数调用信息 static GetCurNodeCallInfoByFuncDeclaration(ast, curNode, parent) { let ret; let funcNode = curNode; if (funcNode) { ret = { name: funcNode.id.name, member: "", kind: "func", node: funcNode } } return ret; } //获取当前所在赋值节点的调用信息 static GetCurNodeCallInfoByAssigmentExpress(ast, curNode, parent) { let ret; let onNode = curNode; if (onNode.left.type == AstNode.MemberExpression) { let leftCallName = ""; if (onNode.left.object.type == AstNode.MemberExpression || onNode.left.object.type == AstNode.CallExpression) { leftCallName = AstHelper.GetCallLinkInfo(onNode.left.object); } else { leftCallName = onNode.left.object.name; } //xxx.onclick = function(){...}js on 绑定方式 if (onNode.left?.property?.name.indexOf("on") == 0) { ret = { name: leftCallName, member: onNode.left?.property?.name, kind: "event", node: onNode, }; } else { //xxx.init = function(){...} ret = { name: leftCallName, member: onNode.left?.property?.name, kind: "property", node: onNode, }; } } else { ret = { name: onNode.left.name, member: "", kind: "variable", node: onNode, }; } return ret; } //获取变量节点的调用信息 static GetCurNodeCallInfoByVariableDeclarator(ast, curNode, parent) { let ret; ret = { name: curNode.id.name, member: "", kind: "variable",//函数变量 node: curNode, }; return ret; } //获取对象属性节点的调用信息 static GetCurNodeCallInfoByObjectProperty(ast, curNode, parent) { let ret; let fNode = AstHelper.FindParentNode(curNode.parent, AstNode.CallExpression); if (fNode) { ret = AstHelper.GetCurNodeCallInfoByCallExpression(ast, fNode, fNode.parent); } else { fNode = AstHelper.FindParentNode(curNode.parent, AstNode.AssignmentExpression); if (fNode) { ret = AstHelper.GetCurNodeCallInfoByAssigmentExpress(ast, fNode, fNode.parent); if (ret && parent.parent.parent == fNode && curNode.key.type == AstNode.Identifier) { if (ret.member) ret.member = ret.member + "."; ret.member = ret.member + curNode.key.name; } } else { fNode = AstHelper.FindParentNode(curNode.parent, AstNode.VariableDeclarator); if (fNode) { ret = AstHelper.GetCurNodeCallInfoByVariableDeclarator(ast, fNode, fNode.parent); } else { console.error("GetCurNodeCallInfoByObjectProperty调用中未能识别节点类型:" + curNode.type); } } } return ret; } //获取当前节点所在函数表达式的调用 //let xx = function(){...} //let xx.test = function(){...} static GetCurNodeCallInfoByFuncExpression(ast, curNode, parent) { let ret; let expression = curNode; let expParent = expression.parent; if (Array.isArray(expParent)) expParent = expression.parent.parent; if (expression) { if (expParent.type == AstNode.VariableDeclarator) { //通过变量定义的函数中使用 //xx = function(){ ... } ret = AstHelper.GetCurNodeCallInfoByVariableDeclarator(ast, expParent, expParent.parent); } else if (expParent.type == AstNode.AssignmentExpression) { //xx.test = function(){...} ret = AstHelper.GetCurNodeCallInfoByAssigmentExpress(ast, expParent, expParent.parent); } else if (expParent.type == AstNode.CallExpression) { //test("",function(){...}) ret = AstHelper.GetCurNodeCallInfoByCallExpression(ast, expParent, expParent.parent); } else if (expParent.type == AstNode.ObjectProperty) { //$.ajax({url:"",error:function(){...}}) ret = AstHelper.GetCurNodeCallInfoByObjectProperty(ast, expParent, expParent.parent); } else { //(function () {... }) ret = { name: "()", member: "", kind: "other", node: expParent, } } } return ret; } //获取调用前缀 static GetCallPrePath(node) { let curNode = node; let path = ""; if (node.type == AstNode.Identifier) { return node.name } else { if (node.type == AstNode.CallExpression) { curNode = curNode.callee; } else { curNode = curNode.object; } while (curNode) { if (curNode.property) { if (curNode.property.type == AstNode.Identifier) { if (path) path = "/" + path; path = curNode.property.name + path; } } if (curNode.type == AstNode.Identifier) { if (path) path = "/" + path; path = curNode.name + path; curNode = null; } else { if (curNode.type == AstNode.CallExpression) { curNode = curNode.callee; } else { curNode = curNode.object; } } } } return path; } //获取当前节点所在的函数参数中的调用 //test("",function(){...}) //xx.test("",function(){...}) //$("body").on("click", "xxx", function (e) {...}) //ele.addEventListener("click", function(){...}) static GetCurNodeCallInfoByCallExpression(ast, curNode, parent) { let ret; let callNode = curNode; if (callNode.callee?.type == AstNode.MemberExpression) { //$("body").on("click", "xxx", function (e) {xxx();}); let leftName = ""; if (callNode.callee.object?.type == AstNode.MemberExpression || callNode.callee.object?.type == AstNode.CallExpression) { leftName = AstHelper.GetCallLinkInfo(callNode.callee.object, callNode.callee); } else { leftName = callNode.callee?.object?.name; } if (callNode.callee.property?.name == "addEventListener") { //通过addEventListener方式绑定的事件 ret = { name: callNode.callee?.object?.name, member: callNode.arguments[0].value, kind: "event", node: callNode, }; } else if (callNode.callee.property?.name == "on") { //通过jquery方式绑定$("xxx").on("click",function(){}); //$("xxx").on("click",".filter",function(){}); let jNode = AstHelper.FindSubNodeByIdentifierName(callNode, "$"); let argsNode = null; if (jNode) { argsNode = jNode.parent.arguments[0]; } else { argsNode = callNode.callee?.object.arguments[0]; } let curParContext = ""; if (argsNode) { curParContext = AstHelper.GetParasString(argsNode); if (curParContext) curParContext = curParContext.parContext; } if (jNode) { leftName = leftName.replace("$()", `$(${curParContext})`); } ret = { name: leftName, member: callNode.arguments[0].value, kind: "event", node: callNode, }; if (callNode.arguments.length >= 3) { ret.ext = { filter: callNode.arguments[1].value, } } } else if (AstHelper.M_Event.has(callNode.callee.property?.name)) { let jNode = AstHelper.FindSubNodeByIdentifierName(callNode, "$"); let argsNode = null; let curParContext = ""; if (jNode) { argsNode = jNode.parent.arguments[0]; if (argsNode) { curParContext = AstHelper.GetParasString(argsNode); if (curParContext) curParContext = curParContext.parContext; leftName = leftName.replace("$()", `$(${curParContext})`); } } ret = { name: leftName, member: callNode.callee.property?.name, kind: "event", node: callNode, }; } else { //tbody.children().eq(indexSelRow).addClass("choose_row"); ret = { name: leftName, member: callNode.callee.property?.name, kind: "func", node: callNode, }; } } else { if (callNode.callee?.name == "$") { ret = { name: callNode.callee?.name ?? "", member: "", kind: "event", node: callNode, }; } else { let callName = callNode.callee?.name ?? ""; if (!callName) { callName = "(自执行)()"; } ret = { name: callName, member: "", kind: "immediately", node: callNode, }; } } return ret; } //获取当前节点所在箭头函数的调用 //let xx = ()=>{...} //let ele.onxxx = ()=>{...} //let ele.addEventListener("click",()=>{...}) //xx = ()=>{...} //()=>{...} static GetCurNodeCallInfoByArrowFunc(ast, curNode, parent) { let ret; let arrowNode = curNode; let aryParent = arrowNode.parent; if (ArrayisArray(aryParent)) aryParent = aryParent.parent; if (aryParent?.type == AstNode.VariableDeclarator) { //let xx = ()=>{...} ret = AstHelper.GetCurNodeCallInfoByVariableDeclarator(ast, aryParent, aryParent.parent); } else if (aryParent?.type == AstNode.AssignmentExpression) { //xx.test = ()=>{...} ret = AstHelper.GetCurNodeCallInfoByAssigmentExpress(ast, aryParent, aryParent.parent); } else if (aryParent?.type == AstNode.CallExpression) { //test("",()=>{gTest = "bbb";}); ret = AstHelper.GetCurNodeCallInfoByCallExpression(ast, aryParent, aryParent.parent); } else if (aryParent?.type == AstNode.MemberExpression) { //xx.test[()=>{...}]="aaa" let memberNode = aryParent; if (memberNode.object?.type == AstNode.Identifier) { ret = { name: memberNode.object.name, member: "", kind: "array", node: memberNode, }; } else { ret = { name: memberNode.object.object.name, member: memberNode.object.property.name, kind: "property", node: memberNode, }; } } else { ret = { name: "=>", member: "", kind: "arrow", node: arrowNode, }; } return ret; } //获取当前节点所在的类方法的调用信息 static GetCurNodeCallInfoByClassMember(ast, curNode, parent) { let ret; let methodNode = curNode; if (methodNode) { ret = { name: methodNode.parent.parent.parent.id.name, member: methodNode.key.name, kind: "class", node: methodNode } } return ret; } //获取节点的调用关系 static GetNodeCallRel(ast, curNode, parent) { //查找类 //查找函数定义 //查找函数表达式 //查找箭头表达式 //查找调用表达式 //查找赋值表达式 let callInfo; let identifierName = curNode.name; let findNode = AstHelper.FindParentNode(parent, AstNode.ClassDeclaration); if (findNode) { let memberNode = AstHelper.FindParentNodeByTypes(parent, AstHelper.M_ClassMember); if (memberNode) { //类成员中使用包括方法和属性 callInfo = AstHelper.GetCurNodeCallInfoByClassMember(ast, memberNode, memberNode.parent); } } else { findNode = AstHelper.FindParentNode(parent, AstNode.FunctionDeclaration); if (findNode) { //找到了调用的所在函数定义 //callInfo = AstHelper.GetCurNodeCallInfoByFuncDeclaration(ast, findNode, findNode.parent); let isParVar = false; if (identifierName) { //当前identifier定义如果属于FunctionDeclaration参数则退出,如果是变量的identifier,在函数的参数中表示变量定义而不是引用 //如果是callexpression,则不可能出现在函数定义的参数中 findNode.params.forEach((x) => { if (x == curNode) isParVar = true; if (x.type == AstNode.Identifier && x.name == identifierName) isParVar = true; if (x.type == AstNode.AssignmentPattern && x.left.name == identifierName) isParVar = true; }); } if (!isParVar) { callInfo = AstHelper.GetCurNodeCallInfoByFuncDeclaration(ast, findNode, findNode.parent); } } else { findNode = AstHelper.FindParentNode(parent, AstNode.FunctionExpression); if (findNode) { if (findNode.parent.parent?.type == AstNode.CallExpression) { //作为参数形式调用,如test("", function(){vField1 = "222"}) //$(function(){...}); callInfo = AstHelper.GetCurNodeCallInfoByCallExpression(ast, findNode.parent.parent, findNode.parent.parent.parent); } else { callInfo = AstHelper.GetCurNodeCallInfoByFuncExpression(ast, findNode, findNode.parent); } } else { //查找箭头函数 findNode = AstHelper.FindParentNode(parent, AstNode.ArrowFunctionExpression); if (findNode) { if (findNode.parent.parent?.type == AstNode.CallExpression) { callInfo = AstHelper.GetCurNodeCallInfoByCallExpression(ast, findNode.parent.parent, findNode.parent.parent.parent); } else { callInfo = AstHelper.GetCurNodeCallInfoByArrowFunc(ast, findNode, findNode.parent); } } else { //查找调用函数 findNode = AstHelper.FindParentNode(parent, AstNode.CallExpression); if (findNode) { callInfo = AstHelper.GetCurNodeCallInfoByCallExpression(ast, findNode, findNode.parent); } else { findNode = AstHelper.FindParentNode(parent, AstNode.AssignmentExpression); if (findNode) { callInfo = AstHelper.GetCurNodeCallInfoByAssigmentExpress(ast, findNode, findNode.parent); } else { //直接在脚本中调用 callInfo = { name: "", kind: "immediately", start: curNode.start, end: curNode.end, node: curNode, } } } } } } } return callInfo; } } //函数解析插件 class AstParserPlugin { _parser; _option; RegInfo = { Parser: "",//配置解析挂接的ast节点类型,AstNode中所定义的节点 CallRelation: "",//配置调用关系解析挂接的ast节点类型,AstNode中所定义的节点 } constructor(parser, option) { this._parser = parser; this._option = option; } //Parser(ast, pName, curNode, parent, des, depth){ }//配置对应节点的解析处理逻辑 //Checked(){}//配置解析对象的清理和二次分析处理 //CallRelation(){}//配置对应的调用关系逻辑 get Result() { return {}; } } class AstParserPlugin_Func extends AstParserPlugin { RegInfo = { Parse: AstNode.FunctionDeclaration, CallRelation: AstNode.CallExpression, } _funcList = []; constructor(parser, option) { super(parser, option); } #WriteCallRel(ast, curNode, funcDefine, callInfo) { if (funcDefine && callInfo) { let called = funcDefine.called.find((c) => c.file == ast.file && c.name == callInfo.name && c.member == callInfo.member && c.kind == callInfo.kind); if (called) { //找到相同的调用 called.pos.push({ start: curNode.start, end: curNode.end }) } else { //在相同的对象中 funcDefine.called.push({ file: ast.file, name: callInfo.name, member: callInfo.member, kind: callInfo.kind, start: callInfo.node.start, end: callInfo.node.end, ext: callInfo.ext, pos: [{ start: curNode.start, end: curNode.end }], path: AstHelper.GetParentPath(ast, callInfo.node),//查询引用的父级信息 }); } } } #GetFuncCodeAnalyze(ast, funcNode) { //风险类别动态js代码执行, //ele.innerHTML,ele.outerHTML, $("xxx").html(),eval(...),new Function() let riskType = []; let isIgnoreCatch = false; let isHtmlModify = false; let isLoopHtmlModify = false; let option = { identifier: [function (ast, pName, curNode, parent, des, depth) { //if (AstHelper.RiskCodes.indexOf(curNode.name) >= 0) { switch (curNode.name) { case "Function": { if (parent.type == "NewExpression") { if (riskType.indexOf(curNode.name) < 0) riskType.push(curNode.name); } break; } case "eval": { if (parent.type == "CallExpression") { if (riskType.indexOf(curNode.name) < 0) riskType.push(curNode.name); } break; } case "append": case "appendTo": case "prepend": case "prependTo": case "after": case "insertAfter": case "before": case "insertBefore": case "html": { if (pName == "property") { let pre = AstHelper.GetCallPrePath(parent); if (pre.substring(0, 1) == "$") { isHtmlModify = true; //判断父级是否为循环语句 if (!isLoopHtmlModify) { let loopNode = AstHelper.FindParentNodeByTypes(parent, AstHelper.M_LoopBlockStatements, funcNode); if (loopNode) { isLoopHtmlModify = true; } } } } break; } case "innerHTML": case "outerHTML": { if (pName == "property" && parent.type == AstNode.MemberExpression) { isHtmlModify = true; //判断父级是否为循环语句 if (!isLoopHtmlModify) { let loopNode = AstHelper.FindParentNodeByTypes(parent, AstHelper.M_LoopBlockStatements, funcNode); if (loopNode) { isLoopHtmlModify = true; } } } break; } } //} }], catchclause: [function (ast, pName, curNode, parent, des, depth) { if (curNode.body) { if (curNode.body.body.length <= 0) { //let fNode = AstHelper.FindParentNodeByTypes(parent, [AstNode.FunctionExpression, AstNode.ArrowFunctionExpression, AstNode.CallExpression, AstNode.FunctionDeclaration], funcNode); let fNode = AstHelper.FindParentNode(parent, AstNode.FunctionDeclaration, funcNode); if (fNode == funcNode) isIgnoreCatch = true; } } }] /* returnstatement: function (ast, pName, curNode, parent, des, depth) { let pBlock = AstHelper.FindParentNodeByTypes(parent, [AstNode.FunctionExpression, AstNode.CallExpression, AstNode.ArrowFunctionExpression, AstNode.FunctionDeclaration]); if (pBlock && pBlock != funcNode) { // } else { // } }*/ } AstHelper.TraverseNode(ast, funcNode, null, option, false); return { risk: riskType,//是否有代码注入风险即动态js脚本执行,riskType则是js脚本执行方式,eval,或function isIgnoreCatch: isIgnoreCatch,//是否有异常被忽略 isHtmlModify: isHtmlModify,//是否有HTML修改 isLoopHtmlModify: isLoopHtmlModify,//是否在循环中操作HTML } } #FuncBaseCheck(funcList) { let _this = this; funcList.forEach((fItem) => { //位置和所在文件名不同,则可能存在名称冲突 let otherDefine = funcList.find((x) => x.name == fItem.name && (x.start != fItem.start || x.file != fItem.file)); fItem.isConflict = false; if (otherDefine) { fItem.isConflict = true; } //判断是否空的函数定义 fItem.isNullFunc = false; if (fItem.defineNode.body.body?.length <= 0) { fItem.isNullFunc = true; } //获取函数中代码的最大深度 let depth = AstHelper.GetNodeDepth(fItem.defineNode, 0); if (depth > 20) { fItem.codeDepth = ">20"; } else if (depth > 15) { fItem.codeDepth = ">15"; } else if (depth > 10) { fItem.codeDepth = ">10"; } else if (depth > 5) { fItem.codeDepth = ">5"; } else { fItem.codeDepth = ""; } let codeAnalyze = _this.#GetFuncCodeAnalyze(fItem.ast, fItem.defineNode); fItem.risk = codeAnalyze?.risk; fItem.isIgnoreCatch = codeAnalyze?.isIgnoreCatch; fItem.isHtmlModify = codeAnalyze?.isHtmlModify; fItem.isLoopHtmlModify = codeAnalyze?.isLoopHtmlModify; }); } //解析节点 Parse(ast, pName, curNode, parent, des, depth) { let id = curNode.id; if (id.type == AstNode.Identifier) { let des = AstHelper.GetFuncNodeDes(curNode); //判断是否在对应的块下面定义的函数 //如function Init(){ function getData(){...} },getData则表示内部子函数 let isGlobal = true; let blockNode = AstHelper.FindParentNode(parent, AstNode.BlockStatement); if (blockNode) { isGlobal = AstHelper.FindParentNodeByTypes(blockNode, AstHelper.M_BlockStatements) ? false : true; } this._funcList.push({ file: ast.file, range: isGlobal ? "global" : "sub", class: "", isAsync: curNode.async, name: id.name, des: des, start: curNode.start, end: curNode.end, ast: ast, defineNode: curNode, idNode: curNode.id, called: [],//保存被那些地方调用 //refers:[],//保存引用了那些函数 path: AstHelper.GetParentPath(ast, curNode), //sameName:[], }); } } //检查及分析节点 Checked() { //函数基本检查,命名冲突,是否空函数等 this.#FuncBaseCheck(this._funcList); } //关系分析 CallRelation(ast, pName, curNode, parent, des, depth) { let callee = curNode.callee; let funcDefine; let callInfo; if (callee.type == AstNode.Identifier) { //是一个函数调用,如xx(); funcDefine = this._funcList.find((x) => x.name == callee.name); if (funcDefine) { callInfo = AstHelper.GetNodeCallRel(ast, curNode, parent); //判断是否存在嵌套使用 let pFuncDesc = AstHelper.FindParentNode(parent, AstNode.FunctionDeclaration, funcDefine.parent); if (funcDefine.isNested != true) { if (pFuncDesc && pFuncDesc.id?.name == funcDefine.name) { funcDefine.isNested = true; } else { funcDefine.isNested = false; } } this.#WriteCallRel(ast, curNode, funcDefine, callInfo); } else { //根据调用参数名称去匹配 if (curNode.arguments?.length > 0) { curNode.arguments.forEach((arg) => { funcDefine = this._funcList.find((x) => x.name == arg.name); if (funcDefine) { callInfo = AstHelper.GetCurNodeCallInfoByCallExpression(ast, curNode, parent); this.#WriteCallRel(ast, arg, funcDefine, callInfo); } }); } } } else { //根据参数去匹配名称 if (callee.arguments?.length > 0) { callee.arguments.forEach((arg) => { funcDefine = this._funcList.find((x) => x.name == arg.name); if (funcDefine) { callInfo = AstHelper.GetCurNodeCallInfoByCallExpression(ast, curNode, parent); this.#WriteCallRel(ast, arg, funcDefine, callInfo); } }); } } } //结果获取 get Result() { return { AllFuncList: this._funcList, FuncList: function (fileName) { return this.AllFuncList.filter((x) => x.file == fileName); }, } } } window.AstParserPlugin_Func = AstParserPlugin_Func; class AstParserPlugin_GlobalVar extends AstParserPlugin { RegInfo = { Parse: AstNode.Identifier, CallRelation: AstNode.Identifier, }; _globalVarList = []; _tempVars = []; _assignNode = []; constructor(parser, option) { super(parser, option) } //检查变量名称是否存在冲突 #VarBaseCheck(globalVars, tempVars) { //检查全局变量名是否存在冲突或重复定义 globalVars.forEach((gVar) => { let varDefine = tempVars.find((cVar) => cVar.varName == gVar.name && cVar.defineNode != gVar.defineNode); gVar.isConflict = false; if (varDefine) { //存在命名冲突 gVar.isConflict = true; } let globalDefine = globalVars.find((cVar) => cVar.name == gVar.name && cVar.defineNode != gVar.defineNode); gVar.isRepetDefine = false; if (globalDefine) { //存在重复定义 gVar.isRepetDefine = true; } }); } //重新梳理全局变量 #CullGlobalVar(ret, vars, assignNode) { if (assignNode.length > 0) { assignNode.forEach((n) => { let varNode = vars.filter(x => x.varName == n.node.name); let isSameDomain = false;//判断复制表达式是否落在变量定义所在的范围内,是否相同作用域,如果是则不是全局变量 varNode.some((v) => { if (AstHelper.IsInDomainNode(n.parent, v.domainNode)) { //变量使用与变量定义的作用域相同 isSameDomain = true; return true; } }); if (!isSameDomain) { //没有找到定义或作用范围不同 let gVarDefine = ret.find(x => x.name == n.node.name); if (gVarDefine) { //找到了全局变量的定义 let assignmentType = AstHelper.AssignmentTypeConvert(n.parent, n.parent.right); if (assignmentType) { if (gVarDefine.types.indexOf(assignmentType) < 0) gVarDefine.types.push(assignmentType); } } else { let expressionStatement = AstHelper.FindParentNode(n.parent, AstNode.ExpressionStatement); let defTypes = []; let assignmentType = AstHelper.AssignmentTypeConvert(n.parent, n.parent.right); if (assignmentType) { defTypes.push(assignmentType); } ret.push( { file: n.file, name: n.node.name, defWay: "", des: expressionStatement ? AstHelper.GetVarNodeDes(expressionStatement) : "", start: n.parent.start, end: n.parent.end, defineNode: n.node, idNode: n.idNode, types: defTypes, called: [], } ); } } }); } //查找没有使用申明方式定义变量的元素 //let notDeclareds = ret.filter((x) => !x.defWay); for (let i = ret.length - 1; i >= 0; i--) { //该变量是否在其他文件中有定义 let unDefVar = ret[i]; if (!unDefVar.defWay) { //没有申明定义方式 let findDef = ret.find((x) => x.file != unDefVar.file && x.defWay); if (findDef) { //当在其他文件中有定义类别时,则移除当前的定义 ret.splice(i, 1); } } } } Parse(ast, pName, curNode, parent, des, depth) { //对象处于函数参数的定义中,如function xx(p1,p2){} if (parent == parent.parent?.params) { //参数变量 this._tempVars.push({ file: ast.file, varName: curNode.name, defineNode: curNode, domainNode: parent.parent, }); return; } else if (parent.parent == parent.parent.parent.params) { //示例:function test(isFailed = false){} this._tempVars.push({ file: ast.file, varName: curNode.name, defineNode: curNode, domainNode: parent.parent.parent }); return; } //对象处于函数调用的arguments中,如xx(p1,p2); if (parent == parent.parent?.arguments) return; if (parent?.type == AstNode.MemberExpression) { //如果节点类型为成员表达式,则判断是否为window成员 //window.xx = ""; //globalThis.xx=""; //if (window.getSelection){}//IfStatement if (pName == "property" && parent.parent?.type == AstNode.AssignmentExpression && (parent.object.name == "window" || parent.object.name == "globalThis")) { if (AstHelper.M_GlobalVar.has(curNode.name)) return; //如果已经存在相同的windows变量,则直接退出 let fWindowVarNode = this._globalVarList.find((x) => x.name == curNode.name); if (fWindowVarNode) return; let defTypes = []; let assignmentType = AstHelper.AssignmentTypeConvert(parent.parent, parent.parent.right); if (assignmentType) { defTypes.push(assignmentType); } this._globalVarList.push( { file: ast.file, name: curNode.name, defWay: parent.object.name, des: "", start: parent.start, end: parent.end, ast: ast, defineNode: curNode, idNode: curNode, types: defTypes, called: [], } ); } } else if (parent?.type == AstNode.AssignmentExpression) { //a=6; //let varDeclaration = findParentNode(parent); if (pName == "right") return; this._assignNode.push({ file: ast.file, node: curNode, parent: parent, idNode: curNode, }); } else if (parent?.type == AstNode.VariableDeclarator) { if (pName == "init") return; //var xx = 12; let blockNode = AstHelper.FindParentNode(parent, AstNode.BlockStatement); if (blockNode) { let findNode = AstHelper.FindParentNodeByTypes(blockNode, AstHelper.M_BlockStatements); if (findNode) { this._tempVars.push({ file: ast.file, varName: curNode.name, defineNode: curNode, domainNode: findNode, }); } else { let varDesNode = AstHelper.FindParentNode(parent, AstNode.VariableDeclaration); let des = ""; if (varDesNode) des = AstHelper.GetVarNodeDes(varDesNode); let defTypes = []; let assignmentType = AstHelper.AssignmentTypeConvert(parent, parent.init); if (assignmentType) { defTypes.push(assignmentType); } this._globalVarList.push( { file: ast.file, name: curNode.name, defWay: varDesNode.kind, des: des, start: parent.start, end: parent.end, ast: ast, defineNode: curNode, idNode: curNode, types: defTypes, called: [], } ); } } else { let varDesNode = AstHelper.FindParentNode(parent, AstNode.VariableDeclaration); let des = ""; if (varDesNode) des = AstHelper.GetVarNodeDes(varDesNode); let defTypes = []; let assignmentType = AstHelper.AssignmentTypeConvert(parent, parent.init); if (assignmentType) { defTypes.push(assignmentType); } //不在block块中的语句 this._globalVarList.push( { file: ast.file, name: curNode.name, defWay: varDesNode.kind, des: des, start: parent.start, end: parent.end, ast: ast, defineNode: curNode, idNode: curNode, types: defTypes, called: [], } ); } } else { //debugger; } } Checked() { this.#CullGlobalVar(this._globalVarList, this._tempVars, this._assignNode); //变量基本检查,检查名称冲突及重复定义 this.#VarBaseCheck(this._globalVarList, this._tempVars); } CallRelation(ast, pName, curNode, parent, des, depth) { //函数定义不参与变量的使用判断 if (parent.type == AstNode.FunctionDeclaration) return; if (parent.type == AstNode.MemberExpression) return; if (parent.type == AstNode.ObjectProperty) return; let identifierName = curNode.name; let findVar = this._globalVarList.find((x) => x.name == identifierName); let callInfo; if (findVar) { //全局变量被使用(先排除重名变量和函数) if (findVar.idNode == curNode) return; //检查最近的范围内,是否有重名变量定义... let curTempVars = this._tempVars.filter((x) => x.file == ast.file && x.varName == identifierName);//在当前ast文件中查找和全局变量名称重名的定义 for (let i = 0; i <= curTempVars.length - 1; i++) { // if (AstHelper.IsInDomainNode(parent, curTempVars[i].domainNode)) return; } callInfo = AstHelper.GetNodeCallRel(ast, curNode, parent); if (callInfo) { let called = findVar.called.find((c) => c.file == ast.file && c.name == callInfo.name && c.member == callInfo.member && c.kind == callInfo.kind); //检查是否涉及到变量的值类型改变 let isAssignment = false; if ((pName == "left" && parent.type == AstNode.AssignmentExpression) || (pName == "property" && parent.type == AstNode.MemberExpression)) { isAssignment = true; let valType = AstHelper.AssignmentTypeConvert(parent, parent.right); if (valType && findVar.types.indexOf(valType) < 0) { findVar.types.push(valType); } findVar.isValTypeChange = false; if (findVar.types.length > 1) { findVar.isValTypeChange = true; } } if (called) { //找到相同的调用 called.pos.push({ start: curNode.start, end: curNode.end, }); } else { //在相同的对象中 findVar.called.push({ file: ast.file, name: callInfo.name, member: callInfo.member, kind: callInfo.kind, isAssignment: isAssignment, start: callInfo.node.start, end: callInfo.node.end, ext: callInfo.ext, pos: [{ start: curNode.start, end: curNode.end, }], path: AstHelper.GetParentPath(ast, callInfo.node),//查询当前调用的父级信息 }); } } } } get Result() { return { AllGlobalVarList: this._globalVarList, GlobalVarList: function (fileName) { return this.AllGlobalVarList.filter((x) => x.file == fileName); }, } } } window.AstParserPlugin_GlobalVar = AstParserPlugin_GlobalVar; /** * 当前主要过滤使用原生的getElementBy...和jquery相关调用的选择器形式 * 如:document.getElementById("name")及$("#name")的相关使用解析 */ class AstParserPlugin_Selector extends AstParserPlugin { SelectorType = { ID: "ID选择器", Name: "名称选择器", Classes: "类选择器", Label: "标签选择器", Undefined: "未能识别", } RegInfo = { Parse: AstNode.Identifier, //CallRelation: AstNode.FunctionDeclaration, } _selectorList = []; constructor(parser, option) { super(parser, option) } #GetSelectorType(callMethod, selectorPar) { if (callMethod != "$" && callMethod != "querySelector" && callMethod != "querySelectorAll") { switch (callMethod) { case "getElementById": { return this.SelectorType.ID; } case "getElementsByName": { return this.SelectorType.Name; } case "getElementsByClassName": { return this.SelectorType.Classes; } case "getElementsByTagName": { return this.SelectorType.Label; } } } else { let filterContext = selectorPar.parContext; /* if (filterContext.replaceAll(" ", "").substring(0, 2) == "'<" && filterContext.replaceAll(" ", "").slice(-2) == ">'") { //$("
...
") return ""; }*/ if (selectorPar.parType != "值" && selectorPar.parType != "表达式") { if (selectorPar.parType == "模板字符") { let f = filterContext.replaceAll(" ", "").substring(0, 2); if (f == "`#") { return this.SelectorType.ID; } else if (f == "`.") { return this.SelectorType.Classes; } else if (f == "`$") { return this.SelectorType.Undefined; } else { if (filterContext.indexOf("[name=") > 0) { return this.SelectorType.Name; } else { return this.SelectorType.Label; } } } else { return this.SelectorType.Undefined; } } else { let f = filterContext.replaceAll(" ", "").substring(0, 2); if (f == "'#") { return this.SelectorType.ID; } else if (f == "'.") { return this.SelectorType.Classes; } else { if (filterContext.indexOf("[name=") > 0) { return this.SelectorType.Name; } else { return this.SelectorType.Label; } } } } } //选择器接口调用方式 _SelectorInterface = new Map([["getElementById", null], ["getElementsByName", null], ["getElementsByClassName", null], ["getElementsByTagName", null], ["getElementsByTagNameNS", null], ["querySelector", null], ["querySelectorAll", null]]); //从Identifier节点获取调用的名称是否满足要求 Parse(ast, pName, curNode, parent, des, depth) { if ((pName == "property" && this._SelectorInterface.has(curNode.name)) || (pName == "callee" && curNode.name == "$" && parent.arguments[0].type != AstNode.FunctionExpression)) { //js原生选择器和$选择器 let callNode = AstHelper.FindParentNode(parent, AstNode.CallExpression); if (callNode) { let selectorPar = ""; let firstParNode = callNode.arguments[0]; if (callNode.arguments.length > 0) selectorPar = AstHelper.GetParasString(firstParNode); if (!selectorPar.parContext) return; //读取选择器类别 let selectWay = this.#GetSelectorType(curNode.name, selectorPar); if (!selectWay) return; this._selectorList.push({ file: ast.file, selectorWay: selectWay, selectorCall: (curNode.name == "$") ? "jquery" : curNode.name, start: callNode.start, end: callNode.end, ast: ast, defineNode: callNode, expressionNode: AstHelper.FindParentNode(callNode.parent, AstNode.ExpressionStatement),//整个表达式节点 selectorFilter: selectorPar.parContext, des: AstHelper.GetVarNodeDes(callNode), }); } } } //获取操作类型 #GetMemberCallType(selectorNode) { let ret = { kind: "未能识别", kindDes: '', } if (!selectorNode) return ret; //获取成员的事件配置参数,如$("#name").on("change", function(){...}) let getMemberArgs = function () { let eventName = ""; if (selectorParent.parent?.type == AstNode.CallExpression) { let arg0 = selectorParent.parent.arguments[0]; if (arg0.type == AstNode.Identifier) { eventName = arg0.name; } else { eventName = arg0.value; } } return eventName; } let selectorParent = selectorNode.parent; if (selectorParent?.type == AstNode.MemberExpression) { //判断父级是否属于成员调用 let propName = selectorParent.property.name; switch (propName) { case "append": case "appendTo": case "prepend": case "prependTo": case "after": case "insertAfter": case "before": case "insertBefore": { ret.kind = "新增元素"; return ret; } case "html": { if (selectorParent.parent.arguments.length > 0) { ret.kind = "修改元素"; } else { ret.kind = "获取属性/元素"; } return ret; } case "get": case "find": case "not": case "children": case "parents": case "has": case "parents": case "parentsUntil": case "closest": { ret.kind = "获取属性/元素"; return ret; } case "remove": case "removeChild": case "empty": case "detach": case "unwrap": { ret.kind = "移除元素"; return ret; } case "attr": case "prop": { if (selectorParent.parent.arguments.length > 1) { ret.kind = "修改属性"; } else { ret.kind = "获取属性/元素"; } return ret; } case "text": case "val": case "width": case "height": case "scrollTop": { if (selectorParent.parent.arguments.length > 0) { ret.kind = "修改属性"; } else { ret.kind = "获取属性/元素"; } return ret; } case "removeAttr": { ret.kind = "修改属性"; return ret; } case "css": { if (selectorParent.parent.arguments?.length == 1) { if (selectorParent.parent.arguments[0].type == AstNode.ObjectExpression) { ret.kind = "修改样式"; let props = []; for (let prop of selectorParent.parent.arguments[0].properties) { props.push({ name: (prop.key.type == AstNode.Identifier) ? prop.key.name : prop.key.value, defineNode: prop, }); } ret.kindDes = props; } else { ret.kind = "获取属性/元素"; } } else { ret.kind = "修改样式"; let propName = ""; if (selectorParent.parent.arguments[0].type == AstNode.Identifier) { propName = selectorParent.parent.arguments[0].name; } else { propName = selectorParent.parent.arguments[0].value; } ret.kindDes = [ { name: propName, defineNode: selectorParent.parent.arguments[0], } ] } return ret; } case "hide": case "show": case "classList": case "addClass": case "removeClass": { ret.kind = "修改样式" return ret; } case "on": case "bind": case "live": { ret.kind = "事件处理"; //获取事件名称 ret.kindDes = getMemberArgs() ?? ""; return ret; } case "change": case "click": case "dblclick": case "mousedown": case "mouseup": case "mouseover": case "mouseout": case "mousemove": case "mouseenter": case "mouseleave": case "focus": case "blur": case "keydown": case "keyup": case "keypress": case "drag": case "dragstart": case "dragend": case "dragover": case "drop": case "error": case "scroll": { ret.kind = "事件处理"; ret.kindDes = propName; /*暂不区分事件绑定和事件执行 if (selectorParent.parent.arguments?.length > 0) { } else { } */ return ret; } case "addEventListener": { ret.kind = "事件处理"; //获取事件名称 ret.kindDes = getMemberArgs() ?? ""; return ret; } case "off": case "removeEventListener": { ret.kind = "事件处理"; return ret; } default: { ret.kind = "获取属性/元素"; return ret; } } } else { //既不在赋值表达式,也不在变量定义中,同时不是成员调用,则可能作为了方法的调用参数 ret.kind = "获取属性/元素"; return ret; } } _selectorParentNodeType = new Map([[AstNode.AssignmentExpression, null], [AstNode.VariableDeclarator, null], [AstNode.ObjectProperty, null], [AstNode.ExpressionStatement, null]]); #SelectorBaseCheck() { for (let selector of this._selectorList) { //查找selector所在函数 let funcNode = AstHelper.FindParentNode(selector.defineNode.parent, AstNode.FunctionDeclaration); if (funcNode) { selector.funcInfo = AstHelper.GetCurNodeCallInfoByFuncDeclaration(selector.ast, funcNode, funcNode.parent); } else { funcNode = AstHelper.FindParentNode(selector.defineNode.parent, AstNode.FunctionExpression); if (funcNode) { selector.funcInfo = AstHelper.GetCurNodeCallInfoByFuncExpression(selector.ast, funcNode, funcNode.parent); } else { selector.funcInfo = { name: "全局", member: "", kind: "global", node: null } } } //查找selector操作类别 let funcExpressionNode = AstHelper.FindParentNodeByTypes(selector.defineNode.parent, AstHelper.M_FuncExpression); //todo:跟踪选择器对应变量的使用情况... let k = {}; //查找最先满足条件的父级节点 let findNode = AstHelper.FindParentNodeByTypes(selector.defineNode.parent, this._selectorParentNodeType, funcExpressionNode); if (findNode == null) { k = this.#GetMemberCallType(selector.defineNode); } else if (findNode.type == AstNode.AssignmentExpression) { if (AstHelper.IsInDomainNode(selector.defineNode, findNode.right, findNode)) { //在赋值表达式的右侧出现 //xxx=$("#con").width() + 100; k.kind = "获取属性/元素"; } else { //如果是在左侧,则需要判断是否作为调用的参数出现 let isPars = AstHelper.IsInParasNode(selector.defineNode, findNode); if (isPars) { //getObj($("#name").val()).name = "..."; k.kind = "获取属性/元素"; } else { //判断是否onchange类似赋值处理... if (AstHelper.IsArrayEleNode(selector.defineNode, findNode)) { //xxx.info[$("#name").val()] = "..." k.kind = "获取属性/元素"; } else { if (findNode.left.property?.name.indexOf("on") == 0) { //document.getElementBy...("").onclick = ()=>{...} k.kindDes = findNode.left.property.name.replace("on", ""); k.kind = "事件处理"; } else { if (selector.defineNode.parent.property.name == "style") { //document.getElementBy...("").style.width = "100px;" k.kind = "修改样式"; } else { k.kind = "修改属性"; } } } } } } else if (findNode.type == AstNode.VariableDeclarator) { //let xx = $("#name").val(); //let xx = data[$("#name").val()]; k.kind = "获取属性/元素"; } else if (findNode.type == AstNode.ObjectProperty) { //{aa: $("#name").val()} k.kind = "获取属性/元素"; } else if (findNode.type == AstNode.ExpressionStatement) { if (AstHelper.IsInParasNode(selector.defineNode, findNode)) { //call($("#name").val(),"..."); k.kind = "获取属性/元素"; } else { if (findNode.expression.type == AstNode.AwaitExpression) { //这种情况可能不存在,兼容处理... if (findNode.expression.argument.callee.type == AstNode.MemberExpression) { k = this.#GetMemberCallType(findNode.expression.argument.callee.property); } else { k = this.#GetMemberCallType(findNode.expression.argument.callee); } } else if (findNode.expression.type == AstNode.LogicalExpression) { //isOk && $("#name").on("click",function(){...}) if (findNode.expression.right.callee?.type == AstNode.MemberExpression) { k = this.#GetMemberCallType(findNode.expression.right.callee.property); } else { k.kind = "获取属性/元素"; } } else { //$("#name").change(function () { ...}) k = this.#GetMemberCallType(findNode.expression.callee.property); } } } else { debugger; console.log("SelectorBaseCheck中发现未能识别的节点类型" + findNode.type); } selector.kind = k.kind; selector.kindDes = k.kindDes; } } Checked() { this.#SelectorBaseCheck(); } get Result() { return { AllSelectorList: this._selectorList, SelectorList: function (fileName) { return this.AllSelectorList.filter((x) => x.file == fileName); }, } } } window.AstParserPlugin_Selector = AstParserPlugin_Selector; class AstParser { _ast = [];//_ast可以是当对象,也可以是一个ast的数组 {type:"File",start:"0",end:"", program:"",file:""} _regPlugins = []; constructor() { } /** * Ast属性 */ get Ast() { return this._ast; } /** * 创建解析对象 * @param {any} ast * @returns */ static CreateParser(ast) { let parser = new AstParser(); parser.Insert(ast); return parser; } /** * 清除ast */ Clear() { this._ast = []; } Insert(ast, fileName) { if (!ast) return; if (fileName) ast.file = fileName; ast.root = true; this._ast.push(ast);// = ast; } /** * 查找指定函数引用 * @param {any} funcName */ GetFuncCall(funcName) { let ret = []; let option = { callExp: (ast, pName, curNode, parent, des, depth) => { let callee = curNode.callee; if (callee.type == AstNode.Identifier) {//MemberExpression //对象成员调用 //函数调用 if (callee.name == funcName) { let curInfo = AstHelper.GetCurNodeCallInfoByCallExpression(ast, curNode, parent); ret.push({ file: ast.file, class: "", name: funcName, start: curInfo.start, end: curInfo.end, node: curInfo.node, called: [], }) } } } } this.#StartAstParser(option); return ret; } /** * 查找指定函数的定义 * @param {any} funcName */ GetFuncDefine(funcName) { let ret = []; let option = { funcDec: (ast, pName, curNode, parent, des, depth) => { let id = curNode.id; if (id.name == funcName) { let curInfo = AstHelper.GetCurNodeCallInfoByFuncDeclaration(ast, curNode, parent); ret.push({ file: ast.file, class: "", name: funcName, start: curInfo.start, end: curInfo.end, node: curInfo.node, called: [], }) } } } this.#StartAstParser(option); return ret; } /** * 开始ast解析 * @param {any} option */ #StartAstParser(option, useBuffer) { if (Array.isArray(this._ast)) { //如果是数组,则查找多个ast this._ast.forEach((astItem) => { let curAst = astItem.ast ?? astItem; curAst.file = astItem.file; curAst.root = true; AstHelper.TraverseNode(curAst, curAst, null, option, 0, useBuffer); }); } else { let curAst = this._ast.ast ?? this._ast; curAst.file = this._ast.file; curAst.root = true; AstHelper.TraverseNode(this._ast.ast ?? this._ast, this._ast.ast ?? this._ast, null, option, 0, useBuffer); } } //克隆对象 #DeepClone(obj) { if (obj === null || typeof obj !== 'object') { return obj; } let clone = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (key == "parent" || key == "idNode" || key == "defineNode") continue; if (obj.hasOwnProperty(key)) { clone[key] = this.#DeepClone(obj[key]); } } return clone; } /** * 解析子对象列表 * @param {any} subNode * @param {any} option */ AnalyzeSubNodeObjectList(subNode, option) { let parseNode = this.#DeepClone(subNode); let subParser = AstParser.CreateParser(); subParser.Insert(parseNode); if (!option) option = { func: { enabled: true,//解析函数 analyzeCallRel: true,//解析调用关系 }, globalVar: { enabled: true,//解析变量 analyzeCallRel: true,//解析调用关系 }, selector: {//选择器解析 enabled: true, } } return subParser.AnalyzeObjectList(option); } #ConfigAnalyzePlugin(analyzeOption, type, plugin) { let regInfo = plugin.RegInfo; switch (regInfo[type]) { case AstNode.Program: { if (!analyzeOption.program) analyzeOption.program = []; analyzeOption.program.push(plugin[type].bind(plugin)); break; } case AstNode.ExpressionStatement: { if (!analyzeOption.expression) analyzeOption.expression = []; analyzeOption.expression.push(plugin[type].bind(plugin)); break; } case AstNode.CallExpression: { if (!analyzeOption.callExp) analyzeOption.callExp = []; analyzeOption.callExp.push(plugin[type].bind(plugin)); break; } case AstNode.FunctionExpression: { if (!analyzeOption.funcExp) analyzeOption.funcExp = []; analyzeOption.funcExp.push(plugin[type].bind(plugin)); break; } case AstNode.BlockStatement: { if (!analyzeOption.block) analyzeOption.block = []; analyzeOption.block.push(plugin[type].bind(plugin)); break; } case AstNode.FunctionDeclaration: { if (!analyzeOption.funcDec) analyzeOption.funcDec = []; analyzeOption.funcDec.push(plugin[type].bind(plugin)); break; } case AstNode.Identifier: { if (!analyzeOption.identifier) analyzeOption.identifier = []; analyzeOption.identifier.push(plugin[type].bind(plugin)); break; } case AstNode.ReturnStatement: { if (!analyzeOption.returnstatement) analyzeOption.returnstatement = []; analyzeOption.returnstatement.push(plugin[type].bind(plugin)); break; } case AstNode.CatchClause: { if (!analyzeOption.catchclause) analyzeOption.catchclause = []; analyzeOption.catchclause.push(plugin[type].bind(plugin)); break; } } } //注册插件 RegPlugin(pluginName, option) { this._regPlugins.push({ name: pluginName, option: option, }); } //清除插件 ClearPlugin() { this._regPlugins = []; } //获取所有对象列表 AnalyzeObjectList(useBuffer) { //{funcOption:{enabled:true},varOption:{enabled:true}} console.time("AnalyzeObjectList"); let anaOption = {}; let parserPluginObj = []; if (useBuffer == undefined) useBuffer = true; //配置默认插件 if (this._regPlugins.length <= 0) { this._regPlugins = [ { name: "AstParserPlugin_Func", option: null }, { name: "AstParserPlugin_GlobalVar", option: null }, { name: "AstParserPlugin_Selector", option: null }, ]; } //实例化插件 for (let pluginInfo of this._regPlugins) { parserPluginObj.push(new window[pluginInfo.name](this, pluginInfo.option)); } //挂接插件接口 parserPluginObj.forEach((x) => { this.#ConfigAnalyzePlugin(anaOption, "Parse", x); }); //获取到对应的对象 this.#StartAstParser(anaOption, useBuffer); anaOption = {}; parserPluginObj.forEach((x) => { if (x.Checked) x.Checked(); }); anaOption = {}; //挂接插件接口 parserPluginObj.forEach((x) => { this.#ConfigAnalyzePlugin(anaOption, "CallRelation", x); }); //获取调用关系 this.#StartAstParser(anaOption, useBuffer); console.timeEnd("AnalyzeObjectList"); //配置返回结果 let ret = {}; parserPluginObj.forEach((x) => { ret = Object.assign({}, ret, x.Result); }); parserPluginObj = null; return ret; } /** * 查找所有函数列表 */ GetAllFuncList(isFindCallRel) { return this.AnalyzeObjectList({ func: { enabled: true, analyzeCallRel: isFindCallRel } }); } /** * 查找所有全局变量 */ GetAllGlobalVarList(isFindCallRel) { return this.AnalyzeObjectList({ globalVar: { enabled: true, analyzeCallRel: isFindCallRel } }); } /** * 查找全局变量的引用 */ GetGlobalVarCall(varName) { } /** * 查找所有类列表 */ GetAllClassList() { } /** * 查找类成员列表 * @param {any} className */ GetClassMemberList(className) { } /** * 查找对象类成员定义 */ GetClassMemberDefine(className, memberName) { } /** * 查找类成员引用 * @param {any} className * @param {any} memberName */ GetClassMemberCall(className, memberName) { } }