Skip to content

Commit

Permalink
feat: update rule engine
Browse files Browse the repository at this point in the history
  • Loading branch information
thezzisu committed Dec 23, 2024
1 parent 0d9e43e commit c8e8328
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .yarn/versions/a381126e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
releases:
"@aoi-js/frontend": minor
"@aoi-js/rule": minor
"@aoi-js/server": minor
21 changes: 21 additions & 0 deletions libs/rule/src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,27 @@ describe('condition', () => {
assert.equal(evaluateCondition('abc', { $endsWith: 'b' }), false)
assert.equal(evaluateCondition(1, { $endsWith: '1' }), true)
})

it('should work with $includes', () => {
assert.equal(evaluateCondition([1, 2, 3], { $includes: 1 }), true)
assert.equal(evaluateCondition([1, 2, 3], { $includes: 4 }), false)
// @ts-expect-error: invalid condition
assert.equal(evaluateCondition(1, { $includes: 1 }), false)
})

it('should work with $includesEach', () => {
assert.equal(evaluateCondition([1, 2, 3], { $includesEach: [1, 2] }), true)
assert.equal(evaluateCondition([1, 2, 3], { $includesEach: [1, 4] }), false)
// @ts-expect-error: invalid condition
assert.equal(evaluateCondition(1, { $includesEach: [1] }), false)
})

it('should work with $includesSome', () => {
assert.equal(evaluateCondition([1, 2, 3], { $includesSome: [1, 4] }), true)
assert.equal(evaluateCondition([1, 2, 3], { $includesSome: [4, 5] }), false)
// @ts-expect-error: invalid condition
assert.equal(evaluateCondition(1, { $includesSome: [1] }), false)
})
})

describe('matcher', () => {
Expand Down
11 changes: 10 additions & 1 deletion libs/rule/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export function deepGet<T, K extends string>(value: T, key: K): DeepGet<T, K> {
return deepGet(value[cur as keyof T], key.slice(cur.length + 1)) as DeepGet<T, K>
}

export type ElementType<T> = T extends (infer U)[] ? U : never

export class ConditionOps<Value> {
$eq = (value: Value, expected: Value) => value === expected
$ne = (value: Value, expected: Value) => value !== expected
Expand All @@ -41,6 +43,13 @@ export class ConditionOps<Value> {

$startsWith = (value: Value, expected: string) => `${value}`.startsWith(expected)
$endsWith = (value: Value, expected: string) => `${value}`.endsWith(expected)

$includes = (value: Value, expected: ElementType<Value>) =>
Array.isArray(value) && value.includes(expected)
$includesEach = (value: Value, expected: ElementType<Value>[]) =>
Array.isArray(value) && Array.isArray(expected) && expected.every((v) => value.includes(v))
$includesSome = (value: Value, expected: ElementType<Value>[]) =>
Array.isArray(value) && Array.isArray(expected) && expected.some((v) => value.includes(v))
}

const conditionOps = new ConditionOps()
Expand All @@ -53,7 +62,7 @@ export function evaluateCondition<Value>(value: Value, condition: Condition<Valu
for (const opName of Object.getOwnPropertyNames(condition)) {
if (!Object.hasOwn(conditionOps, opName)) throw new Error('Invalid condition')
const op = conditionOps[opName as keyof ConditionOps<Value>]
if (!op(value, condition[opName as keyof Condition<Value>] as any)) return false
if (!op(value, condition[opName as keyof Condition<Value>] as never)) return false
}
return true
}
Expand Down

0 comments on commit c8e8328

Please sign in to comment.