如何从js文件中获取所有函数及其参数?javascript
有一个test.js:如何从js文件中获取所有函数及其参数?javascript,javascript,node.js,automation,Javascript,Node.js,Automation,有一个test.js: const add = (x,y) => { return x+y; } const multiply = (x,y,z) => { return x*y*z; } 我想从index.js中读取test.js并打印它的所有函数名和参数 const fs = require("fs"); let file = fs.readFileSync("./test.js", "utf8"); let functionArg = "Do some
const add = (x,y) => {
return x+y;
}
const multiply = (x,y,z) => {
return x*y*z;
}
我想从index.js中读取test.js并打印它的所有函数名和参数
const fs = require("fs");
let file = fs.readFileSync("./test.js", "utf8");
let functionArg = "Do some operations"
console.log(functionArg)
//Result:
// add : [x,y]
// multiply : [x,y,z]
没有模块。导出。是否可以读取js文件并返回其所有函数及其参数。
- 读取js文件
- 将
替换为const
this.
- 将其包装在构造函数中并对其求值
- 创建它的一个实例
- 由于您将
替换为const
,test.js中的所有变量都成为实例的成员。现在可以交互此实例以获取成员this.
- 要获取函数签名,必须将函数对象转换为字符串并手动获取参数
const fs = require("fs");
let file = fs.readFileSync("./test.js", "utf8");
const getFuncInfo = function(file) {
file = file.replace(new RegExp('const ', 'g'), 'this.');
eval(`function Container(){
${file}}
`)
const instance = new Container()
const names = Object.keys(instance)
return names.reduce((res, cur) => {
if(typeof instance[cur] == 'function') {
let args = instance[cur].toString()
res[cur] = args.split('(')[1].split(')')[0].split(',')
}
return res;
}, {})
}
let functionArg = getFuncInfo(file)
console.log(functionArg)
结果是:
{ add: [ 'x', 'y' ], multiply: [ 'x', 'y', 'z' ] }
编辑:
关于eval
做什么的问题,
如下所示:
const getFuncInfo = function(file) {
file = file.replace(new RegExp('const ', 'g'), 'this.');
// think like eval replace the content with below one
function Container(){
// content of test.js except `const ` is replaced with `this.`
this.add = (x,y) => {
return x+y;
}
this.multiply = (x,y,z) => {
return x*y*z;
}
}
// end of replacement
const instance = new Container()
const names = Object.keys(instance)
return names.reduce((res, cur) => {
if(typeof instance[cur] == 'function') {
let args = instance[cur].toString()
res[cur] = args.split('(')[1].split(')')[0].split(',')
}
return res;
}, {})
}
我认为您已经走上了正确的道路,但您从未使用过您阅读的文件,它实际上应该是(我希望我正确地回答了您的问题):
当您需要读取代码文件时,最好是在可用时直接使用编译器 它是一个众所周知的解析器,您可能已经在不知不觉中使用了它,因为您可能正在使用babel 使用
acorn
可以将源文件解析为一个抽象的源代码树,然后通过它找到所需的内容
例如:
testfiletoparse.js
export function factorialR(n) {
if (n <= 1) {
return 1;
}
return factorialR(n - 1) * n;
}
export function bound(v, min, max) {
return Math.max(Math.min(v, min), max);
}
export function isNullOrEmpty(str) {
return !str || str.length === 0;
}
export const arrowFunction = v => v;
import fs from 'fs';
const acorn = require('acorn');
const walk = require('acorn-walk');
require('acorn-object-rest-spread/inject')(acorn);
require('acorn-static-class-property-initializer/inject')(acorn);
require('acorn-class-fields/inject')(acorn);
const filePath = 'src/testfiletoparse.js';
const sourceCode = String(fs.readFileSync(filePath));
const program = acorn.parse(
sourceCode,
{
ranges: true,
locations: true,
sourceType: 'module',
plugins: {
objectRestSpread: true,
// es7: true,
staticClassPropertyInitializer: true,
classFields: true,
}
}
);
walk.full(
program,
/**
* @param {}
*/
(node) => {
if (node.type === 'FunctionDeclaration') {
console.log(`There's a FunctionDeclaration node at ${JSON.stringify(node.loc.start)}`);
console.log(`Function name is ${node.id.name}`);
const params = node.params.map((param) => {
return param.name;
}).join();
console.log(`Function params are ${params}`);
}
// it is a little tricky to catch arrow functions but trial and error will get you through it
if (node.type === 'VariableDeclarator' && node.init.type === 'ArrowFunctionExpression') {
console.log(`There's an arrow function expression declaration node at ${JSON.stringify(node.loc.start)}`);
console.log(`Its name is ${node.id.name}`);
const params = node.init.params.map((param) => {
return param.name;
}).join();
console.log(`Function params are ${params}`);
}
}
);
输出
There's a FunctionDeclaration node at {"line":1,"column":7}
Function name is factorialR
Function params are n
There's a FunctionDeclaration node at {"line":8,"column":7}
Function name is bound
Function params are v,min,max
There's a FunctionDeclaration node at {"line":12,"column":7}
Function name is isNullOrEmpty
Function params are str
There's an arrow function expression declaration node at {"line":16,"column":13}
Its name is arrowFunction
Function params are v
从这一点开始,找到问题的解决方案应该非常简单。您可以在JavaScript解析器的帮助下获得函数及其参数,如
因为您不想导入函数,所以可以读取文件的每一行,并检查该行是否是函数定义或声明。如何做到这一点?对于函数,我可以读取每一行并将其拆分为一个空格,然后可以检查它是否属于函数类型。争论呢?你能解释一下你的方法吗?谢谢,您不必阅读每一行的函数。请看下面我的答案,我可以确认remix23的答案是有效的。谢谢你的回答,实际上我不想打印js文件的内容,我只想要js文件中的函数名和它们的参数。你能解释一下eval到底在做什么吗?代码正在运行。thankseval正在执行代码。看看它的参数。这不仅仅是test.js的内容。它由另一个函数包装。把它想象成编译器。
const instance=新函数(文件);这就是eval中运行的内容
。不,不是:)。请检查我编辑的答案。好的,现在我明白了,当我们放置函数Container(){file};它将file作为变量。但是当我们使用eval时,它首先用$file编写完整的函数,然后运行,感谢它的解释。出于许多原因,使用eval是一个不好的选择。谢谢分享答案。我以前听说过ESPrima,但从未使用过。在你的回答之后,我阅读了更多关于它的内容,阅读了它的代码,这有助于提高我的JS知识。@NirajKumar很好的反射。请注意,该项目在TypeScript中占68%,因此它也将有助于改进TS;)
There's a FunctionDeclaration node at {"line":1,"column":7}
Function name is factorialR
Function params are n
There's a FunctionDeclaration node at {"line":8,"column":7}
Function name is bound
Function params are v,min,max
There's a FunctionDeclaration node at {"line":12,"column":7}
Function name is isNullOrEmpty
Function params are str
There's an arrow function expression declaration node at {"line":16,"column":13}
Its name is arrowFunction
Function params are v
const fs = require("fs");
const esprima = require('esprima');
let file = fs.readFileSync("./test.js", "utf8");
let functionArg = esprima.parseScript(file);
functionArg.body.forEach(el => {
let variableDeclarator = el.declarations[0]
let params = []
variableDeclarator.init.params.forEach(arg => {
params.push(arg.name)
})
console.log(variableDeclarator.id.name, ' : ', [params.join()])
})
//Result:
// add : [ 'x,y' ]
// multiply : [ 'x,y,z' ]