@featurevisor/sdk 2.18.0 → 2.19.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/CHANGELOG.md +11 -0
- package/coverage/clover.xml +328 -312
- package/coverage/coverage-final.json +9 -9
- package/coverage/lcov-report/bucketer.ts.html +16 -16
- package/coverage/lcov-report/child.ts.html +1 -1
- package/coverage/lcov-report/conditions.ts.html +7 -7
- package/coverage/lcov-report/datafileReader.ts.html +55 -55
- package/coverage/lcov-report/emitter.ts.html +2 -2
- package/coverage/lcov-report/evaluate.ts.html +247 -85
- package/coverage/lcov-report/events.ts.html +1 -1
- package/coverage/lcov-report/helpers.ts.html +4 -4
- package/coverage/lcov-report/hooks.ts.html +6 -6
- package/coverage/lcov-report/index.html +25 -25
- package/coverage/lcov-report/instance.ts.html +21 -21
- package/coverage/lcov-report/logger.ts.html +14 -14
- package/coverage/lcov.info +586 -554
- package/dist/evaluate.d.ts +3 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.gz +0 -0
- package/dist/index.mjs.map +1 -1
- package/lib/evaluate.d.ts +3 -1
- package/package.json +3 -3
- package/src/evaluate.ts +78 -24
- package/src/instance.spec.ts +131 -0
package/src/evaluate.ts
CHANGED
|
@@ -35,7 +35,8 @@ export enum EvaluationReason {
|
|
|
35
35
|
VARIABLE_NOT_FOUND = "variable_not_found", // variable's schema is not defined in the feature
|
|
36
36
|
VARIABLE_DEFAULT = "variable_default", // default variable value used
|
|
37
37
|
VARIABLE_DISABLED = "variable_disabled", // feature is disabled, and variable's disabledValue is used
|
|
38
|
-
|
|
38
|
+
VARIABLE_OVERRIDE_VARIATION = "variable_override_variation", // variable overridden from inside a variation
|
|
39
|
+
VARIABLE_OVERRIDE_RULE = "variable_override_rule", // variable overridden from inside a rule
|
|
39
40
|
|
|
40
41
|
// common
|
|
41
42
|
NO_MATCH = "no_match", // no rules matched
|
|
@@ -75,6 +76,7 @@ export interface Evaluation {
|
|
|
75
76
|
variableKey?: VariableKey;
|
|
76
77
|
variableValue?: VariableValue;
|
|
77
78
|
variableSchema?: ResolvedVariableSchema;
|
|
79
|
+
variableOverrideIndex?: number;
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
export interface EvaluateDependencies {
|
|
@@ -688,27 +690,76 @@ export function evaluate(options: EvaluateOptions): Evaluation {
|
|
|
688
690
|
// variable
|
|
689
691
|
if (type === "variable" && variableKey) {
|
|
690
692
|
// override from rule
|
|
691
|
-
if (
|
|
692
|
-
|
|
693
|
-
matchedTraffic.
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
variableSchema,
|
|
706
|
-
variableValue: matchedTraffic.variables[variableKey],
|
|
707
|
-
};
|
|
693
|
+
if (matchedTraffic) {
|
|
694
|
+
// "variableOverrides"
|
|
695
|
+
if (matchedTraffic.variableOverrides && matchedTraffic.variableOverrides[variableKey]) {
|
|
696
|
+
const overrides = matchedTraffic.variableOverrides[variableKey];
|
|
697
|
+
|
|
698
|
+
const overrideIndex = overrides.findIndex((o) => {
|
|
699
|
+
if (o.conditions) {
|
|
700
|
+
return datafileReader.allConditionsAreMatched(
|
|
701
|
+
typeof o.conditions === "string" && o.conditions !== "*"
|
|
702
|
+
? JSON.parse(o.conditions)
|
|
703
|
+
: o.conditions,
|
|
704
|
+
context,
|
|
705
|
+
);
|
|
706
|
+
}
|
|
708
707
|
|
|
709
|
-
|
|
708
|
+
if (o.segments) {
|
|
709
|
+
return datafileReader.allSegmentsAreMatched(
|
|
710
|
+
datafileReader.parseSegmentsIfStringified(o.segments),
|
|
711
|
+
context,
|
|
712
|
+
);
|
|
713
|
+
}
|
|
710
714
|
|
|
711
|
-
|
|
715
|
+
return false;
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
if (overrideIndex !== -1) {
|
|
719
|
+
const override = overrides[overrideIndex];
|
|
720
|
+
|
|
721
|
+
evaluation = {
|
|
722
|
+
type,
|
|
723
|
+
featureKey,
|
|
724
|
+
reason: EvaluationReason.VARIABLE_OVERRIDE_RULE,
|
|
725
|
+
bucketKey,
|
|
726
|
+
bucketValue,
|
|
727
|
+
ruleKey: matchedTraffic?.key,
|
|
728
|
+
traffic: matchedTraffic,
|
|
729
|
+
variableKey,
|
|
730
|
+
variableSchema,
|
|
731
|
+
variableValue: override.value,
|
|
732
|
+
variableOverrideIndex: overrideIndex,
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
logger.debug("variable override from rule", evaluation);
|
|
736
|
+
|
|
737
|
+
return evaluation;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// from "variables"
|
|
742
|
+
if (
|
|
743
|
+
matchedTraffic.variables &&
|
|
744
|
+
typeof matchedTraffic.variables[variableKey] !== "undefined"
|
|
745
|
+
) {
|
|
746
|
+
evaluation = {
|
|
747
|
+
type,
|
|
748
|
+
featureKey,
|
|
749
|
+
reason: EvaluationReason.RULE,
|
|
750
|
+
bucketKey,
|
|
751
|
+
bucketValue,
|
|
752
|
+
ruleKey: matchedTraffic.key,
|
|
753
|
+
traffic: matchedTraffic,
|
|
754
|
+
variableKey,
|
|
755
|
+
variableSchema,
|
|
756
|
+
variableValue: matchedTraffic.variables[variableKey],
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
logger.debug("override from rule", evaluation);
|
|
760
|
+
|
|
761
|
+
return evaluation;
|
|
762
|
+
}
|
|
712
763
|
}
|
|
713
764
|
|
|
714
765
|
// check variations
|
|
@@ -728,7 +779,7 @@ export function evaluate(options: EvaluateOptions): Evaluation {
|
|
|
728
779
|
if (variation && variation.variableOverrides && variation.variableOverrides[variableKey]) {
|
|
729
780
|
const overrides = variation.variableOverrides[variableKey];
|
|
730
781
|
|
|
731
|
-
const
|
|
782
|
+
const overrideIndex = overrides.findIndex((o) => {
|
|
732
783
|
if (o.conditions) {
|
|
733
784
|
return datafileReader.allConditionsAreMatched(
|
|
734
785
|
typeof o.conditions === "string" && o.conditions !== "*"
|
|
@@ -748,11 +799,13 @@ export function evaluate(options: EvaluateOptions): Evaluation {
|
|
|
748
799
|
return false;
|
|
749
800
|
});
|
|
750
801
|
|
|
751
|
-
if (
|
|
802
|
+
if (overrideIndex !== -1) {
|
|
803
|
+
const override = overrides[overrideIndex];
|
|
804
|
+
|
|
752
805
|
evaluation = {
|
|
753
806
|
type,
|
|
754
807
|
featureKey,
|
|
755
|
-
reason: EvaluationReason.
|
|
808
|
+
reason: EvaluationReason.VARIABLE_OVERRIDE_VARIATION,
|
|
756
809
|
bucketKey,
|
|
757
810
|
bucketValue,
|
|
758
811
|
ruleKey: matchedTraffic?.key,
|
|
@@ -760,9 +813,10 @@ export function evaluate(options: EvaluateOptions): Evaluation {
|
|
|
760
813
|
variableKey,
|
|
761
814
|
variableSchema,
|
|
762
815
|
variableValue: override.value,
|
|
816
|
+
variableOverrideIndex: overrideIndex,
|
|
763
817
|
};
|
|
764
818
|
|
|
765
|
-
logger.debug("variable override", evaluation);
|
|
819
|
+
logger.debug("variable override from variation", evaluation);
|
|
766
820
|
|
|
767
821
|
return evaluation;
|
|
768
822
|
}
|
package/src/instance.spec.ts
CHANGED
|
@@ -1147,6 +1147,137 @@ describe("sdk: instance", function () {
|
|
|
1147
1147
|
).toEqual("orange");
|
|
1148
1148
|
});
|
|
1149
1149
|
|
|
1150
|
+
it("should apply rule variableOverrides on top of rule variables", function () {
|
|
1151
|
+
const sdk = createInstance({
|
|
1152
|
+
datafile: {
|
|
1153
|
+
schemaVersion: "2",
|
|
1154
|
+
revision: "1.0",
|
|
1155
|
+
segments: {
|
|
1156
|
+
germany: {
|
|
1157
|
+
key: "germany",
|
|
1158
|
+
conditions: JSON.stringify([
|
|
1159
|
+
{
|
|
1160
|
+
attribute: "country",
|
|
1161
|
+
operator: "equals",
|
|
1162
|
+
value: "de",
|
|
1163
|
+
},
|
|
1164
|
+
]),
|
|
1165
|
+
},
|
|
1166
|
+
mobile: {
|
|
1167
|
+
key: "mobile",
|
|
1168
|
+
conditions: JSON.stringify([
|
|
1169
|
+
{
|
|
1170
|
+
attribute: "device",
|
|
1171
|
+
operator: "equals",
|
|
1172
|
+
value: "mobile",
|
|
1173
|
+
},
|
|
1174
|
+
]),
|
|
1175
|
+
},
|
|
1176
|
+
},
|
|
1177
|
+
features: {
|
|
1178
|
+
test: {
|
|
1179
|
+
key: "test",
|
|
1180
|
+
bucketBy: "userId",
|
|
1181
|
+
variablesSchema: {
|
|
1182
|
+
config: {
|
|
1183
|
+
key: "config",
|
|
1184
|
+
type: "object",
|
|
1185
|
+
defaultValue: {
|
|
1186
|
+
source: "default",
|
|
1187
|
+
nested: { value: 0 },
|
|
1188
|
+
},
|
|
1189
|
+
},
|
|
1190
|
+
},
|
|
1191
|
+
traffic: [
|
|
1192
|
+
{
|
|
1193
|
+
key: "germany",
|
|
1194
|
+
segments: "germany",
|
|
1195
|
+
percentage: 100000,
|
|
1196
|
+
variables: {
|
|
1197
|
+
config: {
|
|
1198
|
+
source: "rule",
|
|
1199
|
+
nested: { value: 10 },
|
|
1200
|
+
flag: true,
|
|
1201
|
+
},
|
|
1202
|
+
},
|
|
1203
|
+
variableOverrides: {
|
|
1204
|
+
config: [
|
|
1205
|
+
{
|
|
1206
|
+
segments: "mobile",
|
|
1207
|
+
value: {
|
|
1208
|
+
source: "rule",
|
|
1209
|
+
nested: { value: 20 },
|
|
1210
|
+
flag: true,
|
|
1211
|
+
},
|
|
1212
|
+
},
|
|
1213
|
+
{
|
|
1214
|
+
conditions: [
|
|
1215
|
+
{
|
|
1216
|
+
attribute: "country",
|
|
1217
|
+
operator: "equals",
|
|
1218
|
+
value: "de",
|
|
1219
|
+
},
|
|
1220
|
+
],
|
|
1221
|
+
value: {
|
|
1222
|
+
source: "rule",
|
|
1223
|
+
nested: { value: 30 },
|
|
1224
|
+
flag: true,
|
|
1225
|
+
},
|
|
1226
|
+
},
|
|
1227
|
+
],
|
|
1228
|
+
},
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
key: "everyone",
|
|
1232
|
+
segments: "*",
|
|
1233
|
+
percentage: 100000,
|
|
1234
|
+
variables: {
|
|
1235
|
+
config: {
|
|
1236
|
+
source: "everyone",
|
|
1237
|
+
nested: { value: 1 },
|
|
1238
|
+
},
|
|
1239
|
+
},
|
|
1240
|
+
},
|
|
1241
|
+
],
|
|
1242
|
+
},
|
|
1243
|
+
},
|
|
1244
|
+
},
|
|
1245
|
+
});
|
|
1246
|
+
|
|
1247
|
+
expect(
|
|
1248
|
+
sdk.getVariableObject("test", "config", {
|
|
1249
|
+
userId: "user-1",
|
|
1250
|
+
country: "de",
|
|
1251
|
+
}),
|
|
1252
|
+
).toEqual({
|
|
1253
|
+
source: "rule",
|
|
1254
|
+
nested: { value: 30 },
|
|
1255
|
+
flag: true,
|
|
1256
|
+
});
|
|
1257
|
+
|
|
1258
|
+
expect(
|
|
1259
|
+
sdk.getVariableObject("test", "config", {
|
|
1260
|
+
userId: "user-1",
|
|
1261
|
+
country: "de",
|
|
1262
|
+
device: "mobile",
|
|
1263
|
+
}),
|
|
1264
|
+
).toEqual({
|
|
1265
|
+
source: "rule",
|
|
1266
|
+
nested: { value: 20 },
|
|
1267
|
+
flag: true,
|
|
1268
|
+
});
|
|
1269
|
+
|
|
1270
|
+
expect(
|
|
1271
|
+
sdk.getVariableObject("test", "config", {
|
|
1272
|
+
userId: "user-1",
|
|
1273
|
+
country: "nl",
|
|
1274
|
+
}),
|
|
1275
|
+
).toEqual({
|
|
1276
|
+
source: "everyone",
|
|
1277
|
+
nested: { value: 1 },
|
|
1278
|
+
});
|
|
1279
|
+
});
|
|
1280
|
+
|
|
1150
1281
|
describe("array and object variables", function () {
|
|
1151
1282
|
const arrayAndObjectDatafile: DatafileContent = {
|
|
1152
1283
|
schemaVersion: "2",
|