@featurevisor/sdk 0.15.0 → 0.17.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/src/feature.ts CHANGED
@@ -13,24 +13,56 @@ import { allConditionsAreMatched } from "./conditions";
13
13
  import { VariableSchema } from "@featurevisor/types/src";
14
14
  import { Logger } from "./logger";
15
15
 
16
- export function getMatchedTraffic(
16
+ /**
17
+ * Traffic
18
+ */
19
+ export function getMatchedAllocation(
20
+ traffic: Traffic,
21
+ bucketValue: number,
22
+ ): Allocation | undefined {
23
+ let total = 0; // @TODO: remove it in next breaking semver
24
+ const usePercentage =
25
+ traffic.allocation.length > 0 && typeof traffic.allocation[0].range === "undefined"; // @TODO: remove it in next breaking semver
26
+
27
+ for (const allocation of traffic.allocation) {
28
+ if (
29
+ allocation.range &&
30
+ allocation.range.start <= bucketValue &&
31
+ allocation.range.end >= bucketValue
32
+ ) {
33
+ return allocation;
34
+ }
35
+
36
+ // @TODO: remove it in next breaking semver
37
+ if (usePercentage) {
38
+ total += allocation.percentage || 0;
39
+ if (bucketValue <= total) {
40
+ return allocation;
41
+ }
42
+ }
43
+ }
44
+
45
+ return undefined;
46
+ }
47
+
48
+ export interface MatchedTrafficAndAllocation {
49
+ matchedTraffic: Traffic | undefined;
50
+ matchedAllocation: Allocation | undefined;
51
+ }
52
+
53
+ export function getMatchedTrafficAndAllocation(
17
54
  traffic: Traffic[],
18
55
  attributes: Attributes,
19
56
  bucketValue: number,
20
57
  datafileReader: DatafileReader,
21
58
  logger: Logger,
22
- ): Traffic | undefined {
23
- return traffic.find((traffic) => {
24
- if (bucketValue > traffic.percentage) {
25
- // out of bucket range
26
- return false;
27
- }
59
+ ): MatchedTrafficAndAllocation {
60
+ let matchedAllocation: Allocation | undefined;
28
61
 
62
+ const matchedTraffic = traffic.find((t) => {
29
63
  if (
30
64
  !allGroupSegmentsAreMatched(
31
- typeof traffic.segments === "string" && traffic.segments !== "*"
32
- ? JSON.parse(traffic.segments)
33
- : traffic.segments,
65
+ typeof t.segments === "string" && t.segments !== "*" ? JSON.parse(t.segments) : t.segments,
34
66
  attributes,
35
67
  datafileReader,
36
68
  )
@@ -38,32 +70,24 @@ export function getMatchedTraffic(
38
70
  return false;
39
71
  }
40
72
 
41
- logger.debug("matched rule", {
42
- ruleKey: traffic.key,
43
- });
44
-
45
- return true;
46
- });
47
- }
48
-
49
- // @TODO: make this function better with tests
50
- export function getMatchedAllocation(
51
- matchedTraffic: Traffic,
52
- bucketValue: number,
53
- ): Allocation | undefined {
54
- let total = 0;
55
-
56
- for (const allocation of matchedTraffic.allocation) {
57
- total += allocation.percentage;
73
+ matchedAllocation = getMatchedAllocation(t, bucketValue);
58
74
 
59
- if (bucketValue <= total) {
60
- return allocation;
75
+ if (matchedAllocation) {
76
+ return true;
61
77
  }
62
- }
63
78
 
64
- return undefined;
79
+ return false;
80
+ });
81
+
82
+ return {
83
+ matchedTraffic,
84
+ matchedAllocation,
85
+ };
65
86
  }
66
87
 
88
+ /**
89
+ * Variations and variables
90
+ */
67
91
  function findForceFromFeature(
68
92
  feature: Feature,
69
93
  attributes: Attributes,
@@ -107,7 +131,7 @@ export function getBucketedVariation(
107
131
  datafileReader: DatafileReader,
108
132
  logger: Logger,
109
133
  ): Variation | undefined {
110
- const matchedTraffic = getMatchedTraffic(
134
+ const { matchedTraffic, matchedAllocation } = getMatchedTrafficAndAllocation(
111
135
  feature.traffic,
112
136
  attributes,
113
137
  bucketValue,
@@ -140,9 +164,7 @@ export function getBucketedVariation(
140
164
  }
141
165
  }
142
166
 
143
- const allocation = getMatchedAllocation(matchedTraffic, bucketValue);
144
-
145
- if (!allocation) {
167
+ if (!matchedAllocation) {
146
168
  logger.debug("no matched allocation found", {
147
169
  featureKey: feature.key,
148
170
  bucketValue,
@@ -151,7 +173,7 @@ export function getBucketedVariation(
151
173
  return undefined;
152
174
  }
153
175
 
154
- const variationValue = allocation.variation;
176
+ const variationValue = matchedAllocation.variation;
155
177
 
156
178
  const variation = feature.variations.find((v) => {
157
179
  return v.value === variationValue;
@@ -207,7 +229,7 @@ export function getBucketedVariableValue(
207
229
  logger: Logger,
208
230
  ): VariableValue | undefined {
209
231
  // get traffic
210
- const matchedTraffic = getMatchedTraffic(
232
+ const { matchedTraffic, matchedAllocation } = getMatchedTrafficAndAllocation(
211
233
  feature.traffic,
212
234
  attributes,
213
235
  bucketValue,
@@ -238,9 +260,7 @@ export function getBucketedVariableValue(
238
260
  return matchedTraffic.variables[variableKey];
239
261
  }
240
262
 
241
- const allocation = getMatchedAllocation(matchedTraffic, bucketValue);
242
-
243
- if (!allocation) {
263
+ if (!matchedAllocation) {
244
264
  logger.debug("no matched allocation found", {
245
265
  featureKey: feature.key,
246
266
  variableKey,
@@ -250,7 +270,7 @@ export function getBucketedVariableValue(
250
270
  return undefined;
251
271
  }
252
272
 
253
- const variationValue = allocation.variation;
273
+ const variationValue = matchedAllocation.variation;
254
274
 
255
275
  const variation = feature.variations.find((v) => {
256
276
  return v.value === variationValue;