All files conditions.ts

98.64% Statements 73/74
92.5% Branches 74/80
100% Functions 3/3
98.63% Lines 72/73

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 108 109 110 111 112 113 114 115 116 117 118      6x   6x 1004x 992x     24x     6x         754x 754x   754x 666x 88x 2x 86x   8x     8x 8x   8x     78x           8x   8x 4x 4x 4x   70x   40x   40x 3x 37x 3x 34x   34x 3x 31x 2x 29x 2x 27x 2x 25x 3x 22x 2x 20x 2x 18x 10x 10x 8x 8x 8x   30x   12x   12x 2x 10x 4x 6x 2x 4x 4x   18x 6x 12x 6x 6x               4x 4x   4x 2x 2x 2x       2x    
import type { Context, PlainCondition, AttributeValue } from "@featurevisor/types";
 
import { GetRegex } from "./datafileReader";
import { compareVersions } from "./compareVersions";
 
export function getValueFromContext(obj, path): AttributeValue {
  if (path.indexOf(".") === -1) {
    return obj[path];
  }
 
  return path.split(".").reduce((o, i) => (o ? o[i] : undefined), obj);
}
 
export function conditionIsMatched(
  condition: PlainCondition,
  context: Context,
  getRegex: GetRegex,
): boolean {
  const { attribute, operator, value, regexFlags } = condition;
  const contextValueFromPath = getValueFromContext(context, attribute) as AttributeValue;
 
  if (operator === "equals") {
    return contextValueFromPath === value;
  } else if (operator === "notEquals") {
    return contextValueFromPath !== value;
  } else if (operator === "before" || operator === "after") {
    // date comparisons
    const valueInContext = contextValueFromPath as string | Date;
 
    const dateInContext =
      valueInContext instanceof Date ? valueInContext : new Date(valueInContext);
    const dateInCondition = value instanceof Date ? value : new Date(value as string);
 
    return operator === "before"
      ? dateInContext < dateInCondition
      : dateInContext > dateInCondition;
  } else if (
    Array.isArray(value) &&
    (["string", "number"].indexOf(typeof contextValueFromPath) !== -1 ||
      contextValueFromPath === null)
  ) {
    // in / notIn (where condition value is an array)
    const valueInContext = contextValueFromPath as string;
 
    if (operator === "in") {
      return value.indexOf(valueInContext) !== -1;
    } else if (operator === "notIn") {
      return value.indexOf(valueInContext) === -1;
    }
  } else if (typeof contextValueFromPath === "string" && typeof value === "string") {
    // string
    const valueInContext = contextValueFromPath as string;
 
    if (operator === "contains") {
      return valueInContext.indexOf(value) !== -1;
    } else if (operator === "notContains") {
      return valueInContext.indexOf(value) === -1;
    } else Iif (operator === "startsWith") {
      return valueInContext.startsWith(value);
    } else if (operator === "endsWith") {
      return valueInContext.endsWith(value);
    } else if (operator === "semverEquals") {
      return compareVersions(valueInContext, value) === 0;
    } else if (operator === "semverNotEquals") {
      return compareVersions(valueInContext, value) !== 0;
    } else if (operator === "semverGreaterThan") {
      return compareVersions(valueInContext, value) === 1;
    } else if (operator === "semverGreaterThanOrEquals") {
      return compareVersions(valueInContext, value) >= 0;
    } else if (operator === "semverLessThan") {
      return compareVersions(valueInContext, value) === -1;
    } else if (operator === "semverLessThanOrEquals") {
      return compareVersions(valueInContext, value) <= 0;
    } else if (operator === "matches") {
      const regex = getRegex(value, regexFlags || "");
      return regex.test(valueInContext);
    } else if (operator === "notMatches") {
      const regex = getRegex(value, regexFlags || "");
      return !regex.test(valueInContext);
    }
  } else if (typeof contextValueFromPath === "number" && typeof value === "number") {
    // numeric
    const valueInContext = contextValueFromPath as number;
 
    if (operator === "greaterThan") {
      return valueInContext > value;
    } else if (operator === "greaterThanOrEquals") {
      return valueInContext >= value;
    } else if (operator === "lessThan") {
      return valueInContext < value;
    } else if (operator === "lessThanOrEquals") {
      return valueInContext <= value;
    }
  } else if (operator === "exists") {
    return typeof contextValueFromPath !== "undefined";
  } else if (operator === "notExists") {
    return typeof contextValueFromPath === "undefined";
  } else if (
    Array.isArray(contextValueFromPath) &&
    (typeof value === "string" ||
      typeof value === "number" ||
      typeof value === "boolean" ||
      value === null)
  ) {
    // includes / notIncludes (where context value is an array of primitive values)
    const valueInContext = contextValueFromPath as Array<string | number | boolean | null>;
    const primitiveValue = value as string | number | boolean | null;
 
    if (operator === "includes") {
      return valueInContext.indexOf(primitiveValue) > -1;
    } else if (operator === "notIncludes") {
      return valueInContext.indexOf(primitiveValue) === -1;
    }
  }
 
  return false;
}