zoukankan      html  css  js  c++  java
  • nodejs vm+ babel ast 实现类似cube.js schema 的处理能力

    很简单主要是学习下cube.js 关于schema 的特殊处理了解下原理
    以下部分代码参考了cube.js compiler 部分

    参考项目

    • package.json
     
    {
      "name": "vm-scripts",
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT",
      "dependencies": {
        "@babel/core": "^7.12.10",
        "@babel/generator": "^7.12.11",
        "@babel/parser": "^7.12.11",
        "@babel/preset-env": "^7.12.11",
        "@babel/traverse": "^7.12.12",
        "@babel/types": "^7.12.12"
      }
    }
    • 仿cube.js schema 定义
    app("dalong2",{
        "name":{
            age:333,
            version:"v1",
            name:"v1 rongfengliang",
            full_name: `${JSON.stringify(COMPILE_CONTEXT)}---demoapp`
        },
        "info":`${COMPILE_CONTEXT.name}`
    })

    简单说明,对于info 我们认为应该一个函数,同时app 也是我们一个全局变量,类似cube.js 的cube
    同时我们也提供了一个全局变量COMPILE_CONTEXT,类似cube.js 编译时的schema 处理,当然其他的也是可以扩展的

    • 基于babel 的ast 进行代码转换
      主要是将info 属性变为info: COMPILE_CONTEXT=>${COMPILE_CONTEXT.name},这样就和cube.js sql 是一个函数类似了
      参考代码
     
    const vm = require("vm")
    const fs = require("fs")
    const { parse } = require("@babel/parser")
    const generate = require("@babel/generator")
    const traverse = require("@babel/traverse")
    const t = require("@babel/types")
    // 进行数据的中间存储
    const cubes = [];
    const field  = /^.*(info|sql|conf)$/
    // 包装的基于babel ast+ vm 的处理函数
    function call_vm(context) {
            const code = fs.readFileSync("./cube.js", {
                encoding: "utf8"
            }).toString();
            const ast1 = parse(
                code,
                {
                    sourceFilename: "cube.js",
                    sourceType: 'module',
                    plugins: ['objectRestSpread']
                },
            );
            traverse.default(ast1, {
                ObjectProperty(path) {
                    console.log("path info:",JSON.stringify(path.node))
                     // 进行ast类型判断处理,同时进行as的替换处理,将info 的包含为一个箭头函数
                    if (path.node.key.type === 'StringLiteral' && path.node.key.value.match(field)) {
                      path.get('value').replaceWith(
                        t.arrowFunctionExpression([t.identifier("COMPILE_CONTEXT")], path.node.value, false)
                      );
                    }
                  }
            })
            const output = generate.default(
                ast1,
                {},
                code
            );
            console.log(output)
            // 使用vm 沙箱提供数据隔离的环境
            vm.runInNewContext(output.code, {
               // 提供上下文的函数
                app: (name, conf) => {
                    cubes.push({
                        name:name,
                        conf:conf
                    })
                },
                COMPILE_CONTEXT: context
            })
    }
    context = {
        name: "rongfengliangdemoapp",
        appid: "app001",
        auth: {
            name: "dalong",
            age: 22
        }
    }
    call_vm(context)
    cubes.forEach(cube => {
        console.log(cube)
        let result = cube.conf.info(cube.conf.name)
        console.log("=======",result,"=======")
    });
    • 运行效果

    参考资料

    https://babeljs.io/docs/en/
    https://astexplorer.net/
    https://cube.dev/docs/schema/dynamic-schema-creation
    https://nodejs.org/api/vm.html

  • 相关阅读:
    [翻译]JavaScript Scoping and Hoisting
    SVN服务器的本地搭建和使用(一)
    SVN服务器搭建和使用(二)
    优酷站内获取m3u8地址(转)
    jQuery 获取屏幕高度、宽度
    5. Eclipse下SVN应用
    echo print printf() sprintf()区别
    URL 中,查询字符串与HTML实体冲突,可能带来的问题.
    完美解决failed to open stream: HTTP request failed!
    解决xml_parse(): input conversion failed due to input error
  • 原文地址:https://www.cnblogs.com/rongfengliang/p/14375123.html
Copyright © 2011-2022 走看看