@f-o-t/rules-engine 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +513 -0
- package/dist/index.cjs +3020 -0
- package/dist/index.d.cts +1312 -0
- package/dist/index.d.ts +1312 -0
- package/dist/index.js +2999 -0
- package/package.json +69 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 FOT
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
# @f-o-t/rules-engine
|
|
2
|
+
|
|
3
|
+
A fully type-safe, functional, enterprise-grade rules orchestration engine for TypeScript. Built on top of `@f-o-t/condition-evaluator` for condition evaluation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Type-Safe**: Full TypeScript support with autocomplete for consequences
|
|
8
|
+
- **Functional**: Pure functions, immutable data structures, composable APIs
|
|
9
|
+
- **Fluent Builders**: Chainable rule and condition builders
|
|
10
|
+
- **Caching**: Built-in TTL-based caching with configurable eviction
|
|
11
|
+
- **Validation**: Rule schema validation, conflict detection, integrity checks
|
|
12
|
+
- **Versioning**: Track rule changes with rollback support
|
|
13
|
+
- **Simulation**: Test rules without side effects, compare rule sets
|
|
14
|
+
- **Indexing**: Fast rule lookups by field, tag, category, priority
|
|
15
|
+
- **Analysis**: Rule complexity analysis, usage statistics
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bun add @f-o-t/rules-engine
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { createEngine, rule, all, num, str } from "@f-o-t/rules-engine";
|
|
27
|
+
|
|
28
|
+
// Create an engine
|
|
29
|
+
const engine = createEngine();
|
|
30
|
+
|
|
31
|
+
// Add rules using the fluent builder
|
|
32
|
+
engine.addRule(
|
|
33
|
+
rule()
|
|
34
|
+
.named("Premium Discount")
|
|
35
|
+
.when(
|
|
36
|
+
all(
|
|
37
|
+
num("orderTotal", "gt", 100),
|
|
38
|
+
str("customerType", "eq", "premium")
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
.then("apply_discount", { percentage: 15 })
|
|
42
|
+
.withPriority(100)
|
|
43
|
+
.tagged("pricing", "discount")
|
|
44
|
+
.build()
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Evaluate against context
|
|
48
|
+
const result = await engine.evaluate({
|
|
49
|
+
orderTotal: 150,
|
|
50
|
+
customerType: "premium",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
console.log(result.matchedRules); // Rules that matched
|
|
54
|
+
console.log(result.consequences); // Actions to execute
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Building Conditions
|
|
58
|
+
|
|
59
|
+
### Shorthand Helpers
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { num, str, bool, date, arr, all, any } from "@f-o-t/rules-engine";
|
|
63
|
+
|
|
64
|
+
// Number conditions
|
|
65
|
+
num("amount", "gt", 100) // amount > 100
|
|
66
|
+
num("count", "lte", 10) // count <= 10
|
|
67
|
+
num("price", "eq", 50) // price === 50
|
|
68
|
+
|
|
69
|
+
// String conditions
|
|
70
|
+
str("status", "eq", "active")
|
|
71
|
+
str("name", "contains", "test")
|
|
72
|
+
str("email", "ends_with", "@example.com")
|
|
73
|
+
str("role", "in", ["admin", "moderator"])
|
|
74
|
+
|
|
75
|
+
// Boolean conditions
|
|
76
|
+
bool("isActive", "eq", true)
|
|
77
|
+
|
|
78
|
+
// Date conditions
|
|
79
|
+
date("createdAt", "gt", "2024-01-01")
|
|
80
|
+
date("expiresAt", "between", ["2024-01-01", "2024-12-31"])
|
|
81
|
+
|
|
82
|
+
// Array conditions
|
|
83
|
+
arr("tags", "contains", "urgent")
|
|
84
|
+
arr("items", "is_not_empty", undefined)
|
|
85
|
+
|
|
86
|
+
// Combine with AND/OR
|
|
87
|
+
all(num("amount", "gt", 100), str("status", "eq", "approved"))
|
|
88
|
+
any(bool("isVip", "eq", true), num("orders", "gt", 10))
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Fluent Condition Builder
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { and, or, conditions } from "@f-o-t/rules-engine";
|
|
95
|
+
|
|
96
|
+
// Using and/or with builder function
|
|
97
|
+
const complexCondition = and((c) =>
|
|
98
|
+
c.number("amount", "gt", 100)
|
|
99
|
+
.string("status", "eq", "active")
|
|
100
|
+
.or((nested) =>
|
|
101
|
+
nested.boolean("isVip", "eq", true)
|
|
102
|
+
.number("loyaltyPoints", "gt", 1000)
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Building Rules
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { rule } from "@f-o-t/rules-engine";
|
|
111
|
+
|
|
112
|
+
const myRule = rule()
|
|
113
|
+
.id("rule-001") // Optional custom ID
|
|
114
|
+
.named("My Rule") // Required name
|
|
115
|
+
.describedAs("Rule description") // Optional description
|
|
116
|
+
.when(conditions) // Required conditions
|
|
117
|
+
.then("action_type", { payload: "data" }) // Required consequence(s)
|
|
118
|
+
.then("another_action", {}) // Multiple consequences
|
|
119
|
+
.withPriority(100) // Higher = evaluated first
|
|
120
|
+
.enabled() // Enabled by default
|
|
121
|
+
.stopOnMatch() // Stop evaluation on match
|
|
122
|
+
.tagged("tag1", "tag2") // Categorization tags
|
|
123
|
+
.inCategory("pricing") // Single category
|
|
124
|
+
.withMetadata({ custom: "data" }) // Custom metadata
|
|
125
|
+
.build();
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Engine API
|
|
129
|
+
|
|
130
|
+
### Rule Management
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const engine = createEngine();
|
|
134
|
+
|
|
135
|
+
// Add rules
|
|
136
|
+
const addedRule = engine.addRule(ruleInput);
|
|
137
|
+
const addedRules = engine.addRules([rule1, rule2]);
|
|
138
|
+
|
|
139
|
+
// Get rules
|
|
140
|
+
const singleRule = engine.getRule("rule-id");
|
|
141
|
+
const allRules = engine.getRules();
|
|
142
|
+
const filteredRules = engine.getRules({
|
|
143
|
+
enabled: true,
|
|
144
|
+
tags: ["pricing"],
|
|
145
|
+
category: "discounts",
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Update rules
|
|
149
|
+
engine.updateRule("rule-id", { priority: 200 });
|
|
150
|
+
engine.enableRule("rule-id");
|
|
151
|
+
engine.disableRule("rule-id");
|
|
152
|
+
|
|
153
|
+
// Remove rules
|
|
154
|
+
engine.removeRule("rule-id");
|
|
155
|
+
engine.clearRules();
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Evaluation
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const result = await engine.evaluate(context, {
|
|
162
|
+
skipDisabled: true, // Skip disabled rules (default: true)
|
|
163
|
+
bypassCache: false, // Bypass cache (default: false)
|
|
164
|
+
maxRules: 100, // Limit rules evaluated
|
|
165
|
+
tags: ["pricing"], // Filter by tags
|
|
166
|
+
category: "discounts", // Filter by category
|
|
167
|
+
ruleSetId: "set-001", // Use specific rule set
|
|
168
|
+
conflictResolution: "all", // "all" | "first-match" | "highest-priority"
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Result structure
|
|
172
|
+
result.matchedRules // Rules that matched
|
|
173
|
+
result.consequences // Aggregated consequences
|
|
174
|
+
result.totalRulesEvaluated // Count of rules evaluated
|
|
175
|
+
result.totalRulesMatched // Count of matches
|
|
176
|
+
result.executionTimeMs // Execution time
|
|
177
|
+
result.cacheHit // Whether result was cached
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Rule Sets
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// Group rules into sets
|
|
184
|
+
engine.addRuleSet({
|
|
185
|
+
name: "Holiday Promotions",
|
|
186
|
+
ruleIds: ["rule-1", "rule-2", "rule-3"],
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Evaluate only rules in a set
|
|
190
|
+
await engine.evaluate(context, { ruleSetId: "set-id" });
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Engine Configuration
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { createEngine } from "@f-o-t/rules-engine";
|
|
197
|
+
import { z } from "zod";
|
|
198
|
+
|
|
199
|
+
const engine = createEngine({
|
|
200
|
+
// Type-safe consequence definitions
|
|
201
|
+
consequences: {
|
|
202
|
+
apply_discount: z.object({ percentage: z.number() }),
|
|
203
|
+
send_email: z.object({ template: z.string(), to: z.string() }),
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
// Cache configuration
|
|
207
|
+
cache: {
|
|
208
|
+
enabled: true,
|
|
209
|
+
ttl: 60000, // 1 minute
|
|
210
|
+
maxSize: 1000,
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
// Conflict resolution
|
|
214
|
+
conflictResolution: "all", // "all" | "first-match" | "highest-priority"
|
|
215
|
+
|
|
216
|
+
// Error handling
|
|
217
|
+
continueOnError: true,
|
|
218
|
+
|
|
219
|
+
// Performance monitoring
|
|
220
|
+
slowRuleThresholdMs: 100,
|
|
221
|
+
|
|
222
|
+
// Lifecycle hooks
|
|
223
|
+
hooks: {
|
|
224
|
+
onBeforeEvaluation: async (context, rules) => {},
|
|
225
|
+
onAfterEvaluation: async (result) => {},
|
|
226
|
+
onRuleMatch: async (rule, context) => {},
|
|
227
|
+
onRuleError: async (rule, error) => {},
|
|
228
|
+
onCacheHit: async (key, result) => {},
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Validation
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import {
|
|
237
|
+
validateRule,
|
|
238
|
+
detectConflicts,
|
|
239
|
+
checkIntegrity,
|
|
240
|
+
} from "@f-o-t/rules-engine";
|
|
241
|
+
|
|
242
|
+
// Validate single rule
|
|
243
|
+
const validation = validateRule(rule);
|
|
244
|
+
if (!validation.valid) {
|
|
245
|
+
console.log(validation.errors);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Detect conflicts between rules
|
|
249
|
+
const conflicts = detectConflicts(rules);
|
|
250
|
+
// Types: DUPLICATE_ID, DUPLICATE_CONDITIONS, OVERLAPPING_CONDITIONS,
|
|
251
|
+
// PRIORITY_COLLISION, UNREACHABLE_RULE
|
|
252
|
+
|
|
253
|
+
// Check rule set integrity
|
|
254
|
+
const integrity = checkIntegrity(rules);
|
|
255
|
+
// Checks: negative priority, missing fields, invalid operators
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Simulation
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { simulate, whatIf, batchSimulate } from "@f-o-t/rules-engine";
|
|
262
|
+
|
|
263
|
+
// Simulate without side effects
|
|
264
|
+
const result = simulate(rules, { data: context });
|
|
265
|
+
|
|
266
|
+
// Compare two rule sets
|
|
267
|
+
const comparison = whatIf(originalRules, modifiedRules, { data: context });
|
|
268
|
+
console.log(comparison.differences.newMatches);
|
|
269
|
+
console.log(comparison.differences.lostMatches);
|
|
270
|
+
console.log(comparison.differences.consequenceChanges);
|
|
271
|
+
|
|
272
|
+
// Test multiple contexts
|
|
273
|
+
const batchResults = batchSimulate(rules, [
|
|
274
|
+
{ data: { amount: 50 } },
|
|
275
|
+
{ data: { amount: 150 } },
|
|
276
|
+
{ data: { amount: 500 } },
|
|
277
|
+
]);
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Versioning
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
import {
|
|
284
|
+
createVersionStore,
|
|
285
|
+
addVersion,
|
|
286
|
+
getHistory,
|
|
287
|
+
rollbackToVersion,
|
|
288
|
+
} from "@f-o-t/rules-engine";
|
|
289
|
+
|
|
290
|
+
let store = createVersionStore();
|
|
291
|
+
|
|
292
|
+
// Track changes
|
|
293
|
+
store = addVersion(store, rule, "create", { comment: "Initial version" });
|
|
294
|
+
store = addVersion(store, updatedRule, "update", { comment: "Increased priority" });
|
|
295
|
+
|
|
296
|
+
// Get history
|
|
297
|
+
const history = getHistory(store, rule.id);
|
|
298
|
+
|
|
299
|
+
// Rollback
|
|
300
|
+
const { store: newStore, rule: restoredRule } = rollbackToVersion(
|
|
301
|
+
store,
|
|
302
|
+
rule.id,
|
|
303
|
+
1 // version number
|
|
304
|
+
);
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Indexing & Optimization
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
import {
|
|
311
|
+
buildIndex,
|
|
312
|
+
getRulesByField,
|
|
313
|
+
getRulesByTag,
|
|
314
|
+
analyzeOptimizations,
|
|
315
|
+
} from "@f-o-t/rules-engine";
|
|
316
|
+
|
|
317
|
+
// Build index for fast lookups
|
|
318
|
+
const index = buildIndex(rules);
|
|
319
|
+
|
|
320
|
+
// Query by field
|
|
321
|
+
const amountRules = getRulesByField(index, "amount");
|
|
322
|
+
|
|
323
|
+
// Query by tag
|
|
324
|
+
const pricingRules = getRulesByTag(index, "pricing");
|
|
325
|
+
|
|
326
|
+
// Get optimization suggestions
|
|
327
|
+
const suggestions = analyzeOptimizations(rules);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Analysis
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
import {
|
|
334
|
+
analyzeRuleSet,
|
|
335
|
+
analyzeRuleComplexity,
|
|
336
|
+
findMostComplexRules,
|
|
337
|
+
} from "@f-o-t/rules-engine";
|
|
338
|
+
|
|
339
|
+
// Analyze entire rule set
|
|
340
|
+
const analysis = analyzeRuleSet(rules);
|
|
341
|
+
console.log(analysis.ruleCount);
|
|
342
|
+
console.log(analysis.uniqueFields);
|
|
343
|
+
console.log(analysis.uniqueCategories);
|
|
344
|
+
console.log(analysis.fieldUsage);
|
|
345
|
+
console.log(analysis.operatorUsage);
|
|
346
|
+
|
|
347
|
+
// Find complex rules
|
|
348
|
+
const complexRules = findMostComplexRules(rules, 5);
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Serialization
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
import {
|
|
355
|
+
exportToJson,
|
|
356
|
+
importFromJson,
|
|
357
|
+
cloneRule,
|
|
358
|
+
mergeRuleSets,
|
|
359
|
+
diffRuleSets,
|
|
360
|
+
} from "@f-o-t/rules-engine";
|
|
361
|
+
|
|
362
|
+
// Export/Import
|
|
363
|
+
const json = exportToJson(rules);
|
|
364
|
+
const { success, rules: imported } = importFromJson(json, {
|
|
365
|
+
generateNewIds: true, // Generate new IDs on import
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// Clone rule
|
|
369
|
+
const cloned = cloneRule(rule, { generateNewId: true });
|
|
370
|
+
|
|
371
|
+
// Merge rule sets
|
|
372
|
+
const merged = mergeRuleSets(rulesA, rulesB, {
|
|
373
|
+
onConflict: "keep-first", // "keep-first" | "keep-second" | "keep-both"
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Diff rule sets
|
|
377
|
+
const diff = diffRuleSets(rulesA, rulesB);
|
|
378
|
+
console.log(diff.added);
|
|
379
|
+
console.log(diff.removed);
|
|
380
|
+
console.log(diff.modified);
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Filtering, Sorting & Grouping
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
import {
|
|
387
|
+
filterRules,
|
|
388
|
+
filterByTags,
|
|
389
|
+
filterByCategory,
|
|
390
|
+
filterByEnabled,
|
|
391
|
+
sortRules,
|
|
392
|
+
sortByPriority,
|
|
393
|
+
sortByName,
|
|
394
|
+
sortByCreatedAt,
|
|
395
|
+
groupRules,
|
|
396
|
+
groupByCategory,
|
|
397
|
+
groupByPriority,
|
|
398
|
+
groupByEnabled,
|
|
399
|
+
} from "@f-o-t/rules-engine";
|
|
400
|
+
|
|
401
|
+
// Filter rules
|
|
402
|
+
const activeRules = filterByEnabled(rules, true);
|
|
403
|
+
const pricingRules = filterByTags(rules, ["pricing"]);
|
|
404
|
+
const discountRules = filterByCategory(rules, "discounts");
|
|
405
|
+
|
|
406
|
+
// Combined filters
|
|
407
|
+
const filtered = filterRules(rules, {
|
|
408
|
+
enabled: true,
|
|
409
|
+
tags: ["pricing"],
|
|
410
|
+
category: "discounts",
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// Sort rules
|
|
414
|
+
const byPriority = sortByPriority(rules, "desc"); // Highest first
|
|
415
|
+
const byName = sortByName(rules, "asc");
|
|
416
|
+
const byDate = sortByCreatedAt(rules, "desc");
|
|
417
|
+
|
|
418
|
+
// Custom sort
|
|
419
|
+
const sorted = sortRules(rules, { field: "priority", direction: "desc" });
|
|
420
|
+
|
|
421
|
+
// Group rules
|
|
422
|
+
const byCategory = groupByCategory(rules);
|
|
423
|
+
const byPriorityLevel = groupByPriority(rules);
|
|
424
|
+
const byStatus = groupByEnabled(rules);
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
## Utilities
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import {
|
|
431
|
+
generateId,
|
|
432
|
+
hashContext,
|
|
433
|
+
hashRules,
|
|
434
|
+
pipe,
|
|
435
|
+
compose,
|
|
436
|
+
identity,
|
|
437
|
+
always,
|
|
438
|
+
tap,
|
|
439
|
+
measureTime,
|
|
440
|
+
measureTimeAsync,
|
|
441
|
+
withTimeout,
|
|
442
|
+
delay,
|
|
443
|
+
} from "@f-o-t/rules-engine";
|
|
444
|
+
|
|
445
|
+
// Generate unique IDs
|
|
446
|
+
const id = generateId();
|
|
447
|
+
|
|
448
|
+
// Hash context for caching
|
|
449
|
+
const hash = hashContext({ amount: 100 });
|
|
450
|
+
|
|
451
|
+
// Functional composition
|
|
452
|
+
const process = pipe(
|
|
453
|
+
(rules) => filterRules(rules, { enabled: true }),
|
|
454
|
+
(rules) => sortByPriority(rules, "desc"),
|
|
455
|
+
(rules) => rules.slice(0, 10)
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
// Measure execution time
|
|
459
|
+
const { result, durationMs } = measureTime(() => expensiveOperation());
|
|
460
|
+
|
|
461
|
+
// Async timing
|
|
462
|
+
const { result: asyncResult, durationMs: asyncTime } = await measureTimeAsync(
|
|
463
|
+
() => fetchData()
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
// Timeout wrapper
|
|
467
|
+
const resultWithTimeout = await withTimeout(
|
|
468
|
+
() => slowOperation(),
|
|
469
|
+
5000 // 5 second timeout
|
|
470
|
+
);
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
## State Management (Functional API)
|
|
474
|
+
|
|
475
|
+
For functional programming without the engine wrapper:
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
import {
|
|
479
|
+
createInitialState,
|
|
480
|
+
addRule,
|
|
481
|
+
addRules,
|
|
482
|
+
updateRule,
|
|
483
|
+
removeRule,
|
|
484
|
+
getRule,
|
|
485
|
+
getRules,
|
|
486
|
+
enableRule,
|
|
487
|
+
disableRule,
|
|
488
|
+
cloneState,
|
|
489
|
+
} from "@f-o-t/rules-engine";
|
|
490
|
+
|
|
491
|
+
// Create initial state
|
|
492
|
+
let state = createInitialState();
|
|
493
|
+
|
|
494
|
+
// Add rules (returns new state)
|
|
495
|
+
state = addRule(state, ruleInput);
|
|
496
|
+
state = addRules(state, [rule1, rule2]);
|
|
497
|
+
|
|
498
|
+
// Query rules
|
|
499
|
+
const rule = getRule(state, "rule-id");
|
|
500
|
+
const allRules = getRules(state);
|
|
501
|
+
|
|
502
|
+
// Update rules
|
|
503
|
+
state = updateRule(state, "rule-id", { priority: 200 });
|
|
504
|
+
state = enableRule(state, "rule-id");
|
|
505
|
+
state = disableRule(state, "rule-id");
|
|
506
|
+
|
|
507
|
+
// Clone state for comparison
|
|
508
|
+
const clonedState = cloneState(state);
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
## License
|
|
512
|
+
|
|
513
|
+
MIT
|