import { isDefined, TestResults } from "src/domain"; import _, { intersection, set } from "lodash"; export const OR = (...args: [boolean, ...boolean[]]) => args.includes(true); export const AND = (...args: [boolean, ...boolean[]]) => _.every(args, Boolean); export const multiLineString = (joinWith = " ") => (...args: [string, ...string[]]) => args.filter(isDefined).join(joinWith); export class MultiLineString { public message = ""; constructor(initialValue: string = "") { this.message = initialValue; } addLine(line: string) { this.message += `\n${line}`; } } export const ANY = (states: any[]) => states.filter(Boolean).length > 0; /** * designed to collect the purified results and return the common paths; * this is useful because it means that if one error is purified in one * purifier but not in others it will be purified in this step, which * avoids race conditions and keeps logic linear and shallow (improves * readability) * * @param parent common ancestor between potentially mutated objects * @param objects mutated objects from ancestor * @returns common paths of the mutated objects relative to the parent */ export const innerJoinAncestors = ( parent: TestResults, objects: TestResults[] ) => { const objectPaths = objects.map(getAllTruthyObjectPaths); const commonPaths = intersection(...objectPaths); const clearPaths = getAllTruthyObjectPaths(parent).filter( (path) => !commonPaths.includes(path) ); return clearPaths.reduce( (obj, path) => set(obj, path, undefined), parent ) as TestResults; }; export const getAllTruthyObjectPaths = (obj: object) => { function rKeys(o: object, path?: string) { if (!o) return; if (typeof o !== "object") return path; return Object.keys(o).map((key) => rKeys(o[key], path ? [path, key].join(".") : key) ); } return rKeys(obj).toString().split(",").filter(isDefined); }; export const getAllFalseObjectPaths = (obj: object) => { function rKeys(o: object, path?: string) { if (typeof o !== "object" || _.isNull(o)) { if (o === false) return path; return; } return Object.keys(o).map((key) => rKeys(o[key], path ? [path, key].join(".") : key) ); } return rKeys(obj).toString().split(",").filter(isDefined); }; export const getAllNullObjectPaths = (obj: object) => { function rKeys(o: object, path?: string) { if (typeof o !== "object") { if (_.isNull(o)) return path; return; } return Object.keys(o).map((key) => rKeys(o[key], path ? [path, key].join(".") : key) ); } return rKeys(obj).toString().split(",").filter(isDefined); };