@aligov/gov-venom-transformer
Venom DSL code转化为React render。
Example
const { venomToReact, plugin } = require("@aligov/gov-venom-transformer");
// class
const code = `
<div
:class={{active : true, current: false}}
>123</div>
`;
const transedCode = venomToReact(code);
转化后的结果:
// transedCode值:
import React from 'react';
import _ from 'lodash';
export default function () {
return React.createElement('div', {
'className': _.transform({
active: true,
current: false
}, function (res, value, key) {
if (value) {
res.push(key);
}
}, []).join(' ')
}, '123');
}
venom-transformer插件机制
@aligov/gov-venom-transformer
库通过提供可扩展的插件机制,为我们实现venom以及可定制的DSL语法提供了便利。
目前,@aligov/gov-venom-transformer
库的插件机制提供两种能力的可扩展:标签
及标签属性
。
标签属性的插件扩展机制
格式如下:
module.exports = {
type: "prop",
name: /\:class|className/,
func(ctx, { value, node }) {
// console.log("ctx:", ctx, val);
value = value || "";
// 支持表达式范式
if (/^\{\{.+\}\}$/.test(value)) {
value = value.slice(1, -1);
}
// key: 属性名
// value: 该属性所对应的实际代码值
return {
// 如果是定制的样式,需要维持原来的属性名
[isCustomElement(node.name)
? "class"
: "className"
]: classSetTemplate({ classSet: value })
};
}
};
插件最终需要提供一个对象格式,对象里有三个属性:
type
告知transformer库是什么类型的插件,可选值:prop/tag
。
name
表明是对哪个属性的代码转换插件,支持字符串及正则表达式。
func
func需要是一个方法,transformer库会传对应的内部实现参数给到该方法,该方法需要实现对对应标签属性的转化,并返回一个对象,对象名为转化后的属性名字,对象值为转化后的React标签的属性值,字符串属性。
标签的插件扩展机制
格式如下:
import _ from "lodash";
const ifTemplate = _.template("((<%= condition %>)?(<%= body %>):null)");
const ifAttr = `condition`;
module.exports = {
type: "tag",
name: /if/i, // 忽略大小写
func(ctx, {
node,
children,
VenomCodeError
}) {
if(_.startsWith(children, ',')) {
children = children.slice(1);
}
const condStr = node.attribs[ifAttr] || 'false'; // 条件不写默认为false
const data = {
condition: condStr.trim(),
body: children,
};
return ifTemplate(data);
}
};
type
跟name
跟标签属性的说明一致,主要是func有点区别:
- func的参数里会多传一个children过来,代表该标签的children已经被转化成的js代码;
- func方法不再需要返回对象,而是只需要返回被转化后的代码即可。
同时,在实际的插件书写过程中,可能需要用到内部的,用于方便实现上下文的context
的部分机制,比如:
- 如果需要引入一些第三方模块,那么可以使用context的defines属性,该属性是一个数组,只需要将参数组装成有一定格式的对象,然后被push进该数组,最终会生成类似
import {Button} from '@alife/next';
之类的代码; - 如果需要生成一些辅助性的通用函数,且需要借助于render的上下文环境,则需要用到:
context.injectedFunctions
数组,将生成的函数代码字符串push进该数组即可。
TODO
- [x] 1、去this写法支持;
- [x] 2、else/elseif标签支持;
- [x] 3、编译出的代码的lodash引用去掉;
- [x] 4、venom-transformer实现无用代码精简;
- [ ] 5、styled-components支持;