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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2020-02-04 pgspider docker 镜像
2020-02-04 pgspider基于pg 的高性能数据可视化sql 集群引擎
2019-02-04 What is Zeebe?
2019-02-04 pipenv 方便的python 开发工作流工具
2019-02-04 zeebe docker-compose 运行(包含monitor)
2019-02-04 几个微服务编排工具
2016-02-04 Mozilla Brick:一个Web组件Polyfill库