@splitsoftware/splitio-commons
Version:
Split JavaScript SDK common components
83 lines (71 loc) • 2.98 kB
text/typescript
import { matchersTransform } from '../matchersTransform';
import { Treatments } from '../treatments';
import { matcherFactory } from '../matchers';
import { sanitizeValue } from '../value';
import { conditionContext } from '../condition';
import { ifElseIfCombinerContext } from '../combiners/ifelseif';
import { andCombinerContext } from '../combiners/and';
import { thenable } from '../../utils/promise/thenable';
import { IEvaluator, IMatcherDto, IDefinitionEvaluator } from '../types';
import { IDefinitionCondition, MaybeThenable } from '../../dtos/types';
import { IStorageAsync, IStorageSync } from '../../storages/types';
import SplitIO from '../../../types/splitio';
import { ILogger } from '../../logger/types';
import { ENGINE_MATCHER_ERROR, ENGINE_MATCHER_RESULT } from '../../logger/constants';
export function parser(log: ILogger, conditions: IDefinitionCondition[], storage: IStorageSync | IStorageAsync): IEvaluator {
let predicates = [];
for (let i = 0; i < conditions.length; i++) {
let {
matcherGroup,
partitions,
label,
conditionType
} = conditions[i];
// transform data structure
const matchers = matchersTransform(matcherGroup.matchers);
// create a set of pure functions from the matcher's dto
const expressions = matchers.map((matcherDto: IMatcherDto) => {
let matcher: ReturnType<typeof matcherFactory>;
try {
matcher = matcherFactory(log, matcherDto, storage);
} catch (error) {
log.error(ENGINE_MATCHER_ERROR, [matcherDto.name, error]);
}
// Evaluator function.
return (key: SplitIO.SplitKey, attributes?: SplitIO.Attributes, splitEvaluator?: IDefinitionEvaluator) => {
const value = sanitizeValue(log, key, matcherDto, attributes);
let result: MaybeThenable<boolean> = false;
if (value !== undefined && matcher) {
try {
result = matcher(value, splitEvaluator);
} catch (error) {
log.error(ENGINE_MATCHER_ERROR, [matcherDto.name, error]);
}
}
function handleResult(result: boolean) {
log.debug(ENGINE_MATCHER_RESULT, [matcherDto.name, result, matcherDto.value, value]); // @ts-ignore
return Boolean(result ^ matcherDto.negate);
}
return thenable(result) ?
result.then(handleResult) :
handleResult(result);
};
});
// if matcher's factory can't instantiate the matchers, the expressions array will be empty
if (expressions.length === 0) {
// reset any data collected during parsing
predicates = [];
// and break the loop
break;
}
predicates.push(conditionContext(
log,
andCombinerContext(log, expressions),
partitions && Treatments.parse(partitions),
label,
conditionType
));
}
// Instantiate evaluator given the set of conditions using if else if logic
return ifElseIfCombinerContext(log, predicates);
}