1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-06-14 01:16:17 +02:00
unleash.unleash/src/lib/features/playground/feature-evaluator/variant.ts

115 lines
2.9 KiB
TypeScript

import { Context } from './context';
// eslint-disable-next-line import/no-cycle
import { FeatureInterface } from './feature';
import normalizedValue from './strategy/util';
import { resolveContextValue } from './helpers';
import { PayloadType } from 'unleash-client';
interface Override {
contextName: string;
values: string[];
}
export interface Payload {
type: PayloadType;
value: string;
}
export interface VariantDefinition {
name: string;
weight: number;
stickiness?: string;
payload: Payload;
overrides: Override[];
}
export interface Variant {
name: string;
enabled: boolean;
payload?: Payload;
}
export function getDefaultVariant(): Variant {
return {
name: 'disabled',
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(
feature: FeatureInterface,
context: Context,
): VariantDefinition | undefined {
return feature.variants
.filter((variant) => variant.overrides)
.find((variant) =>
variant.overrides.some(overrideMatchesContext(context)),
);
}
export function selectVariant(
feature: FeatureInterface,
context: Context,
): VariantDefinition | null {
const totalWeight = feature.variants.reduce((acc, v) => acc + v.weight, 0);
if (totalWeight <= 0) {
return null;
}
const variantOverride = findOverride(feature, context);
if (variantOverride) {
return variantOverride;
}
const { stickiness } = feature.variants[0];
const target = normalizedValue(
getSeed(context, stickiness),
feature.name,
totalWeight,
);
let counter = 0;
const variant = feature.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;
}