用小提琴完成解决方案:
下面是一些用于测试运行的 JavaScript 代码:
var hello = 41;
function aaaaa(p1, p2, p3){
var a1 = 7, a2 = 8;
var a3 = 9;
function bbbbb(q1, q2){
var b1 = 10, b2 = 11;
return 12;
}
var a4 = 99;
function ccccc(r1, r2, r3){
var c1 = 13;
var c2 = 14;
var c3 = 15, c4 = 16;
return 17;
}
var a5 = 88, a6 = 77;
function ddddd(s1){
return s1 === 18
? function (x){ return x+1; }
: function (y){ return 22; }
}
return p1 + a3 <= 42 ? 55 : ccc(p1, 0, 0);
}
var world = 42;
function xxxxx(x){
var z=0;
return 0;
}
我假设这是所需的输出:
{
"vars": ["hello", "world" ],
"funcs": [
{
"name": "aaaaa",
"params": ["p1", "p2", "p3"],
"variables": ["a1","a2","a3","a4","a5","a6"]
},
{
"name": "bbbbb",
"params": ["q1","q2"],
"variables": ["b1","b2"]
},
{
"name": "ccccc",
"params": ["r1","r2","r3"],
"variables": ["c1","c2","c3","c4"]
},
{
"name": "ddddd",
"params": ["s1"],
"variables": []
},
{
"name": "xxxxx",
"params": ["x"],
"variables": ["z"]
}
]
}
列表是扁平的,并且 ddddd 中的匿名函数被忽略(它们是 FunctionExpressions 而不是 FunctionDeclarations)。猜猜这就是你想要的。
这是代码 - 可能/希望很容易理解,无需进一步解释:
function findDeclarations(code){
var ast = esprima.parse(code);
var funcDecls = [];
var globalVarDecls = [];
var funcStack = [];
function visitEachAstNode(root, enter, leave){
function visit(node){
function isSubNode(key){
var child = node[key];
if (child===null) return false;
var ty = typeof child;
if (ty!=='object') return false;
if (child.constructor===Array) return ( key!=='range' );
if (key==='loc') return false;
if ('type' in child){
if (child.type in esprima.Syntax) return true;
debugger; throw new Error('unexpected');
} else { return false; }
}
enter(node);
var keys = Object.keys(node);
var subNodeKeys = keys.filter(isSubNode);
for (var i=0; i<subNodeKeys.length; i++){
var key = subNodeKeys[i];
visit(node[key]);
}
leave(node);
}
visit(root);
}
function myEnter(node){
if (node.type==='FunctionDeclaration') {
var current = {
name : node.id.name,
params : node.params.map(function(p){return p.name;}),
variables : []
}
funcDecls.push(current);
funcStack.push(current);
}
if (node.type==='VariableDeclaration'){
var foundVarNames = node.declarations.map(function(d){ return d.id.name; });
if (funcStack.length===0){
globalVarDecls = globalVarDecls.concat(foundVarNames);
} else {
var onTopOfStack = funcStack[funcStack.length-1];
onTopOfStack.variables = onTopOfStack.variables.concat(foundVarNames);
}
}
}
function myLeave(node){
if (node.type==='FunctionDeclaration') {
funcStack.pop();
}
}
visitEachAstNode(ast, myEnter, myLeave);
return {
vars : globalVarDecls,
funcs : funcDecls
};
}
对于测试,您可以键入
JSON.stringify(
findDeclarations(
'var hello=41;\n' +
aaaaa.toString() +
'var world=42;\n' +
xxxxx.toString()
),
null, 4
)
你也可以使用 estraverse 包,它可以在 github 上找到。然后,本质上,函数 visitEachAstNode 应该替换为 estraverse.traverse,否则您可以保持代码不变。
小提琴