@choiceform/expression-engine
高性能、安全的前端表达式引擎。专为现代前端应用设计,提供实时表达式求值、模板解析和数据处理能力。
🎮 在线体验
立即体验表达式引擎的强大功能!
🔗 Expression Engine Playground
- 🎯 交互式测试环境 - 实时编辑和验证表达式
- 📚 完整文档中心 - 详细的使用指南和API参考
- 🎨 智能代码补全 - 基于AST的上下文感知自动补全
- 🛡️ 实时安全验证 - 五层验证体系保障表达式安全
- 🌙 深色/浅色主题 - 舒适的开发体验
🚀 快速开始体验
// 在 Playground 中试试这些表达式: // 基础数学计算 {{ 1 + 2 * 3 }} // 输出: 7 // 字符串处理 {{ "Hello " + $json.name }} // 动态文本生成 // 条件判断 {{ $json.age >= 18 ? "成年" : "未成年" }} // 日期时间 {{ $now.toFormat("yyyy-MM-dd") }} // 当前日期 // 数据查询 {{ $json.users[?age > 25].name }} // JMESPath 查询
✨ 核心特性
🚀 高性能
- 零依赖核心:轻量级架构,快速启动
- 智能缓存:表达式解析结果缓存,避免重复计算
- 惰性求值:按需解析和执行表达式
🔒 安全可靠
- 🛡️ 五层验证体系:语法、语义、安全、性能、业务全方位验证
- 🔍 智能安全检测:自动识别危险代码、原型污染、代码注入等威胁
- ⚡ 资源限制保护:防止资源耗尽和无限循环攻击
- 🎯 沙箱执行环境:安全隔离的表达式运行空间
- 📊 实时监控:详细的验证结果和性能指标
🎯 完全兼容
- n8n 语法:100% 兼容 n8n 工作流表达式
- 内置变量:支持
$json、$node、$vars等所有 n8n 变量 - 内置函数:完整的 n8n 函数库支持
- JMESPath:原生支持 JMESPath 查询语法
🛠 开发友好
- TypeScript 原生支持:完整的类型定义
- AST 输出支持:结构化语法树,支持静态分析和代码生成
- 模块化设计:可按需引入功能模块
- 丰富的 API:灵活的配置和扩展接口
- 详细错误信息:精确的错误定位和提示
📦 安装
# 使用 pnpm (推荐) pnpm add @choiceform/expression-engine # 使用 npm npm install @choiceform/expression-engine # 使用 yarn yarn add @choiceform/expression-engine
🚀 快速开始
基础使用
import { ExpressionEngine, ContextManager } from "@choiceform/expression-engine" // 创建引擎实例 const engine = new ExpressionEngine() const contextManager = new ContextManager() // 创建运行时上下文 const context = contextManager.createRuntimeContext({ // 用户数据 json: { name: "Alice", age: 30 }, // 工作流变量 vars: { threshold: 100 }, // 节点数据 node: { id: "node1", type: "transform" }, }) // 执行表达式 const result = engine.evaluate("Hello {{ $json.name }}!", context) console.log(result.value) // "Hello Alice!"
数学计算
// 基础数学运算 engine.evaluate("{{ 1 + 2 * 3 }}", context) // 7 engine.evaluate("{{ Math.pow(2, 3) }}", context) // 8 engine.evaluate("{{ Math.round(3.14159, 2) }}", context) // 3.14 // 条件表达式 engine.evaluate('{{ $json.age >= 18 ? "成年" : "未成年" }}', context) // "成年"
字符串处理
// 字符串操作 engine.evaluate("{{ $json.name.toUpperCase() }}", context) // "ALICE" engine.evaluate('{{ "Hello World".split(" ")[1] }}', context) // "World" engine.evaluate("{{ $json.name.length > 3 }}", context) // true
日期时间处理
// Luxon DateTime 支持 engine.evaluate('{{ $now.toFormat("yyyy-MM-dd") }}', context) // "2024-01-15" engine.evaluate("{{ $now.plus({days: 7}).toISO() }}", context) // ISO 日期字符串 engine.evaluate("{{ $today.weekday }}", context) // 星期几 (1-7)
内置函数
// 条件函数 engine.evaluate('{{ $if($json.age >= 18, "adult", "minor") }}', context) // 数组操作 const arrayContext = contextManager.createRuntimeContext({ json: { items: [1, 2, 3, 4, 5] }, }) engine.evaluate("{{ $json.items.length }}", arrayContext) // 5 engine.evaluate("{{ $json.items[0] }}", arrayContext) // 1 // 字符串函数 engine.evaluate("{{ $length($json.name) }}", context) // 5 engine.evaluate('{{ $split("a,b,c", ",") }}', context) // ["a", "b", "c"]
JMESPath 查询
const complexData = { users: [ { name: "Alice", age: 30, city: "Beijing" }, { name: "Bob", age: 25, city: "Shanghai" }, { name: "Charlie", age: 35, city: "Guangzhou" }, ], } const complexContext = contextManager.createRuntimeContext({ json: complexData }) // 复杂数据查询 engine.evaluate("{{ $json.users[?age > `30`].name }}", complexContext) // ["Charlie"] engine.evaluate("{{ $json.users[*].city }}", complexContext) // ["Beijing", "Shanghai", "Guangzhou"]
🛡️ 表达式验证系统
强大的五层验证体系,确保表达式的安全性和可靠性:
import { ValidationManager } from "@choiceform/expression-engine" const validator = new ValidationManager({ layers: { syntax: true, // 语法验证 semantic: true, // 语义验证 security: true, // 安全检查 performance: true, // 性能监控 business: false, // 业务规则 }, }) // 验证表达式 const result = validator.validate("{{ $json.name.toUpperCase() }}") if (result.isValid) { console.log("✅ 表达式安全有效") } else { console.log("❌ 发现问题:") result.errors.forEach((error) => { console.log(` ${error.layer}: ${error.message}`) }) }
🔍 安全威胁检测
自动识别和阻止各种安全威胁:
// 🚨 危险代码检测 validator.validate('{{ eval("malicious") }}') // ❌ 阻止 eval 函数 validator.validate("{{ __proto__.constructor }}") // ❌ 阻止原型污染 validator.validate('{{ Function("return process") }}') // ❌ 阻止 Function 构造器 // ⚠️ 可疑模式警告 validator.validate("{{ setTimeout(code, 100) }}") // ⚠️ 定时器函数警告 validator.validate('{{ "SELECT * FROM users" }}') // ⚠️ SQL 注入模式警告 validator.validate("{{ counter++ }}") // ⚠️ 副作用操作警告 // ✅ 安全表达式 validator.validate("{{ Math.max(1, 2, 3) }}") // ✅ 数学函数安全 validator.validate("{{ $json.items.length }}") // ✅ 属性访问安全
📊 性能和资源监控
防止资源耗尽和性能问题:
const config = { performanceThresholds: { maxComplexity: 100, // 最大复杂度 maxDepth: 10, // 最大嵌套深度 maxLength: 1000, // 最大表达式长度 maxFunctionCalls: 50, // 最大函数调用数 }, } // 复杂度检查 validator.validate("{{ very.deep.nested.object.access }}", config) // ⚠️ 警告:嵌套层次过深 // 表达式长度检查 validator.validate("{{ " + "long".repeat(500) + " }}", config) // ❌ 错误:表达式过长 // 函数调用限制 validator.validate("{{ func1().func2().func3()...[50次] }}", config) // ❌ 错误:函数调用过多
🌳 AST 输出功能
// 切换到AST输出模式 engine.setOutputFormat("ast") // 获取表达式的AST结构 const astResult = engine.evaluate("Hello {{ $json.name }}!", context) console.log(astResult.ast.type) // "Template" console.log(astResult.ast.dependencies) // ["$json"] console.log(astResult.ast.complexity) // 4 // 直接生成AST(不求值) const ast = engine.generateAST('{{ $json.age > 18 ? "成年" : "未成年" }}') console.log(ast.type) // "Template" console.log(ast.dependencies) // ["$json"] // 静态分析 function analyzeExpression(template: string) { const ast = engine.generateAST(template) if (ast.type === "Template") { return { dependencies: ast.dependencies, // 依赖的变量 complexity: ast.complexity, // 复杂度评分 componentCount: ast.parts.length, // 组件数量 } } } const analysis = analyzeExpression("{{ $json.user.name }} 在 {{ $json.user.city }} 工作") console.log(analysis) // { // dependencies: ['$json'], // complexity: 8, // componentCount: 5 // } // 字符串模式 + AST元数据 const engineWithMetadata = new ExpressionEngine({ output: { format: "string", includeMetadata: true }, }) const result = engineWithMetadata.evaluate("{{ $json.name }}", context) console.log("字符串结果:", result.value) // "Alice" console.log("AST结构:", result.ast) // AST对象
🔧 API 参考
ExpressionEngine
主引擎类,提供表达式解析和求值功能。
构造函数
new ExpressionEngine(config?: EngineConfig)
主要方法
evaluate(expression: string, context: ExpressionContext): EvaluationResult
执行表达式并返回结果。
const result = engine.evaluate("{{ 1 + 1 }}", context) if (result.success) { console.log("结果:", result.value) console.log("类型:", result.type) console.log("执行时间:", result.executionTime) } else { console.error("错误:", result.error.message) console.error("位置:", result.error.position) }
parse(template: string): ParsedTemplate
解析模板字符串,提取表达式和静态部分。
const parsed = engine.parse("Hello {{ $json.name }}!") console.log("是否为模板:", parsed.isTemplate) console.log("表达式数量:", parsed.expressions.length) console.log("依赖变量:", parsed.dependencies)
validate(expression: string): ValidationResult
验证表达式语法。
const validation = engine.validate("{{ $json.invalidSyntax... }}") if (!validation.isValid) { console.log("语法错误:", validation.errors) console.log("警告信息:", validation.warnings) }
setOutputFormat(format: 'string' | 'ast'): void
设置输出格式。
// 设置为字符串输出(默认) engine.setOutputFormat("string") // 设置为AST输出 engine.setOutputFormat("ast") // 获取当前输出格式 console.log(engine.getOutputFormat()) // 'ast'
generateAST(template: string): ASTNode
直接生成AST结构,不执行求值。
const ast = engine.generateAST("{{ $json.user.name }} ({{ $json.user.age }}岁)") if (ast.type === "Template") { console.log("依赖变量:", ast.dependencies) // ['$json'] console.log("复杂度:", ast.complexity) // 8 console.log("组件数量:", ast.parts.length) // 5 // 遍历AST组件 ast.parts.forEach((part, index) => { if (part.type === "TemplateText") { console.log(`${index}: 静态文本 "${part.value}"`) } else { console.log(`${index}: 表达式 ${part.value.type}`) } }) }
getASTMetadata(): ASTMetadata
获取AST生成器的元数据信息。
const metadata = engine.getASTMetadata() console.log("版本:", metadata.version) // "1.0.0" console.log("源类型:", metadata.sourceType) // "expression" console.log("生成时间:", metadata.generated) // Date对象
ContextManager
上下文管理器,负责创建和管理表达式执行环境。
const contextManager = new ContextManager() // 创建基础上下文 const context = contextManager.createRuntimeContext({ json: { /* 当前数据 */ }, vars: { /* 工作流变量 */ }, node: { /* 节点信息 */ }, workflow: { /* 工作流信息 */ }, execution: { /* 执行信息 */ }, }) // 添加自定义函数 contextManager.addFunction("customFunc", (arg1, arg2) => { return arg1 + arg2 }) // 添加自定义变量 contextManager.addVariable("$custom", { value: "custom data" })
🛡️ ValidationManager
表达式验证管理器,提供五层验证体系的完整验证功能。
构造函数
new ValidationManager(config?: ValidationConfig)
主要方法
validate(expression: string, config?: ValidationConfig): ValidationResult
验证表达式的安全性、正确性和性能。
const validator = new ValidationManager() const result = validator.validate("{{ $json.name.toUpperCase() }}", { layers: { syntax: true, // 语法验证 semantic: true, // 语义验证 security: true, // 安全检查 performance: true, // 性能监控 business: false, // 业务规则 }, }) if (result.isValid) { console.log("✅ 验证通过") } else { result.errors.forEach((error) => { console.log(`❌ ${error.layer}: ${error.message}`) }) } // 检查警告 result.warnings.forEach((warning) => { console.log(`⚠️ ${warning.layer}: ${warning.message}`) })
addValidator(validator: BaseValidator): void
添加自定义验证器。
import { BaseValidator } from "@choiceform/expression-engine" class CustomValidator extends BaseValidator { readonly name = "Custom" readonly layer = "business" as const validate(context: ValidationContext): ValidationResult { // 自定义验证逻辑 return { isValid: true, errors: [], warnings: [], } } } validator.addValidator(new CustomValidator())
removeValidator(name: string): void
移除指定的验证器。
validator.removeValidator("Custom")
getValidators(): BaseValidator[]
获取所有已注册的验证器列表。
const validators = validator.getValidators() console.log(validators.map((v) => v.name)) // ['JavaScriptSyntax', 'TemplateSyntax', ...]
ValidationResult 结构
interface ValidationResult { isValid: boolean // 整体验证是否通过 errors: ValidationError[] // 错误列表 warnings: ValidationWarning[] // 警告列表 metadata: { totalChecks: number // 总检查数 executionTime: number // 验证耗时 (ms) layers: string[] // 执行的验证层 } } interface ValidationError { code: string // 错误代码 message: string // 错误消息 layer: string // 所属验证层 severity: "error" // 严重程度 position?: { // 错误位置 start: number end: number line: number column: number } suggestions?: string[] // 修复建议 }
验证配置选项
interface ValidationConfig { // 验证层配置 layers: { syntax?: boolean // 语法验证 semantic?: boolean // 语义验证 security?: boolean // 安全检查 performance?: boolean // 性能监控 business?: boolean // 业务规则 } // 错误处理配置 maxErrors?: number // 最大错误数量 (-1 = 无限制) strict?: boolean // 严格模式 (warnings 也作为错误) // 性能阈值配置 performanceThresholds?: { maxComplexity?: number // 最大复杂度 maxDepth?: number // 最大嵌套深度 maxLength?: number // 最大表达式长度 maxFunctionCalls?: number // 最大函数调用数 maxMemoryUsage?: number // 最大内存使用 (KB) maxLoops?: number // 最大循环次数 } // 安全配置 security?: { allowedGlobals?: string[] // 允许的全局对象 bannedKeywords?: string[] // 禁用的关键字 maxStringLength?: number // 最大字符串长度 allowPrototypeAccess?: boolean // 是否允许原型访问 } }
预设配置
// 开发环境配置(宽松) const developmentConfig: ValidationConfig = { layers: { syntax: true }, strict: false, maxErrors: -1, } // 生产环境配置(严格) const productionConfig: ValidationConfig = { layers: { syntax: true, semantic: true, security: true, performance: true }, strict: true, maxErrors: 5, performanceThresholds: { maxComplexity: 50, maxDepth: 5, maxLength: 500, }, } // 高安全配置(最严格) const highSecurityConfig: ValidationConfig = { layers: { syntax: true, semantic: true, security: true, performance: true, business: true }, strict: true, maxErrors: 1, performanceThresholds: { maxComplexity: 30, maxDepth: 3, maxLength: 200, }, security: { allowedGlobals: [], bannedKeywords: ["eval", "Function", "setTimeout", "setInterval"], allowPrototypeAccess: false, }, } // 使用预设配置 const result = validator.validate(expression, productionConfig)
配置选项
interface EngineConfig { // 安全配置 security?: { maxExecutionTime?: number // 最大执行时间 (ms) maxMemoryUsage?: number // 最大内存使用 (bytes) allowedGlobals?: string[] // 允许的全局变量 bannedKeywords?: string[] // 禁用的关键字 } // 输出配置 output?: { format?: "string" | "ast" // 输出格式:字符串或AST includeMetadata?: boolean // 字符串模式下是否包含AST元数据 } // 性能配置 performance?: { enableCache?: boolean // 启用表达式缓存 cacheSize?: number // 缓存大小 enableOptimization?: boolean // 启用优化 } // 功能配置 features?: { enableJMESPath?: boolean // 启用 JMESPath 支持 enableDateTime?: boolean // 启用日期时间函数 enableBuiltins?: boolean // 启用内置函数 } }
🧪 内置函数库
条件函数
$if(condition, trueValue, falseValue)- 条件判断$switch(value, case1, result1, case2, result2, ..., defaultResult)- 多条件判断
字符串函数
$length(string)- 获取字符串长度$split(string, delimiter)- 分割字符串$join(array, delimiter)- 连接数组元素$trim(string)- 去除首尾空格$replace(string, search, replace)- 替换字符串
数组函数
$first(array)- 获取第一个元素$last(array)- 获取最后一个元素$slice(array, start, end)- 数组切片$filter(array, expression)- 过滤数组$map(array, expression)- 映射数组
数学函数
$abs(number)- 绝对值$ceil(number)- 向上取整$floor(number)- 向下取整$round(number, precision)- 四舍五入
日期时间函数
$now()- 当前时间 (Luxon DateTime)$today()- 今天日期$formatDate(date, format)- 格式化日期$addDays(date, days)- 添加天数
📊 测试覆盖
本项目拥有完整的测试覆盖,包含 16 个测试套件,265 个测试用例,覆盖率 100%:
核心功能测试
- ✅ 基础功能测试 (15/15) - 数学运算、逻辑判断、字符串处理
- ✅ n8n 变量兼容性 (14/14) - 所有 n8n 内置变量支持
- ✅ 内置函数库 (17/17) - 完整的函数库测试
- ✅ Luxon 日期时间 (20/20) - 日期时间处理能力
- ✅ JMESPath 查询 (9/9) - 复杂数据查询支持
错误处理与性能
- ✅ 错误处理 (20/20) - 全面的错误处理机制
- ✅ 性能与安全 (8/8) - 性能优化和安全防护
- ✅ 集成测试 (9/9) - 真实场景测试
- ✅ 压力测试 (7/7) - 极限条件测试
高级功能测试
- ✅ AST 输出功能 (16/16) - AST生成、分析和应用场景测试
- ✅ 极限AST测试 (15/15) - AST系统的极限挑战和边界测试
- ✅ 代码补全 (23/23) - 智能代码补全功能测试
🛡️ 验证系统测试
- ✅ 安全验证器 (26/26) - 危险代码检测、原型污染防护、代码注入阻断
- ✅ 语法验证器 (32/32) - JavaScript语法检查、模板语法验证、结构完整性
- ✅ 语义安全验证 (20/20) - 变量依赖、函数参数、类型兼容性检查
- ✅ 基础验证器 (14/14) - 验证系统核心功能测试
# 运行测试 pnpm test # 生成覆盖率报告 pnpm test:coverage # 运行验证系统测试 pnpm test tests/*validator*.test.ts
🏗 开发指南
环境要求
- Node.js >= 18.0.0
- pnpm >= 8.0.0
- TypeScript >= 5.4.0
开发环境设置
# 克隆仓库 git clone https://github.com/automation/expression-engine.git cd expression-engine/packages/expression-engine # 安装依赖 pnpm install # 开发模式构建 pnpm dev # 运行测试 pnpm test # 类型检查 pnpm typecheck # 代码格式化 pnpm lint:fix
项目结构
src/
├── engine.ts # 主引擎类
├── index.ts # 导出接口
├── config/ # 配置文件
├── context/ # 上下文管理
├── evaluator/ # 表达式求值器
├── libraries/ # 内置函数库
├── parser/ # 模板解析器
├── security/ # 安全沙箱
├── types/ # TypeScript 类型定义
└── utils/ # 工具函数
tests/ # 测试文件
docs/ # 文档
构建
# 构建生产版本 pnpm build # 监听模式构建 pnpm build:watch # 清理构建文件 pnpm clean
🤝 贡献指南
我们欢迎任何形式的贡献!请查看 CONTRIBUTING.md 了解详细信息。
提交流程
- Fork 本仓库
- 创建功能分支 (
git checkout -b feature/amazing-feature) - 提交更改 (
git commit -m 'Add some amazing feature') - 推送到分支 (
git push origin feature/amazing-feature) - 打开 Pull Request
开发规范
- 使用 TypeScript 编写代码
- 遵循 ESLint 规则
- 为新功能添加测试
- 更新相关文档
🎨 AST 应用场景
AST(抽象语法树)输出功能为表达式引擎开启了无限可能,特别适用于以下场景:
🔍 静态代码分析
// 依赖分析 - 检查表达式使用了哪些变量 const dependencies = engine.generateAST(template).dependencies if (!dependencies.every((dep) => availableVars.includes(dep))) { console.warn("表达式包含未定义的变量") } // 复杂度评估 - 识别过于复杂的表达式 const complexity = engine.generateAST(template).complexity if (complexity > 10) { console.warn("表达式过于复杂,建议简化") }
🎨 可视化编程
// 将AST转换为可视化编辑器的节点 function createVisualNodes(template: string) { const ast = engine.generateAST(template) return ast.parts.map((part) => ({ id: generateId(), type: part.type === "TemplateText" ? "text" : "expression", content: part.type === "TemplateText" ? part.value : "{{...}}", editable: part.type === "TemplateExpression", })) }
🔄 代码转换
// 将n8n表达式转换为其他语言 function convertToJavaScript(template: string): string { const ast = engine.generateAST(template) return ast.parts .map((part) => { if (part.type === "TemplateText") { return `"${part.value}"` } else { return part.value.raw?.replace(/\$json/g, "data") || "" } }) .join(" + ") } // n8n: "Hello {{ $json.name }}!" // JavaScript: "Hello " + data.name + "!"
🚀 智能IDE插件
// 代码补全 function getCompletions(template: string, position: number) { const ast = engine.generateAST(template) const context = findNodeAtPosition(ast, position) if (context?.type === "MemberExpression") { return getObjectProperties(context.object) } return getGlobalVariables() } // 语法高亮 function getSyntaxHighlighting(template: string) { const ast = engine.generateAST(template) return ast.parts.map((part) => ({ range: [part.start, part.end], type: part.type === "TemplateText" ? "string" : "expression", })) }
📋 模板优化
// 自动优化表达式 function optimizeTemplate(template: string): string { const ast = engine.generateAST(template) // 合并相邻的静态文本 const optimized = mergeAdjacentText(ast) // 简化常量表达式 const simplified = simplifyConstants(optimized) return reconstructTemplate(simplified) }
更多AST功能详情请查看:AST使用指南
📄 许可证
本项目采用 MIT 许可证。
🔗 相关链接
📞 技术支持
如果您在使用过程中遇到问题或有任何建议,请: