rulepilot
Version:
Rule parsing engine for JSON rules
169 lines (168 loc) • 9.31 kB
JavaScript
"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;
});
};