@f-o-t/rules-engine 1.0.0 → 2.0.1
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 +286 -218
- package/dist/index.d.cts +191 -186
- package/dist/index.d.ts +191 -186
- package/dist/index.js +291 -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,6 @@ var createEngine = (config = {}) => {
|
|
|
1388
1417
|
}),
|
|
1389
1418
|
getStats: () => {
|
|
1390
1419
|
const enabledRules = Array.from(state.rules.values()).filter((r) => r.enabled).length;
|
|
1391
|
-
const cacheStats = cache.getStats();
|
|
1392
1420
|
return {
|
|
1393
1421
|
totalRules: state.rules.size,
|
|
1394
1422
|
enabledRules,
|
|
@@ -1406,29 +1434,12 @@ var createEngine = (config = {}) => {
|
|
|
1406
1434
|
};
|
|
1407
1435
|
};
|
|
1408
1436
|
// src/optimizer/index-builder.ts
|
|
1409
|
-
import {
|
|
1410
|
-
isConditionGroup as isConditionGroup2
|
|
1411
|
-
} from "@f-o-t/condition-evaluator";
|
|
1412
1437
|
var DEFAULT_OPTIONS = {
|
|
1413
1438
|
indexByField: true,
|
|
1414
1439
|
indexByTag: true,
|
|
1415
1440
|
indexByCategory: true,
|
|
1416
1441
|
indexByPriority: true
|
|
1417
1442
|
};
|
|
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
1443
|
var buildIndex = (rules, options = {}) => {
|
|
1433
1444
|
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
1434
1445
|
const byId = new Map;
|
|
@@ -1439,7 +1450,7 @@ var buildIndex = (rules, options = {}) => {
|
|
|
1439
1450
|
for (const rule2 of rules) {
|
|
1440
1451
|
byId.set(rule2.id, rule2);
|
|
1441
1452
|
if (opts.indexByField) {
|
|
1442
|
-
const fields =
|
|
1453
|
+
const fields = collectConditionFields(rule2.conditions);
|
|
1443
1454
|
for (const field of fields) {
|
|
1444
1455
|
const existing = byField.get(field) ?? [];
|
|
1445
1456
|
existing.push(rule2);
|
|
@@ -1544,7 +1555,7 @@ var analyzeOptimizations = (rules) => {
|
|
|
1544
1555
|
const suggestions = [];
|
|
1545
1556
|
const fieldUsage = new Map;
|
|
1546
1557
|
for (const rule2 of rules) {
|
|
1547
|
-
const fields =
|
|
1558
|
+
const fields = collectConditionFields(rule2.conditions);
|
|
1548
1559
|
for (const field of fields) {
|
|
1549
1560
|
fieldUsage.set(field, (fieldUsage.get(field) ?? 0) + 1);
|
|
1550
1561
|
}
|
|
@@ -1697,6 +1708,8 @@ var importRules = (data, options = {}) => {
|
|
|
1697
1708
|
for (let i = 0;i < data.rules.length; i++) {
|
|
1698
1709
|
try {
|
|
1699
1710
|
const serialized = data.rules[i];
|
|
1711
|
+
if (!serialized)
|
|
1712
|
+
continue;
|
|
1700
1713
|
const rule2 = deserializeRule(serialized, options);
|
|
1701
1714
|
idMapping.set(serialized.id, rule2.id);
|
|
1702
1715
|
rules.push(rule2);
|
|
@@ -1712,6 +1725,8 @@ var importRules = (data, options = {}) => {
|
|
|
1712
1725
|
for (let i = 0;i < data.ruleSets.length; i++) {
|
|
1713
1726
|
try {
|
|
1714
1727
|
const serialized = data.ruleSets[i];
|
|
1728
|
+
if (!serialized)
|
|
1729
|
+
continue;
|
|
1715
1730
|
const ruleSet = deserializeRuleSet(serialized, idMapping, options);
|
|
1716
1731
|
ruleSets.push(ruleSet);
|
|
1717
1732
|
} catch (error) {
|
|
@@ -1723,12 +1738,25 @@ var importRules = (data, options = {}) => {
|
|
|
1723
1738
|
}
|
|
1724
1739
|
}
|
|
1725
1740
|
}
|
|
1741
|
+
const importedRuleIds = new Set(rules.map((r) => r.id));
|
|
1742
|
+
const orphanedReferences = [];
|
|
1743
|
+
for (const ruleSet of ruleSets) {
|
|
1744
|
+
const missingRuleIds = ruleSet.ruleIds.filter((id) => !importedRuleIds.has(id));
|
|
1745
|
+
if (missingRuleIds.length > 0) {
|
|
1746
|
+
orphanedReferences.push({
|
|
1747
|
+
ruleSetId: ruleSet.id,
|
|
1748
|
+
ruleSetName: ruleSet.name,
|
|
1749
|
+
missingRuleIds
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1726
1753
|
return {
|
|
1727
1754
|
success: errors.length === 0,
|
|
1728
1755
|
rules,
|
|
1729
1756
|
ruleSets,
|
|
1730
1757
|
errors,
|
|
1731
|
-
idMapping
|
|
1758
|
+
idMapping,
|
|
1759
|
+
orphanedReferences
|
|
1732
1760
|
};
|
|
1733
1761
|
};
|
|
1734
1762
|
var importFromJson = (json, options = {}) => {
|
|
@@ -1747,7 +1775,8 @@ var importFromJson = (json, options = {}) => {
|
|
|
1747
1775
|
message: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
1748
1776
|
}
|
|
1749
1777
|
],
|
|
1750
|
-
idMapping: new Map
|
|
1778
|
+
idMapping: new Map,
|
|
1779
|
+
orphanedReferences: []
|
|
1751
1780
|
};
|
|
1752
1781
|
}
|
|
1753
1782
|
};
|
|
@@ -1884,8 +1913,8 @@ var whatIf = (originalRules, modifiedRules, context) => {
|
|
|
1884
1913
|
const [ruleId, consequenceType] = key.split(":");
|
|
1885
1914
|
consequenceChanges.push({
|
|
1886
1915
|
type: "added",
|
|
1887
|
-
consequenceType,
|
|
1888
|
-
ruleId
|
|
1916
|
+
consequenceType: consequenceType ?? "",
|
|
1917
|
+
ruleId: ruleId ?? ""
|
|
1889
1918
|
});
|
|
1890
1919
|
}
|
|
1891
1920
|
}
|
|
@@ -1894,8 +1923,8 @@ var whatIf = (originalRules, modifiedRules, context) => {
|
|
|
1894
1923
|
const [ruleId, consequenceType] = key.split(":");
|
|
1895
1924
|
consequenceChanges.push({
|
|
1896
1925
|
type: "removed",
|
|
1897
|
-
consequenceType,
|
|
1898
|
-
ruleId
|
|
1926
|
+
consequenceType: consequenceType ?? "",
|
|
1927
|
+
ruleId: ruleId ?? ""
|
|
1899
1928
|
});
|
|
1900
1929
|
}
|
|
1901
1930
|
}
|
|
@@ -1984,49 +2013,59 @@ var formatSimulationResult = (result) => {
|
|
|
1984
2013
|
return lines.join(`
|
|
1985
2014
|
`);
|
|
1986
2015
|
};
|
|
2016
|
+
// src/types/evaluation.ts
|
|
2017
|
+
import { z as z3 } from "zod";
|
|
2018
|
+
var ConflictResolutionStrategySchema = z3.enum([
|
|
2019
|
+
"priority",
|
|
2020
|
+
"first-match",
|
|
2021
|
+
"all",
|
|
2022
|
+
"most-specific"
|
|
2023
|
+
]);
|
|
2024
|
+
var EvaluateOptionsSchema = z3.object({
|
|
2025
|
+
conflictResolution: ConflictResolutionStrategySchema.optional(),
|
|
2026
|
+
maxRules: z3.number().int().positive().optional(),
|
|
2027
|
+
timeout: z3.number().int().positive().optional(),
|
|
2028
|
+
skipDisabled: z3.boolean().optional(),
|
|
2029
|
+
tags: z3.array(z3.string()).optional(),
|
|
2030
|
+
category: z3.string().optional(),
|
|
2031
|
+
ruleSetId: z3.string().optional(),
|
|
2032
|
+
bypassCache: z3.boolean().optional()
|
|
2033
|
+
});
|
|
2034
|
+
var EvaluateConfigSchema = z3.object({
|
|
2035
|
+
conflictResolution: ConflictResolutionStrategySchema,
|
|
2036
|
+
continueOnError: z3.boolean(),
|
|
2037
|
+
collectAllConsequences: z3.boolean()
|
|
2038
|
+
});
|
|
1987
2039
|
// src/types/rule.ts
|
|
1988
|
-
import { z } from "zod";
|
|
1989
|
-
var RuleSchema =
|
|
1990
|
-
id:
|
|
1991
|
-
name:
|
|
1992
|
-
description:
|
|
1993
|
-
conditions:
|
|
2040
|
+
import { z as z4 } from "zod";
|
|
2041
|
+
var RuleSchema = z4.object({
|
|
2042
|
+
id: z4.string().min(1),
|
|
2043
|
+
name: z4.string().min(1),
|
|
2044
|
+
description: z4.string().optional(),
|
|
2045
|
+
conditions: z4.custom((val) => {
|
|
1994
2046
|
return typeof val === "object" && val !== null && "id" in val && "operator" in val;
|
|
1995
2047
|
}, "Invalid condition group"),
|
|
1996
|
-
consequences:
|
|
1997
|
-
type:
|
|
1998
|
-
payload:
|
|
2048
|
+
consequences: z4.array(z4.object({
|
|
2049
|
+
type: z4.string(),
|
|
2050
|
+
payload: z4.unknown()
|
|
1999
2051
|
})),
|
|
2000
|
-
priority:
|
|
2001
|
-
enabled:
|
|
2002
|
-
stopOnMatch:
|
|
2003
|
-
tags:
|
|
2004
|
-
category:
|
|
2005
|
-
metadata:
|
|
2006
|
-
createdAt:
|
|
2007
|
-
updatedAt:
|
|
2052
|
+
priority: z4.number().int().default(0),
|
|
2053
|
+
enabled: z4.boolean().default(true),
|
|
2054
|
+
stopOnMatch: z4.boolean().default(false),
|
|
2055
|
+
tags: z4.array(z4.string()).default([]),
|
|
2056
|
+
category: z4.string().optional(),
|
|
2057
|
+
metadata: z4.record(z4.string(), z4.unknown()).optional(),
|
|
2058
|
+
createdAt: z4.date().default(() => new Date),
|
|
2059
|
+
updatedAt: z4.date().default(() => new Date)
|
|
2008
2060
|
});
|
|
2009
|
-
var RuleSetSchema =
|
|
2010
|
-
id:
|
|
2011
|
-
name:
|
|
2012
|
-
description:
|
|
2013
|
-
ruleIds:
|
|
2014
|
-
enabled:
|
|
2015
|
-
metadata:
|
|
2061
|
+
var RuleSetSchema = z4.object({
|
|
2062
|
+
id: z4.string().min(1),
|
|
2063
|
+
name: z4.string().min(1),
|
|
2064
|
+
description: z4.string().optional(),
|
|
2065
|
+
ruleIds: z4.array(z4.string()),
|
|
2066
|
+
enabled: z4.boolean().default(true),
|
|
2067
|
+
metadata: z4.record(z4.string(), z4.unknown()).optional()
|
|
2016
2068
|
});
|
|
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
2069
|
// src/validation/conflicts.ts
|
|
2031
2070
|
import {
|
|
2032
2071
|
isConditionGroup as isConditionGroup3
|
|
@@ -2038,11 +2077,11 @@ var DEFAULT_OPTIONS2 = {
|
|
|
2038
2077
|
checkPriorityCollisions: true,
|
|
2039
2078
|
checkUnreachableRules: true
|
|
2040
2079
|
};
|
|
2041
|
-
var
|
|
2080
|
+
var collectConditionFields2 = (condition) => {
|
|
2042
2081
|
const fields = new Set;
|
|
2043
2082
|
if (isConditionGroup3(condition)) {
|
|
2044
2083
|
for (const child of condition.conditions) {
|
|
2045
|
-
const childFields =
|
|
2084
|
+
const childFields = collectConditionFields2(child);
|
|
2046
2085
|
for (const field of childFields) {
|
|
2047
2086
|
fields.add(field);
|
|
2048
2087
|
}
|
|
@@ -2077,8 +2116,8 @@ var getConditionOperatorValues = (condition, field) => {
|
|
|
2077
2116
|
return results;
|
|
2078
2117
|
};
|
|
2079
2118
|
var areConditionsOverlapping = (conditions1, conditions2) => {
|
|
2080
|
-
const fields1 =
|
|
2081
|
-
const fields2 =
|
|
2119
|
+
const fields1 = collectConditionFields2(conditions1);
|
|
2120
|
+
const fields2 = collectConditionFields2(conditions2);
|
|
2082
2121
|
const commonFields = new Set([...fields1].filter((f) => fields2.has(f)));
|
|
2083
2122
|
if (commonFields.size === 0)
|
|
2084
2123
|
return false;
|
|
@@ -2161,6 +2200,8 @@ var findOverlappingConditions = (rules) => {
|
|
|
2161
2200
|
for (let j = i + 1;j < rules.length; j++) {
|
|
2162
2201
|
const rule1 = rules[i];
|
|
2163
2202
|
const rule2 = rules[j];
|
|
2203
|
+
if (!rule1 || !rule2)
|
|
2204
|
+
continue;
|
|
2164
2205
|
const key = [rule1.id, rule2.id].sort().join(":");
|
|
2165
2206
|
if (checked.has(key))
|
|
2166
2207
|
continue;
|
|
@@ -2173,8 +2214,8 @@ var findOverlappingConditions = (rules) => {
|
|
|
2173
2214
|
ruleIds: [rule1.id, rule2.id],
|
|
2174
2215
|
rules: [rule1, rule2],
|
|
2175
2216
|
details: {
|
|
2176
|
-
rule1Fields: [...
|
|
2177
|
-
rule2Fields: [...
|
|
2217
|
+
rule1Fields: [...collectConditionFields2(rule1.conditions)],
|
|
2218
|
+
rule2Fields: [...collectConditionFields2(rule2.conditions)]
|
|
2178
2219
|
}
|
|
2179
2220
|
});
|
|
2180
2221
|
}
|
|
@@ -2197,6 +2238,8 @@ var findPriorityCollisions = (rules) => {
|
|
|
2197
2238
|
for (let j = i + 1;j < rulesWithPriority.length; j++) {
|
|
2198
2239
|
const r1 = rulesWithPriority[i];
|
|
2199
2240
|
const r2 = rulesWithPriority[j];
|
|
2241
|
+
if (!r1 || !r2)
|
|
2242
|
+
continue;
|
|
2200
2243
|
if (areConditionsOverlapping(r1.conditions, r2.conditions)) {
|
|
2201
2244
|
overlappingPairs.add(r1.id);
|
|
2202
2245
|
overlappingPairs.add(r2.id);
|
|
@@ -2223,10 +2266,14 @@ var findUnreachableRules = (rules) => {
|
|
|
2223
2266
|
const sortedRules = [...rules].sort((a, b) => b.priority - a.priority);
|
|
2224
2267
|
for (let i = 0;i < sortedRules.length; i++) {
|
|
2225
2268
|
const rule2 = sortedRules[i];
|
|
2269
|
+
if (!rule2)
|
|
2270
|
+
continue;
|
|
2226
2271
|
if (!rule2.enabled)
|
|
2227
2272
|
continue;
|
|
2228
2273
|
for (let j = 0;j < i; j++) {
|
|
2229
2274
|
const higherPriorityRule = sortedRules[j];
|
|
2275
|
+
if (!higherPriorityRule)
|
|
2276
|
+
continue;
|
|
2230
2277
|
if (!higherPriorityRule.enabled || !higherPriorityRule.stopOnMatch) {
|
|
2231
2278
|
continue;
|
|
2232
2279
|
}
|
|
@@ -2367,7 +2414,7 @@ var checkRuleIntegrity = (rule2, options) => {
|
|
|
2367
2414
|
}
|
|
2368
2415
|
}
|
|
2369
2416
|
if (options.allowedTags) {
|
|
2370
|
-
const invalidTags = rule2.tags.filter((t) => !options.allowedTags
|
|
2417
|
+
const invalidTags = rule2.tags.filter((t) => !options.allowedTags?.includes(t));
|
|
2371
2418
|
if (invalidTags.length > 0) {
|
|
2372
2419
|
issues.push(createIssue("INVALID_TAGS", `Rule "${rule2.name}" has invalid tags: ${invalidTags.join(", ")}`, "warning", {
|
|
2373
2420
|
ruleId: rule2.id,
|
|
@@ -2542,11 +2589,22 @@ ${severity.toUpperCase()}S (${issues.length}):`);
|
|
|
2542
2589
|
import {
|
|
2543
2590
|
isConditionGroup as isConditionGroup5
|
|
2544
2591
|
} from "@f-o-t/condition-evaluator";
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2592
|
+
import { z as z5 } from "zod";
|
|
2593
|
+
var ValidationErrorSchema = z5.object({
|
|
2594
|
+
path: z5.string(),
|
|
2595
|
+
message: z5.string(),
|
|
2596
|
+
code: z5.string()
|
|
2597
|
+
});
|
|
2598
|
+
var ValidationResultSchema = z5.object({
|
|
2599
|
+
valid: z5.boolean(),
|
|
2600
|
+
errors: z5.array(ValidationErrorSchema)
|
|
2601
|
+
});
|
|
2602
|
+
var ValidationOptionsSchema = z5.object({
|
|
2603
|
+
validateConditions: z5.boolean().optional(),
|
|
2604
|
+
validateConsequences: z5.boolean().optional(),
|
|
2605
|
+
strictMode: z5.boolean().optional()
|
|
2606
|
+
});
|
|
2607
|
+
var DEFAULT_OPTIONS4 = ValidationOptionsSchema.parse({});
|
|
2550
2608
|
var createError = (path, message, code) => ({
|
|
2551
2609
|
path,
|
|
2552
2610
|
message,
|
|
@@ -2558,7 +2616,7 @@ var validResult = () => ({
|
|
|
2558
2616
|
});
|
|
2559
2617
|
var invalidResult = (errors) => ({
|
|
2560
2618
|
valid: false,
|
|
2561
|
-
errors
|
|
2619
|
+
errors: [...errors]
|
|
2562
2620
|
});
|
|
2563
2621
|
var validateConditionStructure = (condition, path) => {
|
|
2564
2622
|
const errors = [];
|
|
@@ -2599,6 +2657,8 @@ var validateConsequenceStructure = (consequences, consequenceSchemas, strictMode
|
|
|
2599
2657
|
const errors = [];
|
|
2600
2658
|
for (let i = 0;i < consequences.length; i++) {
|
|
2601
2659
|
const consequence = consequences[i];
|
|
2660
|
+
if (!consequence)
|
|
2661
|
+
continue;
|
|
2602
2662
|
const path = `consequences[${i}]`;
|
|
2603
2663
|
if (!consequence.type || typeof consequence.type !== "string") {
|
|
2604
2664
|
errors.push(createError(`${path}.type`, "Consequence must have a type", "MISSING_CONSEQUENCE_TYPE"));
|
|
@@ -2635,8 +2695,8 @@ var validateRule = (rule2, options = {}) => {
|
|
|
2635
2695
|
const conditionErrors = validateConditionStructure(validRule.conditions, "conditions");
|
|
2636
2696
|
errors.push(...conditionErrors);
|
|
2637
2697
|
}
|
|
2638
|
-
if (opts.validateConsequences) {
|
|
2639
|
-
const consequenceErrors = validateConsequenceStructure(validRule.consequences, opts.consequenceSchemas, opts.strictMode);
|
|
2698
|
+
if (opts.validateConsequences || opts.strictMode) {
|
|
2699
|
+
const consequenceErrors = validateConsequenceStructure(validRule.consequences, opts.consequenceSchemas, opts.strictMode ?? false);
|
|
2640
2700
|
errors.push(...consequenceErrors);
|
|
2641
2701
|
}
|
|
2642
2702
|
return errors.length > 0 ? invalidResult(errors) : validResult();
|
|
@@ -2867,7 +2927,6 @@ export {
|
|
|
2867
2927
|
validateRule,
|
|
2868
2928
|
validateConditions,
|
|
2869
2929
|
updateRule,
|
|
2870
|
-
tap,
|
|
2871
2930
|
str,
|
|
2872
2931
|
sortRules,
|
|
2873
2932
|
sortByUpdatedAt,
|
|
@@ -2885,16 +2944,18 @@ export {
|
|
|
2885
2944
|
removeRuleSet,
|
|
2886
2945
|
removeRule,
|
|
2887
2946
|
pruneOldVersions,
|
|
2888
|
-
|
|
2947
|
+
parseVersioningConfig,
|
|
2948
|
+
parseValidationConfig,
|
|
2889
2949
|
parseRule,
|
|
2950
|
+
parseCacheConfig,
|
|
2890
2951
|
or,
|
|
2891
2952
|
num,
|
|
2892
2953
|
mergeRuleSets,
|
|
2893
2954
|
measureTimeAsync,
|
|
2894
2955
|
measureTime,
|
|
2956
|
+
isConditionGroup6 as isConditionGroup,
|
|
2895
2957
|
importRules,
|
|
2896
2958
|
importFromJson,
|
|
2897
|
-
identity,
|
|
2898
2959
|
hashRules,
|
|
2899
2960
|
hashContext,
|
|
2900
2961
|
hasErrors,
|
|
@@ -2925,6 +2986,11 @@ export {
|
|
|
2925
2986
|
getLatestVersion,
|
|
2926
2987
|
getIndexStats,
|
|
2927
2988
|
getHistory,
|
|
2989
|
+
getDefaultVersioningConfig,
|
|
2990
|
+
getDefaultValidationConfig,
|
|
2991
|
+
getDefaultLogLevel,
|
|
2992
|
+
getDefaultConflictResolution,
|
|
2993
|
+
getDefaultCacheConfig,
|
|
2928
2994
|
getConflictsByType,
|
|
2929
2995
|
getConflictsBySeverity,
|
|
2930
2996
|
getAllVersions,
|
|
@@ -2953,7 +3019,6 @@ export {
|
|
|
2953
3019
|
detectConflicts,
|
|
2954
3020
|
deserializeRuleSet,
|
|
2955
3021
|
deserializeRule,
|
|
2956
|
-
delay,
|
|
2957
3022
|
date,
|
|
2958
3023
|
createVersionStore,
|
|
2959
3024
|
createRuleValidator,
|
|
@@ -2965,7 +3030,6 @@ export {
|
|
|
2965
3030
|
createEngine,
|
|
2966
3031
|
createCache,
|
|
2967
3032
|
conditions,
|
|
2968
|
-
compose,
|
|
2969
3033
|
compareVersions,
|
|
2970
3034
|
cloneState,
|
|
2971
3035
|
cloneRule,
|
|
@@ -2984,16 +3048,25 @@ export {
|
|
|
2984
3048
|
analyzeOperatorUsage,
|
|
2985
3049
|
analyzeFieldUsage,
|
|
2986
3050
|
analyzeConsequenceUsage,
|
|
2987
|
-
always,
|
|
2988
3051
|
all,
|
|
2989
3052
|
addVersion,
|
|
2990
3053
|
addRules,
|
|
2991
3054
|
addRuleSet,
|
|
2992
3055
|
addRule,
|
|
3056
|
+
VersioningConfigSchema,
|
|
3057
|
+
ValidationResultSchema,
|
|
3058
|
+
ValidationOptionsSchema,
|
|
3059
|
+
ValidationErrorSchema,
|
|
3060
|
+
ValidationConfigSchema,
|
|
3061
|
+
RuleStatsSchema,
|
|
2993
3062
|
RuleSetSchema,
|
|
2994
3063
|
RuleSchema,
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
3064
|
+
LogLevelSchema,
|
|
3065
|
+
EvaluateOptionsSchema,
|
|
3066
|
+
EvaluateConfigSchema,
|
|
3067
|
+
EngineStatsSchema,
|
|
3068
|
+
ConflictResolutionStrategySchema,
|
|
3069
|
+
ConditionGroup as ConditionGroupSchema,
|
|
3070
|
+
CacheStatsSchema,
|
|
3071
|
+
CacheConfigSchema
|
|
2999
3072
|
};
|