@f-o-t/rules-engine 1.0.0 → 2.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/README.md +78 -20
- package/dist/index.cjs +287 -218
- package/dist/index.d.cts +191 -186
- package/dist/index.d.ts +191 -186
- package/dist/index.js +292 -218
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
ConditionGroup,
|
|
4
|
+
isConditionGroup as isConditionGroup6
|
|
5
|
+
} from "@f-o-t/condition-evaluator";
|
|
6
|
+
|
|
1
7
|
// src/analyzer/analysis.ts
|
|
8
|
+
import {
|
|
9
|
+
isConditionGroup as isConditionGroup2
|
|
10
|
+
} from "@f-o-t/condition-evaluator";
|
|
11
|
+
|
|
12
|
+
// src/utils/conditions.ts
|
|
2
13
|
import {
|
|
3
14
|
isConditionGroup
|
|
4
15
|
} from "@f-o-t/condition-evaluator";
|
|
16
|
+
var collectConditionFields = (condition) => {
|
|
17
|
+
const fields = new Set;
|
|
18
|
+
const traverse = (c) => {
|
|
19
|
+
if (isConditionGroup(c)) {
|
|
20
|
+
for (const child of c.conditions) {
|
|
21
|
+
traverse(child);
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
fields.add(c.field);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
traverse(condition);
|
|
28
|
+
return fields;
|
|
29
|
+
};
|
|
5
30
|
var countConditions = (condition) => {
|
|
6
31
|
if (isConditionGroup(condition)) {
|
|
7
32
|
return condition.conditions.reduce((sum, c) => sum + countConditions(c), 0);
|
|
@@ -16,30 +41,18 @@ var calculateMaxDepth = (condition, currentDepth = 1) => {
|
|
|
16
41
|
}
|
|
17
42
|
return currentDepth;
|
|
18
43
|
};
|
|
19
|
-
var
|
|
44
|
+
var countConditionGroups = (condition) => {
|
|
20
45
|
if (isConditionGroup(condition)) {
|
|
21
|
-
return 1 + condition.conditions.reduce((sum, c) => sum +
|
|
46
|
+
return 1 + condition.conditions.reduce((sum, c) => sum + countConditionGroups(c), 0);
|
|
22
47
|
}
|
|
23
48
|
return 0;
|
|
24
49
|
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const traverse = (c) => {
|
|
28
|
-
if (isConditionGroup(c)) {
|
|
29
|
-
for (const child of c.conditions) {
|
|
30
|
-
traverse(child);
|
|
31
|
-
}
|
|
32
|
-
} else {
|
|
33
|
-
fields.add(c.field);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
traverse(condition);
|
|
37
|
-
return fields;
|
|
38
|
-
};
|
|
50
|
+
|
|
51
|
+
// src/analyzer/analysis.ts
|
|
39
52
|
var collectOperators = (condition) => {
|
|
40
53
|
const operators = new Set;
|
|
41
54
|
const traverse = (c) => {
|
|
42
|
-
if (
|
|
55
|
+
if (isConditionGroup2(c)) {
|
|
43
56
|
operators.add(c.operator);
|
|
44
57
|
for (const child of c.conditions) {
|
|
45
58
|
traverse(child);
|
|
@@ -57,8 +70,8 @@ var calculateComplexityScore = (totalConditions, maxDepth, groupCount, uniqueFie
|
|
|
57
70
|
var analyzeRuleComplexity = (rule) => {
|
|
58
71
|
const totalConditions = countConditions(rule.conditions);
|
|
59
72
|
const maxDepth = calculateMaxDepth(rule.conditions);
|
|
60
|
-
const groupCount =
|
|
61
|
-
const uniqueFields =
|
|
73
|
+
const groupCount = countConditionGroups(rule.conditions);
|
|
74
|
+
const uniqueFields = collectConditionFields(rule.conditions).size;
|
|
62
75
|
const uniqueOperators = collectOperators(rule.conditions).size;
|
|
63
76
|
const consequenceCount = rule.consequences.length;
|
|
64
77
|
const complexityScore = calculateComplexityScore(totalConditions, maxDepth, groupCount, uniqueFields);
|
|
@@ -95,7 +108,7 @@ var analyzeRuleSet = (rules) => {
|
|
|
95
108
|
maxPriority = rule.priority;
|
|
96
109
|
if (rule.enabled)
|
|
97
110
|
enabledCount++;
|
|
98
|
-
for (const field of
|
|
111
|
+
for (const field of collectConditionFields(rule.conditions)) {
|
|
99
112
|
allFields.add(field);
|
|
100
113
|
}
|
|
101
114
|
for (const operator of collectOperators(rule.conditions)) {
|
|
@@ -139,7 +152,7 @@ var analyzeFieldUsage = (rules) => {
|
|
|
139
152
|
const fieldMap = new Map;
|
|
140
153
|
for (const rule of rules) {
|
|
141
154
|
const traverse = (c) => {
|
|
142
|
-
if (
|
|
155
|
+
if (isConditionGroup2(c)) {
|
|
143
156
|
for (const child of c.conditions) {
|
|
144
157
|
traverse(child);
|
|
145
158
|
}
|
|
@@ -171,7 +184,7 @@ var analyzeOperatorUsage = (rules) => {
|
|
|
171
184
|
const operatorMap = new Map;
|
|
172
185
|
for (const rule of rules) {
|
|
173
186
|
const traverse = (c) => {
|
|
174
|
-
if (
|
|
187
|
+
if (isConditionGroup2(c)) {
|
|
175
188
|
for (const child of c.conditions) {
|
|
176
189
|
traverse(child);
|
|
177
190
|
}
|
|
@@ -189,12 +202,15 @@ var analyzeOperatorUsage = (rules) => {
|
|
|
189
202
|
};
|
|
190
203
|
traverse(rule.conditions);
|
|
191
204
|
}
|
|
192
|
-
return [...operatorMap.entries()].map(([key, data]) =>
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
205
|
+
return [...operatorMap.entries()].map(([key, data]) => {
|
|
206
|
+
const parts = key.split(":");
|
|
207
|
+
return {
|
|
208
|
+
operator: parts[1] ?? "",
|
|
209
|
+
type: data.type,
|
|
210
|
+
count: data.rules.length,
|
|
211
|
+
rules: data.rules
|
|
212
|
+
};
|
|
213
|
+
}).sort((a, b) => b.count - a.count);
|
|
198
214
|
};
|
|
199
215
|
var analyzeConsequenceUsage = (rules) => {
|
|
200
216
|
const consequenceMap = new Map;
|
|
@@ -483,15 +499,8 @@ var createCache = (options) => {
|
|
|
483
499
|
const evictOldest = () => {
|
|
484
500
|
if (entries.size === 0)
|
|
485
501
|
return;
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
for (const [key, entry] of entries) {
|
|
489
|
-
if (entry.createdAt < oldestTime) {
|
|
490
|
-
oldestTime = entry.createdAt;
|
|
491
|
-
oldestKey = key;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
if (oldestKey) {
|
|
502
|
+
const oldestKey = entries.keys().next().value;
|
|
503
|
+
if (oldestKey !== undefined) {
|
|
495
504
|
const entry = entries.get(oldestKey);
|
|
496
505
|
entries.delete(oldestKey);
|
|
497
506
|
evictions++;
|
|
@@ -618,9 +627,6 @@ var withTimeout = (promise, timeoutMs, errorMessage = "Operation timed out") =>
|
|
|
618
627
|
});
|
|
619
628
|
});
|
|
620
629
|
};
|
|
621
|
-
var delay = (ms) => {
|
|
622
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
623
|
-
};
|
|
624
630
|
|
|
625
631
|
// src/core/evaluate.ts
|
|
626
632
|
var evaluateRule = (rule2, context, options = {}) => {
|
|
@@ -854,30 +860,67 @@ var sortByUpdatedAt = (direction = "desc") => {
|
|
|
854
860
|
return sortRules({ field: "updatedAt", direction });
|
|
855
861
|
};
|
|
856
862
|
// src/types/config.ts
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
};
|
|
870
|
-
var
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
};
|
|
863
|
+
import { z } from "zod";
|
|
864
|
+
var LogLevelSchema = z.enum([
|
|
865
|
+
"none",
|
|
866
|
+
"error",
|
|
867
|
+
"warn",
|
|
868
|
+
"info",
|
|
869
|
+
"debug"
|
|
870
|
+
]);
|
|
871
|
+
var CacheConfigSchema = z.object({
|
|
872
|
+
enabled: z.boolean().default(true),
|
|
873
|
+
ttl: z.number().int().positive().default(60000),
|
|
874
|
+
maxSize: z.number().int().positive().default(1000)
|
|
875
|
+
});
|
|
876
|
+
var ValidationConfigSchema = z.object({
|
|
877
|
+
enabled: z.boolean().default(true),
|
|
878
|
+
strict: z.boolean().default(false)
|
|
879
|
+
});
|
|
880
|
+
var VersioningConfigSchema = z.object({
|
|
881
|
+
enabled: z.boolean().default(false),
|
|
882
|
+
maxVersions: z.number().int().positive().default(10)
|
|
883
|
+
});
|
|
884
|
+
var parseCacheConfig = (input) => CacheConfigSchema.parse(input ?? {});
|
|
885
|
+
var parseValidationConfig = (input) => ValidationConfigSchema.parse(input ?? {});
|
|
886
|
+
var parseVersioningConfig = (input) => VersioningConfigSchema.parse(input ?? {});
|
|
887
|
+
var getDefaultCacheConfig = () => CacheConfigSchema.parse({});
|
|
888
|
+
var getDefaultValidationConfig = () => ValidationConfigSchema.parse({});
|
|
889
|
+
var getDefaultVersioningConfig = () => VersioningConfigSchema.parse({});
|
|
890
|
+
var getDefaultLogLevel = () => "warn";
|
|
891
|
+
var getDefaultConflictResolution = () => "priority";
|
|
879
892
|
|
|
880
893
|
// src/types/state.ts
|
|
894
|
+
import { z as z2 } from "zod";
|
|
895
|
+
var RuleStatsSchema = z2.object({
|
|
896
|
+
evaluations: z2.number().int().nonnegative(),
|
|
897
|
+
matches: z2.number().int().nonnegative(),
|
|
898
|
+
errors: z2.number().int().nonnegative(),
|
|
899
|
+
totalTimeMs: z2.number().nonnegative(),
|
|
900
|
+
avgTimeMs: z2.number().nonnegative(),
|
|
901
|
+
lastEvaluated: z2.date().optional()
|
|
902
|
+
});
|
|
903
|
+
var CacheStatsSchema = z2.object({
|
|
904
|
+
size: z2.number().int().nonnegative(),
|
|
905
|
+
maxSize: z2.number().int().positive(),
|
|
906
|
+
hits: z2.number().int().nonnegative(),
|
|
907
|
+
misses: z2.number().int().nonnegative(),
|
|
908
|
+
hitRate: z2.number().min(0).max(1),
|
|
909
|
+
evictions: z2.number().int().nonnegative()
|
|
910
|
+
});
|
|
911
|
+
var EngineStatsSchema = z2.object({
|
|
912
|
+
totalRules: z2.number().int().nonnegative(),
|
|
913
|
+
enabledRules: z2.number().int().nonnegative(),
|
|
914
|
+
disabledRules: z2.number().int().nonnegative(),
|
|
915
|
+
totalRuleSets: z2.number().int().nonnegative(),
|
|
916
|
+
totalEvaluations: z2.number().int().nonnegative(),
|
|
917
|
+
totalMatches: z2.number().int().nonnegative(),
|
|
918
|
+
totalErrors: z2.number().int().nonnegative(),
|
|
919
|
+
avgEvaluationTimeMs: z2.number().nonnegative(),
|
|
920
|
+
cacheHits: z2.number().int().nonnegative(),
|
|
921
|
+
cacheMisses: z2.number().int().nonnegative(),
|
|
922
|
+
cacheHitRate: z2.number().min(0).max(1)
|
|
923
|
+
});
|
|
881
924
|
var createInitialState = () => ({
|
|
882
925
|
rules: new Map,
|
|
883
926
|
ruleSets: new Map,
|
|
@@ -934,82 +977,73 @@ var generateId = () => {
|
|
|
934
977
|
};
|
|
935
978
|
|
|
936
979
|
// src/engine/hooks.ts
|
|
937
|
-
var
|
|
980
|
+
var toError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
981
|
+
var executeWithTimeout = async (hookName, hookFn, hooks, timeoutMs) => {
|
|
982
|
+
try {
|
|
983
|
+
const promise = Promise.resolve(hookFn());
|
|
984
|
+
if (timeoutMs !== undefined && timeoutMs > 0) {
|
|
985
|
+
await withTimeout(promise, timeoutMs, `Hook '${hookName}' timed out after ${timeoutMs}ms`);
|
|
986
|
+
} else {
|
|
987
|
+
await promise;
|
|
988
|
+
}
|
|
989
|
+
} catch (error) {
|
|
990
|
+
hooks.onHookError?.(hookName, toError(error));
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
var executeBeforeEvaluation = async (hooks, context, rules, timeoutMs) => {
|
|
938
994
|
if (!hooks.beforeEvaluation)
|
|
939
995
|
return;
|
|
940
|
-
|
|
941
|
-
await hooks.beforeEvaluation(context, rules);
|
|
942
|
-
} catch {}
|
|
996
|
+
await executeWithTimeout("beforeEvaluation", () => hooks.beforeEvaluation(context, rules), hooks, timeoutMs);
|
|
943
997
|
};
|
|
944
|
-
var executeAfterEvaluation = async (hooks, result) => {
|
|
998
|
+
var executeAfterEvaluation = async (hooks, result, timeoutMs) => {
|
|
945
999
|
if (!hooks.afterEvaluation)
|
|
946
1000
|
return;
|
|
947
|
-
|
|
948
|
-
await hooks.afterEvaluation(result);
|
|
949
|
-
} catch {}
|
|
1001
|
+
await executeWithTimeout("afterEvaluation", () => hooks.afterEvaluation(result), hooks, timeoutMs);
|
|
950
1002
|
};
|
|
951
|
-
var executeBeforeRuleEvaluation = async (hooks, rule2, context) => {
|
|
1003
|
+
var executeBeforeRuleEvaluation = async (hooks, rule2, context, timeoutMs) => {
|
|
952
1004
|
if (!hooks.beforeRuleEvaluation)
|
|
953
1005
|
return;
|
|
954
|
-
|
|
955
|
-
await hooks.beforeRuleEvaluation(rule2, context);
|
|
956
|
-
} catch {}
|
|
1006
|
+
await executeWithTimeout("beforeRuleEvaluation", () => hooks.beforeRuleEvaluation(rule2, context), hooks, timeoutMs);
|
|
957
1007
|
};
|
|
958
|
-
var executeAfterRuleEvaluation = async (hooks, rule2, result) => {
|
|
1008
|
+
var executeAfterRuleEvaluation = async (hooks, rule2, result, timeoutMs) => {
|
|
959
1009
|
if (!hooks.afterRuleEvaluation)
|
|
960
1010
|
return;
|
|
961
|
-
|
|
962
|
-
await hooks.afterRuleEvaluation(rule2, result);
|
|
963
|
-
} catch {}
|
|
1011
|
+
await executeWithTimeout("afterRuleEvaluation", () => hooks.afterRuleEvaluation(rule2, result), hooks, timeoutMs);
|
|
964
1012
|
};
|
|
965
|
-
var executeOnRuleMatch = async (hooks, rule2, context) => {
|
|
1013
|
+
var executeOnRuleMatch = async (hooks, rule2, context, timeoutMs) => {
|
|
966
1014
|
if (!hooks.onRuleMatch)
|
|
967
1015
|
return;
|
|
968
|
-
|
|
969
|
-
await hooks.onRuleMatch(rule2, context);
|
|
970
|
-
} catch {}
|
|
1016
|
+
await executeWithTimeout("onRuleMatch", () => hooks.onRuleMatch(rule2, context), hooks, timeoutMs);
|
|
971
1017
|
};
|
|
972
|
-
var executeOnRuleSkip = async (hooks, rule2, reason) => {
|
|
1018
|
+
var executeOnRuleSkip = async (hooks, rule2, reason, timeoutMs) => {
|
|
973
1019
|
if (!hooks.onRuleSkip)
|
|
974
1020
|
return;
|
|
975
|
-
|
|
976
|
-
await hooks.onRuleSkip(rule2, reason);
|
|
977
|
-
} catch {}
|
|
1021
|
+
await executeWithTimeout("onRuleSkip", () => hooks.onRuleSkip(rule2, reason), hooks, timeoutMs);
|
|
978
1022
|
};
|
|
979
|
-
var executeOnRuleError = async (hooks, rule2,
|
|
1023
|
+
var executeOnRuleError = async (hooks, rule2, ruleError, timeoutMs) => {
|
|
980
1024
|
if (!hooks.onRuleError)
|
|
981
1025
|
return;
|
|
982
|
-
|
|
983
|
-
await hooks.onRuleError(rule2, error);
|
|
984
|
-
} catch {}
|
|
1026
|
+
await executeWithTimeout("onRuleError", () => hooks.onRuleError(rule2, ruleError), hooks, timeoutMs);
|
|
985
1027
|
};
|
|
986
|
-
var executeOnConsequenceCollected = async (hooks, rule2, consequence) => {
|
|
1028
|
+
var executeOnConsequenceCollected = async (hooks, rule2, consequence, timeoutMs) => {
|
|
987
1029
|
if (!hooks.onConsequenceCollected)
|
|
988
1030
|
return;
|
|
989
|
-
|
|
990
|
-
await hooks.onConsequenceCollected(rule2, consequence);
|
|
991
|
-
} catch {}
|
|
1031
|
+
await executeWithTimeout("onConsequenceCollected", () => hooks.onConsequenceCollected(rule2, consequence), hooks, timeoutMs);
|
|
992
1032
|
};
|
|
993
|
-
var executeOnCacheHit = async (hooks, key, result) => {
|
|
1033
|
+
var executeOnCacheHit = async (hooks, key, result, timeoutMs) => {
|
|
994
1034
|
if (!hooks.onCacheHit)
|
|
995
1035
|
return;
|
|
996
|
-
|
|
997
|
-
await hooks.onCacheHit(key, result);
|
|
998
|
-
} catch {}
|
|
1036
|
+
await executeWithTimeout("onCacheHit", () => hooks.onCacheHit(key, result), hooks, timeoutMs);
|
|
999
1037
|
};
|
|
1000
|
-
var executeOnCacheMiss = async (hooks, key) => {
|
|
1038
|
+
var executeOnCacheMiss = async (hooks, key, timeoutMs) => {
|
|
1001
1039
|
if (!hooks.onCacheMiss)
|
|
1002
1040
|
return;
|
|
1003
|
-
|
|
1004
|
-
await hooks.onCacheMiss(key);
|
|
1005
|
-
} catch {}
|
|
1041
|
+
await executeWithTimeout("onCacheMiss", () => hooks.onCacheMiss(key), hooks, timeoutMs);
|
|
1006
1042
|
};
|
|
1007
|
-
var executeOnSlowRule = async (hooks, rule2, timeMs, threshold) => {
|
|
1043
|
+
var executeOnSlowRule = async (hooks, rule2, timeMs, threshold, timeoutMs) => {
|
|
1008
1044
|
if (!hooks.onSlowRule)
|
|
1009
1045
|
return;
|
|
1010
|
-
|
|
1011
|
-
await hooks.onSlowRule(rule2, timeMs, threshold);
|
|
1012
|
-
} catch {}
|
|
1046
|
+
await executeWithTimeout("onSlowRule", () => hooks.onSlowRule(rule2, timeMs, threshold), hooks, timeoutMs);
|
|
1013
1047
|
};
|
|
1014
1048
|
|
|
1015
1049
|
// src/engine/state.ts
|
|
@@ -1194,24 +1228,25 @@ var cloneState = (state) => {
|
|
|
1194
1228
|
var resolveConfig = (config) => {
|
|
1195
1229
|
return {
|
|
1196
1230
|
consequences: config.consequences,
|
|
1197
|
-
conflictResolution: config.conflictResolution ??
|
|
1231
|
+
conflictResolution: config.conflictResolution ?? getDefaultConflictResolution(),
|
|
1198
1232
|
cache: {
|
|
1199
|
-
...
|
|
1233
|
+
...getDefaultCacheConfig(),
|
|
1200
1234
|
...config.cache
|
|
1201
1235
|
},
|
|
1202
1236
|
validation: {
|
|
1203
|
-
...
|
|
1237
|
+
...getDefaultValidationConfig(),
|
|
1204
1238
|
...config.validation
|
|
1205
1239
|
},
|
|
1206
1240
|
versioning: {
|
|
1207
|
-
...
|
|
1241
|
+
...getDefaultVersioningConfig(),
|
|
1208
1242
|
...config.versioning
|
|
1209
1243
|
},
|
|
1210
1244
|
hooks: config.hooks ?? {},
|
|
1211
|
-
logLevel: config.logLevel ??
|
|
1245
|
+
logLevel: config.logLevel ?? getDefaultLogLevel(),
|
|
1212
1246
|
logger: config.logger ?? console,
|
|
1213
|
-
continueOnError: config.continueOnError ??
|
|
1214
|
-
slowRuleThresholdMs: config.slowRuleThresholdMs ??
|
|
1247
|
+
continueOnError: config.continueOnError ?? true,
|
|
1248
|
+
slowRuleThresholdMs: config.slowRuleThresholdMs ?? 10,
|
|
1249
|
+
hookTimeoutMs: config.hookTimeoutMs
|
|
1215
1250
|
};
|
|
1216
1251
|
};
|
|
1217
1252
|
var createEngine = (config = {}) => {
|
|
@@ -1243,12 +1278,6 @@ var createEngine = (config = {}) => {
|
|
|
1243
1278
|
const ruleSetIds = new Set(ruleSetRules.map((r) => r.id));
|
|
1244
1279
|
rulesToEvaluate = rulesToEvaluate.filter((r) => ruleSetIds.has(r.id));
|
|
1245
1280
|
}
|
|
1246
|
-
rulesToEvaluate = [
|
|
1247
|
-
...sortRules({
|
|
1248
|
-
field: "priority",
|
|
1249
|
-
direction: "desc"
|
|
1250
|
-
})(rulesToEvaluate)
|
|
1251
|
-
];
|
|
1252
1281
|
if (options.maxRules && options.maxRules > 0) {
|
|
1253
1282
|
rulesToEvaluate = rulesToEvaluate.slice(0, options.maxRules);
|
|
1254
1283
|
}
|
|
@@ -1257,15 +1286,15 @@ var createEngine = (config = {}) => {
|
|
|
1257
1286
|
const cached = cache.get(cacheKey);
|
|
1258
1287
|
if (cached) {
|
|
1259
1288
|
cacheHits++;
|
|
1260
|
-
await executeOnCacheHit(resolvedConfig.hooks, cacheKey, cached);
|
|
1289
|
+
await executeOnCacheHit(resolvedConfig.hooks, cacheKey, cached, resolvedConfig.hookTimeoutMs);
|
|
1261
1290
|
return { ...cached, cacheHit: true };
|
|
1262
1291
|
}
|
|
1263
1292
|
}
|
|
1264
1293
|
if (cacheKey) {
|
|
1265
1294
|
cacheMisses++;
|
|
1266
|
-
await executeOnCacheMiss(resolvedConfig.hooks, cacheKey);
|
|
1295
|
+
await executeOnCacheMiss(resolvedConfig.hooks, cacheKey, resolvedConfig.hookTimeoutMs);
|
|
1267
1296
|
}
|
|
1268
|
-
await executeBeforeEvaluation(resolvedConfig.hooks, context, rulesToEvaluate);
|
|
1297
|
+
await executeBeforeEvaluation(resolvedConfig.hooks, context, rulesToEvaluate, resolvedConfig.hookTimeoutMs);
|
|
1269
1298
|
const { result: evaluationResult, durationMs } = measureTime(() => {
|
|
1270
1299
|
const results = [];
|
|
1271
1300
|
for (const rule2 of rulesToEvaluate) {
|
|
@@ -1282,29 +1311,29 @@ var createEngine = (config = {}) => {
|
|
|
1282
1311
|
let rulesErrored = 0;
|
|
1283
1312
|
const conflictResolution = options.conflictResolution ?? resolvedConfig.conflictResolution;
|
|
1284
1313
|
for (const { rule: rule2, result } of evaluationResult) {
|
|
1285
|
-
await executeBeforeRuleEvaluation(resolvedConfig.hooks, rule2, context);
|
|
1314
|
+
await executeBeforeRuleEvaluation(resolvedConfig.hooks, rule2, context, resolvedConfig.hookTimeoutMs);
|
|
1286
1315
|
ruleResults.push(result);
|
|
1287
1316
|
if (result.error) {
|
|
1288
1317
|
rulesErrored++;
|
|
1289
|
-
await executeOnRuleError(resolvedConfig.hooks, rule2, result.error);
|
|
1318
|
+
await executeOnRuleError(resolvedConfig.hooks, rule2, result.error, resolvedConfig.hookTimeoutMs);
|
|
1290
1319
|
if (!resolvedConfig.continueOnError) {
|
|
1291
1320
|
break;
|
|
1292
1321
|
}
|
|
1293
1322
|
}
|
|
1294
1323
|
if (result.skipped) {
|
|
1295
|
-
await executeOnRuleSkip(resolvedConfig.hooks, rule2, result.skipReason ?? "Unknown");
|
|
1324
|
+
await executeOnRuleSkip(resolvedConfig.hooks, rule2, result.skipReason ?? "Unknown", resolvedConfig.hookTimeoutMs);
|
|
1296
1325
|
}
|
|
1297
1326
|
if (result.evaluationTimeMs > resolvedConfig.slowRuleThresholdMs) {
|
|
1298
|
-
await executeOnSlowRule(resolvedConfig.hooks, rule2, result.evaluationTimeMs, resolvedConfig.slowRuleThresholdMs);
|
|
1327
|
+
await executeOnSlowRule(resolvedConfig.hooks, rule2, result.evaluationTimeMs, resolvedConfig.slowRuleThresholdMs, resolvedConfig.hookTimeoutMs);
|
|
1299
1328
|
}
|
|
1300
|
-
await executeAfterRuleEvaluation(resolvedConfig.hooks, rule2, result);
|
|
1329
|
+
await executeAfterRuleEvaluation(resolvedConfig.hooks, rule2, result, resolvedConfig.hookTimeoutMs);
|
|
1301
1330
|
if (result.matched) {
|
|
1302
1331
|
matchedRules.push(rule2);
|
|
1303
1332
|
for (const consequence of result.consequences) {
|
|
1304
1333
|
consequences.push(consequence);
|
|
1305
|
-
await executeOnConsequenceCollected(resolvedConfig.hooks, rule2, consequence);
|
|
1334
|
+
await executeOnConsequenceCollected(resolvedConfig.hooks, rule2, consequence, resolvedConfig.hookTimeoutMs);
|
|
1306
1335
|
}
|
|
1307
|
-
await executeOnRuleMatch(resolvedConfig.hooks, rule2, context);
|
|
1336
|
+
await executeOnRuleMatch(resolvedConfig.hooks, rule2, context, resolvedConfig.hookTimeoutMs);
|
|
1308
1337
|
if (rule2.stopOnMatch) {
|
|
1309
1338
|
stoppedEarly = true;
|
|
1310
1339
|
stoppedByRuleId = rule2.id;
|
|
@@ -1338,7 +1367,7 @@ var createEngine = (config = {}) => {
|
|
|
1338
1367
|
if (cacheKey) {
|
|
1339
1368
|
cache.set(cacheKey, executionResult);
|
|
1340
1369
|
}
|
|
1341
|
-
await executeAfterEvaluation(resolvedConfig.hooks, executionResult);
|
|
1370
|
+
await executeAfterEvaluation(resolvedConfig.hooks, executionResult, resolvedConfig.hookTimeoutMs);
|
|
1342
1371
|
return executionResult;
|
|
1343
1372
|
};
|
|
1344
1373
|
return {
|
|
@@ -1388,7 +1417,7 @@ var createEngine = (config = {}) => {
|
|
|
1388
1417
|
}),
|
|
1389
1418
|
getStats: () => {
|
|
1390
1419
|
const enabledRules = Array.from(state.rules.values()).filter((r) => r.enabled).length;
|
|
1391
|
-
const
|
|
1420
|
+
const _cacheStats = cache.getStats();
|
|
1392
1421
|
return {
|
|
1393
1422
|
totalRules: state.rules.size,
|
|
1394
1423
|
enabledRules,
|
|
@@ -1406,29 +1435,12 @@ var createEngine = (config = {}) => {
|
|
|
1406
1435
|
};
|
|
1407
1436
|
};
|
|
1408
1437
|
// src/optimizer/index-builder.ts
|
|
1409
|
-
import {
|
|
1410
|
-
isConditionGroup as isConditionGroup2
|
|
1411
|
-
} from "@f-o-t/condition-evaluator";
|
|
1412
1438
|
var DEFAULT_OPTIONS = {
|
|
1413
1439
|
indexByField: true,
|
|
1414
1440
|
indexByTag: true,
|
|
1415
1441
|
indexByCategory: true,
|
|
1416
1442
|
indexByPriority: true
|
|
1417
1443
|
};
|
|
1418
|
-
var collectFields2 = (condition) => {
|
|
1419
|
-
const fields = new Set;
|
|
1420
|
-
const traverse = (c) => {
|
|
1421
|
-
if (isConditionGroup2(c)) {
|
|
1422
|
-
for (const child of c.conditions) {
|
|
1423
|
-
traverse(child);
|
|
1424
|
-
}
|
|
1425
|
-
} else {
|
|
1426
|
-
fields.add(c.field);
|
|
1427
|
-
}
|
|
1428
|
-
};
|
|
1429
|
-
traverse(condition);
|
|
1430
|
-
return fields;
|
|
1431
|
-
};
|
|
1432
1444
|
var buildIndex = (rules, options = {}) => {
|
|
1433
1445
|
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
1434
1446
|
const byId = new Map;
|
|
@@ -1439,7 +1451,7 @@ var buildIndex = (rules, options = {}) => {
|
|
|
1439
1451
|
for (const rule2 of rules) {
|
|
1440
1452
|
byId.set(rule2.id, rule2);
|
|
1441
1453
|
if (opts.indexByField) {
|
|
1442
|
-
const fields =
|
|
1454
|
+
const fields = collectConditionFields(rule2.conditions);
|
|
1443
1455
|
for (const field of fields) {
|
|
1444
1456
|
const existing = byField.get(field) ?? [];
|
|
1445
1457
|
existing.push(rule2);
|
|
@@ -1544,7 +1556,7 @@ var analyzeOptimizations = (rules) => {
|
|
|
1544
1556
|
const suggestions = [];
|
|
1545
1557
|
const fieldUsage = new Map;
|
|
1546
1558
|
for (const rule2 of rules) {
|
|
1547
|
-
const fields =
|
|
1559
|
+
const fields = collectConditionFields(rule2.conditions);
|
|
1548
1560
|
for (const field of fields) {
|
|
1549
1561
|
fieldUsage.set(field, (fieldUsage.get(field) ?? 0) + 1);
|
|
1550
1562
|
}
|
|
@@ -1697,6 +1709,8 @@ var importRules = (data, options = {}) => {
|
|
|
1697
1709
|
for (let i = 0;i < data.rules.length; i++) {
|
|
1698
1710
|
try {
|
|
1699
1711
|
const serialized = data.rules[i];
|
|
1712
|
+
if (!serialized)
|
|
1713
|
+
continue;
|
|
1700
1714
|
const rule2 = deserializeRule(serialized, options);
|
|
1701
1715
|
idMapping.set(serialized.id, rule2.id);
|
|
1702
1716
|
rules.push(rule2);
|
|
@@ -1712,6 +1726,8 @@ var importRules = (data, options = {}) => {
|
|
|
1712
1726
|
for (let i = 0;i < data.ruleSets.length; i++) {
|
|
1713
1727
|
try {
|
|
1714
1728
|
const serialized = data.ruleSets[i];
|
|
1729
|
+
if (!serialized)
|
|
1730
|
+
continue;
|
|
1715
1731
|
const ruleSet = deserializeRuleSet(serialized, idMapping, options);
|
|
1716
1732
|
ruleSets.push(ruleSet);
|
|
1717
1733
|
} catch (error) {
|
|
@@ -1723,12 +1739,25 @@ var importRules = (data, options = {}) => {
|
|
|
1723
1739
|
}
|
|
1724
1740
|
}
|
|
1725
1741
|
}
|
|
1742
|
+
const importedRuleIds = new Set(rules.map((r) => r.id));
|
|
1743
|
+
const orphanedReferences = [];
|
|
1744
|
+
for (const ruleSet of ruleSets) {
|
|
1745
|
+
const missingRuleIds = ruleSet.ruleIds.filter((id) => !importedRuleIds.has(id));
|
|
1746
|
+
if (missingRuleIds.length > 0) {
|
|
1747
|
+
orphanedReferences.push({
|
|
1748
|
+
ruleSetId: ruleSet.id,
|
|
1749
|
+
ruleSetName: ruleSet.name,
|
|
1750
|
+
missingRuleIds
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1726
1754
|
return {
|
|
1727
1755
|
success: errors.length === 0,
|
|
1728
1756
|
rules,
|
|
1729
1757
|
ruleSets,
|
|
1730
1758
|
errors,
|
|
1731
|
-
idMapping
|
|
1759
|
+
idMapping,
|
|
1760
|
+
orphanedReferences
|
|
1732
1761
|
};
|
|
1733
1762
|
};
|
|
1734
1763
|
var importFromJson = (json, options = {}) => {
|
|
@@ -1747,7 +1776,8 @@ var importFromJson = (json, options = {}) => {
|
|
|
1747
1776
|
message: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
1748
1777
|
}
|
|
1749
1778
|
],
|
|
1750
|
-
idMapping: new Map
|
|
1779
|
+
idMapping: new Map,
|
|
1780
|
+
orphanedReferences: []
|
|
1751
1781
|
};
|
|
1752
1782
|
}
|
|
1753
1783
|
};
|
|
@@ -1884,8 +1914,8 @@ var whatIf = (originalRules, modifiedRules, context) => {
|
|
|
1884
1914
|
const [ruleId, consequenceType] = key.split(":");
|
|
1885
1915
|
consequenceChanges.push({
|
|
1886
1916
|
type: "added",
|
|
1887
|
-
consequenceType,
|
|
1888
|
-
ruleId
|
|
1917
|
+
consequenceType: consequenceType ?? "",
|
|
1918
|
+
ruleId: ruleId ?? ""
|
|
1889
1919
|
});
|
|
1890
1920
|
}
|
|
1891
1921
|
}
|
|
@@ -1894,8 +1924,8 @@ var whatIf = (originalRules, modifiedRules, context) => {
|
|
|
1894
1924
|
const [ruleId, consequenceType] = key.split(":");
|
|
1895
1925
|
consequenceChanges.push({
|
|
1896
1926
|
type: "removed",
|
|
1897
|
-
consequenceType,
|
|
1898
|
-
ruleId
|
|
1927
|
+
consequenceType: consequenceType ?? "",
|
|
1928
|
+
ruleId: ruleId ?? ""
|
|
1899
1929
|
});
|
|
1900
1930
|
}
|
|
1901
1931
|
}
|
|
@@ -1984,49 +2014,59 @@ var formatSimulationResult = (result) => {
|
|
|
1984
2014
|
return lines.join(`
|
|
1985
2015
|
`);
|
|
1986
2016
|
};
|
|
2017
|
+
// src/types/evaluation.ts
|
|
2018
|
+
import { z as z3 } from "zod";
|
|
2019
|
+
var ConflictResolutionStrategySchema = z3.enum([
|
|
2020
|
+
"priority",
|
|
2021
|
+
"first-match",
|
|
2022
|
+
"all",
|
|
2023
|
+
"most-specific"
|
|
2024
|
+
]);
|
|
2025
|
+
var EvaluateOptionsSchema = z3.object({
|
|
2026
|
+
conflictResolution: ConflictResolutionStrategySchema.optional(),
|
|
2027
|
+
maxRules: z3.number().int().positive().optional(),
|
|
2028
|
+
timeout: z3.number().int().positive().optional(),
|
|
2029
|
+
skipDisabled: z3.boolean().optional(),
|
|
2030
|
+
tags: z3.array(z3.string()).optional(),
|
|
2031
|
+
category: z3.string().optional(),
|
|
2032
|
+
ruleSetId: z3.string().optional(),
|
|
2033
|
+
bypassCache: z3.boolean().optional()
|
|
2034
|
+
});
|
|
2035
|
+
var EvaluateConfigSchema = z3.object({
|
|
2036
|
+
conflictResolution: ConflictResolutionStrategySchema,
|
|
2037
|
+
continueOnError: z3.boolean(),
|
|
2038
|
+
collectAllConsequences: z3.boolean()
|
|
2039
|
+
});
|
|
1987
2040
|
// src/types/rule.ts
|
|
1988
|
-
import { z } from "zod";
|
|
1989
|
-
var RuleSchema =
|
|
1990
|
-
id:
|
|
1991
|
-
name:
|
|
1992
|
-
description:
|
|
1993
|
-
conditions:
|
|
2041
|
+
import { z as z4 } from "zod";
|
|
2042
|
+
var RuleSchema = z4.object({
|
|
2043
|
+
id: z4.string().min(1),
|
|
2044
|
+
name: z4.string().min(1),
|
|
2045
|
+
description: z4.string().optional(),
|
|
2046
|
+
conditions: z4.custom((val) => {
|
|
1994
2047
|
return typeof val === "object" && val !== null && "id" in val && "operator" in val;
|
|
1995
2048
|
}, "Invalid condition group"),
|
|
1996
|
-
consequences:
|
|
1997
|
-
type:
|
|
1998
|
-
payload:
|
|
2049
|
+
consequences: z4.array(z4.object({
|
|
2050
|
+
type: z4.string(),
|
|
2051
|
+
payload: z4.unknown()
|
|
1999
2052
|
})),
|
|
2000
|
-
priority:
|
|
2001
|
-
enabled:
|
|
2002
|
-
stopOnMatch:
|
|
2003
|
-
tags:
|
|
2004
|
-
category:
|
|
2005
|
-
metadata:
|
|
2006
|
-
createdAt:
|
|
2007
|
-
updatedAt:
|
|
2053
|
+
priority: z4.number().int().default(0),
|
|
2054
|
+
enabled: z4.boolean().default(true),
|
|
2055
|
+
stopOnMatch: z4.boolean().default(false),
|
|
2056
|
+
tags: z4.array(z4.string()).default([]),
|
|
2057
|
+
category: z4.string().optional(),
|
|
2058
|
+
metadata: z4.record(z4.string(), z4.unknown()).optional(),
|
|
2059
|
+
createdAt: z4.date().default(() => new Date),
|
|
2060
|
+
updatedAt: z4.date().default(() => new Date)
|
|
2008
2061
|
});
|
|
2009
|
-
var RuleSetSchema =
|
|
2010
|
-
id:
|
|
2011
|
-
name:
|
|
2012
|
-
description:
|
|
2013
|
-
ruleIds:
|
|
2014
|
-
enabled:
|
|
2015
|
-
metadata:
|
|
2062
|
+
var RuleSetSchema = z4.object({
|
|
2063
|
+
id: z4.string().min(1),
|
|
2064
|
+
name: z4.string().min(1),
|
|
2065
|
+
description: z4.string().optional(),
|
|
2066
|
+
ruleIds: z4.array(z4.string()),
|
|
2067
|
+
enabled: z4.boolean().default(true),
|
|
2068
|
+
metadata: z4.record(z4.string(), z4.unknown()).optional()
|
|
2016
2069
|
});
|
|
2017
|
-
// src/utils/pipe.ts
|
|
2018
|
-
function pipe(...fns) {
|
|
2019
|
-
return (value) => fns.reduce((acc, fn) => fn(acc), value);
|
|
2020
|
-
}
|
|
2021
|
-
function compose(...fns) {
|
|
2022
|
-
return (value) => fns.reduceRight((acc, fn) => fn(acc), value);
|
|
2023
|
-
}
|
|
2024
|
-
var identity = (value) => value;
|
|
2025
|
-
var always = (value) => () => value;
|
|
2026
|
-
var tap = (fn) => (value) => {
|
|
2027
|
-
fn(value);
|
|
2028
|
-
return value;
|
|
2029
|
-
};
|
|
2030
2070
|
// src/validation/conflicts.ts
|
|
2031
2071
|
import {
|
|
2032
2072
|
isConditionGroup as isConditionGroup3
|
|
@@ -2038,11 +2078,11 @@ var DEFAULT_OPTIONS2 = {
|
|
|
2038
2078
|
checkPriorityCollisions: true,
|
|
2039
2079
|
checkUnreachableRules: true
|
|
2040
2080
|
};
|
|
2041
|
-
var
|
|
2081
|
+
var collectConditionFields2 = (condition) => {
|
|
2042
2082
|
const fields = new Set;
|
|
2043
2083
|
if (isConditionGroup3(condition)) {
|
|
2044
2084
|
for (const child of condition.conditions) {
|
|
2045
|
-
const childFields =
|
|
2085
|
+
const childFields = collectConditionFields2(child);
|
|
2046
2086
|
for (const field of childFields) {
|
|
2047
2087
|
fields.add(field);
|
|
2048
2088
|
}
|
|
@@ -2077,8 +2117,8 @@ var getConditionOperatorValues = (condition, field) => {
|
|
|
2077
2117
|
return results;
|
|
2078
2118
|
};
|
|
2079
2119
|
var areConditionsOverlapping = (conditions1, conditions2) => {
|
|
2080
|
-
const fields1 =
|
|
2081
|
-
const fields2 =
|
|
2120
|
+
const fields1 = collectConditionFields2(conditions1);
|
|
2121
|
+
const fields2 = collectConditionFields2(conditions2);
|
|
2082
2122
|
const commonFields = new Set([...fields1].filter((f) => fields2.has(f)));
|
|
2083
2123
|
if (commonFields.size === 0)
|
|
2084
2124
|
return false;
|
|
@@ -2161,6 +2201,8 @@ var findOverlappingConditions = (rules) => {
|
|
|
2161
2201
|
for (let j = i + 1;j < rules.length; j++) {
|
|
2162
2202
|
const rule1 = rules[i];
|
|
2163
2203
|
const rule2 = rules[j];
|
|
2204
|
+
if (!rule1 || !rule2)
|
|
2205
|
+
continue;
|
|
2164
2206
|
const key = [rule1.id, rule2.id].sort().join(":");
|
|
2165
2207
|
if (checked.has(key))
|
|
2166
2208
|
continue;
|
|
@@ -2173,8 +2215,8 @@ var findOverlappingConditions = (rules) => {
|
|
|
2173
2215
|
ruleIds: [rule1.id, rule2.id],
|
|
2174
2216
|
rules: [rule1, rule2],
|
|
2175
2217
|
details: {
|
|
2176
|
-
rule1Fields: [...
|
|
2177
|
-
rule2Fields: [...
|
|
2218
|
+
rule1Fields: [...collectConditionFields2(rule1.conditions)],
|
|
2219
|
+
rule2Fields: [...collectConditionFields2(rule2.conditions)]
|
|
2178
2220
|
}
|
|
2179
2221
|
});
|
|
2180
2222
|
}
|
|
@@ -2197,6 +2239,8 @@ var findPriorityCollisions = (rules) => {
|
|
|
2197
2239
|
for (let j = i + 1;j < rulesWithPriority.length; j++) {
|
|
2198
2240
|
const r1 = rulesWithPriority[i];
|
|
2199
2241
|
const r2 = rulesWithPriority[j];
|
|
2242
|
+
if (!r1 || !r2)
|
|
2243
|
+
continue;
|
|
2200
2244
|
if (areConditionsOverlapping(r1.conditions, r2.conditions)) {
|
|
2201
2245
|
overlappingPairs.add(r1.id);
|
|
2202
2246
|
overlappingPairs.add(r2.id);
|
|
@@ -2223,10 +2267,14 @@ var findUnreachableRules = (rules) => {
|
|
|
2223
2267
|
const sortedRules = [...rules].sort((a, b) => b.priority - a.priority);
|
|
2224
2268
|
for (let i = 0;i < sortedRules.length; i++) {
|
|
2225
2269
|
const rule2 = sortedRules[i];
|
|
2270
|
+
if (!rule2)
|
|
2271
|
+
continue;
|
|
2226
2272
|
if (!rule2.enabled)
|
|
2227
2273
|
continue;
|
|
2228
2274
|
for (let j = 0;j < i; j++) {
|
|
2229
2275
|
const higherPriorityRule = sortedRules[j];
|
|
2276
|
+
if (!higherPriorityRule)
|
|
2277
|
+
continue;
|
|
2230
2278
|
if (!higherPriorityRule.enabled || !higherPriorityRule.stopOnMatch) {
|
|
2231
2279
|
continue;
|
|
2232
2280
|
}
|
|
@@ -2367,7 +2415,7 @@ var checkRuleIntegrity = (rule2, options) => {
|
|
|
2367
2415
|
}
|
|
2368
2416
|
}
|
|
2369
2417
|
if (options.allowedTags) {
|
|
2370
|
-
const invalidTags = rule2.tags.filter((t) => !options.allowedTags
|
|
2418
|
+
const invalidTags = rule2.tags.filter((t) => !options.allowedTags?.includes(t));
|
|
2371
2419
|
if (invalidTags.length > 0) {
|
|
2372
2420
|
issues.push(createIssue("INVALID_TAGS", `Rule "${rule2.name}" has invalid tags: ${invalidTags.join(", ")}`, "warning", {
|
|
2373
2421
|
ruleId: rule2.id,
|
|
@@ -2542,11 +2590,22 @@ ${severity.toUpperCase()}S (${issues.length}):`);
|
|
|
2542
2590
|
import {
|
|
2543
2591
|
isConditionGroup as isConditionGroup5
|
|
2544
2592
|
} from "@f-o-t/condition-evaluator";
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2593
|
+
import { z as z5 } from "zod";
|
|
2594
|
+
var ValidationErrorSchema = z5.object({
|
|
2595
|
+
path: z5.string(),
|
|
2596
|
+
message: z5.string(),
|
|
2597
|
+
code: z5.string()
|
|
2598
|
+
});
|
|
2599
|
+
var ValidationResultSchema = z5.object({
|
|
2600
|
+
valid: z5.boolean(),
|
|
2601
|
+
errors: z5.array(ValidationErrorSchema)
|
|
2602
|
+
});
|
|
2603
|
+
var ValidationOptionsSchema = z5.object({
|
|
2604
|
+
validateConditions: z5.boolean().optional(),
|
|
2605
|
+
validateConsequences: z5.boolean().optional(),
|
|
2606
|
+
strictMode: z5.boolean().optional()
|
|
2607
|
+
});
|
|
2608
|
+
var DEFAULT_OPTIONS4 = ValidationOptionsSchema.parse({});
|
|
2550
2609
|
var createError = (path, message, code) => ({
|
|
2551
2610
|
path,
|
|
2552
2611
|
message,
|
|
@@ -2558,7 +2617,7 @@ var validResult = () => ({
|
|
|
2558
2617
|
});
|
|
2559
2618
|
var invalidResult = (errors) => ({
|
|
2560
2619
|
valid: false,
|
|
2561
|
-
errors
|
|
2620
|
+
errors: [...errors]
|
|
2562
2621
|
});
|
|
2563
2622
|
var validateConditionStructure = (condition, path) => {
|
|
2564
2623
|
const errors = [];
|
|
@@ -2599,6 +2658,8 @@ var validateConsequenceStructure = (consequences, consequenceSchemas, strictMode
|
|
|
2599
2658
|
const errors = [];
|
|
2600
2659
|
for (let i = 0;i < consequences.length; i++) {
|
|
2601
2660
|
const consequence = consequences[i];
|
|
2661
|
+
if (!consequence)
|
|
2662
|
+
continue;
|
|
2602
2663
|
const path = `consequences[${i}]`;
|
|
2603
2664
|
if (!consequence.type || typeof consequence.type !== "string") {
|
|
2604
2665
|
errors.push(createError(`${path}.type`, "Consequence must have a type", "MISSING_CONSEQUENCE_TYPE"));
|
|
@@ -2635,8 +2696,8 @@ var validateRule = (rule2, options = {}) => {
|
|
|
2635
2696
|
const conditionErrors = validateConditionStructure(validRule.conditions, "conditions");
|
|
2636
2697
|
errors.push(...conditionErrors);
|
|
2637
2698
|
}
|
|
2638
|
-
if (opts.validateConsequences) {
|
|
2639
|
-
const consequenceErrors = validateConsequenceStructure(validRule.consequences, opts.consequenceSchemas, opts.strictMode);
|
|
2699
|
+
if (opts.validateConsequences || opts.strictMode) {
|
|
2700
|
+
const consequenceErrors = validateConsequenceStructure(validRule.consequences, opts.consequenceSchemas, opts.strictMode ?? false);
|
|
2640
2701
|
errors.push(...consequenceErrors);
|
|
2641
2702
|
}
|
|
2642
2703
|
return errors.length > 0 ? invalidResult(errors) : validResult();
|
|
@@ -2867,7 +2928,6 @@ export {
|
|
|
2867
2928
|
validateRule,
|
|
2868
2929
|
validateConditions,
|
|
2869
2930
|
updateRule,
|
|
2870
|
-
tap,
|
|
2871
2931
|
str,
|
|
2872
2932
|
sortRules,
|
|
2873
2933
|
sortByUpdatedAt,
|
|
@@ -2885,16 +2945,18 @@ export {
|
|
|
2885
2945
|
removeRuleSet,
|
|
2886
2946
|
removeRule,
|
|
2887
2947
|
pruneOldVersions,
|
|
2888
|
-
|
|
2948
|
+
parseVersioningConfig,
|
|
2949
|
+
parseValidationConfig,
|
|
2889
2950
|
parseRule,
|
|
2951
|
+
parseCacheConfig,
|
|
2890
2952
|
or,
|
|
2891
2953
|
num,
|
|
2892
2954
|
mergeRuleSets,
|
|
2893
2955
|
measureTimeAsync,
|
|
2894
2956
|
measureTime,
|
|
2957
|
+
isConditionGroup6 as isConditionGroup,
|
|
2895
2958
|
importRules,
|
|
2896
2959
|
importFromJson,
|
|
2897
|
-
identity,
|
|
2898
2960
|
hashRules,
|
|
2899
2961
|
hashContext,
|
|
2900
2962
|
hasErrors,
|
|
@@ -2925,6 +2987,11 @@ export {
|
|
|
2925
2987
|
getLatestVersion,
|
|
2926
2988
|
getIndexStats,
|
|
2927
2989
|
getHistory,
|
|
2990
|
+
getDefaultVersioningConfig,
|
|
2991
|
+
getDefaultValidationConfig,
|
|
2992
|
+
getDefaultLogLevel,
|
|
2993
|
+
getDefaultConflictResolution,
|
|
2994
|
+
getDefaultCacheConfig,
|
|
2928
2995
|
getConflictsByType,
|
|
2929
2996
|
getConflictsBySeverity,
|
|
2930
2997
|
getAllVersions,
|
|
@@ -2953,7 +3020,6 @@ export {
|
|
|
2953
3020
|
detectConflicts,
|
|
2954
3021
|
deserializeRuleSet,
|
|
2955
3022
|
deserializeRule,
|
|
2956
|
-
delay,
|
|
2957
3023
|
date,
|
|
2958
3024
|
createVersionStore,
|
|
2959
3025
|
createRuleValidator,
|
|
@@ -2965,7 +3031,6 @@ export {
|
|
|
2965
3031
|
createEngine,
|
|
2966
3032
|
createCache,
|
|
2967
3033
|
conditions,
|
|
2968
|
-
compose,
|
|
2969
3034
|
compareVersions,
|
|
2970
3035
|
cloneState,
|
|
2971
3036
|
cloneRule,
|
|
@@ -2984,16 +3049,25 @@ export {
|
|
|
2984
3049
|
analyzeOperatorUsage,
|
|
2985
3050
|
analyzeFieldUsage,
|
|
2986
3051
|
analyzeConsequenceUsage,
|
|
2987
|
-
always,
|
|
2988
3052
|
all,
|
|
2989
3053
|
addVersion,
|
|
2990
3054
|
addRules,
|
|
2991
3055
|
addRuleSet,
|
|
2992
3056
|
addRule,
|
|
3057
|
+
VersioningConfigSchema,
|
|
3058
|
+
ValidationResultSchema,
|
|
3059
|
+
ValidationOptionsSchema,
|
|
3060
|
+
ValidationErrorSchema,
|
|
3061
|
+
ValidationConfigSchema,
|
|
3062
|
+
RuleStatsSchema,
|
|
2993
3063
|
RuleSetSchema,
|
|
2994
3064
|
RuleSchema,
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
3065
|
+
LogLevelSchema,
|
|
3066
|
+
EvaluateOptionsSchema,
|
|
3067
|
+
EvaluateConfigSchema,
|
|
3068
|
+
EngineStatsSchema,
|
|
3069
|
+
ConflictResolutionStrategySchema,
|
|
3070
|
+
ConditionGroup as ConditionGroupSchema,
|
|
3071
|
+
CacheStatsSchema,
|
|
3072
|
+
CacheConfigSchema
|
|
2999
3073
|
};
|