@airgrid/edgekit
Version:
A privacy focused library for cookie-less audience creation.
64 lines (58 loc) • 2.03 kB
text/typescript
import * as reducers from './reducers';
import * as matchers from './matchers';
import { queryMatches } from './filters';
import {
PageView,
EngineCondition,
AudienceDefinitionFilter,
} from '../../types';
/* Filter the pageView array by matching queries
* and evaluates if it matches the conditions
* based on the condition reducing rules
*/
export const evaluateCondition = (
condition: Readonly<EngineCondition<AudienceDefinitionFilter>>,
pageViews: Readonly<PageView[]>
): boolean => {
try {
const { filter, rules } = condition;
// if no queries, do not match at all
if (pageViews.length === 0 || filter.queries.length === 0) {
return false;
}
/* Checks each pageView once for any matching queries
* and returns the filtered array containing the matched
* pageViews
*
* TODO Here, also, we have an opportunity to implement the
* internal AND logic, swapping some for every
* according to the value of filter.any
*
* NOTE: there is actually a semantic problem here.
* The filter definition specifies an 'any' switch,
* which defaults to false. However, the current
* filtering uses `some` to check the query conditions.
* The complete implementation here would be:
* ```
* filter.queries[filter.any ? 'some' : 'every']((query) => ...
* ```
* Yet, there is too much (testing) code depending on
* this defaulting to `some` and the refactor would take
* some time.
*/
const filteredPageViews = pageViews.filter((pageView) =>
filter.queries.some((query) => {
const pageFeatures = pageView.features[query.queryProperty];
return queryMatches(query, pageFeatures);
})
);
return rules.every((rule) => {
const reducer = reducers[rule.reducer.name]();
const value = reducer(filteredPageViews);
const matches = matchers[rule.matcher.name](rule.matcher.args);
return matches(value);
});
} catch (error) {
return false;
}
};