Sign in

    moonata

    JSONata rewritten in moonbit.

    Download zip
    Author
    Version
    0.11.0
    License
    Apache-2.0
    Last updated
    3 months ago
    Downloads
    45

    #Moonata

    CI

    Moonata 是 JSONata 的 MoonBit 实现。JSONata 是一门面向 JSON 数据的查询与转换语言。

    本项目目前提供解析器、求值器、内建函数注册表、对外 facade API 与 native CLI。

    #功能

    • JSONata 表达式解析与求值。
    • 路径遍历、谓词、通配符、递归下降、变量、块表达式、Lambda、部分应用与函数链。
    • 对象、数组、字符串、数值、布尔、日期时间、正则与高阶内建函数。
    • Facade API:evaluate(expr, data) 与 compile(expr).run(data)。
    • Embedding & Extending(对齐 官方文档):evaluate_with_bindings、evaluate_with_options、Compiled::assign、Compiled::register_function(支持 JSONata 签名语法 <nn:n> 等)。
    • Guardrails(对齐 官方文档):EvalOptions 携带 stack / timeout / sequence 选项,超限分别抛 D1011 / D1012 / D2015;旧路径保持 U1001 向后兼容。
    • Native CLI,支持 --data、--file、--expr-file、--max-depth、--stack、--timeout、--sequence 输入模式。

    #CLI

    构建 native 命令:

    moon build cmd/main --target native

    对 JSON 文件运行表达式:

    moon run --target native cmd/main '$sum(Account.Order.Product.(Price * Quantity))' --file cmd/main/test.json _build/native/debug/build/cmd/main/main.exe '$sum(Account.Order.Product.(Price * Quantity))' --file cmd/main/test.json

    针对 cmd/main/test.json 的示例表达式:

    Account.'Account Name' -> "Firefly" $sum(Account.Order.Product.(Price * Quantity)) -> 336.36

    #库 API

    在 MoonBit 代码中调用时,使用根包 facade:

    ///|
    let data = @json.parse("{\"items\":[{\"price\":10},{\"price\":20}]}")

    ///|
    let result = @moonata.evaluate("$sum(items.price)", data)

    需要重复求值时,可先编译一次:

    ///|
    let expr = @moonata.compile("$sum(items.price)")

    ///|
    let result = expr.run(data)

    Embedding & Extending(对齐 JSONata 官方文档):

    ///|
    // 注册自定义函数(含 JSONata 签名)
    let expr = @moonata.compile("$add(61, 10005)")
    expr.register_function("add", arity=2, signature=Some("<nn:n>"), invoke=fn(args, _ctx) {
    match args[0] {
    Json::Number(a, ..) =>
    match args[1] {
    Json::Number(b, ..) => Json::number(a + b)
    _ => Json::null()
    }
    _ => Json::null()
    }
    })

    ///|
    let result = expr.run(Json::null()) // 10066

    Guardrails(对齐 JSONata 官方文档):

    ///|
    let options = @moonata.EvalOptions::new(
    stack=Some(500), // 最大递归深度,超限抛 D1011
    timeout=Some(1000), // 最大执行时间毫秒,超限抛 D1012
    sequence=Some(1_000_000), // 最大序列长度,超限抛 D2015
    )

    ///|
    let result = @moonata.evaluate_with_options("$sum(items.price)", data, options)

    上述 API 会在语法、运行时、类型、签名与护栏错误时抛出 JsonataError。

    #开发

    常用验证命令:

    moon check moon test moon fmt moon info

    提交代码变更前,应运行完整本地门禁,并检查生成的 .mbti diff 是否符合预期。提交信息使用 Conventional Commit 风格,例如:

    feat(functions): add basic formatNumber support fix(evaluator): align predicate context semantics docs: update official test status

    #CI

    仓库使用 GitHub Actions 执行以下门禁:

    • moon check --deny-warn:类型检查、语法检查,警告视为错误
    • moon fmt --check:格式校验
    • moon info:接口生成
    • moon build --deny-warn:构建,警告视为错误
    • moon test --deny-warn:测试执行,警告视为错误

    #兼容性状态

    固定快照:2026-07-15,CLI 参数解析移入 cmd/main 包阶段。

    本地测试:moon test 321/321 官方可比对审计:eligible 1682, pass 1682, fail 0, skip 0 通过率:100%

    Top failures: 无

    官方测试集审计流程与跳过策略记录在 docs/jsonata-official-workflow.md。

    Ast

    using @rinnein/moonata/ast { type Ast }

    JSONata AST 节点:单一 enum + 标签字段。

    所有节点统一为 Ast enum,子结构 Step/SortTerm 独立定义。 路径访问统一用 Path(Array[Step]) 表示,Step 携带 StepKind 与 StepStage。

    EvalContext

    求值上下文:持有根数据、绑定表与递归/步数/序列护栏。

    • root:$ 根数据(不可变,JSONata 中 $ 始终指原始根)。
    • bindings:变量绑定表(含内建函数),Map 本身可变,字段无需 mut。
    • depth/max_depth:递归深度护栏。
    • steps/max_steps:求值步数护栏。
    • max_sequence:序列长度护栏(-1 不限制),对齐 JSONata guardrails sequence 选项。
    • depth_exceeded_code/steps_exceeded_code/sequence_exceeded_code: 护栏超限时抛出的错误码。默认 U1001/U1001/D2015, 通过 EvalOptions::stack/timeout/sequence 启用时改用 D1011/D1012/D2015 对齐 JSONata 官方文档(U1001 仅用于 jsonata-js test runner 的 timeboxExpression 兼容路径)。
    • current:@ 当前项(谓词过滤/路径迭代时绑定)。
    • parent:$$ 父级上下文。
    • ancestors:当前项的父级链,首项为 %,后续项支持 %.%。

    JsonataError

    再导出关键类型

    Compiled

    pub(all) struct Compiled {
    ast :
    Ast

    assigned_bindings : Map[String,
    JsonataValue
    ]
    }

    已编译的 JSONata 表达式。

    对齐 JSONata embedding-extending 文档中编译表达式对象:
    • run(data) 对应 expression.evaluate(input)
    • run_with_options(data, options) 对应 jsonata(str, options).evaluate(input)
    • assign(name, value) 对应 expression.assign(name, value)
    • register_function(name, impl, signature) 对应 expression.registerFunction(name, impl, signature)

    Compiled::assign

    fn Compiled::assign(self : Compiled, name : String, value : Json) -> Unit

    永久绑定一个值到表达式(对齐 expression.assign(name, value))。

    后续 run / run_with_options / run_with_bindings 调用都会携带此绑定, 直至再次 assign 同名变量覆盖。run_with_bindings 传入的同名绑定会临时覆盖 (仅在本次调用内),对齐 JSONata 文档 "the bindings argument in the expression.evaluate() call clobbers these values"。

    Compiled::register_function

    fn Compiled::register_function(self : Compiled, name : String, arity~ : Int, signature~ : String?, invoke~ : (Array[Json],
    EvalContext
    ) -> Json raise
    JsonataError
    ) -> Unit

    永久绑定一个函数到表达式(对齐 expression.registerFunction(name, impl, signature))。

    与 assign 不同,register_function 接收一个 MoonBit 闭包作为函数实现, 并可选指定 JSONata 签名字符串(如 <nn:n>)用于运行时参数类型校验。 签名语法参见 docs/jsonata-official-workflow.md 与 JSONata 官方文档 embedding-extending 章节。

    闭包接收 Array[Json](已转换自 JsonataValue,便于宿主侧处理)和 EvalContext (仅在使用 @/$$ 等上下文访问器时需要),返回 Json 结果。Moonata 内部会将 返回的 Json 包装为 JsonataValue::Json。

    Compiled::run

    对已编译表达式求值。

    Compiled::run_with_bindings

    fn Compiled::run_with_bindings(self : Compiled, data : Json, bindings : Map[String, Json]) -> Json raise
    JsonataError

    对已编译表达式求值(应用变量绑定)。

    Compiled::run_with_options

    fn Compiled::run_with_options(self : Compiled, data : Json, options : EvalOptions) -> Json raise
    JsonataError

    对已编译表达式求值(应用 guardrails 选项)。

    EvalOptions

    pub struct EvalOptions {
    stack : Int?
    timeout : Int?
    sequence : Int?
    max_steps : Int?
    } derive(Eq)

    Guardrails 选项(对齐 JSONata guardrails 文档)。

    • stack:最大递归深度,超限抛 D1011。None 时使用默认 max_depth=8000 + U1001 语义。
    • timeout:最大执行时间(毫秒),超限抛 D1012。None 时不启用超时护栏。 MoonBit 当前无原生 wall-clock 超时支持,使用 timeout_ms * 1000 作为 max_steps 上限近似。
    • sequence:最大序列长度,超限抛 D2015。None 或 <= 0 时不限制。
    • max_steps:直接指定最大步数(扩展选项,超限抛 D1012)。优先于 timeout 换算值。

    EvalOptions::build_context

    根据选项构造 EvalContext,应用对应的护栏阈值与错误码。

    • stack 为 Some(n) 且 n > 0 时:max_depth = n,depth_exceeded_code = "D1011"
    • timeout 为 Some(ms) 且 ms > 0 时:max_steps = ms * 1000,steps_exceeded_code = "D1012"
    • max_steps 为 Some(n) 且 n > 0 时:覆盖 timeout 换算值
    • sequence 为 Some(n) 且 n > 0 时:max_sequence = n,sequence_exceeded_code = "D2015"
    • 其余情况使用默认值,错误码保持 U1001(向后兼容 jsonata-js test runner)

    EvalOptions::default

    fn EvalOptions::default() -> EvalOptions

    默认 guardrails 选项(不启用任何护栏,沿用 legacy U1001 语义)。

    EvalOptions::new

    fn EvalOptions::new(stack? : Int?, timeout? : Int?, sequence? : Int?, max_steps? : Int?) -> EvalOptions

    构造 guardrails 选项。

    compile

    编译 JSONata 表达式为可重复求值的 Compiled。

    evaluate

    fn evaluate(expr : String, data : Json) -> Json raise
    JsonataError

    JSONata 表达式求值。

    解析并求值 JSONata 表达式,返回 JSON 结果。

    evaluate_undefined

    fn evaluate_undefined(expr : String) -> Json raise
    JsonataError

    JSONata 表达式求值(undefined 上下文)。

    与 evaluate 相同,但使用 Undefined 作为根上下文, 对齐 jsonata-js test runner 中 dataset: null → undefined 的语义。

    evaluate_undefined_with_max_depth

    fn evaluate_undefined_with_max_depth(expr : String, max_depth : Int) -> Json raise
    JsonataError

    JSONata 表达式求值(undefined 上下文,指定 max_depth)。

    evaluate_undefined_with_options

    fn evaluate_undefined_with_options(expr : String, options : EvalOptions) -> Json raise
    JsonataError

    JSONata 表达式求值(undefined 上下文 + guardrails 选项)。

    evaluate_with_bindings

    fn evaluate_with_bindings(expr : String, data : Json, bindings : Map[String, Json]) -> Json raise
    JsonataError

    JSONata 表达式求值(应用变量绑定)。

    对齐 JSONata embedding-extending 文档 expression.evaluate(input, bindings): bindings 中的变量名(含函数)在求值期间绑定到上下文,覆盖同名内建函数。 值为 Json 类型,函数值以 Json::null 占位(如需注册函数用 Compiled::register_function)。

    evaluate_with_max_depth

    fn evaluate_with_max_depth(expr : String, data : Json, max_depth : Int) -> Json raise
    JsonataError

    JSONata 表达式求值(指定 max_depth)。

    用于官方审计脚本传递 case 文件中的 depth 字段,对齐 jsonata-js test runner 的 timeboxExpression 语义。tail-recursion/case002 期望 maxDepth=302 触发 U1001。

    evaluate_with_options

    fn evaluate_with_options(expr : String, data : Json, options : EvalOptions) -> Json raise
    JsonataError

    JSONata 表达式求值(应用 guardrails 选项)。

    对齐 JSONata embedding-extending 文档 jsonata(str, options) 与 guardrails 文档:options 携带 stack / timeout / sequence 护栏, 分别限制递归深度(D1011)、求值步数(D1012,由 timeout 毫秒映射为步数上限)、 序列长度(D2015)。

    • stack:>0 时启用,超限抛 D1011;未设置(None)时使用默认 max_depth=8000 与 U1001 语义。
    • timeout:>0 时启用,超限抛 D1012;当前 MoonBit 无原生 wall-clock 超时支持, 使用 timeout_ms * 1000 作为 max_steps 近似上限(每步约 1μs 量级)。
    • sequence:>0 时启用,超限抛 D2015。

    Source Files