array-expression
Advanced tools
| import type { Data, Expression, Value } from "./interface"; | ||
| export declare const evalVal: (value: Value, data?: Data) => string | number | boolean | Expression; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.evalVal = void 0; | ||
| const decision_1 = require("./functions/decision"); | ||
| const math_1 = require("./functions/math"); | ||
| const string_1 = require("./functions/string"); | ||
| const type_1 = require("./functions/type"); | ||
| const utils_1 = require("./utils"); | ||
| // prettier-ignore | ||
| const FUNCTIONS = { | ||
| "boolean": type_1.bool, | ||
| "string": type_1.str, | ||
| "+": math_1.add, | ||
| "-": math_1.subtract, | ||
| "*": math_1.multiply, | ||
| "/": math_1.divide, | ||
| "%": math_1.remainder, | ||
| "^": math_1.power, | ||
| "sqrt": math_1.sqrt, | ||
| "abs": math_1.abs, | ||
| "sin": math_1.sin, | ||
| "cos": math_1.cos, | ||
| "tan": math_1.tan, | ||
| "log": math_1.log, | ||
| "floor": math_1.floor, | ||
| "ceil": math_1.ceil, | ||
| "round": math_1.round, | ||
| "min": math_1.min, | ||
| "max": math_1.max, | ||
| "!": decision_1.negate, | ||
| "==": decision_1.equalTo, | ||
| "!=": decision_1.notEqualTo, | ||
| "<": decision_1.lessThan, | ||
| "<=": decision_1.lessThanOrEqual, | ||
| ">": decision_1.greaterThan, | ||
| ">=": decision_1.greaterThanOrEqual, | ||
| "all": decision_1.all, | ||
| "any": decision_1.any, | ||
| "if": decision_1.ifElse, | ||
| "concat": string_1.concat, | ||
| "downcase": string_1.downcase, | ||
| "upcase": string_1.upcase, | ||
| "number-format": string_1.numberFormat | ||
| }; | ||
| const evalVal = (value, data) => { | ||
| if ((0, utils_1.isConstant)(value)) { | ||
| if (data && typeof value === "string") { | ||
| const wildcardRegex = /^\$(\w+)$/; | ||
| const match = wildcardRegex.exec(value); | ||
| if (match && match[1]) { | ||
| return data[match[1]]; | ||
| } | ||
| } | ||
| return value; | ||
| } | ||
| if ((0, utils_1.isExpression)(value)) | ||
| return evalExp(value, data); | ||
| throw new Error("Value is not constant or expression"); | ||
| }; | ||
| exports.evalVal = evalVal; | ||
| const evalExp = (expression, data) => { | ||
| const [name, ...args] = expression; | ||
| const func = FUNCTIONS[name]; | ||
| if (!func) | ||
| throw new Error("Invalid expression"); | ||
| return func(...args.map((arg) => (0, exports.evalVal)(arg, data))); | ||
| }; |
| import type { Constant } from '../interface'; | ||
| export declare const negate: (value: Constant) => boolean; | ||
| export declare const equalTo: (a: Constant, b: Constant) => boolean; | ||
| export declare const notEqualTo: (a: Constant, b: Constant) => boolean; | ||
| export declare const lessThan: (a: string | number, b: string | number) => boolean; | ||
| export declare const lessThanOrEqual: (a: string | number, b: string | number) => boolean; | ||
| export declare const greaterThan: (a: string | number, b: string | number) => boolean; | ||
| export declare const greaterThanOrEqual: (a: string | number, b: string | number) => boolean; | ||
| export declare const all: (...values: Constant[]) => boolean; | ||
| export declare const any: (...values: Constant[]) => boolean; | ||
| export declare const ifElse: (...args: Constant[]) => Constant; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.ifElse = exports.any = exports.all = exports.greaterThanOrEqual = exports.greaterThan = exports.lessThanOrEqual = exports.lessThan = exports.notEqualTo = exports.equalTo = exports.negate = void 0; | ||
| const negate = (value) => !value; | ||
| exports.negate = negate; | ||
| const equalTo = (a, b) => a === b; | ||
| exports.equalTo = equalTo; | ||
| const notEqualTo = (a, b) => a !== b; | ||
| exports.notEqualTo = notEqualTo; | ||
| const lessThan = (a, b) => a < b; | ||
| exports.lessThan = lessThan; | ||
| const lessThanOrEqual = (a, b) => a <= b; | ||
| exports.lessThanOrEqual = lessThanOrEqual; | ||
| const greaterThan = (a, b) => a > b; | ||
| exports.greaterThan = greaterThan; | ||
| const greaterThanOrEqual = (a, b) => a >= b; | ||
| exports.greaterThanOrEqual = greaterThanOrEqual; | ||
| const all = (...values) => values.reduce((acc, curr) => acc && !!curr, true); | ||
| exports.all = all; | ||
| const any = (...values) => values.reduce((acc, curr) => acc || !!curr, false); | ||
| exports.any = any; | ||
| const ifElse = (...args) => { | ||
| if (args.length < 3 || args.length % 2 !== 1) | ||
| throw new Error("Invalid arguments for 'if' expression"); | ||
| let argIndex = 0; | ||
| while (argIndex < args.length - 1) { | ||
| const condition = args[argIndex]; | ||
| const output = args[argIndex + 1]; | ||
| if (condition) { | ||
| return output; | ||
| } | ||
| argIndex += 2; | ||
| } | ||
| return args[args.length - 1]; | ||
| }; | ||
| exports.ifElse = ifElse; |
| export declare const add: (a: number, b: number) => number; | ||
| export declare const subtract: (a: number, b: number) => number; | ||
| export declare const multiply: (a: number, b: number) => number; | ||
| export declare const divide: (a: number, b: number) => number; | ||
| export declare const remainder: (a: number, b: number) => number; | ||
| export declare const power: (a: number, b: number) => number; | ||
| export declare const sqrt: (value: number) => number; | ||
| export declare const abs: (value: number) => number; | ||
| export declare const sin: (value: number) => number; | ||
| export declare const cos: (value: number) => number; | ||
| export declare const tan: (value: number) => number; | ||
| export declare const log: (value: number) => number; | ||
| export declare const floor: (value: number) => number; | ||
| export declare const ceil: (value: number) => number; | ||
| export declare const round: (value: number) => number; | ||
| export declare const min: (...values: number[]) => number; | ||
| export declare const max: (...values: number[]) => number; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.max = exports.min = exports.round = exports.ceil = exports.floor = exports.log = exports.tan = exports.cos = exports.sin = exports.abs = exports.sqrt = exports.power = exports.remainder = exports.divide = exports.multiply = exports.subtract = exports.add = void 0; | ||
| const add = (a, b) => a + b; | ||
| exports.add = add; | ||
| const subtract = (a, b) => a - b; | ||
| exports.subtract = subtract; | ||
| const multiply = (a, b) => a * b; | ||
| exports.multiply = multiply; | ||
| const divide = (a, b) => a / b; | ||
| exports.divide = divide; | ||
| const remainder = (a, b) => a % b; | ||
| exports.remainder = remainder; | ||
| const power = (a, b) => Math.pow(a, b); | ||
| exports.power = power; | ||
| const sqrt = (value) => Math.sqrt(value); | ||
| exports.sqrt = sqrt; | ||
| const abs = (value) => Math.abs(value); | ||
| exports.abs = abs; | ||
| const sin = (value) => Math.sin(value); | ||
| exports.sin = sin; | ||
| const cos = (value) => Math.cos(value); | ||
| exports.cos = cos; | ||
| const tan = (value) => Math.tan(value); | ||
| exports.tan = tan; | ||
| const log = (value) => Math.log(value); | ||
| exports.log = log; | ||
| const floor = (value) => Math.floor(value); | ||
| exports.floor = floor; | ||
| const ceil = (value) => Math.ceil(value); | ||
| exports.ceil = ceil; | ||
| const round = (value) => Math.round(value); | ||
| exports.round = round; | ||
| const min = (...values) => Math.min(...values); | ||
| exports.min = min; | ||
| const max = (...values) => Math.max(...values); | ||
| exports.max = max; |
| import type { Constant } from "../interface"; | ||
| export declare const concat: (...args: Constant[]) => string; | ||
| export declare const downcase: (str: string) => string; | ||
| export declare const upcase: (str: string) => string; | ||
| export declare const numberFormat: (number: number, minimumFractionDigits: number, maximumFractionDigits?: number) => string; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.numberFormat = exports.upcase = exports.downcase = exports.concat = void 0; | ||
| const concat = (...args) => args.join(""); | ||
| exports.concat = concat; | ||
| const downcase = (str) => str.toLowerCase(); | ||
| exports.downcase = downcase; | ||
| const upcase = (str) => str.toUpperCase(); | ||
| exports.upcase = upcase; | ||
| const numberFormat = (number, minimumFractionDigits, maximumFractionDigits) => { | ||
| const formatter = new Intl.NumberFormat("en-US", { | ||
| minimumFractionDigits, | ||
| maximumFractionDigits, | ||
| }); | ||
| return formatter.format(number); | ||
| }; | ||
| exports.numberFormat = numberFormat; |
| import type { Constant } from "../interface"; | ||
| export declare const bool: (value: Constant) => boolean; | ||
| export declare const str: (value: Constant) => string; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.str = exports.bool = void 0; | ||
| const bool = (value) => !!value; | ||
| exports.bool = bool; | ||
| const str = (value) => String(value); | ||
| exports.str = str; |
| export type { Constant, Data, Expression, Value } from "./interface"; | ||
| export { evalVal as exp } from "./evaluator"; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.exp = void 0; | ||
| var evaluator_1 = require("./evaluator"); | ||
| Object.defineProperty(exports, "exp", { enumerable: true, get: function () { return evaluator_1.evalVal; } }); |
| export {}; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const _1 = require("."); | ||
| describe("type", () => { | ||
| test("boolean", () => { | ||
| expect((0, _1.exp)(["boolean", 1])).toBe(true); | ||
| expect((0, _1.exp)(["boolean", 0])).toBe(false); | ||
| expect((0, _1.exp)(["boolean", "a"])).toBe(true); | ||
| expect((0, _1.exp)(["boolean", ""])).toBe(false); | ||
| expect((0, _1.exp)(["boolean", true])).toBe(true); | ||
| expect((0, _1.exp)(["boolean", false])).toBe(false); | ||
| }); | ||
| test("string", () => { | ||
| expect((0, _1.exp)(["string", 1])).toBe("1"); | ||
| expect((0, _1.exp)(["string", 1.5])).toBe("1.5"); | ||
| expect((0, _1.exp)(["string", true])).toBe("true"); | ||
| }); | ||
| }); | ||
| describe("math", () => { | ||
| test("+", () => { | ||
| expect((0, _1.exp)(["+", 1, 2])).toBe(3); | ||
| }); | ||
| test("-", () => { | ||
| expect((0, _1.exp)(["-", 3, 1])).toBe(2); | ||
| }); | ||
| test("*", () => { | ||
| expect((0, _1.exp)(["*", 3, 5])).toBe(15); | ||
| }); | ||
| test("/", () => { | ||
| expect((0, _1.exp)(["/", 15, 3])).toBe(5); | ||
| }); | ||
| test("%", () => { | ||
| expect((0, _1.exp)(["%", 15, 3])).toBe(0); | ||
| expect((0, _1.exp)(["%", 15, 2])).toBe(1); | ||
| expect((0, _1.exp)(["%", 2, 3])).toBe(2); | ||
| }); | ||
| test("^", () => { | ||
| expect((0, _1.exp)(["^", 2, 3])).toBe(8); | ||
| }); | ||
| test("sqrt", () => { | ||
| expect((0, _1.exp)(["sqrt", 9])).toBe(3); | ||
| }); | ||
| test("abs", () => { | ||
| expect((0, _1.exp)(["abs", -5])).toBe(5); | ||
| }); | ||
| test("sin", () => { | ||
| expect((0, _1.exp)(["sin", Math.PI / 2])).toBe(1); | ||
| }); | ||
| test("cos", () => { | ||
| expect((0, _1.exp)(["cos", 0])).toBe(1); | ||
| }); | ||
| test("tan", () => { | ||
| expect((0, _1.exp)(["tan", 0])).toBe(0); | ||
| }); | ||
| test("log", () => { | ||
| expect((0, _1.exp)(["log", 1])).toBe(0); | ||
| expect((0, _1.exp)(["log", 30])).toBe(Math.log(30)); | ||
| }); | ||
| test("floor", () => { | ||
| expect((0, _1.exp)(["floor", 1.5])).toBe(1); | ||
| expect((0, _1.exp)(["floor", -1.5])).toBe(-2); | ||
| }); | ||
| test("ceil", () => { | ||
| expect((0, _1.exp)(["ceil", 1.5])).toBe(2); | ||
| expect((0, _1.exp)(["ceil", -1.5])).toBe(-1); | ||
| }); | ||
| test("round", () => { | ||
| expect((0, _1.exp)(["round", 1.6])).toBe(2); | ||
| expect((0, _1.exp)(["round", 1.4])).toBe(1); | ||
| }); | ||
| test("min", () => { | ||
| expect((0, _1.exp)(["min", 1, 2])).toBe(1); | ||
| expect((0, _1.exp)(["min", 4, 2, 3])).toBe(2); | ||
| }); | ||
| test("max", () => { | ||
| expect((0, _1.exp)(["max", 1, 2])).toBe(2); | ||
| expect((0, _1.exp)(["max", 4, 2, 3])).toBe(4); | ||
| }); | ||
| }); | ||
| describe("decision", () => { | ||
| test("!", () => { | ||
| expect((0, _1.exp)(["!", true])).toBe(false); | ||
| expect((0, _1.exp)(["!", false])).toBe(true); | ||
| expect((0, _1.exp)(["!", 1])).toBe(false); | ||
| expect((0, _1.exp)(["!", 0])).toBe(true); | ||
| expect((0, _1.exp)(["!", "a"])).toBe(false); | ||
| expect((0, _1.exp)(["!", ""])).toBe(true); | ||
| }); | ||
| test("==", () => { | ||
| expect((0, _1.exp)(["==", 1, 1])).toBe(true); | ||
| expect((0, _1.exp)(["==", 1, 2])).toBe(false); | ||
| expect((0, _1.exp)(["==", 1, "1"])).toBe(false); | ||
| expect((0, _1.exp)(["==", "a", "a"])).toBe(true); | ||
| expect((0, _1.exp)(["==", true, true])).toBe(true); | ||
| expect((0, _1.exp)(["==", false, false])).toBe(true); | ||
| expect((0, _1.exp)(["==", true, false])).toBe(false); | ||
| }); | ||
| test("!=", () => { | ||
| expect((0, _1.exp)(["!=", 1, 1])).toBe(false); | ||
| expect((0, _1.exp)(["!=", 1, 2])).toBe(true); | ||
| expect((0, _1.exp)(["!=", 1, "1"])).toBe(true); | ||
| expect((0, _1.exp)(["!=", "a", "a"])).toBe(false); | ||
| expect((0, _1.exp)(["!=", true, true])).toBe(false); | ||
| expect((0, _1.exp)(["!=", false, false])).toBe(false); | ||
| expect((0, _1.exp)(["!=", true, false])).toBe(true); | ||
| }); | ||
| test("<", () => { | ||
| expect((0, _1.exp)(["<", 1, 2])).toBe(true); | ||
| expect((0, _1.exp)(["<", 2, 1])).toBe(false); | ||
| expect((0, _1.exp)(["<", 1, 1])).toBe(false); | ||
| expect((0, _1.exp)(["<", "a", "b"])).toBe(true); | ||
| expect((0, _1.exp)(["<", "b", "a"])).toBe(false); | ||
| expect((0, _1.exp)(["<", "a", "a"])).toBe(false); | ||
| }); | ||
| test("<=", () => { | ||
| expect((0, _1.exp)(["<=", 1, 2])).toBe(true); | ||
| expect((0, _1.exp)(["<=", 2, 1])).toBe(false); | ||
| expect((0, _1.exp)(["<=", 1, 1])).toBe(true); | ||
| expect((0, _1.exp)(["<=", "a", "b"])).toBe(true); | ||
| expect((0, _1.exp)(["<=", "b", "a"])).toBe(false); | ||
| expect((0, _1.exp)(["<=", "a", "a"])).toBe(true); | ||
| }); | ||
| test(">", () => { | ||
| expect((0, _1.exp)([">", 1, 2])).toBe(false); | ||
| expect((0, _1.exp)([">", 2, 1])).toBe(true); | ||
| expect((0, _1.exp)([">", 1, 1])).toBe(false); | ||
| expect((0, _1.exp)([">", "a", "b"])).toBe(false); | ||
| expect((0, _1.exp)([">", "b", "a"])).toBe(true); | ||
| expect((0, _1.exp)([">", "a", "a"])).toBe(false); | ||
| }); | ||
| test(">=", () => { | ||
| expect((0, _1.exp)([">=", 1, 2])).toBe(false); | ||
| expect((0, _1.exp)([">=", 2, 1])).toBe(true); | ||
| expect((0, _1.exp)([">=", 1, 1])).toBe(true); | ||
| expect((0, _1.exp)([">=", "a", "b"])).toBe(false); | ||
| expect((0, _1.exp)([">=", "b", "a"])).toBe(true); | ||
| expect((0, _1.exp)([">=", "a", "a"])).toBe(true); | ||
| }); | ||
| test("all", () => { | ||
| expect((0, _1.exp)(["all", 1, 2, 3, 4, 5])).toBe(true); | ||
| expect((0, _1.exp)(["all", 1, 2, 3, 0, 4, 5])).toBe(false); | ||
| expect((0, _1.exp)(["all", "a", "b", 1, "c", "d"])).toBe(true); | ||
| expect((0, _1.exp)(["all", "a", "b", 1, "", "d"])).toBe(false); | ||
| expect((0, _1.exp)(["all", "a", "b", 1, true, "d"])).toBe(true); | ||
| expect((0, _1.exp)(["all", "a", "b", 1, false, "d"])).toBe(false); | ||
| }); | ||
| test("any", () => { | ||
| expect((0, _1.exp)(["any", 0, 0, 0, 0, 1, 0])).toBe(true); | ||
| expect((0, _1.exp)(["any", 0, 0, 0, 0, 0, 0])).toBe(false); | ||
| expect((0, _1.exp)(["any", "", "", 1, "", ""])).toBe(true); | ||
| expect((0, _1.exp)(["any", "", "", "", "", ""])).toBe(false); | ||
| expect((0, _1.exp)(["any", "", "", 1, true, ""])).toBe(true); | ||
| expect((0, _1.exp)(["any", "", "", 0, false, ""])).toBe(false); | ||
| }); | ||
| test("if", () => { | ||
| expect((0, _1.exp)(["if", true, "success", "failure"])).toBe("success"); | ||
| expect((0, _1.exp)(["if", false, "success", "failure"])).toBe("failure"); | ||
| expect((0, _1.exp)(["if", 1, "success", "failure"])).toBe("success"); | ||
| expect((0, _1.exp)(["if", 0, "success", "failure"])).toBe("failure"); | ||
| expect((0, _1.exp)(["if", "a", "success", "failure"])).toBe("success"); | ||
| expect((0, _1.exp)(["if", "", "success", "failure"])).toBe("failure"); | ||
| expect((0, _1.exp)([ | ||
| "if", | ||
| ["==", 5, 1], | ||
| "equal to one", | ||
| ["==", 2, 2], | ||
| "equal to two", | ||
| "failure", | ||
| ])).toBe("equal to two"); | ||
| expect((0, _1.exp)([ | ||
| "if", | ||
| ["==", 5, 1], | ||
| "equal to one", | ||
| ["==", 3, 2], | ||
| "equal to two", | ||
| "failure", | ||
| ])).toBe("failure"); | ||
| }); | ||
| }); | ||
| describe("decision", () => { | ||
| test("concat", () => { | ||
| expect((0, _1.exp)(["concat", "Edward", " ", "Anthony"])).toBe("Edward Anthony"); | ||
| expect((0, _1.exp)(["concat", 1, "pm"])).toBe("1pm"); | ||
| }); | ||
| test("downcase", () => { | ||
| expect((0, _1.exp)(["downcase", "PM"])).toBe("pm"); | ||
| expect((0, _1.exp)(["downcase", "pm"])).toBe("pm"); | ||
| }); | ||
| test("upcase", () => { | ||
| expect((0, _1.exp)(["upcase", "pm"])).toBe("PM"); | ||
| expect((0, _1.exp)(["upcase", "PM"])).toBe("PM"); | ||
| }); | ||
| test("number-format", () => { | ||
| expect((0, _1.exp)(["number-format", 3.1415926535, 1, 3])).toBe("3.142"); | ||
| expect((0, _1.exp)(["number-format", 3, 2, 5])).toBe("3.00"); | ||
| }); | ||
| }); | ||
| describe("nested", () => { | ||
| test("convert liter/minute to US gallon/hour", () => { | ||
| const literPerMinute = 5; | ||
| expect((0, _1.exp)([ | ||
| "concat", | ||
| ["*", ["*", literPerMinute, 0.2641722], 60], | ||
| " ", | ||
| "gallon/hour", | ||
| ])).toBe("79.25166 gallon/hour"); | ||
| }); | ||
| test("nested conditional", () => { | ||
| const getExpression = (animal) => [ | ||
| "if", | ||
| ["==", animal, "cat"], | ||
| "meow", | ||
| ["==", animal, "dog"], | ||
| "woof", | ||
| "Wa-pa-pa-pa-pa-pa-pow!", | ||
| ]; | ||
| expect((0, _1.exp)(getExpression("cat"))).toBe("meow"); | ||
| expect((0, _1.exp)(getExpression("dog"))).toBe("woof"); | ||
| expect((0, _1.exp)(getExpression("fox"))).toBe("Wa-pa-pa-pa-pa-pa-pow!"); | ||
| }); | ||
| test("wildcard", () => { | ||
| const data = { | ||
| value: 5, | ||
| }; | ||
| expect((0, _1.exp)([ | ||
| "concat", | ||
| ["number-format", ["*", ["*", "$value", 0.2641722], 60], 0, 1], | ||
| " ", | ||
| "gallon/hour", | ||
| ], data)).toBe("79.3 gallon/hour"); | ||
| const expression = [ | ||
| "if", | ||
| ["==", "$animal", "cat"], | ||
| "meow", | ||
| ["==", "$animal", "dog"], | ||
| "woof", | ||
| "Wa-pa-pa-pa-pa-pa-pow!", | ||
| ]; | ||
| expect((0, _1.exp)(expression, { animal: "cat" })).toBe("meow"); | ||
| expect((0, _1.exp)(expression, { animal: "dog" })).toBe("woof"); | ||
| expect((0, _1.exp)(expression, { animal: "fox" })).toBe("Wa-pa-pa-pa-pa-pa-pow!"); | ||
| }); | ||
| }); |
| export type Constant = string | number | boolean; | ||
| export type Expression = [string, Value, ...Value[]]; | ||
| export type Value = Expression | Constant; | ||
| export type Data = { | ||
| [s: string]: Constant; | ||
| }; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); |
| import type { Constant, Expression, Value } from "./interface"; | ||
| export declare const isExpression: (value: Value) => value is Expression; | ||
| export declare const isConstant: (value: Value) => value is Constant; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.isConstant = exports.isExpression = void 0; | ||
| const isExpression = (value) => { | ||
| return (Array.isArray(value) && value.length >= 2 && typeof value[0] === "string"); | ||
| }; | ||
| exports.isExpression = isExpression; | ||
| const isConstant = (value) => { | ||
| return ["string", "number", "boolean"].includes(typeof value); | ||
| }; | ||
| exports.isConstant = isConstant; |
+6
-1
| { | ||
| "name": "array-expression", | ||
| "version": "0.0.1", | ||
| "version": "0.0.2", | ||
| "description": "Formatter declaration that can be transported through network and executed securely.", | ||
| "main": "dist/index.js", | ||
| "types": "dist/index.d.ts", | ||
| "scripts": { | ||
| "build": "tsc", | ||
| "prebuild": "rimraf dist", | ||
| "dev": "npm run prebuild && tsc -w", | ||
| "test": "jest" | ||
@@ -26,2 +30,3 @@ }, | ||
| "jest": "^29.3.1", | ||
| "rimraf": "^5.0.5", | ||
| "ts-jest": "^29.0.5", | ||
@@ -28,0 +33,0 @@ "ts-node": "^10.9.1", |
-16
| { | ||
| "arrowParens": "always", | ||
| "bracketSpacing": true, | ||
| "htmlWhitespaceSensitivity": "ignore", | ||
| "insertPragma": false, | ||
| "singleQuote": true, | ||
| "proseWrap": "preserve", | ||
| "quoteProps": "as-needed", | ||
| "requirePragma": false, | ||
| "semi": true, | ||
| "tabWidth": 2, | ||
| "trailingComma": "es5", | ||
| "useTabs": false, | ||
| "endOfLine": "auto", | ||
| "printWidth": 100 | ||
| } |
-195
| /* | ||
| * For a detailed explanation regarding each configuration property and type check, visit: | ||
| * https://jestjs.io/docs/configuration | ||
| */ | ||
| export default { | ||
| // All imported modules in your tests should be mocked automatically | ||
| // automock: false, | ||
| // Stop running tests after `n` failures | ||
| // bail: 0, | ||
| // The directory where Jest should store its cached dependency information | ||
| // cacheDirectory: "/private/var/folders/tp/_0j13b5s4vbbzfm8bcj8flzr0000gn/T/jest_dx", | ||
| // Automatically clear mock calls, instances, contexts and results before every test | ||
| clearMocks: true, | ||
| // Indicates whether the coverage information should be collected while executing the test | ||
| collectCoverage: true, | ||
| // An array of glob patterns indicating a set of files for which coverage information should be collected | ||
| // collectCoverageFrom: undefined, | ||
| // The directory where Jest should output its coverage files | ||
| coverageDirectory: "coverage", | ||
| // An array of regexp pattern strings used to skip coverage collection | ||
| // coveragePathIgnorePatterns: [ | ||
| // "/node_modules/" | ||
| // ], | ||
| // Indicates which provider should be used to instrument code for coverage | ||
| coverageProvider: "v8", | ||
| // A list of reporter names that Jest uses when writing coverage reports | ||
| // coverageReporters: [ | ||
| // "json", | ||
| // "text", | ||
| // "lcov", | ||
| // "clover" | ||
| // ], | ||
| // An object that configures minimum threshold enforcement for coverage results | ||
| // coverageThreshold: undefined, | ||
| // A path to a custom dependency extractor | ||
| // dependencyExtractor: undefined, | ||
| // Make calling deprecated APIs throw helpful error messages | ||
| // errorOnDeprecated: false, | ||
| // The default configuration for fake timers | ||
| // fakeTimers: { | ||
| // "enableGlobally": false | ||
| // }, | ||
| // Force coverage collection from ignored files using an array of glob patterns | ||
| // forceCoverageMatch: [], | ||
| // A path to a module which exports an async function that is triggered once before all test suites | ||
| // globalSetup: undefined, | ||
| // A path to a module which exports an async function that is triggered once after all test suites | ||
| // globalTeardown: undefined, | ||
| // A set of global variables that need to be available in all test environments | ||
| // globals: {}, | ||
| // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. | ||
| // maxWorkers: "50%", | ||
| // An array of directory names to be searched recursively up from the requiring module's location | ||
| // moduleDirectories: [ | ||
| // "node_modules" | ||
| // ], | ||
| // An array of file extensions your modules use | ||
| // moduleFileExtensions: [ | ||
| // "js", | ||
| // "mjs", | ||
| // "cjs", | ||
| // "jsx", | ||
| // "ts", | ||
| // "tsx", | ||
| // "json", | ||
| // "node" | ||
| // ], | ||
| // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module | ||
| // moduleNameMapper: {}, | ||
| // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader | ||
| // modulePathIgnorePatterns: [], | ||
| // Activates notifications for test results | ||
| // notify: false, | ||
| // An enum that specifies notification mode. Requires { notify: true } | ||
| // notifyMode: "failure-change", | ||
| // A preset that is used as a base for Jest's configuration | ||
| preset: "ts-jest", | ||
| // Run tests from one or more projects | ||
| // projects: undefined, | ||
| // Use this configuration option to add custom reporters to Jest | ||
| // reporters: undefined, | ||
| // Automatically reset mock state before every test | ||
| // resetMocks: false, | ||
| // Reset the module registry before running each individual test | ||
| // resetModules: false, | ||
| // A path to a custom resolver | ||
| // resolver: undefined, | ||
| // Automatically restore mock state and implementation before every test | ||
| // restoreMocks: false, | ||
| // The root directory that Jest should scan for tests and modules within | ||
| // rootDir: undefined, | ||
| // A list of paths to directories that Jest should use to search for files in | ||
| // roots: [ | ||
| // "<rootDir>" | ||
| // ], | ||
| // Allows you to use a custom runner instead of Jest's default test runner | ||
| // runner: "jest-runner", | ||
| // The paths to modules that run some code to configure or set up the testing environment before each test | ||
| // setupFiles: [], | ||
| // A list of paths to modules that run some code to configure or set up the testing framework before each test | ||
| // setupFilesAfterEnv: [], | ||
| // The number of seconds after which a test is considered as slow and reported as such in the results. | ||
| // slowTestThreshold: 5, | ||
| // A list of paths to snapshot serializer modules Jest should use for snapshot testing | ||
| // snapshotSerializers: [], | ||
| // The test environment that will be used for testing | ||
| // testEnvironment: "jest-environment-node", | ||
| // Options that will be passed to the testEnvironment | ||
| // testEnvironmentOptions: {}, | ||
| // Adds a location field to test results | ||
| // testLocationInResults: false, | ||
| // The glob patterns Jest uses to detect test files | ||
| // testMatch: [ | ||
| // "**/__tests__/**/*.[jt]s?(x)", | ||
| // "**/?(*.)+(spec|test).[tj]s?(x)" | ||
| // ], | ||
| // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped | ||
| // testPathIgnorePatterns: [ | ||
| // "/node_modules/" | ||
| // ], | ||
| // The regexp pattern or array of patterns that Jest uses to detect test files | ||
| // testRegex: [], | ||
| // This option allows the use of a custom results processor | ||
| // testResultsProcessor: undefined, | ||
| // This option allows use of a custom test runner | ||
| // testRunner: "jest-circus/runner", | ||
| // A map from regular expressions to paths to transformers | ||
| // transform: undefined, | ||
| // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation | ||
| // transformIgnorePatterns: [ | ||
| // "/node_modules/", | ||
| // "\\.pnp\\.[^\\/]+$" | ||
| // ], | ||
| // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them | ||
| // unmockedModulePathPatterns: undefined, | ||
| // Indicates whether each individual test should be reported during the run | ||
| // verbose: undefined, | ||
| // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode | ||
| // watchPathIgnorePatterns: [], | ||
| // Whether to use watchman for file crawling | ||
| // watchman: true, | ||
| }; |
-102
| import { | ||
| all, | ||
| any, | ||
| equalTo, | ||
| greaterThan, | ||
| greaterThanOrEqual, | ||
| ifElse, | ||
| lessThan, | ||
| lessThanOrEqual, | ||
| negate, | ||
| notEqualTo, | ||
| } from "./functions/decision"; | ||
| import { | ||
| abs, | ||
| add, | ||
| ceil, | ||
| cos, | ||
| divide, | ||
| floor, | ||
| log, | ||
| max, | ||
| min, | ||
| multiply, | ||
| power, | ||
| remainder, | ||
| round, | ||
| sin, | ||
| sqrt, | ||
| subtract, | ||
| tan, | ||
| } from "./functions/math"; | ||
| import { concat, downcase, numberFormat, upcase } from "./functions/string"; | ||
| import { bool, str } from "./functions/type"; | ||
| import type { Data, Expression, Value } from "./interface"; | ||
| import { isConstant, isExpression } from "./utils"; | ||
| // prettier-ignore | ||
| const FUNCTIONS: Record<string, Function> = { | ||
| "boolean": bool, | ||
| "string": str, | ||
| "+": add, | ||
| "-": subtract, | ||
| "*": multiply, | ||
| "/": divide, | ||
| "%": remainder, | ||
| "^": power, | ||
| "sqrt": sqrt, | ||
| "abs": abs, | ||
| "sin": sin, | ||
| "cos": cos, | ||
| "tan": tan, | ||
| "log": log, | ||
| "floor": floor, | ||
| "ceil": ceil, | ||
| "round": round, | ||
| "min": min, | ||
| "max": max, | ||
| "!": negate, | ||
| "==": equalTo, | ||
| "!=": notEqualTo, | ||
| "<": lessThan, | ||
| "<=": lessThanOrEqual, | ||
| ">": greaterThan, | ||
| ">=": greaterThanOrEqual, | ||
| "all": all, | ||
| "any": any, | ||
| "if": ifElse, | ||
| "concat": concat, | ||
| "downcase": downcase, | ||
| "upcase": upcase, | ||
| "number-format": numberFormat | ||
| }; | ||
| export const evalVal = (value: Value, data?: Data) => { | ||
| if (isConstant(value)) { | ||
| if (data && typeof value === "string") { | ||
| const wildcardRegex = /^\$(\w+)$/; | ||
| const match = wildcardRegex.exec(value); | ||
| if (match && match[1]) { | ||
| return data[match[1]]; | ||
| } | ||
| } | ||
| return value; | ||
| } | ||
| if (isExpression(value)) return evalExp(value, data); | ||
| throw new Error("Value is not constant or expression"); | ||
| }; | ||
| const evalExp = (expression: Expression, data?: Data): Value => { | ||
| const [name, ...args] = expression; | ||
| const func = FUNCTIONS[name]; | ||
| if (!func) throw new Error("Invalid expression"); | ||
| return func(...args.map((arg) => evalVal(arg, data))); | ||
| }; |
| import type { Constant } from '../interface'; | ||
| export const negate = (value: Constant) => !value; | ||
| export const equalTo = (a: Constant, b: Constant) => a === b; | ||
| export const notEqualTo = (a: Constant, b: Constant) => a !== b; | ||
| export const lessThan = (a: string | number, b: string | number) => a < b; | ||
| export const lessThanOrEqual = (a: string | number, b: string | number) => a <= b; | ||
| export const greaterThan = (a: string | number, b: string | number) => a > b; | ||
| export const greaterThanOrEqual = (a: string | number, b: string | number) => a >= b; | ||
| export const all = (...values: Constant[]) => | ||
| values.reduce<boolean>((acc, curr) => acc && !!curr, true); | ||
| export const any = (...values: Constant[]) => | ||
| values.reduce<boolean>((acc, curr) => acc || !!curr, false); | ||
| export const ifElse = (...args: Constant[]) => { | ||
| if (args.length < 3 || args.length % 2 !== 1) | ||
| throw new Error("Invalid arguments for 'if' expression"); | ||
| let argIndex = 0; | ||
| while (argIndex < args.length - 1) { | ||
| const condition = args[argIndex]; | ||
| const output = args[argIndex + 1]; | ||
| if (condition) { | ||
| return output; | ||
| } | ||
| argIndex += 2; | ||
| } | ||
| return args[args.length - 1]; | ||
| }; |
| export const add = (a: number, b: number) => a + b; | ||
| export const subtract = (a: number, b: number) => a - b; | ||
| export const multiply = (a: number, b: number) => a * b; | ||
| export const divide = (a: number, b: number) => a / b; | ||
| export const remainder = (a: number, b: number) => a % b; | ||
| export const power = (a: number, b: number) => Math.pow(a, b); | ||
| export const sqrt = (value: number) => Math.sqrt(value); | ||
| export const abs = (value: number) => Math.abs(value); | ||
| export const sin = (value: number) => Math.sin(value); | ||
| export const cos = (value: number) => Math.cos(value); | ||
| export const tan = (value: number) => Math.tan(value); | ||
| export const log = (value: number) => Math.log(value); | ||
| export const floor = (value: number) => Math.floor(value); | ||
| export const ceil = (value: number) => Math.ceil(value); | ||
| export const round = (value: number) => Math.round(value); | ||
| export const min = (...values: number[]) => Math.min(...values); | ||
| export const max = (...values: number[]) => Math.max(...values); |
| import type { Constant } from "../interface"; | ||
| export const concat = (...args: Constant[]) => args.join(""); | ||
| export const downcase = (str: string) => str.toLowerCase(); | ||
| export const upcase = (str: string) => str.toUpperCase(); | ||
| export const numberFormat = ( | ||
| number: number, | ||
| minimumFractionDigits: number, | ||
| maximumFractionDigits?: number | ||
| ) => { | ||
| const formatter = new Intl.NumberFormat("en-US", { | ||
| minimumFractionDigits, | ||
| maximumFractionDigits, | ||
| }); | ||
| return formatter.format(number); | ||
| }; |
| import type { Constant } from "../interface"; | ||
| export const bool = (value: Constant) => !!value; | ||
| export const str = (value: Constant) => String(value); |
| import { Data, exp, Expression } from "."; | ||
| describe("type", () => { | ||
| test("boolean", () => { | ||
| expect(exp(["boolean", 1])).toBe(true); | ||
| expect(exp(["boolean", 0])).toBe(false); | ||
| expect(exp(["boolean", "a"])).toBe(true); | ||
| expect(exp(["boolean", ""])).toBe(false); | ||
| expect(exp(["boolean", true])).toBe(true); | ||
| expect(exp(["boolean", false])).toBe(false); | ||
| }); | ||
| test("string", () => { | ||
| expect(exp(["string", 1])).toBe("1"); | ||
| expect(exp(["string", 1.5])).toBe("1.5"); | ||
| expect(exp(["string", true])).toBe("true"); | ||
| }); | ||
| }); | ||
| describe("math", () => { | ||
| test("+", () => { | ||
| expect(exp(["+", 1, 2])).toBe(3); | ||
| }); | ||
| test("-", () => { | ||
| expect(exp(["-", 3, 1])).toBe(2); | ||
| }); | ||
| test("*", () => { | ||
| expect(exp(["*", 3, 5])).toBe(15); | ||
| }); | ||
| test("/", () => { | ||
| expect(exp(["/", 15, 3])).toBe(5); | ||
| }); | ||
| test("%", () => { | ||
| expect(exp(["%", 15, 3])).toBe(0); | ||
| expect(exp(["%", 15, 2])).toBe(1); | ||
| expect(exp(["%", 2, 3])).toBe(2); | ||
| }); | ||
| test("^", () => { | ||
| expect(exp(["^", 2, 3])).toBe(8); | ||
| }); | ||
| test("sqrt", () => { | ||
| expect(exp(["sqrt", 9])).toBe(3); | ||
| }); | ||
| test("abs", () => { | ||
| expect(exp(["abs", -5])).toBe(5); | ||
| }); | ||
| test("sin", () => { | ||
| expect(exp(["sin", Math.PI / 2])).toBe(1); | ||
| }); | ||
| test("cos", () => { | ||
| expect(exp(["cos", 0])).toBe(1); | ||
| }); | ||
| test("tan", () => { | ||
| expect(exp(["tan", 0])).toBe(0); | ||
| }); | ||
| test("log", () => { | ||
| expect(exp(["log", 1])).toBe(0); | ||
| expect(exp(["log", 30])).toBe(Math.log(30)); | ||
| }); | ||
| test("floor", () => { | ||
| expect(exp(["floor", 1.5])).toBe(1); | ||
| expect(exp(["floor", -1.5])).toBe(-2); | ||
| }); | ||
| test("ceil", () => { | ||
| expect(exp(["ceil", 1.5])).toBe(2); | ||
| expect(exp(["ceil", -1.5])).toBe(-1); | ||
| }); | ||
| test("round", () => { | ||
| expect(exp(["round", 1.6])).toBe(2); | ||
| expect(exp(["round", 1.4])).toBe(1); | ||
| }); | ||
| test("min", () => { | ||
| expect(exp(["min", 1, 2])).toBe(1); | ||
| expect(exp(["min", 4, 2, 3])).toBe(2); | ||
| }); | ||
| test("max", () => { | ||
| expect(exp(["max", 1, 2])).toBe(2); | ||
| expect(exp(["max", 4, 2, 3])).toBe(4); | ||
| }); | ||
| }); | ||
| describe("decision", () => { | ||
| test("!", () => { | ||
| expect(exp(["!", true])).toBe(false); | ||
| expect(exp(["!", false])).toBe(true); | ||
| expect(exp(["!", 1])).toBe(false); | ||
| expect(exp(["!", 0])).toBe(true); | ||
| expect(exp(["!", "a"])).toBe(false); | ||
| expect(exp(["!", ""])).toBe(true); | ||
| }); | ||
| test("==", () => { | ||
| expect(exp(["==", 1, 1])).toBe(true); | ||
| expect(exp(["==", 1, 2])).toBe(false); | ||
| expect(exp(["==", 1, "1"])).toBe(false); | ||
| expect(exp(["==", "a", "a"])).toBe(true); | ||
| expect(exp(["==", true, true])).toBe(true); | ||
| expect(exp(["==", false, false])).toBe(true); | ||
| expect(exp(["==", true, false])).toBe(false); | ||
| }); | ||
| test("!=", () => { | ||
| expect(exp(["!=", 1, 1])).toBe(false); | ||
| expect(exp(["!=", 1, 2])).toBe(true); | ||
| expect(exp(["!=", 1, "1"])).toBe(true); | ||
| expect(exp(["!=", "a", "a"])).toBe(false); | ||
| expect(exp(["!=", true, true])).toBe(false); | ||
| expect(exp(["!=", false, false])).toBe(false); | ||
| expect(exp(["!=", true, false])).toBe(true); | ||
| }); | ||
| test("<", () => { | ||
| expect(exp(["<", 1, 2])).toBe(true); | ||
| expect(exp(["<", 2, 1])).toBe(false); | ||
| expect(exp(["<", 1, 1])).toBe(false); | ||
| expect(exp(["<", "a", "b"])).toBe(true); | ||
| expect(exp(["<", "b", "a"])).toBe(false); | ||
| expect(exp(["<", "a", "a"])).toBe(false); | ||
| }); | ||
| test("<=", () => { | ||
| expect(exp(["<=", 1, 2])).toBe(true); | ||
| expect(exp(["<=", 2, 1])).toBe(false); | ||
| expect(exp(["<=", 1, 1])).toBe(true); | ||
| expect(exp(["<=", "a", "b"])).toBe(true); | ||
| expect(exp(["<=", "b", "a"])).toBe(false); | ||
| expect(exp(["<=", "a", "a"])).toBe(true); | ||
| }); | ||
| test(">", () => { | ||
| expect(exp([">", 1, 2])).toBe(false); | ||
| expect(exp([">", 2, 1])).toBe(true); | ||
| expect(exp([">", 1, 1])).toBe(false); | ||
| expect(exp([">", "a", "b"])).toBe(false); | ||
| expect(exp([">", "b", "a"])).toBe(true); | ||
| expect(exp([">", "a", "a"])).toBe(false); | ||
| }); | ||
| test(">=", () => { | ||
| expect(exp([">=", 1, 2])).toBe(false); | ||
| expect(exp([">=", 2, 1])).toBe(true); | ||
| expect(exp([">=", 1, 1])).toBe(true); | ||
| expect(exp([">=", "a", "b"])).toBe(false); | ||
| expect(exp([">=", "b", "a"])).toBe(true); | ||
| expect(exp([">=", "a", "a"])).toBe(true); | ||
| }); | ||
| test("all", () => { | ||
| expect(exp(["all", 1, 2, 3, 4, 5])).toBe(true); | ||
| expect(exp(["all", 1, 2, 3, 0, 4, 5])).toBe(false); | ||
| expect(exp(["all", "a", "b", 1, "c", "d"])).toBe(true); | ||
| expect(exp(["all", "a", "b", 1, "", "d"])).toBe(false); | ||
| expect(exp(["all", "a", "b", 1, true, "d"])).toBe(true); | ||
| expect(exp(["all", "a", "b", 1, false, "d"])).toBe(false); | ||
| }); | ||
| test("any", () => { | ||
| expect(exp(["any", 0, 0, 0, 0, 1, 0])).toBe(true); | ||
| expect(exp(["any", 0, 0, 0, 0, 0, 0])).toBe(false); | ||
| expect(exp(["any", "", "", 1, "", ""])).toBe(true); | ||
| expect(exp(["any", "", "", "", "", ""])).toBe(false); | ||
| expect(exp(["any", "", "", 1, true, ""])).toBe(true); | ||
| expect(exp(["any", "", "", 0, false, ""])).toBe(false); | ||
| }); | ||
| test("if", () => { | ||
| expect(exp(["if", true, "success", "failure"])).toBe("success"); | ||
| expect(exp(["if", false, "success", "failure"])).toBe("failure"); | ||
| expect(exp(["if", 1, "success", "failure"])).toBe("success"); | ||
| expect(exp(["if", 0, "success", "failure"])).toBe("failure"); | ||
| expect(exp(["if", "a", "success", "failure"])).toBe("success"); | ||
| expect(exp(["if", "", "success", "failure"])).toBe("failure"); | ||
| expect( | ||
| exp([ | ||
| "if", | ||
| ["==", 5, 1], | ||
| "equal to one", | ||
| ["==", 2, 2], | ||
| "equal to two", | ||
| "failure", | ||
| ]) | ||
| ).toBe("equal to two"); | ||
| expect( | ||
| exp([ | ||
| "if", | ||
| ["==", 5, 1], | ||
| "equal to one", | ||
| ["==", 3, 2], | ||
| "equal to two", | ||
| "failure", | ||
| ]) | ||
| ).toBe("failure"); | ||
| }); | ||
| }); | ||
| describe("decision", () => { | ||
| test("concat", () => { | ||
| expect(exp(["concat", "Edward", " ", "Anthony"])).toBe("Edward Anthony"); | ||
| expect(exp(["concat", 1, "pm"])).toBe("1pm"); | ||
| }); | ||
| test("downcase", () => { | ||
| expect(exp(["downcase", "PM"])).toBe("pm"); | ||
| expect(exp(["downcase", "pm"])).toBe("pm"); | ||
| }); | ||
| test("upcase", () => { | ||
| expect(exp(["upcase", "pm"])).toBe("PM"); | ||
| expect(exp(["upcase", "PM"])).toBe("PM"); | ||
| }); | ||
| test("number-format", () => { | ||
| expect(exp(["number-format", 3.1415926535, 1, 3])).toBe("3.142"); | ||
| expect(exp(["number-format", 3, 2, 5])).toBe("3.00"); | ||
| }); | ||
| }); | ||
| describe("nested", () => { | ||
| test("convert liter/minute to US gallon/hour", () => { | ||
| const literPerMinute = 5; | ||
| expect( | ||
| exp([ | ||
| "concat", | ||
| ["*", ["*", literPerMinute, 0.2641722], 60], | ||
| " ", | ||
| "gallon/hour", | ||
| ]) | ||
| ).toBe("79.25166 gallon/hour"); | ||
| }); | ||
| test("nested conditional", () => { | ||
| const getExpression = (animal: string): Expression => [ | ||
| "if", | ||
| ["==", animal, "cat"], | ||
| "meow", | ||
| ["==", animal, "dog"], | ||
| "woof", | ||
| "Wa-pa-pa-pa-pa-pa-pow!", | ||
| ]; | ||
| expect(exp(getExpression("cat"))).toBe("meow"); | ||
| expect(exp(getExpression("dog"))).toBe("woof"); | ||
| expect(exp(getExpression("fox"))).toBe("Wa-pa-pa-pa-pa-pa-pow!"); | ||
| }); | ||
| test("wildcard", () => { | ||
| const data: Data = { | ||
| value: 5, | ||
| }; | ||
| expect( | ||
| exp( | ||
| [ | ||
| "concat", | ||
| ["number-format", ["*", ["*", "$value", 0.2641722], 60], 0, 1], | ||
| " ", | ||
| "gallon/hour", | ||
| ], | ||
| data | ||
| ) | ||
| ).toBe("79.3 gallon/hour"); | ||
| const expression: Expression = [ | ||
| "if", | ||
| ["==", "$animal", "cat"], | ||
| "meow", | ||
| ["==", "$animal", "dog"], | ||
| "woof", | ||
| "Wa-pa-pa-pa-pa-pa-pow!", | ||
| ]; | ||
| expect(exp(expression, { animal: "cat" })).toBe("meow"); | ||
| expect(exp(expression, { animal: "dog" })).toBe("woof"); | ||
| expect(exp(expression, { animal: "fox" })).toBe("Wa-pa-pa-pa-pa-pa-pow!"); | ||
| }); | ||
| }); |
| export type { Constant, Data, Expression, Value } from "./interface"; | ||
| export { evalVal as exp } from "./evaluator"; |
| export type Constant = string | number | boolean; | ||
| export type Expression = [string, Value, ...Value[]]; | ||
| export type Value = Expression | Constant; | ||
| export type Data = { | ||
| [s: string]: Constant; | ||
| }; |
-11
| import type { Constant, Expression, Value } from "./interface"; | ||
| export const isExpression = (value: Value): value is Expression => { | ||
| return ( | ||
| Array.isArray(value) && value.length >= 2 && typeof value[0] === "string" | ||
| ); | ||
| }; | ||
| export const isConstant = (value: Value): value is Constant => { | ||
| return ["string", "number", "boolean"].includes(typeof value); | ||
| }; |
| { | ||
| "compilerOptions": { | ||
| "target": "es2016", | ||
| "module": "commonjs", | ||
| "esModuleInterop": true, | ||
| "forceConsistentCasingInFileNames": true, | ||
| "strict": true, | ||
| "skipLibCheck": true, | ||
| "outDir": "dist" | ||
| }, | ||
| "include": ["src"] | ||
| } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
21
40%27866
-4.32%7
16.67%475
-17.39%1
Infinity%