@splitsoftware/splitio-commons
Version:
Split JavaScript SDK common components
129 lines (128 loc) • 5.29 kB
JavaScript
import { engineParser } from './Engine';
import { thenable } from '../utils/promise/thenable';
import { EXCEPTION, SPLIT_NOT_FOUND } from '../utils/labels';
import { CONTROL } from '../utils/constants';
import { returnSetsUnion, setToArray } from '../utils/lang/sets';
import { WARN_FLAGSET_WITHOUT_FLAGS } from '../logger/constants';
var treatmentException = {
treatment: CONTROL,
label: EXCEPTION,
config: null
};
function treatmentsException(splitNames) {
var evaluations = {};
splitNames.forEach(function (splitName) {
evaluations[splitName] = treatmentException;
});
return evaluations;
}
export function evaluateFeature(log, key, splitName, attributes, storage) {
var parsedSplit;
try {
parsedSplit = storage.splits.getSplit(splitName);
}
catch (e) {
// Exception on sync `getSplit` storage. Not possible ATM with InMemory and InLocal storages.
return treatmentException;
}
if (thenable(parsedSplit)) {
return parsedSplit.then(function (split) { return getEvaluation(log, key, split, attributes, storage); }).catch(
// Exception on async `getSplit` storage. For example, when the storage is redis or
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
function () { return treatmentException; });
}
return getEvaluation(log, key, parsedSplit, attributes, storage);
}
export function evaluateFeatures(log, key, splitNames, attributes, storage) {
var parsedSplits;
try {
parsedSplits = storage.splits.getSplits(splitNames);
}
catch (e) {
// Exception on sync `getSplits` storage. Not possible ATM with InMemory and InLocal storages.
return treatmentsException(splitNames);
}
return thenable(parsedSplits) ?
parsedSplits.then(function (splits) { return getEvaluations(log, key, splitNames, splits, attributes, storage); })
.catch(function () {
// Exception on async `getSplits` storage. For example, when the storage is redis or
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
return treatmentsException(splitNames);
}) :
getEvaluations(log, key, splitNames, parsedSplits, attributes, storage);
}
export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method) {
var storedFlagNames;
function evaluate(featureFlagsByFlagSets) {
var featureFlags = new Set();
for (var i = 0; i < flagSets.length; i++) {
var featureFlagByFlagSet = featureFlagsByFlagSets[i];
if (featureFlagByFlagSet.size) {
featureFlags = returnSetsUnion(featureFlags, featureFlagByFlagSet);
}
else {
log.warn(WARN_FLAGSET_WITHOUT_FLAGS, [method, flagSets[i]]);
}
}
return featureFlags.size ?
evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage) :
{};
}
// get features by flag sets
try {
storedFlagNames = storage.splits.getNamesByFlagSets(flagSets);
}
catch (e) {
// return empty evaluations
return {};
}
// evaluate related features
return thenable(storedFlagNames) ?
storedFlagNames.then(function (storedFlagNames) { return evaluate(storedFlagNames); })
.catch(function () {
return {};
}) :
evaluate(storedFlagNames);
}
function getEvaluation(log, key, splitJSON, attributes, storage) {
var evaluation = {
treatment: CONTROL,
label: SPLIT_NOT_FOUND,
config: null
};
if (splitJSON) {
var split = engineParser(log, splitJSON, storage);
evaluation = split.getTreatment(key, attributes, evaluateFeature);
// If the storage is async and the evaluated flag uses segments or dependencies, evaluation is thenable
if (thenable(evaluation)) {
return evaluation.then(function (result) {
result.changeNumber = splitJSON.changeNumber;
result.config = splitJSON.configurations && splitJSON.configurations[result.treatment] || null;
result.impressionsDisabled = splitJSON.impressionsDisabled;
return result;
});
}
else {
evaluation.changeNumber = splitJSON.changeNumber;
evaluation.config = splitJSON.configurations && splitJSON.configurations[evaluation.treatment] || null;
evaluation.impressionsDisabled = splitJSON.impressionsDisabled;
}
}
return evaluation;
}
function getEvaluations(log, key, splitNames, splits, attributes, storage) {
var result = {};
var thenables = [];
splitNames.forEach(function (splitName) {
var evaluation = getEvaluation(log, key, splits[splitName], attributes, storage);
if (thenable(evaluation)) {
thenables.push(evaluation.then(function (res) {
result[splitName] = res;
}));
}
else {
result[splitName] = evaluation;
}
});
return thenables.length > 0 ? Promise.all(thenables).then(function () { return result; }) : result;
}