-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathvariant.ts
107 lines (95 loc) · 2.72 KB
/
variant.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import type { Context, Variant } from "unleash-client/lib";
import type { FeatureInterface } from "unleash-client/lib/feature";
import type { VariantDefinition } from "unleash-client/lib/variant";
import { resolveContextValue } from "./client/helpers";
import normalizedValue from "./hash";
type Override = {
contextName: string;
values: string[];
};
const VARIANT_HASH_SEED = 86028157;
export function getDefaultVariant(): Variant {
return {
name: "disabled",
enabled: false,
feature_enabled: false,
};
}
function randomString() {
return String(Math.round(Math.random() * 100000));
}
const stickinessSelectors = ["userId", "sessionId", "remoteAddress"];
function getSeed(context: Context, stickiness: string = "default"): string {
if (stickiness !== "default") {
const value = resolveContextValue(context, stickiness);
return value ? value.toString() : randomString();
}
let result;
stickinessSelectors.some((key: string): boolean => {
const value = context[key];
if (typeof value === "string" && value !== "") {
result = value;
return true;
}
return false;
});
return result || randomString();
}
function overrideMatchesContext(context: Context): (o: Override) => boolean {
return (o: Override) =>
o.values.some(
(value) => value === resolveContextValue(context, o.contextName)
);
}
function findOverride(
variants: VariantDefinition[],
context: Context
): VariantDefinition | undefined {
return variants
.filter((variant) => variant.overrides)
.find(
(variant) => variant.overrides?.some(overrideMatchesContext(context))
);
}
export function selectVariantDefinition(
groupId: string,
stickiness: string | undefined,
variants: VariantDefinition[],
context: Context
): VariantDefinition | null {
const totalWeight = variants.reduce((acc, v) => acc + v.weight, 0);
if (totalWeight <= 0) {
return null;
}
const variantOverride = findOverride(variants, context);
if (variantOverride) {
return variantOverride;
}
const target = normalizedValue(
getSeed(context, stickiness),
groupId,
totalWeight,
VARIANT_HASH_SEED
);
let counter = 0;
const variant = variants.find(
(v: VariantDefinition): VariantDefinition | undefined => {
if (v.weight === 0) {
return undefined;
}
counter += v.weight;
if (counter < target) {
return undefined;
}
return v;
}
);
return variant || null;
}
export function selectVariant(
feature: FeatureInterface,
context: Context
): VariantDefinition | null {
const stickiness = feature.variants?.[0]?.stickiness ?? undefined;
return selectVariantDefinition(feature.name, stickiness, feature.variants || [], context);
}