wickr-bedrock-bot
Version:
AWS Wickr's own Bedrock Bot
420 lines (417 loc) • 15.5 kB
JavaScript
/*!
* mergician
* v1.1.0
* https://jhildenbiddle.github.io/mergician/
* (c) 2022-2023 John Hildenbiddle
* MIT license
*/
var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
// src/util.cjs
var require_util = __commonJS({
"src/util.cjs"(exports, module) {
function countOccurrences(...arrays) {
const countObj = {};
arrays.forEach((array) => {
array.forEach((v) => {
countObj[v] = v in countObj ? ++countObj[v] : 1;
});
});
return countObj;
}
function getInMultiple(...arrays) {
const countObj = countOccurrences(...arrays);
return Object.keys(countObj).filter((v) => countObj[v] > 1);
}
function getInAll(...arrays) {
return arrays.reduce(
(acc, curr) => acc.filter(Set.prototype.has, new Set(curr))
);
}
function getNotInMultiple(...arrays) {
const countObj = countOccurrences(...arrays);
return Object.keys(countObj).filter((v) => countObj[v] === 1);
}
function getNotInAll(...arrays) {
const countObj = countOccurrences(...arrays);
return Object.keys(countObj).filter((v) => countObj[v] < arrays.length);
}
function getObjectKeys(obj, includeProto = false) {
if (includeProto) {
const keys = [];
for (const key in obj) {
keys.push(key);
}
return keys;
} else {
return Object.keys(obj);
}
}
function isObject(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function isPropDescriptor(obj) {
if (!isObject(obj)) {
return false;
}
const hasFlagKey = ["writable", "enumerable", "configurable"].some((key) => key in obj);
const hasMethod = ["get", "set"].some((key) => typeof obj[key] === "function");
const hasMethodKeys = ["get", "set"].every((key) => key in obj);
let isDescriptor = "value" in obj && hasFlagKey || hasMethod && (hasMethodKeys || hasFlagKey);
if (isDescriptor) {
const validKeys = [
"configurable",
"get",
"set",
"enumerable",
"value",
"writable"
];
isDescriptor = Object.keys(obj).some((key) => !(key in validKeys));
}
return isDescriptor;
}
module.exports = {
countOccurrences,
getInMultiple,
getInAll,
getNotInMultiple,
getNotInAll,
getObjectKeys,
isObject,
isPropDescriptor
};
}
});
// src/index.cjs
var require_src = __commonJS({
"src/index.cjs"(exports, module) {
var {
getInMultiple,
getInAll,
getNotInMultiple,
getNotInAll,
getObjectKeys,
isObject,
isPropDescriptor
} = require_util();
var defaults = {
// Keys
onlyKeys: [],
skipKeys: [],
onlyCommonKeys: false,
onlyUniversalKeys: false,
skipCommonKeys: false,
skipUniversalKeys: false,
// Values
invokeGetters: false,
skipSetters: false,
// Arrays
appendArrays: false,
prependArrays: false,
dedupArrays: false,
sortArrays: false,
// Prototype
hoistProto: false,
// Callbacks
filter: Function.prototype,
beforeEach: Function.prototype,
afterEach: Function.prototype,
onCircular: Function.prototype
};
/**
* Deep recursive object merging with options to inspect, modify, and filter
* keys/values, merge arrays (append/prepend), and remove duplicate values from
* merged arrays. Returns new object without modifying sources (immutable).
*
* @preserve
*
* @example
* // Without options (use default option values)
* mergician(obj1, obj2, obj3, ...);
*
* @example
* // With options (defaults shown)
* mergician({
* // Keys
* onlyKeys: [],
* skipKeys: [],
* onlyCommonKeys: false,
* onlyUniversalKeys: false,
* skipCommonKeys: false,
* skipUniversalKeys: false,
* // Values
* invokeGetters: false,
* skipSetters: false,
* // Arrays
* appendArrays: false,
* prependArrays: false,
* dedupArrays: false,
* sortArrays: false,
* // Prototype
* hoistProto: false,
* // Callbacks
* filter({ depth, key, srcObj, srcVal, targetObj, targetVal }) {},
* beforeEach({ depth, key, srcObj, srcVal, targetObj, targetVal }) {},
* afterEach({ depth, key, mergeVal, srcObj, targetObj }) {},
* onCircular({ depth, key, srcObj, srcVal, targetObj, targetVal }) {}
* })(obj1, obj2, obj3, ...)
*
* @param {...object} optionsOrObjects - Options or objects to merge
* @param {array} [options.onlyKeys] - Exclusive array of keys to be merged
* (others are skipped)
* @param {array} [options.skipKeys] - Array of keys to skip (others are merged)
* @param {boolean} [options.onlyCommonKeys = false] - Merge only keys found in
* multiple objects (ignore single occurrence keys)
* @param {boolean} [options.onlyUniversalKeys = false] - Merge only keys found
* in all objects
* @param {boolean} [options.skipCommonKeys = false] - Skip keys found in
* multiple objects (merge only single occurrence keys)
* @param {boolean} [options.skipUniversalKeys = false] - Skip keys found in all
* objects (merge only common keys)
* @param {boolean} [options.invokeGetters = false] - Invoke "getter" methods
* and merge returned values
* @param {boolean} [options.skipSetters = false] - Skip "setter" methods during
* merge
* @param {boolean} [options.appendArrays = false] - Merge array values at the
* end of existing arrays
* @param {boolean} [options.prependArrays = false] - Merge array values at the
* beginning of existing arrays
* @param {boolean} [options.dedupArrays = false] - Remove duplicate array
* values in new merged object
* @param {boolean|function} [options.sortArrays = false] - Sort array values in
* new merged object
* @param {boolean} [options.hoistProto = false] - Clone prototype properties as
* direct properties of merged/cloned object
* @param {function} [options.filter] - Callback used to conditionally merge or
* skip a property. Return a "truthy" value to merge or a "falsy" value to skip.
* Return no value to proceed according to other option values.
* @param {function} [options.beforeEach] - Callback used for
* inspecting/modifying properties before merge. Return value is used as value
* to merge.
* @param {function} [options.afterEach] - Callback used for
* inspecting/modifying properties after merge. Return value is used as merged
* value.
* @param {function} [options.onCircular] - Callback used for handling circular
* object references during merge
* @returns {function|object} Merge function with options applied or new merged
* object
* @param {...object} [objects] - Objects to merge
* @returns {object} New merged object
*/
function mergician(...optionsOrObjects) {
const options = arguments.length === 1 ? arguments[0] : {};
const settings = { ...defaults, ...options };
const dedupArrayMap = /* @__PURE__ */ new Map();
const sortArrayMap = /* @__PURE__ */ new Map();
const sortArrayFn = typeof settings.sortArrays === "function" ? settings.sortArrays : void 0;
const circularRefs = /* @__PURE__ */ new WeakMap();
let mergeDepth = 0;
function _getObjectKeys(obj) {
return getObjectKeys(obj, settings.hoistProto);
}
function _mergician(...objects) {
let mergeKeyList;
if (objects.length > 1) {
if (settings.onlyCommonKeys) {
mergeKeyList = getInMultiple(...objects.map((obj) => _getObjectKeys(obj)));
} else if (settings.onlyUniversalKeys) {
mergeKeyList = getInAll(...objects.map((obj) => _getObjectKeys(obj)));
} else if (settings.skipCommonKeys) {
mergeKeyList = getNotInMultiple(...objects.map((obj) => _getObjectKeys(obj)));
} else if (settings.skipUniversalKeys) {
mergeKeyList = getNotInAll(...objects.map((obj) => _getObjectKeys(obj)));
}
}
if (!mergeKeyList && settings.onlyKeys.length) {
mergeKeyList = settings.onlyKeys;
}
if (mergeKeyList && mergeKeyList !== settings.onlyKeys && settings.onlyKeys.length) {
mergeKeyList = mergeKeyList.filter((key) => settings.onlyKeys.includes(key));
}
const newObj = objects.reduce((targetObj, srcObj) => {
circularRefs.set(srcObj, targetObj);
let keys = mergeKeyList || _getObjectKeys(srcObj);
if (settings.skipKeys.length) {
keys = keys.filter((key) => settings.skipKeys.indexOf(key) === -1);
}
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const targetVal = targetObj[key];
let isReturnVal = false;
let mergeVal;
if (key in srcObj === false) {
continue;
}
try {
mergeVal = srcObj[key];
} catch (err) {
console.error(err);
continue;
}
const srcDescriptor = Object.getOwnPropertyDescriptor(srcObj, key);
const isSetterOnly = srcDescriptor && typeof srcDescriptor.set === "function" && typeof srcDescriptor.get !== "function";
if (isSetterOnly) {
if (!settings.skipSetters) {
srcDescriptor.configurable = true;
Object.defineProperty(targetObj, key, srcDescriptor);
}
continue;
}
if (settings.filter !== defaults.filter) {
const returnVal = settings.filter({
depth: mergeDepth,
key,
srcObj,
srcVal: mergeVal,
targetObj,
targetVal
});
if (returnVal !== void 0 && !returnVal) {
continue;
}
}
if (settings.beforeEach !== defaults.beforeEach) {
const returnVal = settings.beforeEach({
depth: mergeDepth,
key,
srcObj,
srcVal: mergeVal,
targetObj,
targetVal
});
if (returnVal !== void 0) {
isReturnVal = true;
mergeVal = returnVal;
}
}
if (typeof mergeVal === "object" && mergeVal !== null) {
if (circularRefs.has(srcObj[key])) {
const returnVal = settings.onCircular({
depth: mergeDepth,
key,
srcObj,
srcVal: srcObj[key],
targetObj,
targetVal
});
if (returnVal === void 0) {
mergeVal = circularRefs.get(srcObj[key]);
targetObj[key] = mergeVal;
continue;
}
isReturnVal = true;
mergeVal = returnVal;
}
}
if (Array.isArray(mergeVal)) {
mergeVal = [...mergeVal];
if (Array.isArray(targetVal)) {
if (settings.appendArrays) {
mergeVal = [...targetVal, ...mergeVal];
} else if (settings.prependArrays) {
mergeVal = [...mergeVal, ...targetVal];
}
}
if (settings.dedupArrays) {
if (settings.afterEach !== defaults.afterEach) {
mergeVal = [...new Set(mergeVal)];
} else {
const keyArray = dedupArrayMap.get(targetObj);
if (keyArray && !keyArray.includes(key)) {
keyArray.push(key);
} else {
dedupArrayMap.set(targetObj, [key]);
}
}
}
if (settings.sortArrays) {
if (settings.afterEach !== defaults.afterEach) {
mergeVal = mergeVal.sort(sortArrayFn);
} else {
const keyArray = sortArrayMap.get(targetObj);
if (keyArray && !keyArray.includes(key)) {
keyArray.push(key);
} else {
sortArrayMap.set(targetObj, [key]);
}
}
}
} else if (isObject(mergeVal) && (!isReturnVal || !isPropDescriptor(mergeVal))) {
mergeDepth++;
if (isObject(targetVal)) {
mergeVal = _mergician(targetVal, mergeVal);
} else {
mergeVal = _mergician(mergeVal);
}
mergeDepth--;
}
if (settings.afterEach !== defaults.afterEach) {
const returnVal = settings.afterEach({
depth: mergeDepth,
key,
mergeVal,
srcObj,
targetObj
});
if (returnVal !== void 0) {
isReturnVal = true;
mergeVal = returnVal;
}
}
if (isReturnVal) {
if (isPropDescriptor(mergeVal)) {
mergeVal.configurable = true;
mergeVal.enumerable = !("enumerable" in mergeVal) ? true : mergeVal.enumerable;
if ("value" in mergeVal && !("writable" in mergeVal)) {
mergeVal.writable = true;
}
Object.defineProperty(targetObj, key, mergeVal);
} else {
targetObj[key] = mergeVal;
}
} else {
const mergeDescriptor = Object.getOwnPropertyDescriptor(srcObj, key);
if (mergeDescriptor && typeof mergeDescriptor.get === "function" && !settings.invokeGetters) {
if (settings.skipSetters) {
mergeDescriptor.set = void 0;
}
mergeDescriptor.configurable = true;
Object.defineProperty(targetObj, key, mergeDescriptor);
} else {
targetObj[key] = mergeVal;
}
}
}
return targetObj;
}, {});
for (const [obj, keyArray] of dedupArrayMap.entries()) {
for (const key of keyArray) {
obj[key] = [...new Set(obj[key])];
}
}
for (const [obj, keyArray] of sortArrayMap.entries()) {
for (const key of keyArray) {
obj[key].sort(sortArrayFn);
}
}
return newObj;
}
if (arguments.length === 1) {
return function(...objects) {
if (arguments.length === 1) {
return mergician({ ...settings, ...objects[0] });
} else {
return _mergician(...objects);
}
};
} else {
return _mergician(...arguments);
}
}
module.exports = mergician;
}
});
export default require_src();