• npm获取函数名称和测试js脚本


    这边遇到一个类似于测试的需求,需要从一个js文件里获取函数名,然后尝试执行这些函数和创建实例。这边首先遇到了一个问题是如何动态获取js里的函数名和类名,我这边暂时没找到特别好的方法,已有的方法都是类似于提取语法树那种提取函数名
    最后想的还是通过正则匹配函数名来尝试执行,有参数需求的函数尝试用数字代替作为参数尽量执行,加了个5秒超时

    附:安装npm
    https://nodejs.org/en

    安装minimist(用于调用参数)

    npm i minimist
    
    • 1

    调用

    node tester.js --fp sample.js
    
    • 1

    代码:

    const fs = require('fs');
    const path = require('path');
    
    console.log("--fp指定路径");
    var args = require('minimist')(process.argv.slice(2));
    console.log("filepath:",args.fp);
    // 目标文件路径
    const targetPath = path.join(__dirname, args.fp);
    
    // 读取index.js文件内容
    const fileContent = fs.readFileSync(targetPath, 'utf8');
    
    // 正则表达式匹配函数名和类名
    const functionRegex = /function\s+(\w+)\s*\(/g;
    const classRegex = /class\s+(\w+)/g;
    const arrowFunctionRegex =  /([a-zA-Z_\$][a-zA-Z_\$0-9]*)\s*=\s*\([^)]*\)\s*=>/g;
    // const arrowFunctionRegex = /^([^\(\)]+)\s*=>/;
    
    const functions = [];
    const classes = [];
    
    // 匹配函数名
    let match;
    while ((match = functionRegex.exec(fileContent)) !== null) {
      functions.push(match[1]);
    }
    while ((match = arrowFunctionRegex.exec(fileContent)) !== null) {
      functions.push(match[1]);
    }
    
    // 匹配类名
    while ((match = classRegex.exec(fileContent)) !== null) {
      classes.push(match[1]);
    }
    
    if (!fileContent.includes('module.exports')) {
      fs.writeFileSync(
        targetPath,
        fileContent +
          `\nmodule.exports = {${functions.join(',') + ',' + classes.join(',')}}`
      );
    }
    
    const newRequire = require(targetPath);
    
    /**
    *@name asyncFunction
    *@des 异步函数
    *@param use: () => void | unknow
    *@return {Promise}
     */
    
    const  asyncFunction = async(use) => {
      return new Promise( (resolve, reject) => {
        // 异步操作,例如 Ajax 请求或者定时器
        try {
            const result = use();
            if(result) resolve(result)
        } catch (error) {
            reject(error)
        }
      });
    }
    
    // -- timeout 机制
    function withTimeout(promise, timeout) {
      return Promise.race([
        promise,
        new Promise((resolve, reject) => {
          setTimeout(() => {
            reject(new Error('操作超时'));
          }, timeout);
        })
      ]);
    }
    
    // 处理类的方法
    const onHandleClassFn = async (ClassName, target, name) => {
      const params = [];
      for (let i = 0; i < target.length; i++) {
        params.push('拟参' + i);
      }
      if (!/^class\s/.test(Function.prototype.toString.call(target))) {
        try {
          const result = await withTimeout(
            asyncFunction(() => {
            return target.length
                ? 
                target(...params)
                : 
                target()
            }),
            5000
          );
            console.log(`---------类${ClassName}${name}()的return结果:`, result);
        } catch (error) {
          console.log(`+++++++++抛出错误类${ClassName}${name}()函数执行出错,error信息:`, error);
        } 
      }
    };
    for (const iterator in newRequire) {
      const target = newRequire[iterator];
      const params = [];
      for (let i = 0; i < target.length; i++) {
        params.push('拟参' + i);
      }
      if (!/^class\s/.test(Function.prototype.toString.call(target))) {
        try {
          target.length
            ? console.log(
                `---------以上是${iterator}()执行的log,return:`,
                target(...params),
                '---------'
              )
            : console.log(
                `---------以上是${iterator}()执行的log,return:`,
                target(),
                '---------'
              );
          continue;
        } catch (error) {
          console.log(`+++++++++抛出错误函数${iterator}执行出错,error:`, error);
        }
      }
      const Instance = target.length ? new target(...params) : new target();
      // 获取构造函数包含的所有方法
      const methods = Object.getOwnPropertyNames(Instance.__proto__).filter(
        (item) => item !== 'constructor'
      );
    
      methods.forEach((item) => {
        onHandleClassFn(iterator, Instance[item], item);
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134

    用于测试的脚本

    function AFn() {
      console.log('Run Function A');
      return 'AFn is true'
    }
    function BFn(param1, param2) {
      console.log('Run Function B', param1, param2);
      return 'BFn is true'
    }
    const CFn = (param1, param2) => {
      console.log('Run Function C', param1, param2);
      return 'CFn is true'
    }
    class Cat {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
      Say1(param1) {
        console.log('Say1方法参数:', param1);
        return 'Say1 is ' + +new Date();
      }
      Say2(param1,param2) {
        console.log('say2方法参数:', param1, param2);
        return 'Say2 is ' + +new Date();
      }
      ThrowerrFn(){
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            console.log('这是一个异步模拟抛error出错误的函数');
            reject('this is a error_throw');
          }, 200);
        })
      }
      ThrowSuccessFn(){
        return new Promise((resolve) => {
          setTimeout(() => {
            console.log('这是一个异步模拟success的函数');
            resolve('success') 
          }, 2000);
        })
      }
      ThrowTimeoutFn(){
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve('timeout_success, 此结果会因为超时被阻塞输出')
          }, 6000);
        })
      }
      Say3(param1,param2) {
        console.log('say3方法参数:', param1, param2);
        return 'Say3 is ' + +new Date();
      }
    }
    
    module.exports = {AFn,BFn,CFn,Cat}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
  • 相关阅读:
    程序员买啥游戏机,自己动手做一个体感小游戏
    2022年湖北师范大学招生简章--成人高等教育高起专、专升本学历提升
    Visual Studio 2022下载安装的详细步骤-----C语言编辑器
    线程安全
    CRM、DMP、CDP都是什么?
    小白从CentOS7到安装CDH6.3.2入坑实操指北(一)
    MachineLearning 23. 机器学习之岭回归预测基因型和表型 (Ridge)
    [附源码]计算机毕业设计springboot学分制环境下本科生学业预警帮扶系统
    Java 并行 GC 调优
    155_模型_Power BI & Power Pivot 进销存之安全库存
  • 原文地址:https://blog.csdn.net/qq_43199509/article/details/132557116