mirror of
https://github.com/gorules/zen.git
synced 2026-10-04 00:02:18 +00:00
feat: crates restructure (#22)
This commit is contained in:
@@ -120,11 +120,8 @@ jobs:
|
||||
- name: Login to Crates.IO
|
||||
run: cargo login ${{ secrets.CRATES_TOKEN }}
|
||||
|
||||
- name: Publish Parser
|
||||
run: cd core/parser && cargo publish
|
||||
|
||||
- name: Publish VM
|
||||
run: cd core/vm && cargo publish
|
||||
- name: Publish Expression
|
||||
run: cd core/expression && cargo publish
|
||||
|
||||
- name: Publish Engine
|
||||
run: cd core/engine && cargo publish
|
||||
|
||||
+4
-8
@@ -11268,14 +11268,12 @@ var semver = __nccwpck_require__(1383);
|
||||
var toml = __nccwpck_require__(4920);
|
||||
;// CONCATENATED MODULE: ./src/cargo.ts
|
||||
|
||||
const versionRegex = /version = "[0-9]+\.[0-9]+\.[0-9]+"$/mi;
|
||||
const vmDep = /zen-vm =.*$/mi;
|
||||
const parserDep = /zen-parser =.*$/mi;
|
||||
const versionRegex = /version = "[0-9]+\.[0-9]+\.[0-9]+"$/im;
|
||||
const expressionDep = /zen-expression =.*$/im;
|
||||
const updateCargoContents = (contents, { version }) => {
|
||||
return contents
|
||||
.replace(versionRegex, `version = "${version}"`)
|
||||
.replace(parserDep, `zen-parser = { path = "../parser", version = "${version}" }`)
|
||||
.replace(vmDep, `zen-vm = { path = "../vm", version = "${version}" }`);
|
||||
.replace(expressionDep, `zen-expression = { path = "../expression", version = "${version}" }`);
|
||||
};
|
||||
const getCargoVersion = (contents) => {
|
||||
var _a;
|
||||
@@ -11310,9 +11308,7 @@ function run() {
|
||||
const project = 'engine';
|
||||
const projectsFolder = 'core';
|
||||
const directory = yield promises_namespaceObject.readdir(external_path_.join(...[workspace, projectsFolder]), { withFileTypes: true });
|
||||
const folders = directory
|
||||
.filter((dirent) => dirent.isDirectory())
|
||||
.map((dirent) => dirent.name);
|
||||
const folders = directory.filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
||||
const cargoFilePath = external_path_.join(...[workspace, projectsFolder, project, 'Cargo.toml']);
|
||||
const cargoFile = yield promises_namespaceObject.readFile(cargoFilePath, 'utf-8');
|
||||
const currentVersion = getCargoVersion(cargoFile);
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import * as toml from "toml";
|
||||
import * as toml from 'toml';
|
||||
|
||||
type UpdateCargoOptions = {
|
||||
version: string;
|
||||
}
|
||||
};
|
||||
|
||||
const versionRegex = /version = "[0-9]+\.[0-9]+\.[0-9]+"$/mi;
|
||||
const vmDep = /zen-vm =.*$/mi;
|
||||
const parserDep = /zen-parser =.*$/mi;
|
||||
const versionRegex = /version = "[0-9]+\.[0-9]+\.[0-9]+"$/im;
|
||||
const expressionDep = /zen-expression =.*$/im;
|
||||
|
||||
export const updateCargoContents = (contents: string, {version}: UpdateCargoOptions): string => {
|
||||
export const updateCargoContents = (contents: string, { version }: UpdateCargoOptions): string => {
|
||||
return contents
|
||||
.replace(versionRegex, `version = "${version}"`)
|
||||
.replace(parserDep, `zen-parser = { path = "../parser", version = "${version}" }`)
|
||||
.replace(vmDep, `zen-vm = { path = "../vm", version = "${version}" }`);
|
||||
}
|
||||
.replace(expressionDep, `zen-expression = { path = "../expression", version = "${version}" }`);
|
||||
};
|
||||
|
||||
export const getCargoVersion = (contents: string): string => {
|
||||
const t = toml.parse(contents);
|
||||
return t?.package?.version;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {describe} from "node:test";
|
||||
import {expect, test} from "@jest/globals";
|
||||
import {getCargoVersion, updateCargoContents} from "./cargo";
|
||||
import {inc, ReleaseType} from "semver";
|
||||
import * as fs from "fs/promises";
|
||||
import * as path from "path";
|
||||
import { describe } from 'node:test';
|
||||
import { expect, test } from '@jest/globals';
|
||||
import { getCargoVersion, updateCargoContents } from './cargo';
|
||||
import { inc, ReleaseType } from 'semver';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
|
||||
// language=Toml
|
||||
const makeToml = ({version}): string => `
|
||||
const makeToml = ({ version }): string => `
|
||||
[package]
|
||||
authors = ["GoRules Team <bot@gorules.io>"]
|
||||
description = "Business rules engine"
|
||||
@@ -28,37 +28,36 @@ serde_v8 = { version = "0.88.0" }
|
||||
once_cell = { version = "1.17.1" }
|
||||
futures = "0.3.27"
|
||||
v8 = { version = "0.66.0" }
|
||||
zen-parser = { path = "../parser", version = "${version}" }
|
||||
zen-vm = { path = "../vm", version = "${version}" }
|
||||
`
|
||||
zen-expression = { path = "../expression", version = "${version}" }
|
||||
`;
|
||||
|
||||
describe("GitHub Action", () => {
|
||||
test("Bumps package", () => {
|
||||
const version = "0.2.0";
|
||||
const initialToml = makeToml({version});
|
||||
describe('GitHub Action', () => {
|
||||
test('Bumps package', () => {
|
||||
const version = '0.2.0';
|
||||
const initialToml = makeToml({ version });
|
||||
|
||||
const releases: ReleaseType[] = ["major", "minor", "patch"];
|
||||
const releases: ReleaseType[] = ['major', 'minor', 'patch'];
|
||||
for (const release of releases) {
|
||||
const newVersion = inc(version, release);
|
||||
const expectedToml = makeToml({version: newVersion});
|
||||
const expectedToml = makeToml({ version: newVersion });
|
||||
|
||||
expect(updateCargoContents(initialToml, {version: newVersion})).toEqual(expectedToml);
|
||||
expect(updateCargoContents(initialToml, { version: newVersion })).toEqual(expectedToml);
|
||||
}
|
||||
});
|
||||
|
||||
test("Extracts package version", () => {
|
||||
const versions = ["0.1.0", "0.2.0", "0.3.0"];
|
||||
test('Extracts package version', () => {
|
||||
const versions = ['0.1.0', '0.2.0', '0.3.0'];
|
||||
for (const version of versions) {
|
||||
const versionedToml = makeToml({ version });
|
||||
expect(getCargoVersion(versionedToml)).toEqual(version);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
test("Points to right directory", async () => {
|
||||
test('Points to right directory', async () => {
|
||||
const escapeDir = (count: number) => '../'.repeat(count);
|
||||
const coreDirectory = path.join(__dirname, escapeDir(3), 'core');
|
||||
|
||||
const folders = await fs.readdir(coreDirectory);
|
||||
expect(folders).toEqual(expect.arrayContaining(["engine", "parser", "vm"]))
|
||||
expect(folders).toEqual(expect.arrayContaining(['engine', 'expression']));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,8 +3,8 @@ import * as exec from '@actions/exec';
|
||||
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import {inc, ReleaseType} from 'semver';
|
||||
import {getCargoVersion, updateCargoContents} from "./cargo";
|
||||
import { inc, ReleaseType } from 'semver';
|
||||
import { getCargoVersion, updateCargoContents } from './cargo';
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
@@ -16,10 +16,8 @@ async function run() {
|
||||
const project = 'engine';
|
||||
const projectsFolder = 'core';
|
||||
|
||||
const directory = await fs.readdir(path.join(...[workspace, projectsFolder]), {withFileTypes: true});
|
||||
const folders = directory
|
||||
.filter((dirent) => dirent.isDirectory())
|
||||
.map((dirent) => dirent.name);
|
||||
const directory = await fs.readdir(path.join(...[workspace, projectsFolder]), { withFileTypes: true });
|
||||
const folders = directory.filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
||||
|
||||
const cargoFilePath = path.join(...[workspace, projectsFolder, project, 'Cargo.toml']);
|
||||
const cargoFile = await fs.readFile(cargoFilePath, 'utf-8');
|
||||
@@ -33,7 +31,7 @@ async function run() {
|
||||
folders.map(async (folder) => {
|
||||
const cargoFilePath = path.join(...[workspace, projectsFolder, folder, 'Cargo.toml']);
|
||||
const cargoFile = await fs.readFile(cargoFilePath, 'utf-8');
|
||||
const updatedCargoFile = updateCargoContents(cargoFile, {version});
|
||||
const updatedCargoFile = updateCargoContents(cargoFile, { version });
|
||||
|
||||
console.log(`Writing new version to: ${cargoFilePath}`);
|
||||
await fs.writeFile(cargoFilePath, updatedCargoFile);
|
||||
|
||||
@@ -22,7 +22,7 @@ serde_v8 = { version = "0.88.0" }
|
||||
once_cell = { version = "1.17.1" }
|
||||
futures = "0.3.27"
|
||||
v8 = { version = "0.66.0" }
|
||||
zen-vm = { path = "../vm", version = "0.2.1" }
|
||||
zen-expression = { path = "../expression", version = "0.2.1" }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-test = "0.4.2"
|
||||
|
||||
@@ -7,7 +7,7 @@ use serde_json::Value;
|
||||
use crate::handler::node::{NodeRequest, NodeResponse, NodeResult};
|
||||
use crate::handler::table::{RowOutput, RowOutputKind};
|
||||
use crate::model::{DecisionNodeKind, DecisionTableContent, DecisionTableHitPolicy};
|
||||
use zen_vm::isolate::Isolate;
|
||||
use zen_expression::isolate::Isolate;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct RowResult {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
authors = ["GoRules Team <bot@gorules.io>"]
|
||||
description = "Zen expression language virtual machine"
|
||||
name = "zen-vm"
|
||||
description = "Zen Expression Language"
|
||||
name = "zen-expression"
|
||||
license = "MIT"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
@@ -16,15 +16,27 @@ hashbrown = { workspace = true, features = ["bumpalo"] }
|
||||
humantime = { workspace = true }
|
||||
fastrand = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
phf = { workspace = true, features = ["macros"] }
|
||||
serde_json = { workspace = true, features = ["arbitrary_precision"] }
|
||||
thiserror = { workspace = true }
|
||||
rust_decimal = { workspace = true, features = ["maths-nopanic"] }
|
||||
rust_decimal_macros = { workspace = true }
|
||||
zen-parser = { path = "../parser", version = "0.2.1" }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { workspace = true }
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "unary"
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "standard"
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "lexer"
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "isolate"
|
||||
@@ -1,7 +1,7 @@
|
||||
# ZEN VM
|
||||
# ZEN Expression
|
||||
|
||||
Parser for business-first expression language used in
|
||||
Zen business rules engine by GoRules. The language is designed
|
||||
Zen Expression is business-first expression language used in
|
||||
Zen Business rules engine by GoRules. The language is designed
|
||||
to follow these principles:
|
||||
|
||||
- Side-effect free
|
||||
@@ -1,7 +1,7 @@
|
||||
use criterion::{criterion_group, criterion_main, Bencher, Criterion};
|
||||
use serde_json::Value;
|
||||
|
||||
use zen_vm::isolate::Isolate;
|
||||
use zen_expression::isolate::Isolate;
|
||||
|
||||
fn bench_source(b: &mut Bencher, source: &'static str) {
|
||||
let s: Value = serde_json::from_str(r#"{ "$": "ru" }"#).unwrap();
|
||||
@@ -1,6 +1,6 @@
|
||||
use criterion::{criterion_group, criterion_main, Bencher, Criterion};
|
||||
|
||||
use zen_parser::lexer::Lexer;
|
||||
use zen_expression::lexer::Lexer;
|
||||
|
||||
fn bench_source(b: &mut Bencher, source: &'static str) {
|
||||
let lexer = Lexer::new();
|
||||
@@ -1,8 +1,8 @@
|
||||
use bumpalo::Bump;
|
||||
use criterion::{criterion_group, criterion_main, Bencher, Criterion};
|
||||
|
||||
use zen_parser::lexer::Lexer;
|
||||
use zen_parser::parser::StandardParser;
|
||||
use zen_expression::lexer::Lexer;
|
||||
use zen_expression::parser::StandardParser;
|
||||
|
||||
fn bench_source(b: &mut Bencher, src: &'static str) {
|
||||
let lexer = Lexer::new();
|
||||
@@ -1,8 +1,8 @@
|
||||
use bumpalo::Bump;
|
||||
use criterion::{criterion_group, criterion_main, Bencher, Criterion};
|
||||
|
||||
use zen_parser::lexer::Lexer;
|
||||
use zen_parser::parser::UnaryParser;
|
||||
use zen_expression::lexer::Lexer;
|
||||
use zen_expression::parser::UnaryParser;
|
||||
|
||||
fn bench_source(b: &mut Bencher, src: &'static str) {
|
||||
let lexer = Lexer::new();
|
||||
@@ -4,7 +4,7 @@ use std::rc::Rc;
|
||||
use bumpalo::Bump;
|
||||
use thiserror::Error;
|
||||
|
||||
use zen_parser::ast::Node;
|
||||
use crate::ast::Node;
|
||||
|
||||
use crate::compiler::CompilerError::{
|
||||
ArgumentNotFound, UnknownBinaryOperator, UnknownBuiltIn, UnknownUnaryOperator,
|
||||
@@ -10,10 +10,10 @@ use bumpalo::Bump;
|
||||
use serde_json::Value;
|
||||
use thiserror::Error;
|
||||
|
||||
use zen_parser::lexer::error::LexerError;
|
||||
use zen_parser::lexer::Lexer;
|
||||
use zen_parser::parser::error::ParserError;
|
||||
use zen_parser::parser::{StandardParser, UnaryParser};
|
||||
use crate::lexer::error::LexerError;
|
||||
use crate::lexer::Lexer;
|
||||
use crate::parser::error::ParserError;
|
||||
use crate::parser::{StandardParser, UnaryParser};
|
||||
|
||||
use crate::compiler::{Compiler, CompilerError};
|
||||
use crate::opcodes::{ExecResult, Opcode, Variable};
|
||||
@@ -5,7 +5,10 @@ extern crate core;
|
||||
|
||||
mod helpers;
|
||||
|
||||
pub mod ast;
|
||||
pub mod compiler;
|
||||
pub mod isolate;
|
||||
pub mod lexer;
|
||||
pub mod opcodes;
|
||||
pub mod parser;
|
||||
pub mod vm;
|
||||
@@ -2,8 +2,8 @@ use bumpalo::Bump;
|
||||
use rust_decimal_macros::dec;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use zen_vm::isolate::Isolate;
|
||||
use zen_vm::opcodes::{ExecResult, Variable};
|
||||
use zen_expression::isolate::Isolate;
|
||||
use zen_expression::opcodes::{ExecResult, Variable};
|
||||
|
||||
struct TestEnv {
|
||||
env: Value,
|
||||
@@ -1,5 +1,5 @@
|
||||
use zen_parser::lexer::token::{Token, TokenKind};
|
||||
use zen_parser::lexer::Lexer;
|
||||
use zen_expression::lexer::token::{Token, TokenKind};
|
||||
use zen_expression::lexer::Lexer;
|
||||
|
||||
struct LexerTest {
|
||||
test: &'static str,
|
||||
@@ -3,9 +3,9 @@ use rust_decimal::Decimal;
|
||||
|
||||
use rust_decimal_macros::dec;
|
||||
|
||||
use zen_parser::ast::Node;
|
||||
use zen_parser::lexer::Lexer;
|
||||
use zen_parser::parser::StandardParser;
|
||||
use zen_expression::ast::Node;
|
||||
use zen_expression::lexer::Lexer;
|
||||
use zen_expression::parser::StandardParser;
|
||||
|
||||
struct StandardTest {
|
||||
src: &'static str,
|
||||
@@ -2,9 +2,9 @@ use bumpalo::Bump;
|
||||
use rust_decimal::Decimal;
|
||||
use rust_decimal_macros::dec;
|
||||
|
||||
use zen_parser::ast::Node;
|
||||
use zen_parser::lexer::Lexer;
|
||||
use zen_parser::parser::UnaryParser;
|
||||
use zen_expression::ast::Node;
|
||||
use zen_expression::lexer::Lexer;
|
||||
use zen_expression::parser::UnaryParser;
|
||||
|
||||
struct UnaryTest {
|
||||
src: &'static str,
|
||||
@@ -1,32 +0,0 @@
|
||||
[package]
|
||||
authors = ["GoRules Team <bot@gorules.io>"]
|
||||
description = "Zen expression language parser"
|
||||
name = "zen-parser"
|
||||
license = "MIT"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/gorules/zen.git"
|
||||
|
||||
[dependencies]
|
||||
ahash = { workspace = true }
|
||||
bumpalo = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
phf = { workspace = true, features = ["macros"] }
|
||||
thiserror = { workspace = true }
|
||||
rust_decimal = { workspace = true }
|
||||
rust_decimal_macros = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { workspace = true }
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "unary"
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "standard"
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "lexer"
|
||||
@@ -1,71 +0,0 @@
|
||||
# ZEN Parser
|
||||
|
||||
Virtual machine for business-first expression language used in
|
||||
Zen business rules engine by GoRules. The language is designed
|
||||
to follow these principles:
|
||||
|
||||
- Side-effect free
|
||||
- Dynamic types
|
||||
- Simple syntax for broad audiences
|
||||
|
||||
It's primary objective is to bridge the gap between business analysts and engineers,
|
||||
while providing outstanding performance and readability.
|
||||
|
||||
## Resources
|
||||
|
||||
[Documentation](https://gorules.io/docs/)
|
||||
|
||||
[Zen Language Playground](https://gorules.io/docs/rules-engine/expression-language#playground)
|
||||
|
||||
[Online Rules Editor](https://editor.gorules.io/)
|
||||
|
||||
## Unary tests
|
||||
Unary test is a comma-separated list of simple expressions which
|
||||
evaluate to a boolean value. Each comma separation is treated as
|
||||
or operator. Inside unary expressions, a special symbol is available
|
||||
$ which refers to a current column.
|
||||
|
||||
Some examples:
|
||||
```js
|
||||
// Given: $ = 1
|
||||
1, 2, 3 // true
|
||||
1 // true
|
||||
>= 1 // true
|
||||
< 1 // false
|
||||
[0..10] // true, (internally this is $ >= 0 and $ <= 10)
|
||||
> 0 and < 10 // true
|
||||
|
||||
// Given: $ = 'USD'
|
||||
'GBP', 'USD' // true
|
||||
'EUR' // false
|
||||
startsWith($, "US") // true - defaults to expression mode, comma is unavailable
|
||||
endsWith($, "US") // false - defaults to expression mode
|
||||
lower($) == "usd" // true - defaults to expression mode
|
||||
```
|
||||
|
||||
## Standard tests
|
||||
|
||||
Expressions feature full capability syntax of ZEN language.
|
||||
They give you access to all functions, and are most useful when
|
||||
defining columns or outputs. Full syntax is also available in unary
|
||||
expressions when $ is used (as it forces the expression mode).
|
||||
|
||||
```js
|
||||
100 + 100 // 200
|
||||
10 * 5 // 50
|
||||
10 ^ 2 // 100
|
||||
1 in [1, 2, 3] // true
|
||||
5 in (5..10] // false
|
||||
sum([1, 2, 3]) // 6
|
||||
max([1, 2, 3]) // 3
|
||||
|
||||
"hello" + " " + "world" // "hello world"
|
||||
len("world") // 5
|
||||
weekdayString(date("2022-11-08")) // "Tue"
|
||||
contains("hello world", "hello") // true
|
||||
upper('john') // "JOHN"
|
||||
|
||||
some(['admin', 'user'], # == "admin") // true
|
||||
not all([100, 200, 400, 800], # in (100..800)) // false
|
||||
filter([100, 200, 400, 800], # >= 200) // [200, 400, 800]
|
||||
```
|
||||
@@ -1,7 +0,0 @@
|
||||
#![deny(clippy::unwrap_used)]
|
||||
#![deny(clippy::expect_used)]
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
pub mod ast;
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
Reference in New Issue
Block a user