Как получить все функции и их аргументы из файла js?Javascript - PullRequest
5 голосов
/ 13 марта 2019

есть test.js:

const add = (x,y) => {
    return x+y;
}

const multiply = (x,y,z) => {
    return x*y*z;
}

Я хочу прочитать этот test.js из index.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]

Без module.exports.
Можно ли прочитать файл js и вернуть все его функции и их аргументы.

Ответы [ 4 ]

2 голосов
/ 13 марта 2019

Вы можете получить функции и их аргументы с помощью синтаксического анализатора JavaScript, например esprima .

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' ]
1 голос
/ 13 марта 2019

Когда вам нужно прочитать файл кода, лучше напрямую использовать компилятор, когда он доступен.

Оказывается, желудь - это хорошо известный парсер, и вы, вероятно, уже используете его, не зная, потому что вы, вероятно, используете babel.

С помощью acorn вы можете проанализировать исходный файл в абстрактном дереве исходных текстов, которое, в свою очередь, можно просмотреть с помощью acorn-walk, чтобы найти то, что вам нужно.

пример:

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;

basicparser.js


    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

Начиная с этого, будет довольно просто найти решение вашей проблемы.

1 голос
/ 13 марта 2019
  • читать файл js
  • заменить const на this.
  • оберните его внутри функции конструктора и оцените его.
  • создать экземпляр этого
  • , поскольку вы заменили const на this., все переменные в test.js стали членами экземпляра. теперь вы можете объединить этот экземпляр, чтобы получить членов.
  • чтобы получить сигнатуру функции, вам придется преобразовать объект функции в строку и получить аргументы вручную.

Вот код:

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;
  }, {})
}
0 голосов
/ 13 марта 2019

Я думаю, что вы уже на правильном пути, но вы никогда не использовали прочитанный файл, это действительно должно быть (надеюсь, я правильно понял ваш вопрос):

let file = fs.readFileSync("./test.js", "utf8");
console.log(file);

// Result:
//const add = (x,y) => {
//   return x+y;
//}

//const multiply = (x,y,z) => {
//  return x*y*z;
// }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...