如何基于规则用Go自动生成JavaScript代码?寻求替代Go Template的可行方案
我理解你在尝试用Go Template生成JS规则代码时遇到了复杂度问题——这种嵌套的规则结构(比如AND/OR组合的条件)确实会让模板变得臃肿、难维护。结合我之前做类似需求的经验,给你几个更可行的方案:
1. 模板+自定义函数(最适合快速改造现有项目)
别直接放弃Go Template,但把复杂的表达式生成逻辑从模板移到Go的自定义函数里,模板只负责渲染代码结构。这样模板会非常简洁,所有的规则解析、操作符映射逻辑都在Go代码里处理,更容易调试和扩展。
举个具体实现思路:
首先,定义一个函数把单个条件转成JS表达式:
func conditionToJS(cond Condition) string { // 根据操作符映射成对应的JS语法 switch cond.Operator { case "NOT EQUAL": return fmt.Sprintf("person[%q] !== %q", cond.Field, cond.Value) case "EQUAL": return fmt.Sprintf("person[%q] === %q", cond.Field, cond.Value) // 可扩展支持更多操作符,比如大于、小于、正则匹配等 } }
再定义一个函数处理整个Trigger(AND/OR组合的条件),生成完整的if返回语句:
func triggerToJS(trigger Trigger) string { var conditions []string for _, cond := range trigger.Conditions { conditions = append(conditions, conditionToJS(cond)) } // 默认逻辑运算符为AND,可根据配置切换 operator := "&&" if trigger.Operator == "OR" { operator = "||" } conditionStr := strings.Join(conditions, " "+operator+" ") return fmt.Sprintf("if (%s) { return }", conditionStr) }
然后把这些函数注册到模板中,模板就变得异常简洁:
const jsTpl = `function applyRules(){ {{range .Rules}} {{if .Enabled}} {{triggerToJS .Trigger}} {{end}} } applyRules();` // 注册自定义函数并渲染模板 tpl := template.Must(template.New("js").Funcs(template.FuncMap{ "triggerToJS": triggerToJS, }).Parse(jsTpl))
这种方式既保留了模板的结构清晰性,又把复杂逻辑放在Go代码里处理,比纯模板嵌套好维护太多。
2. 用AST生成JS代码(最严谨,适合复杂规则场景)
如果你的规则未来可能变得非常复杂(比如嵌套多层AND/OR、需要处理运算符优先级),直接拼接字符串容易出语法错误,这时候可以用AST(抽象语法树)来生成JS代码。
Go社区有专门的库可以帮你构建JS的AST并转成代码,比如github.com/yalue/javascript_generator。你可以先把JSON规则解析成Go结构体,然后遍历结构体构建对应的JS AST节点(比如逻辑表达式节点、if语句节点),最后把AST转成标准的JS代码。这种方式能确保生成的JS语法完全正确,不会出现拼接字符串时的引号遗漏、运算符优先级错误等问题。
3. 中间DSL转译(最灵活,适合长期规则扩展)
如果未来需要频繁新增规则类型(比如数值范围判断、数组包含检查),可以先把JSON规则转成一个简单的中间DSL(领域特定语言),再把DSL转成JS代码。
比如,把你的规则转成这样的DSL结构:
type DSLRule struct { Enabled bool Expr interface{} // 可以是单个条件,或者AND/OR组合的嵌套结构 }
然后写一个转译函数,把DSL结构转成对应的JS代码。这种方式相当于在规则和JS之间加了一层抽象,未来要支持新规则时,只需要修改DSL的转译逻辑,不需要动JS生成的核心代码,扩展性极强。
内容的提问来源于stack exchange,提问作者O. San

