UNPKG

unleash-client

Version:
192 lines 7.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Strategy = exports.Operator = void 0; const semver_1 = require("semver"); const helpers_1 = require("../helpers"); const variant_1 = require("../variant"); var Operator; (function (Operator) { Operator["IN"] = "IN"; Operator["NOT_IN"] = "NOT_IN"; Operator["STR_ENDS_WITH"] = "STR_ENDS_WITH"; Operator["STR_STARTS_WITH"] = "STR_STARTS_WITH"; Operator["STR_CONTAINS"] = "STR_CONTAINS"; Operator["NUM_EQ"] = "NUM_EQ"; Operator["NUM_GT"] = "NUM_GT"; Operator["NUM_GTE"] = "NUM_GTE"; Operator["NUM_LT"] = "NUM_LT"; Operator["NUM_LTE"] = "NUM_LTE"; Operator["DATE_AFTER"] = "DATE_AFTER"; Operator["DATE_BEFORE"] = "DATE_BEFORE"; Operator["SEMVER_EQ"] = "SEMVER_EQ"; Operator["SEMVER_GT"] = "SEMVER_GT"; Operator["SEMVER_LT"] = "SEMVER_LT"; })(Operator || (exports.Operator = Operator = {})); const cleanValues = (values) => values.filter((v) => !!v).map((v) => v.trim()); const isValidSemver = (version) => Boolean((0, semver_1.valid)(version)) && !version.startsWith('v'); const InOperator = (constraint, context) => { const field = constraint.contextName; const values = cleanValues(constraint.values); const contextValue = (0, helpers_1.resolveContextValue)(context, field); const isIn = values.some((val) => val === contextValue); return constraint.operator === Operator.IN ? isIn : !isIn; }; const StringOperator = (constraint, context) => { const { contextName, operator, caseInsensitive } = constraint; let values = cleanValues(constraint.values); let contextValue = (0, helpers_1.resolveContextValue)(context, contextName); if (caseInsensitive) { values = values.map((v) => v.toLocaleLowerCase()); contextValue = contextValue === null || contextValue === void 0 ? void 0 : contextValue.toLocaleLowerCase(); } if (typeof contextValue !== 'string') { return false; } if (operator === Operator.STR_STARTS_WITH) { return values.some((val) => contextValue === null || contextValue === void 0 ? void 0 : contextValue.startsWith(val)); } if (operator === Operator.STR_ENDS_WITH) { return values.some((val) => contextValue === null || contextValue === void 0 ? void 0 : contextValue.endsWith(val)); } if (operator === Operator.STR_CONTAINS) { return values.some((val) => contextValue === null || contextValue === void 0 ? void 0 : contextValue.includes(val)); } return false; }; const SemverOperator = (constraint, context) => { const { contextName, operator } = constraint; const value = constraint.value; const contextValue = (0, helpers_1.resolveContextValue)(context, contextName); if (!contextValue) { return false; } try { if (!isValidSemver(contextValue)) { return false; } if (operator === Operator.SEMVER_EQ) { return (0, semver_1.eq)(contextValue, value); } if (operator === Operator.SEMVER_LT) { return (0, semver_1.lt)(contextValue, value); } if (operator === Operator.SEMVER_GT) { return (0, semver_1.gt)(contextValue, value); } } catch (e) { return false; } return false; }; const DateOperator = (constraint, context) => { const { operator } = constraint; const value = new Date(constraint.value); const currentTime = context.currentTime ? new Date(context.currentTime) : new Date(); if (operator === Operator.DATE_AFTER) { return currentTime > value; } if (operator === Operator.DATE_BEFORE) { return currentTime < value; } return false; }; const NumberOperator = (constraint, context) => { const field = constraint.contextName; const { operator } = constraint; const value = Number(constraint.value); const contextValue = Number((0, helpers_1.resolveContextValue)(context, field)); if (Number.isNaN(value) || Number.isNaN(contextValue)) { return false; } if (operator === Operator.NUM_EQ) { return contextValue === value; } if (operator === Operator.NUM_GT) { return contextValue > value; } if (operator === Operator.NUM_GTE) { return contextValue >= value; } if (operator === Operator.NUM_LT) { return contextValue < value; } if (operator === Operator.NUM_LTE) { return contextValue <= value; } return false; }; const operators = new Map(); operators.set(Operator.IN, InOperator); operators.set(Operator.NOT_IN, InOperator); operators.set(Operator.STR_STARTS_WITH, StringOperator); operators.set(Operator.STR_ENDS_WITH, StringOperator); operators.set(Operator.STR_CONTAINS, StringOperator); operators.set(Operator.NUM_EQ, NumberOperator); operators.set(Operator.NUM_LT, NumberOperator); operators.set(Operator.NUM_LTE, NumberOperator); operators.set(Operator.NUM_GT, NumberOperator); operators.set(Operator.NUM_GTE, NumberOperator); operators.set(Operator.DATE_AFTER, DateOperator); operators.set(Operator.DATE_BEFORE, DateOperator); operators.set(Operator.SEMVER_EQ, SemverOperator); operators.set(Operator.SEMVER_GT, SemverOperator); operators.set(Operator.SEMVER_LT, SemverOperator); class Strategy { constructor(name, returnValue = false) { this.name = name || 'unknown'; this.returnValue = returnValue; } checkConstraint(constraint, context) { const evaluator = operators.get(constraint.operator); if (!evaluator) { return false; } if (constraint.inverted) { return !evaluator(constraint, context); } return evaluator(constraint, context); } checkConstraints(context, constraints) { if (!constraints) { return true; } // eslint-disable-next-line no-restricted-syntax for (const constraint of constraints) { if (!constraint || !this.checkConstraint(constraint, context)) { return false; } } return true; } // eslint-disable-next-line @typescript-eslint/no-unused-vars isEnabled(parameters, context) { return this.returnValue; } isEnabledWithConstraints(parameters, context, constraints) { return this.checkConstraints(context, constraints) && this.isEnabled(parameters, context); } getResult(parameters, context, constraints, variants) { const enabled = this.isEnabledWithConstraints(parameters, context, constraints); if (enabled && Array.isArray(variants) && variants.length > 0) { const stickiness = variants[0].stickiness || parameters.stickiness; const variantDefinition = (0, variant_1.selectVariantDefinition)(parameters.groupId, stickiness, variants, context); return variantDefinition ? { enabled: true, variant: { name: variantDefinition.name, enabled: true, payload: variantDefinition.payload, }, } : { enabled: true }; } if (enabled) { return { enabled: true }; } return { enabled: false }; } } exports.Strategy = Strategy; //# sourceMappingURL=strategy.js.map