chore: add benchmarks (#459)

* chore: add benchmarks for tier 1 languages

* improve fixtures

* fix cargo fmt
This commit is contained in:
stefan-gorules
2026-06-25 13:38:33 +02:00
committed by GitHub
parent fc9ab1269f
commit a4cafd0346
24 changed files with 5923 additions and 53 deletions
+124
View File
@@ -0,0 +1,124 @@
name: Benchmark
on:
release:
types: [ published ]
workflow_dispatch:
permissions:
contents: write
pull-requests: write
env:
BENCH_ITERS: '500'
jobs:
rust:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust
run: rustup update stable
- uses: ./.github/actions/setup-rust
with:
shared-key: benchmark-rust
sccache: 'false'
- name: Build
run: cargo build --release -p zen-benchmark
- name: Run
run: ./target/release/zen-benchmark benchmark/manifest.json "$GITHUB_WORKSPACE/bench-rust.json"
- uses: actions/upload-artifact@v4
with:
name: bench-rust
path: bench-rust.json
if-no-files-found: error
node:
runs-on: ubuntu-latest
defaults:
run:
working-directory: bindings/nodejs
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 22
cache: yarn
cache-dependency-path: 'bindings/nodejs/yarn.lock'
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: x86_64-unknown-linux-gnu
- uses: ./.github/actions/setup-rust
with:
shared-key: benchmark-node
sccache: 'false'
- run: yarn install --immutable --mode=skip-build
- run: yarn build
- name: Run
working-directory: ${{ github.workspace }}
run: node benchmark/node/bench.mjs "$GITHUB_WORKSPACE/bench-node.json"
- uses: actions/upload-artifact@v4
with:
name: bench-node
path: bench-node.json
if-no-files-found: error
python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.13'
- name: Install Rust
run: rustup update stable
- uses: ./.github/actions/setup-rust
with:
shared-key: benchmark-python
sccache: 'false'
- run: pip install maturin
- name: Build + install wheel
run: |
maturin build --release --out dist -m bindings/python/Cargo.toml
pip install dist/*.whl
- name: Run
run: python benchmark/python/bench.py "$GITHUB_WORKSPACE/bench-python.json"
- uses: actions/upload-artifact@v4
with:
name: bench-python
path: bench-python.json
if-no-files-found: error
publish:
runs-on: ubuntu-latest
needs: [ rust, node, python ]
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v4
with:
path: results
merge-multiple: true
- name: Merge results
run: |
node -e '
const fs = require("fs");
const out = [];
for (const lang of ["rust", "node", "python"]) {
const r = JSON.parse(fs.readFileSync(`results/bench-${lang}.json`, "utf8"));
for (const e of r) out.push({ ...e, name: `${lang} · ${e.name}` });
}
fs.writeFileSync("bench-all.json", JSON.stringify(out, null, 2));
'
- name: Store + publish
uses: benchmark-action/github-action-benchmark@v1
with:
name: ZEN cross-language
tool: customSmallerIsBetter
output-file-path: bench-all.json
github-token: ${{ secrets.GITHUB_TOKEN }}
auto-push: true
alert-threshold: '150%'
comment-on-alert: true
fail-on-alert: false
Generated
+11
View File
@@ -4933,6 +4933,17 @@ dependencies = [
"synstructure",
]
[[package]]
name = "zen-benchmark"
version = "0.0.0"
dependencies = [
"serde",
"serde_json",
"tokio",
"zen-engine",
"zen-expression",
]
[[package]]
name = "zen-engine"
version = "0.55.1"
+2 -1
View File
@@ -2,7 +2,8 @@
resolver = "2"
members = [
"core/*",
"bindings/*"
"bindings/*",
"benchmark/rust"
]
[workspace.dependencies]
+2
View File
@@ -0,0 +1,2 @@
.venv/
.dist/
+41
View File
@@ -0,0 +1,41 @@
BENCH_ITERS ?= 500
export BENCH_ITERS
ROOT := $(CURDIR)/..
VENV := $(CURDIR)/.venv
PY := $(VENV)/bin/python
BIN := $(ROOT)/target/release/zen-benchmark
.PHONY: all compare fixtures rust node python build-rust build-node build-python
all: rust node python
fixtures:
@node gen.mjs
compare:
@node compare.mjs
rust: build-rust
@printf '\n=== rust ===\n'
@$(BIN) manifest.json
node: build-node
@printf '\n=== node ===\n'
@node node/bench.mjs
python: build-python
@printf '\n=== python ===\n'
@$(PY) python/bench.py
build-rust:
@cargo build --release -q -p zen-benchmark
build-node:
@cd $(ROOT)/bindings/nodejs && yarn install --immutable --mode=skip-build && yarn build
build-python:
@test -d $(VENV) || python3 -m venv $(VENV)
@$(PY) -m pip install --quiet --upgrade pip maturin
@rm -rf $(CURDIR)/.dist && $(PY) -m maturin build --release --out $(CURDIR)/.dist -m $(ROOT)/bindings/python/Cargo.toml
@$(PY) -m pip install --quiet --force-reinstall $(CURDIR)/.dist/*.whl
+54
View File
@@ -0,0 +1,54 @@
import { execSync, execFileSync } from 'node:child_process';
import { readFileSync, mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const dir = path.dirname(fileURLToPath(import.meta.url));
const root = path.join(dir, '..');
const manifest = JSON.parse(readFileSync(path.join(dir, 'manifest.json'), 'utf8'));
const rowNames = manifest.flatMap((e) => [`${e.name} (${e.kind})`, `${e.name} (${e.kind}) +trace`]);
const langs = [
{ key: 'rust', build: 'build-rust', cmd: path.join(root, 'target', 'release', 'zen-benchmark'), args: ['manifest.json'] },
{ key: 'node', build: 'build-node', cmd: process.execPath, args: [path.join(dir, 'node', 'bench.mjs')] },
{ key: 'python', build: 'build-python', cmd: path.join(dir, '.venv', 'bin', 'python'), args: [path.join(dir, 'python', 'bench.py')] },
];
const tmp = mkdtempSync(path.join(tmpdir(), 'zen-bench-'));
const values = {};
for (const lang of langs) {
try {
execSync(`make ${lang.build}`, { cwd: dir, stdio: 'inherit', env: process.env });
const out = path.join(tmp, `${lang.key}.json`);
execFileSync(lang.cmd, [...lang.args, out], { cwd: dir, stdio: ['ignore', 'ignore', 'inherit'], env: process.env });
const arr = JSON.parse(readFileSync(out, 'utf8'));
values[lang.key] = Object.fromEntries(arr.map((e) => [e.name, e.value]));
} catch (err) {
console.error(`! skipping ${lang.key}: ${err.message}`);
values[lang.key] = null;
}
}
rmSync(tmp, { recursive: true, force: true });
const NAME_W = 52;
const COL_W = 22;
const get = (key, name) => (values[key] ? values[key][name] : undefined);
const cell = (v, base) => {
if (v == null) return 'n/a'.padStart(COL_W);
const ns = `${Math.round(v)} ns`;
if (base == null) return ns.padStart(COL_W);
const mult = base === 0 ? '' : `${(v / base).toFixed(2)}x`;
return `${ns} ${mult}`.padStart(COL_W);
};
const header = `${'fixture'.padEnd(NAME_W)}${['rust', 'node', 'python'].map((l) => l.padStart(COL_W)).join('')}`;
console.log('');
console.log(header);
console.log('-'.repeat(header.length));
for (const name of rowNames) {
const r = get('rust', name);
console.log(`${name.padEnd(NAME_W)}${cell(r, null)}${cell(get('node', name), r)}${cell(get('python', name), r)}`);
}
console.log('');
console.log('x = slowdown vs rust (rust is the baseline floor; lower is better)');
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"contentType":"application/vnd.gorules.decision","nodes":[{"type":"inputNode","id":"in","name":"request","content":{"schema":""},"position":{"x":2020,"y":120}},{"type":"expressionNode","id":"dailyStats","name":"dailyStats","content":{"expressions":[{"id":"dailyStats_e0","key":"cost","value":"dataGB * 0.5 + minutes * 0.01 + texts * 0.001"},{"id":"dailyStats_e1","key":"heavy","value":"dataGB > 2"}],"passThrough":true,"inputField":"usageHistory","outputPath":"daily","executionMode":"loop"},"position":{"x":2180,"y":120}},{"type":"decisionTableNode","id":"dailyTier","name":"dailyTier","content":{"hitPolicy":"first","inputs":[{"id":"i","name":"Cost","field":"cost"}],"outputs":[{"id":"o","name":"Tier","field":"usageTier"}],"rules":[{"_id":"r1","i":"> 5","o":"'high'"},{"_id":"r2","i":"> 2","o":"'medium'"},{"_id":"r3","i":"","o":"'low'"}],"passThrough":true,"inputField":"daily","outputPath":"dailyTiered","executionMode":"loop"},"position":{"x":2340,"y":120}},{"type":"expressionNode","id":"aggregate","name":"aggregate","content":{"expressions":[{"id":"aggregate_e0","key":"totalCost","value":"sum(map(daily, #.cost))"},{"id":"aggregate_e1","key":"heavyDays","value":"len(filter(daily, #.heavy))"},{"id":"aggregate_e2","key":"avgData","value":"sum(map(usageHistory, #.dataGB)) / len(usageHistory)"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":2500,"y":120}},{"type":"decisionTableNode","id":"accountStatus","name":"accountStatus","content":{"hitPolicy":"first","inputs":[{"id":"i1","name":"Age","field":"accountInfo.accountAge"},{"id":"i2","name":"Payment","field":"accountInfo.paymentHistory"}],"outputs":[{"id":"o1","name":"Status","field":"eligibility.accountStatus"},{"id":"o2","name":"Good","field":"eligibility.goodStanding"}],"rules":[{"_id":"r1","i1":">= 24","i2":"'excellent'","o1":"'excellent'","o2":"true"},{"_id":"r2","i1":">= 12","i2":"'excellent', 'good'","o1":"'good'","o2":"true"},{"_id":"r3","i1":">= 6","i2":"","o1":"'fair'","o2":"true"},{"_id":"r4","i1":"","i2":"","o1":"'review'","o2":"false"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":2660,"y":120}},{"type":"decisionTableNode","id":"loyaltyTier","name":"loyaltyTier","content":{"hitPolicy":"first","inputs":[{"id":"i1","name":"Age","field":"accountInfo.accountAge"},{"id":"i2","name":"Spend","field":"accountInfo.monthlySpend"}],"outputs":[{"id":"o1","name":"Tier","field":"eligibility.loyaltyTier"},{"id":"o2","name":"Discount","field":"eligibility.loyaltyDiscountPercent"}],"rules":[{"_id":"r1","i1":">= 36","i2":">= 120","o1":"'platinum'","o2":"20"},{"_id":"r2","i1":">= 24","i2":">= 80","o1":"'gold'","o2":"15"},{"_id":"r3","i1":">= 12","i2":">= 50","o1":"'silver'","o2":"10"},{"_id":"r4","i1":"","i2":"","o1":"'standard'","o2":"0"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":2820,"y":120}},{"type":"expressionNode","id":"specialOffers","name":"specialOffers","content":{"expressions":[{"id":"specialOffers_e0","key":"eligibility.specialOffers","value":"{ 'dataBooster': usageStats.dataUtilizationPercent > 80, 'familyPlan': len(customerProfile.devices) >= 3, 'loyaltyReward': eligibility.loyaltyTier in ['platinum', 'gold', 'silver'] }"},{"id":"specialOffers_e1","key":"eligibility.offerCount","value":"len(filter(values($.eligibility.specialOffers), # == true))"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":2980,"y":120}},{"type":"expressionNode","id":"replicate","name":"replicate","content":{"expressions":[{"id":"replicate_e0","key":"historyCopy","value":"usageHistory"},{"id":"replicate_e1","key":"dailyCopy","value":"daily"},{"id":"replicate_e2","key":"tieredCopy","value":"dailyTiered"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":3140,"y":120}}],"edges":[{"id":"edge0","type":"edge","sourceId":"in","targetId":"dailyStats"},{"id":"edge1","type":"edge","sourceId":"dailyStats","targetId":"dailyTier"},{"id":"edge2","type":"edge","sourceId":"dailyTier","targetId":"aggregate"},{"id":"edge3","type":"edge","sourceId":"aggregate","targetId":"accountStatus"},{"id":"edge4","type":"edge","sourceId":"accountStatus","targetId":"loyaltyTier"},{"id":"edge5","type":"edge","sourceId":"loyaltyTier","targetId":"specialOffers"},{"id":"edge6","type":"edge","sourceId":"specialOffers","targetId":"replicate"}]}
@@ -0,0 +1 @@
{"contentType":"application/vnd.gorules.decision","nodes":[{"id":"5eefa8a4-56a9-46b1-a265-7ddbddde3441","type":"inputNode","position":{"x":240,"y":280},"name":"Request"},{"id":"638d767d-ae08-4ba3-9db3-97c6c4e4c6f5","type":"decisionTableNode","position":{"x":520,"y":280},"name":"Discounts","content":{"hitPolicy":"collect","inputs":[{"id":"6fd35e3e-584b-4149-b4bf-5f2d258f40e7","type":"expression","field":"code","name":"Code"},{"id":"a1700de6-fe35-4cec-b66f-0897d2604a3f","name":"Order Date","type":"expression","field":"date(order.createdAt)"},{"id":"813dace4-0b55-4409-adb2-b4739a653302","type":"expression","field":"date(customer.joinDate)","name":"Customer Join Date"},{"id":"f34f2c8b-eba9-4ebe-aeec-384bce69e3aa","type":"expression","field":"len(customer.pastPurchases)","name":"Customer Past Purchases"}],"outputs":[{"field":"discount.percentage","id":"16d637be-1093-4468-b29f-236666bf2f26","name":"Discount Percentage","type":"expression"},{"id":"bccbb1bc-f0da-4b1e-b186-122ba4a193ac","type":"expression","field":"discount.flat","name":"Discount Flat"}],"rules":[{"_id":"eabd4e2e-5c14-4d4d-ada6-b3cdc547ae99","_description":"Welcome bonus of 15%","6fd35e3e-584b-4149-b4bf-5f2d258f40e7":"\"WELCOME_2023\"","a1700de6-fe35-4cec-b66f-0897d2604a3f":"","813dace4-0b55-4409-adb2-b4739a653302":"> date(\"2023-01-01\")","f34f2c8b-eba9-4ebe-aeec-384bce69e3aa":"0","16d637be-1093-4468-b29f-236666bf2f26":"15","bccbb1bc-f0da-4b1e-b186-122ba4a193ac":""},{"_id":"d80dee00-07a7-42fb-bc83-262eeee9fbdb","_description":"Recurring customer 25$ discount","6fd35e3e-584b-4149-b4bf-5f2d258f40e7":"\"BACK_TO_BACK\"","a1700de6-fe35-4cec-b66f-0897d2604a3f":"[date(\"2023-01-01\")..date(\"2023-02-01\")]","813dace4-0b55-4409-adb2-b4739a653302":"","f34f2c8b-eba9-4ebe-aeec-384bce69e3aa":"> 10","16d637be-1093-4468-b29f-236666bf2f26":"","bccbb1bc-f0da-4b1e-b186-122ba4a193ac":"25"},{"_id":"fcfae4b3-5c86-4efe-91cd-ca4bc1fa7c7c","_description":"Old customer 10%","6fd35e3e-584b-4149-b4bf-5f2d258f40e7":"\"EARLY_BIRD\"","a1700de6-fe35-4cec-b66f-0897d2604a3f":"","813dace4-0b55-4409-adb2-b4739a653302":"< date(\"2020-01-01\")","f34f2c8b-eba9-4ebe-aeec-384bce69e3aa":"","16d637be-1093-4468-b29f-236666bf2f26":"10","bccbb1bc-f0da-4b1e-b186-122ba4a193ac":""}]}},{"id":"c87d26e6-f3a2-47ad-9310-cbd1899cc68a","type":"outputNode","position":{"x":830,"y":280},"name":"Response"}],"edges":[{"id":"3b07d6c5-6949-4e5d-a8c6-f5cf44dbba0a","sourceId":"5eefa8a4-56a9-46b1-a265-7ddbddde3441","type":"edge","targetId":"638d767d-ae08-4ba3-9db3-97c6c4e4c6f5"},{"id":"69e558e4-4c20-4a53-9230-c068ebb19830","sourceId":"638d767d-ae08-4ba3-9db3-97c6c4e4c6f5","type":"edge","targetId":"c87d26e6-f3a2-47ad-9310-cbd1899cc68a"}]}
@@ -0,0 +1 @@
{"contentType":"application/vnd.gorules.decision","nodes":[{"type":"inputNode","id":"in","name":"request","content":{"schema":""},"position":{"x":1060,"y":120}},{"type":"expressionNode","id":"dims","name":"dims","content":{"expressions":[{"id":"dims_e0","key":"dimWeight","value":"(length * width * height) / 5000"},{"id":"dims_e1","key":"effWeight","value":"max([weight, (length * width * height) / 5000])"},{"id":"dims_e2","key":"distFactor","value":"distance / 100"}],"passThrough":true,"inputField":"shipments","outputPath":"computed","executionMode":"loop"},"position":{"x":1220,"y":120}},{"type":"decisionTableNode","id":"baseRate","name":"baseRate","content":{"hitPolicy":"first","inputs":[{"id":"i1","name":"Type","field":"shippingType"},{"id":"i2","name":"Weight","field":"effWeight"}],"outputs":[{"id":"o1","name":"Base","field":"baseRate"}],"rules":[{"_id":"r1","i1":"'standard'","i2":"< 20","o1":"10"},{"_id":"r2","i1":"'standard'","i2":"","o1":"20"},{"_id":"r3","i1":"'express'","i2":"< 20","o1":"20"},{"_id":"r4","i1":"'express'","i2":"","o1":"35"},{"_id":"r5","i1":"'priority'","i2":"","o1":"50"},{"_id":"r6","i1":"","i2":"","o1":"15"}],"passThrough":true,"inputField":"computed","outputPath":"rated","executionMode":"loop"},"position":{"x":1380,"y":120}},{"type":"decisionTableNode","id":"finalPrice","name":"finalPrice","content":{"hitPolicy":"first","inputs":[{"id":"i1","name":"Tier","field":"customerTier"}],"outputs":[{"id":"o1","name":"Final","field":"finalPrice"}],"rules":[{"_id":"r1","i1":"'gold'","o1":"baseRate * (effWeight / weight) * (1 + distFactor * 0.1) * 0.9"},{"_id":"r2","i1":"'silver'","o1":"baseRate * (effWeight / weight) * (1 + distFactor * 0.1) * 0.95"},{"_id":"r3","i1":"","o1":"baseRate * (effWeight / weight) * (1 + distFactor * 0.1)"}],"passThrough":true,"inputField":"rated","outputPath":"priced","executionMode":"loop"},"position":{"x":1540,"y":120}},{"type":"expressionNode","id":"replicate","name":"replicate","content":{"expressions":[{"id":"replicate_e0","key":"shipmentsCopy","value":"shipments"},{"id":"replicate_e1","key":"computedCopy","value":"computed"},{"id":"replicate_e2","key":"pricedCopy","value":"priced"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":1700,"y":120}},{"type":"expressionNode","id":"totals","name":"totals","content":{"expressions":[{"id":"totals_e0","key":"totalPrice","value":"sum(map(priced, #.finalPrice))"},{"id":"totals_e1","key":"count","value":"len(shipments)"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":1860,"y":120}}],"edges":[{"id":"edge0","type":"edge","sourceId":"in","targetId":"dims"},{"id":"edge1","type":"edge","sourceId":"dims","targetId":"baseRate"},{"id":"edge2","type":"edge","sourceId":"baseRate","targetId":"finalPrice"},{"id":"edge3","type":"edge","sourceId":"finalPrice","targetId":"replicate"},{"id":"edge4","type":"edge","sourceId":"replicate","targetId":"totals"}]}
@@ -0,0 +1 @@
{"contentType":"application/vnd.gorules.decision","nodes":[{"type":"inputNode","id":"in","name":"request","content":{"schema":""},"position":{"x":260,"y":120}},{"type":"expressionNode","id":"enrich","name":"enrich","content":{"expressions":[{"id":"enrich_e0","key":"subtotal","value":"amount * qty"},{"id":"enrich_e1","key":"premium","value":"amount > 40 and group == 'accessories'"}],"passThrough":true,"inputField":"items","outputPath":"enriched","executionMode":"loop"},"position":{"x":420,"y":120}},{"type":"decisionTableNode","id":"classify","name":"classify","content":{"hitPolicy":"first","inputs":[{"id":"ci","name":"Subtotal","field":"subtotal"}],"outputs":[{"id":"co","name":"Discount","field":"discount"}],"rules":[{"_id":"r1","ci":"> 1000","co":"15"},{"_id":"r2","ci":"> 500","co":"10"},{"_id":"r3","ci":"> 100","co":"5"},{"_id":"r4","ci":"","co":"0"}],"passThrough":true,"inputField":"enriched","outputPath":"classified","executionMode":"loop"},"position":{"x":580,"y":120}},{"type":"expressionNode","id":"replicate","name":"replicate","content":{"expressions":[{"id":"replicate_e0","key":"allItems","value":"items"},{"id":"replicate_e1","key":"enrichedCopy","value":"enriched"},{"id":"replicate_e2","key":"classifiedCopy","value":"classified"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":740,"y":120}},{"type":"expressionNode","id":"totals","name":"totals","content":{"expressions":[{"id":"totals_e0","key":"grandTotal","value":"sum(map(enriched, #.subtotal))"},{"id":"totals_e1","key":"itemCount","value":"len(items)"},{"id":"totals_e2","key":"premiumCount","value":"len(filter(enriched, #.premium))"}],"passThrough":true,"inputField":null,"outputPath":null,"executionMode":"single"},"position":{"x":900,"y":120}}],"edges":[{"id":"edge0","type":"edge","sourceId":"in","targetId":"enrich"},{"id":"edge1","type":"edge","sourceId":"enrich","targetId":"classify"},{"id":"edge2","type":"edge","sourceId":"classify","targetId":"replicate"},{"id":"edge3","type":"edge","sourceId":"replicate","targetId":"totals"}]}
@@ -0,0 +1 @@
{"blocks":[{"id":"dm","type":"dataModel","props":{"data":{"name":"customer","properties":[{"id":"p0","name":"amounts","type":"number","array":true,"optional":false},{"id":"p1","name":"label","type":"string","array":false,"optional":false}]}},"children":[]},{"id":"e1","type":"expression","props":{"data":{"key":"customer.positive","value":"filter(customer.amounts, # > 0)"}}},{"id":"e2","type":"expression","props":{"data":{"key":"customer.negatives","value":"filter(customer.amounts, # < 0)"}}},{"id":"e3","type":"expression","props":{"data":{"key":"customer.doubled","value":"map(customer.amounts, # * 2)"}}},{"id":"e4","type":"expression","props":{"data":{"key":"customer.squared","value":"map(customer.amounts, # * #)"}}},{"id":"e5","type":"expression","props":{"data":{"key":"customer.total","value":"sum(customer.positive)"}}},{"id":"e6","type":"expression","props":{"data":{"key":"customer.negTotal","value":"sum(customer.negatives)"}}},{"id":"e7","type":"expression","props":{"data":{"key":"customer.net","value":"customer.total + customer.negTotal"}}},{"id":"e8","type":"expression","props":{"data":{"key":"customer.posCount","value":"len(customer.positive)"}}},{"id":"e9","type":"expression","props":{"data":{"key":"customer.avg","value":"customer.net / len(customer.amounts)"}}},{"id":"e10","type":"expression","props":{"data":{"key":"customer.maxVal","value":"max(customer.amounts)"}}},{"id":"e11","type":"expression","props":{"data":{"key":"customer.minVal","value":"min(customer.amounts)"}}},{"id":"a1","type":"assertion","props":{"data":{"output":"customer.bigSpender","conditions":[{"id":"a1c","expression":"customer.total > 1000","operator":"and","depth":0}]}},"children":[]},{"id":"a2","type":"assertion","props":{"data":{"output":"customer.balanced","conditions":[{"id":"a2c","expression":"customer.net > 0","operator":"and","depth":0}]}},"children":[]},{"id":"a3","type":"assertion","props":{"data":{"output":"customer.volatile","conditions":[{"id":"a3c","expression":"customer.maxVal - customer.minVal > 50","operator":"and","depth":0}]}},"children":[]}]}
@@ -0,0 +1 @@
{"blocks":[{"id":"dm","type":"dataModel","props":{"data":{"name":"customer","properties":[{"id":"p0","name":"age","type":"number","array":false,"optional":false},{"id":"p1","name":"income","type":"number","array":false,"optional":false}]}},"children":[]},{"id":"e1","type":"expression","props":{"data":{"key":"customer.score","value":"customer.age + customer.income / 1000"}}},{"id":"a1","type":"assertion","props":{"data":{"output":"customer.eligible","conditions":[{"id":"a1c","expression":"customer.score > 50","operator":"and","depth":0}]}},"children":[]}]}
+1
View File
@@ -0,0 +1 @@
{"blocks":[{"id":"dm","type":"dataModel","props":{"data":{"name":"customer","properties":[{"id":"p0","name":"score","type":"number","array":false,"optional":false}]}},"children":[]},{"id":"m1","type":"match","props":{"data":{"key":"customer.tier","arms":[{"id":"a1","condition":"customer.score >= 80","value":"\"gold\""},{"id":"a2","condition":"customer.score >= 50","value":"\"silver\""},{"id":"a3","condition":"","value":"\"bronze\""}]}}}]}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{"blocks":[{"id":"dm","type":"dataModel","props":{"data":{"name":"customer","properties":[{"id":"p0","name":"age","type":"number","array":false,"optional":false}]}},"children":[]},{"id":"a1","type":"assertion","props":{"data":{"output":"customer.isAdult","conditions":[{"id":"a1c","expression":"customer.age >= 18","operator":"and","depth":0}]}},"children":[]}]}
+328
View File
@@ -0,0 +1,328 @@
import { writeFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const dir = path.dirname(fileURLToPath(import.meta.url));
const fixtures = path.join(dir, 'fixtures');
const ITEMS = 250;
const DAYS = 200;
const SHIPMENTS = 150;
const AMOUNTS = 600;
const SCORES = 300;
const ASSERTIONS = 30;
const range = (n) => Array.from({ length: n }, (_, i) => i);
let x = 100;
const pos = () => ({ x: (x += 160), y: 120 });
const inputNode = (id) => ({ type: 'inputNode', id, name: 'request', content: { schema: '' }, position: pos() });
const exprNode = (id, name, exprs, transform = {}) => ({
type: 'expressionNode',
id,
name,
content: {
expressions: exprs.map(([key, value], i) => ({ id: `${id}_e${i}`, key, value })),
passThrough: true,
inputField: null,
outputPath: null,
executionMode: 'single',
...transform,
},
position: pos(),
});
const tableNode = (id, name, inputs, outputs, rules, transform = {}) => ({
type: 'decisionTableNode',
id,
name,
content: {
hitPolicy: 'first',
inputs,
outputs,
rules,
passThrough: true,
inputField: null,
outputPath: null,
executionMode: 'single',
...transform,
},
position: pos(),
});
const graph = (nodes) => ({
contentType: 'application/vnd.gorules.decision',
nodes,
edges: nodes.slice(1).map((n, i) => ({ id: `edge${i}`, type: 'edge', sourceId: nodes[i].id, targetId: n.id })),
});
const dataModel = (name, props) => ({
id: 'dm',
type: 'dataModel',
props: { data: { name, properties: props.map((p, i) => ({ id: `p${i}`, name: p.name, type: p.type, array: !!p.array, optional: !!p.optional })) } },
children: [],
});
const expr = (id, key, value) => ({ id, type: 'expression', props: { data: { key, value } } });
const assertion = (id, output, expression) => ({
id,
type: 'assertion',
props: { data: { output, conditions: [{ id: `${id}c`, expression, operator: 'and', depth: 0 }] } },
children: [],
});
const expressionTableMap = graph([
inputNode('in'),
exprNode('enrich', 'enrich', [
['subtotal', 'amount * qty'],
['premium', "amount > 40 and group == 'accessories'"],
], { inputField: 'items', outputPath: 'enriched', executionMode: 'loop' }),
tableNode('classify', 'classify',
[{ id: 'ci', name: 'Subtotal', field: 'subtotal' }],
[{ id: 'co', name: 'Discount', field: 'discount' }],
[
{ _id: 'r1', ci: '> 1000', co: '15' },
{ _id: 'r2', ci: '> 500', co: '10' },
{ _id: 'r3', ci: '> 100', co: '5' },
{ _id: 'r4', ci: '', co: '0' },
],
{ inputField: 'enriched', outputPath: 'classified', executionMode: 'loop' }),
exprNode('replicate', 'replicate', [
['allItems', 'items'],
['enrichedCopy', 'enriched'],
['classifiedCopy', 'classified'],
]),
exprNode('totals', 'totals', [
['grandTotal', 'sum(map(enriched, #.subtotal))'],
['itemCount', 'len(items)'],
['premiumCount', 'len(filter(enriched, #.premium))'],
]),
]);
const dynamicShipping = graph([
inputNode('in'),
exprNode('dims', 'dims', [
['dimWeight', '(length * width * height) / 5000'],
['effWeight', 'max([weight, (length * width * height) / 5000])'],
['distFactor', 'distance / 100'],
], { inputField: 'shipments', outputPath: 'computed', executionMode: 'loop' }),
tableNode('baseRate', 'baseRate',
[
{ id: 'i1', name: 'Type', field: 'shippingType' },
{ id: 'i2', name: 'Weight', field: 'effWeight' },
],
[{ id: 'o1', name: 'Base', field: 'baseRate' }],
[
{ _id: 'r1', i1: "'standard'", i2: '< 20', o1: '10' },
{ _id: 'r2', i1: "'standard'", i2: '', o1: '20' },
{ _id: 'r3', i1: "'express'", i2: '< 20', o1: '20' },
{ _id: 'r4', i1: "'express'", i2: '', o1: '35' },
{ _id: 'r5', i1: "'priority'", i2: '', o1: '50' },
{ _id: 'r6', i1: '', i2: '', o1: '15' },
],
{ inputField: 'computed', outputPath: 'rated', executionMode: 'loop' }),
tableNode('finalPrice', 'finalPrice',
[{ id: 'i1', name: 'Tier', field: 'customerTier' }],
[{ id: 'o1', name: 'Final', field: 'finalPrice' }],
[
{ _id: 'r1', i1: "'gold'", o1: 'baseRate * (effWeight / weight) * (1 + distFactor * 0.1) * 0.9' },
{ _id: 'r2', i1: "'silver'", o1: 'baseRate * (effWeight / weight) * (1 + distFactor * 0.1) * 0.95' },
{ _id: 'r3', i1: '', o1: 'baseRate * (effWeight / weight) * (1 + distFactor * 0.1)' },
],
{ inputField: 'rated', outputPath: 'priced', executionMode: 'loop' }),
exprNode('replicate', 'replicate', [
['shipmentsCopy', 'shipments'],
['computedCopy', 'computed'],
['pricedCopy', 'priced'],
]),
exprNode('totals', 'totals', [
['totalPrice', 'sum(map(priced, #.finalPrice))'],
['count', 'len(shipments)'],
]),
]);
const customerEligibility = graph([
inputNode('in'),
exprNode('dailyStats', 'dailyStats', [
['cost', 'dataGB * 0.5 + minutes * 0.01 + texts * 0.001'],
['heavy', 'dataGB > 2'],
], { inputField: 'usageHistory', outputPath: 'daily', executionMode: 'loop' }),
tableNode('dailyTier', 'dailyTier',
[{ id: 'i', name: 'Cost', field: 'cost' }],
[{ id: 'o', name: 'Tier', field: 'usageTier' }],
[
{ _id: 'r1', i: '> 5', o: "'high'" },
{ _id: 'r2', i: '> 2', o: "'medium'" },
{ _id: 'r3', i: '', o: "'low'" },
],
{ inputField: 'daily', outputPath: 'dailyTiered', executionMode: 'loop' }),
exprNode('aggregate', 'aggregate', [
['totalCost', 'sum(map(daily, #.cost))'],
['heavyDays', 'len(filter(daily, #.heavy))'],
['avgData', 'sum(map(usageHistory, #.dataGB)) / len(usageHistory)'],
]),
tableNode('accountStatus', 'accountStatus',
[
{ id: 'i1', name: 'Age', field: 'accountInfo.accountAge' },
{ id: 'i2', name: 'Payment', field: 'accountInfo.paymentHistory' },
],
[
{ id: 'o1', name: 'Status', field: 'eligibility.accountStatus' },
{ id: 'o2', name: 'Good', field: 'eligibility.goodStanding' },
],
[
{ _id: 'r1', i1: '>= 24', i2: "'excellent'", o1: "'excellent'", o2: 'true' },
{ _id: 'r2', i1: '>= 12', i2: "'excellent', 'good'", o1: "'good'", o2: 'true' },
{ _id: 'r3', i1: '>= 6', i2: '', o1: "'fair'", o2: 'true' },
{ _id: 'r4', i1: '', i2: '', o1: "'review'", o2: 'false' },
]),
tableNode('loyaltyTier', 'loyaltyTier',
[
{ id: 'i1', name: 'Age', field: 'accountInfo.accountAge' },
{ id: 'i2', name: 'Spend', field: 'accountInfo.monthlySpend' },
],
[
{ id: 'o1', name: 'Tier', field: 'eligibility.loyaltyTier' },
{ id: 'o2', name: 'Discount', field: 'eligibility.loyaltyDiscountPercent' },
],
[
{ _id: 'r1', i1: '>= 36', i2: '>= 120', o1: "'platinum'", o2: '20' },
{ _id: 'r2', i1: '>= 24', i2: '>= 80', o1: "'gold'", o2: '15' },
{ _id: 'r3', i1: '>= 12', i2: '>= 50', o1: "'silver'", o2: '10' },
{ _id: 'r4', i1: '', i2: '', o1: "'standard'", o2: '0' },
]),
exprNode('specialOffers', 'specialOffers', [
['eligibility.specialOffers', "{ 'dataBooster': usageStats.dataUtilizationPercent > 80, 'familyPlan': len(customerProfile.devices) >= 3, 'loyaltyReward': eligibility.loyaltyTier in ['platinum', 'gold', 'silver'] }"],
['eligibility.offerCount', 'len(filter(values($.eligibility.specialOffers), # == true))'],
]),
exprNode('replicate', 'replicate', [
['historyCopy', 'usageHistory'],
['dailyCopy', 'daily'],
['tieredCopy', 'dailyTiered'],
]),
]);
const expressionChain = {
blocks: [
dataModel('customer', [
{ name: 'amounts', type: 'number', array: true },
{ name: 'label', type: 'string' },
]),
expr('e1', 'customer.positive', 'filter(customer.amounts, # > 0)'),
expr('e2', 'customer.negatives', 'filter(customer.amounts, # < 0)'),
expr('e3', 'customer.doubled', 'map(customer.amounts, # * 2)'),
expr('e4', 'customer.squared', 'map(customer.amounts, # * #)'),
expr('e5', 'customer.total', 'sum(customer.positive)'),
expr('e6', 'customer.negTotal', 'sum(customer.negatives)'),
expr('e7', 'customer.net', 'customer.total + customer.negTotal'),
expr('e8', 'customer.posCount', 'len(customer.positive)'),
expr('e9', 'customer.avg', 'customer.net / len(customer.amounts)'),
expr('e10', 'customer.maxVal', 'max(customer.amounts)'),
expr('e11', 'customer.minVal', 'min(customer.amounts)'),
assertion('a1', 'customer.bigSpender', 'customer.total > 1000'),
assertion('a2', 'customer.balanced', 'customer.net > 0'),
assertion('a3', 'customer.volatile', 'customer.maxVal - customer.minVal > 50'),
],
};
const multiAssertion = {
blocks: [
dataModel('customer', [
{ name: 'age', type: 'number' },
{ name: 'income', type: 'number' },
{ name: 'employmentYears', type: 'number' },
{ name: 'scores', type: 'number', array: true },
]),
expr('s1', 'customer.scoreSum', 'sum(customer.scores)'),
expr('s2', 'customer.scoreAvg', 'customer.scoreSum / len(customer.scores)'),
expr('s3', 'customer.highScores', 'filter(customer.scores, # > 50)'),
expr('s4', 'customer.scaled', 'map(customer.scores, # * 1.5)'),
...range(ASSERTIONS).map((i) => assertion(`a${i}`, `customer.flag${i}`, `customer.scoreAvg >= ${i}`)),
],
};
const manifest = [
{
name: 'decision-table-discounts',
kind: 'graph',
file: 'graphs/decision-table-discounts.json',
input: { code: 'WELCOME_2023', order: { createdAt: '2023-01-15' }, customer: { joinDate: '2023-02-01', pastPurchases: [] } },
},
{
name: 'expression-table-map',
kind: 'graph',
file: 'graphs/expression-table-map.json',
input: {
customer: { name: 'John Doe', country: 'US' },
items: range(ITEMS).map((i) => ({ name: `item${i}`, amount: 10 + (i % 90), group: i % 3 === 0 ? 'accessories' : 'electronics', qty: 1 + (i % 5) })),
},
},
{
name: 'credit-limit-adjustment',
kind: 'graph',
file: 'graphs/credit-limit-adjustment.json',
input: {
account: {
customer_id: 'CUST10025',
current_credit_limit: 5000,
payment_history: { on_time_payment_percentage: 98, late_payments_last_12_months: 0, total_payments: 24 },
utilization: { current_percentage: 25, average_last_6_months: 40, highest_balance: 2800 },
financial_behavior: { credit_inquiries_last_12_months: 0, years_with_institution: 4, income_verified: true, has_other_products: true },
},
},
},
{
name: 'dynamic-shipping-cost-calculator',
kind: 'graph',
file: 'graphs/dynamic-shipping-cost-calculator.json',
input: {
shipments: range(SHIPMENTS).map((i) => ({
weight: 5 + (i % 40),
length: 20 + (i % 30),
width: 15 + (i % 20),
height: 10 + (i % 15),
distance: 50 + (i % 500),
shippingType: ['standard', 'express', 'priority'][i % 3],
customerTier: ['gold', 'silver', 'standard'][i % 3],
})),
},
},
{
name: 'customer-eligibility-engine',
kind: 'graph',
file: 'graphs/customer-eligibility-engine.json',
input: {
accountInfo: { accountAge: 28, paymentHistory: 'excellent', currentPlan: 'Family Premium 50GB', monthlySpend: 95, contractStatus: 'pending_renewal' },
usageStats: { dataUsageGB: 42.5, dataUtilizationPercent: 85, callMinutes: 350, textMessages: 1250 },
customerProfile: { segment: 'consumer', location: 'Seattle, WA', devices: ['iPhone 14', 'iPad Air', 'Apple Watch'], previousComplaints: 0 },
usageHistory: range(DAYS).map((d) => ({ day: d, dataGB: 1 + (d % 5), minutes: 100 + (d % 200), texts: 10 + (d % 50) })),
},
},
{ name: 'simple-assertion', kind: 'policy', file: 'policies/simple-assertion.json', input: { customer: { age: 30 } } },
{ name: 'expression', kind: 'policy', file: 'policies/expression.json', input: { customer: { age: 35, income: 60000 } } },
{
name: 'multi-assertion',
kind: 'policy',
file: 'policies/multi-assertion.json',
input: { customer: { age: 40, income: 60000, employmentYears: 5, scores: range(SCORES).map((i) => (i * 13) % 100) } },
},
{
name: 'expression-chain',
kind: 'policy',
file: 'policies/expression-chain.json',
input: { customer: { amounts: range(AMOUNTS).map((i) => ((i * 7) % 41) - 20), label: 'batch' } },
},
{ name: 'match', kind: 'policy', file: 'policies/match.json', input: { customer: { score: 85 } } },
];
writeFileSync(path.join(fixtures, 'graphs', 'expression-table-map.json'), JSON.stringify(expressionTableMap));
writeFileSync(path.join(fixtures, 'graphs', 'dynamic-shipping-cost-calculator.json'), JSON.stringify(dynamicShipping));
writeFileSync(path.join(fixtures, 'graphs', 'customer-eligibility-engine.json'), JSON.stringify(customerEligibility));
writeFileSync(path.join(fixtures, 'policies', 'expression-chain.json'), JSON.stringify(expressionChain));
writeFileSync(path.join(fixtures, 'policies', 'multi-assertion.json'), JSON.stringify(multiAssertion));
writeFileSync(path.join(dir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n');
console.log('generated 5 heavy fixtures + manifest.json');
File diff suppressed because it is too large Load Diff
+43
View File
@@ -0,0 +1,43 @@
import { readFile } from 'node:fs/promises';
import { readFileSync, writeFileSync } from 'node:fs';
import { hrtime, argv, env } from 'node:process';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const { ZenEngine } = require('../../bindings/nodejs/index.js');
const dir = path.dirname(fileURLToPath(import.meta.url));
const root = path.join(dir, '..');
const fixtures = path.join(root, 'fixtures');
const manifest = JSON.parse(readFileSync(path.join(root, 'manifest.json'), 'utf8'));
const iters = Number(env.BENCH_ITERS || 2000);
const outPath = argv[2];
const loader = (key) => readFile(path.join(fixtures, key));
const engine = new ZenEngine({ loader });
const results = [];
for (const e of manifest) {
for (const trace of [false, true]) {
const opts = { trace };
await engine.evaluate(e.file, e.input, opts);
const start = hrtime.bigint();
for (let i = 0; i < iters; i++) {
await engine.evaluate(e.file, e.input, opts);
}
const per = Number(hrtime.bigint() - start) / iters;
results.push({ name: `${e.name} (${e.kind})${trace ? ' +trace' : ''}`, unit: 'ns/op', value: per });
}
}
engine.dispose?.();
if (outPath) {
writeFileSync(outPath, JSON.stringify(results, null, 2));
} else {
for (const r of results) {
console.log(`${r.name.padEnd(44)} ${r.value.toFixed(0).padStart(12)} ns/op`);
}
}
+39
View File
@@ -0,0 +1,39 @@
import json
import os
import sys
import time
import zen
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
fixtures = os.path.join(root, "fixtures")
manifest = json.load(open(os.path.join(root, "manifest.json")))
iters = int(os.environ.get("BENCH_ITERS", "2000"))
out_path = sys.argv[1] if len(sys.argv) > 1 else None
def loader(key):
with open(os.path.join(fixtures, key)) as f:
return f.read()
engine = zen.ZenEngine({"loader": loader})
results = []
for e in manifest:
for trace in (False, True):
opts = {"trace": trace}
engine.evaluate(e["file"], e["input"], opts)
start = time.perf_counter_ns()
for _ in range(iters):
engine.evaluate(e["file"], e["input"], opts)
per = (time.perf_counter_ns() - start) / iters
suffix = " +trace" if trace else ""
results.append({"name": f'{e["name"]} ({e["kind"]}){suffix}', "unit": "ns/op", "value": per})
if out_path:
with open(out_path, "w") as f:
f.write(json.dumps(results, indent=2))
else:
for r in results:
print(f'{r["name"]:<44} {r["value"]:>12.0f} ns/op')
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "zen-benchmark"
version = "0.0.0"
edition = "2021"
publish = false
[dependencies]
zen-engine = { path = "../../core/engine" }
zen-expression = { path = "../../core/expression" }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
+99
View File
@@ -0,0 +1,99 @@
use std::path::Path;
use std::sync::Arc;
use std::time::Instant;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use zen_engine::loader::{FilesystemLoader, FilesystemLoaderOptions};
use zen_engine::{DecisionEngine, EvaluationOptions};
use zen_expression::Variable;
#[derive(Deserialize)]
struct Entry {
name: String,
kind: String,
file: String,
input: Value,
}
#[derive(Serialize)]
struct BenchResult {
name: String,
unit: String,
value: f64,
}
#[tokio::main(flavor = "multi_thread")]
async fn main() {
let mut args = std::env::args().skip(1);
let manifest_path = args
.next()
.unwrap_or_else(|| "../manifest.json".to_string());
let out_path = args.next();
let iters: u32 = std::env::var("BENCH_ITERS")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(2000);
let manifest_path = Path::new(&manifest_path);
let base = manifest_path
.parent()
.unwrap_or_else(|| Path::new("."))
.join("fixtures");
let manifest: Vec<Entry> =
serde_json::from_str(&std::fs::read_to_string(manifest_path).expect("read manifest"))
.expect("parse manifest");
let engine = DecisionEngine::default().with_loader(Arc::new(FilesystemLoader::new(
FilesystemLoaderOptions {
root: base.to_string_lossy().to_string(),
},
)));
let mut results = Vec::new();
for e in &manifest {
let input: Variable = e.input.clone().into();
for trace in [false, true] {
let opts = || EvaluationOptions {
trace,
max_depth: 10,
};
engine
.evaluate_with_opts(e.file.as_str(), input.clone(), opts())
.await
.unwrap_or_else(|err| panic!("warmup {} failed: {err:?}", e.name));
let start = Instant::now();
for _ in 0..iters {
engine
.evaluate_with_opts(e.file.as_str(), input.clone(), opts())
.await
.unwrap();
}
let per = start.elapsed().as_nanos() as f64 / f64::from(iters);
results.push(BenchResult {
name: format!(
"{} ({}){}",
e.name,
e.kind,
if trace { " +trace" } else { "" }
),
unit: "ns/op".to_string(),
value: per,
});
}
}
match out_path {
Some(p) => {
let json = serde_json::to_string_pretty(&results).expect("serialize results");
std::fs::write(p, json).expect("write output");
}
None => {
for r in &results {
println!("{:<44} {:>12.0} ns/op", r.name, r.value);
}
}
}
}
+52 -52
View File
@@ -77,8 +77,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-android-arm64')
const bindingPackageVersion = require('@gorules/zen-engine-android-arm64/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -93,8 +93,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-android-arm-eabi')
const bindingPackageVersion = require('@gorules/zen-engine-android-arm-eabi/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -114,8 +114,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-win32-x64-gnu')
const bindingPackageVersion = require('@gorules/zen-engine-win32-x64-gnu/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -130,8 +130,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-win32-x64-msvc')
const bindingPackageVersion = require('@gorules/zen-engine-win32-x64-msvc/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -147,8 +147,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-win32-ia32-msvc')
const bindingPackageVersion = require('@gorules/zen-engine-win32-ia32-msvc/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -163,8 +163,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-win32-arm64-msvc')
const bindingPackageVersion = require('@gorules/zen-engine-win32-arm64-msvc/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -182,8 +182,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-darwin-universal')
const bindingPackageVersion = require('@gorules/zen-engine-darwin-universal/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -198,8 +198,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-darwin-x64')
const bindingPackageVersion = require('@gorules/zen-engine-darwin-x64/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -214,8 +214,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-darwin-arm64')
const bindingPackageVersion = require('@gorules/zen-engine-darwin-arm64/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -234,8 +234,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-freebsd-x64')
const bindingPackageVersion = require('@gorules/zen-engine-freebsd-x64/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -250,8 +250,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-freebsd-arm64')
const bindingPackageVersion = require('@gorules/zen-engine-freebsd-arm64/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -271,8 +271,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-x64-musl')
const bindingPackageVersion = require('@gorules/zen-engine-linux-x64-musl/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -287,8 +287,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-x64-gnu')
const bindingPackageVersion = require('@gorules/zen-engine-linux-x64-gnu/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -305,8 +305,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-arm64-musl')
const bindingPackageVersion = require('@gorules/zen-engine-linux-arm64-musl/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -321,8 +321,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-arm64-gnu')
const bindingPackageVersion = require('@gorules/zen-engine-linux-arm64-gnu/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -339,8 +339,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-arm-musleabihf')
const bindingPackageVersion = require('@gorules/zen-engine-linux-arm-musleabihf/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -355,8 +355,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-arm-gnueabihf')
const bindingPackageVersion = require('@gorules/zen-engine-linux-arm-gnueabihf/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -373,8 +373,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-loong64-musl')
const bindingPackageVersion = require('@gorules/zen-engine-linux-loong64-musl/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -389,8 +389,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-loong64-gnu')
const bindingPackageVersion = require('@gorules/zen-engine-linux-loong64-gnu/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -407,8 +407,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-riscv64-musl')
const bindingPackageVersion = require('@gorules/zen-engine-linux-riscv64-musl/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -423,8 +423,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-riscv64-gnu')
const bindingPackageVersion = require('@gorules/zen-engine-linux-riscv64-gnu/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -440,8 +440,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-ppc64-gnu')
const bindingPackageVersion = require('@gorules/zen-engine-linux-ppc64-gnu/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -456,8 +456,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-linux-s390x-gnu')
const bindingPackageVersion = require('@gorules/zen-engine-linux-s390x-gnu/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -476,8 +476,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-openharmony-arm64')
const bindingPackageVersion = require('@gorules/zen-engine-openharmony-arm64/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -492,8 +492,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-openharmony-x64')
const bindingPackageVersion = require('@gorules/zen-engine-openharmony-x64/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
@@ -508,8 +508,8 @@ function requireNative() {
try {
const binding = require('@gorules/zen-engine-openharmony-arm')
const bindingPackageVersion = require('@gorules/zen-engine-openharmony-arm/package.json').version
if (bindingPackageVersion !== '0.54.1' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.1 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
if (bindingPackageVersion !== '0.54.0' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
throw new Error(`Native binding package version mismatch, expected 0.54.0 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
}
return binding
} catch (e) {
+1
View File
@@ -4,6 +4,7 @@
"include-component-in-tag": true,
"tag-separator": "-",
"pull-request-title-pattern": "chore(release): publish",
"group-pull-request-title-pattern": "chore(release): publish",
"release-as": "1.0.0-beta.0",
"prerelease": true,
"prerelease-type": "beta",