UNPKG

rulepilot

Version:

Rule parsing engine for JSON rules

169 lines (168 loc) 9.31 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _Mutator_instances, _Mutator_cache, _Mutator_buffer, _Mutator_mutations, _Mutator_objectDiscovery, _Mutator_eventEmitter, _Mutator_hasMutations, _Mutator_applyMutations, _Mutator_execMutation; Object.defineProperty(exports, "__esModule", { value: true }); exports.Mutator = void 0; const crypto_1 = require("crypto"); const events_1 = require("events"); const logger_1 = require("./logger"); const object_discovery_1 = require("./object-discovery"); class Mutator { constructor() { _Mutator_instances.add(this); _Mutator_cache.set(this, new Map()); _Mutator_buffer.set(this, new Map()); _Mutator_mutations.set(this, new Map()); _Mutator_objectDiscovery.set(this, new object_discovery_1.ObjectDiscovery()); _Mutator_eventEmitter.set(this, new events_1.EventEmitter()); } /** * Adds a mutation to the mutator instance. * @param name The name of the mutation. * @param mutation The mutation function. */ add(name, mutation) { __classPrivateFieldGet(this, _Mutator_mutations, "f").set(name, mutation); } /** * Removes a mutation to the mutator instance. * Any cached mutation values for this mutation will be purged. * @param name The name of the mutation. */ remove(name) { this.clearCache(name); __classPrivateFieldGet(this, _Mutator_mutations, "f").delete(name); } /** * Clears the mutator cache. * The entire cache, or cache for a specific mutator, can be cleared * by passing or omitting the mutator name as an argument. * @param name The mutator name to clear the cache for. */ clearCache(name) { if (!name) { __classPrivateFieldGet(this, _Mutator_cache, "f").clear(); return; } for (const key of __classPrivateFieldGet(this, _Mutator_cache, "f").keys()) { if (key.startsWith(name)) { __classPrivateFieldGet(this, _Mutator_cache, "f").delete(key); } } } /** * Mutates and returns a criteria object. * @param criteria The criteria to mutate. */ mutate(criteria) { return __awaiter(this, void 0, void 0, function* () { // Handles checking the mutability of a criteria object // If it is mutable it will be cloned, mutated and returned const exec = (criteria) => __awaiter(this, void 0, void 0, function* () { // If there are no mutations or the criteria does not contain // any of the mutation keys, return the criteria as is. if (!__classPrivateFieldGet(this, _Mutator_mutations, "f").size || !__classPrivateFieldGet(this, _Mutator_instances, "m", _Mutator_hasMutations).call(this, criteria)) { return criteria; } // Make a copy of the criteria. const copy = Object.assign({}, criteria); // Apply the mutations to the copy and return it. yield __classPrivateFieldGet(this, _Mutator_instances, "m", _Mutator_applyMutations).call(this, copy); return copy; }); // If the criteria is an array, we want to apply the mutations // to each item in the array in parallel. if (criteria instanceof Array) { return yield Promise.all(criteria.map((c) => new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { resolve(yield exec(c)); })))); } else { return yield exec(criteria); } }); } } exports.Mutator = Mutator; _Mutator_cache = new WeakMap(), _Mutator_buffer = new WeakMap(), _Mutator_mutations = new WeakMap(), _Mutator_objectDiscovery = new WeakMap(), _Mutator_eventEmitter = new WeakMap(), _Mutator_instances = new WeakSet(), _Mutator_hasMutations = function _Mutator_hasMutations(criteria, result = false, parentPath = "") { // If we have already found a mutation, we can stop. if (result) return true; for (const key of Object.keys(criteria)) { if (result) return true; // Prepare dotted path to the current property. const path = parentPath ? `${parentPath}.${key}` : key; // If the value is an object, we should recurse. result = __classPrivateFieldGet(this, _Mutator_objectDiscovery, "f").isObject(criteria[key]) ? result || __classPrivateFieldGet(this, _Mutator_instances, "m", _Mutator_hasMutations).call(this, criteria[key], result, path) : result || __classPrivateFieldGet(this, _Mutator_mutations, "f").has(path); } return result; }, _Mutator_applyMutations = function _Mutator_applyMutations(criteria_1) { return __awaiter(this, arguments, void 0, function* (criteria, parentPath = "") { const promises = Object.keys(criteria).map((key) => __awaiter(this, void 0, void 0, function* () { return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { // Prepare dotted path to the current property. const path = parentPath ? `${parentPath}.${key}` : key; if (__classPrivateFieldGet(this, _Mutator_objectDiscovery, "f").isObject(criteria[key])) { yield __classPrivateFieldGet(this, _Mutator_instances, "m", _Mutator_applyMutations).call(this, criteria[key], path); } if (__classPrivateFieldGet(this, _Mutator_mutations, "f").has(path)) { criteria[key] = yield __classPrivateFieldGet(this, _Mutator_instances, "m", _Mutator_execMutation).call(this, key, criteria, path); } resolve(criteria[key]); })); })); yield Promise.all(promises); }); }, _Mutator_execMutation = function _Mutator_execMutation(criteriaProp, criteria, mutationKey) { return __awaiter(this, void 0, void 0, function* () { const value = criteria[criteriaProp]; // Create a cache key const cacheKey = `${mutationKey}${(0, crypto_1.createHash)("md5") .update(value.toString()) .digest("hex")}`; // If the mutation has already been executed, return the cached result. if (__classPrivateFieldGet(this, _Mutator_cache, "f").has(cacheKey)) { logger_1.Logger.debug(`Cache hit on "${mutationKey}" with param "${value}"`); return __classPrivateFieldGet(this, _Mutator_cache, "f").get(cacheKey); } // If the mutation is already in progress, wait for it to finish. if (__classPrivateFieldGet(this, _Mutator_buffer, "f").get(cacheKey)) { return yield new Promise((resolve) => { logger_1.Logger.debug(`Waiting on mutation "${mutationKey}" with param "${value}"`); __classPrivateFieldGet(this, _Mutator_eventEmitter, "f").once(`mutation:${cacheKey}`, (result) => { logger_1.Logger.debug(`Resolved mutation "${mutationKey}" with param "${value}"`); resolve(result); }); }); } // Set the buffer to true to indicate that the mutation is in progress. // This prevents duplicate executions of the same mutation. __classPrivateFieldGet(this, _Mutator_buffer, "f").set(cacheKey, true); // Execute the mutation logger_1.Logger.debug(`Running mutation "${mutationKey}" with param "${value}"`); const mutation = __classPrivateFieldGet(this, _Mutator_mutations, "f").get(mutationKey); const result = yield mutation(value, criteria); // Cache the result and release the buffer to false. __classPrivateFieldGet(this, _Mutator_cache, "f").set(cacheKey, result); __classPrivateFieldGet(this, _Mutator_buffer, "f").set(cacheKey, false); // Emit an event to indicate that the mutation has been executed. __classPrivateFieldGet(this, _Mutator_eventEmitter, "f").emit(`mutation:${cacheKey}`, result); return result; }); };