UNPKG

@kwiz/common

Version:

KWIZ common utilities and helpers for M365 platform

283 lines 11.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultProp = exports.noops = exports.noop = exports.$w = void 0; exports.hasOwnProperty = hasOwnProperty; exports.getKWizComGlobal = getKWizComGlobal; exports.getGlobal = getGlobal; exports.autoBind = autoBind; exports.assign = assign; exports.primitivesEqual = primitivesEqual; exports.objectsEqual = objectsEqual; exports.jsonClone = jsonClone; exports.ensureObjectPath = ensureObjectPath; exports.keepOne = keepOne; exports.getAllMemberNames = getAllMemberNames; exports.getAllFunctionNames = getAllFunctionNames; exports.objectValues = objectValues; exports.GetDefaultProp = GetDefaultProp; exports.GetError = GetError; const collections_base_1 = require("./collections.base"); const json_1 = require("./json"); const typecheckers_1 = require("./typecheckers"); /** global window, safe for testing and environments without a browser */ exports.$w = typeof window === "undefined" ? { setTimeout: setTimeout, clearTimeout: clearTimeout, location: { href: "", host: "" } } : window; /** wrapper for hasOwnProperty that satisfies https://eslint.org/docs/latest/rules/no-prototype-builtins */ function hasOwnProperty(obj, prop) { if (!(0, typecheckers_1.isNullOrUndefined)(obj)) { return Object.prototype.hasOwnProperty.call(obj, prop); } return false; } /** empty async function */ /* eslint-disable-next-line @typescript-eslint/no-empty-function */ var noop = async () => { }; exports.noop = noop; /** empty sync function */ /* eslint-disable-next-line @typescript-eslint/no-empty-function */ var noops = () => { }; exports.noops = noops; /** get or create kwizcom object from top window or current window, set allowFromTop if you want to try to get from window.top */ function getKWizComGlobal(allowFromTop) { if (allowFromTop) { try { exports.$w.top["kwizcom"] = exports.$w.top["kwizcom"] || {}; return exports.$w.top["kwizcom"]; } catch (ex) { } } exports.$w["kwizcom"] = exports.$w["kwizcom"] || {}; return exports.$w["kwizcom"]; } /** get or create kwizcom.globals dictionary from top window or current window. Add or return key:name initialize as defaults or blank object if does not already exist */ function getGlobal(name, defaults, notFromTop) { var kGlobal = getKWizComGlobal(notFromTop !== true); kGlobal.globals = kGlobal.globals || {}; if (!kGlobal.globals[name]) { if ((0, typecheckers_1.isObject)(defaults)) { // eslint-disable-next-line @typescript-eslint/ban-types kGlobal.globals[name] = { ...defaults }; } else { kGlobal.globals[name] = {}; } } return kGlobal.globals[name]; } /** * Automatically bind all functions of instance to instance * Note: if you use knockout, you should skip ko.isObservable * @param instance */ //eslint-disable-next-line @typescript-eslint/ban-types function autoBind(instance, skip) { let funcitonNames = getAllFunctionNames(instance, 1); funcitonNames.forEach(prop => { const val = instance[prop]; if (!(0, typecheckers_1.isFunction)(skip) || !skip(prop, val)) instance[prop] = val.bind(instance); }); } /** Implements Object.assign which does not exist in IE * Copies properties over from overrides into original object * Merge default and override settings: var merged = assign({},defaults,props) * Create deep copy of object by var copy = assign({},obj) */ function assign(original, ...overrides) { if (original === undefined || original === null) { throw new TypeError('Cannot convert first argument to object'); } var to = Object(original); if (overrides && overrides.length > 0) overrides.forEach(o => { if (!(0, typecheckers_1.isNullOrUndefined)(o)) { var keysArray = Object.keys(Object(o)); for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { var nextKey = keysArray[nextIndex]; var desc = Object.getOwnPropertyDescriptor(o, nextKey); if (typeof (desc.value) === "undefined" || desc.value === null) { to[nextKey] = desc.value; } else if (typeof (desc.value) === "object") { //reference type, call assign recursively. fixed problem that object value types from overrides were modified when the returnd object was modified. if (!Array.isArray(desc.value)) { to[nextKey] = assign({}, desc.value); } else { to[nextKey] = assign([], desc.value); } } else { if (desc !== undefined && desc.enumerable) { to[nextKey] = desc.value; //this will make a shallow copy, altering the override object o[nextKey]; } } } } }); return to; } function primitivesEqual(o1, o2) { let normalize = (oo) => { if ((0, typecheckers_1.isNullOrUndefined)(oo)) return null; else if ((0, typecheckers_1.isDate)(oo)) return oo.getTime(); return oo; }; o1 = normalize(o1); o2 = normalize(o2); return o1 === o2; } function objectsEqual(o1, o2, ignoreKeys) { let isPrimitive1 = (0, typecheckers_1.isPrimitiveValue)(o1); let isPrimitive2 = (0, typecheckers_1.isPrimitiveValue)(o2); if (isPrimitive1 !== isPrimitive2) return false; //one primitive other not? if (isPrimitive1) return primitivesEqual(o1, o2); if ((0, typecheckers_1.isFunction)(o1) || (0, typecheckers_1.isFunction)(o2)) { try { return o1.toString() === o2.toString(); } catch (e) { return false; } } ignoreKeys = ignoreKeys || []; let allKeys = (0, collections_base_1.makeUniqueArray)(Object.keys(o1).concat(Object.keys(o2))).filter(key => !ignoreKeys.includes(key)); for (let i = 0; i < allKeys.length; i++) { let key = allKeys[i]; if (!objectsEqual(o1[key], o2[key], ignoreKeys)) return false; } return true; } function jsonClone(obj) { //todo: check if assign utility method is faster if ((0, typecheckers_1.isNullOrUndefined)(obj)) return null; let result = obj; try { result = (0, json_1.jsonParse)(JSON.stringify(obj)); } catch (e) { if ((0, typecheckers_1.isNotEmptyArray)(obj)) result = obj.slice(); else result = obj; } //clone date objects try { cloneDatesOnObjectRecursivily(obj, result); } catch (e) { } return result; } function cloneDatesOnObjectRecursivily(obj1, obj2) { Object.keys(obj1).forEach(key => { let v = obj1[key]; if (v === null) obj2[key] = null; else if ((0, typecheckers_1.isDate)(v)) obj2[key] = new Date(v.getTime()); else if ((0, typecheckers_1.isObject)(v) && Object.keys(v).length) { let v2 = obj2[key]; if ((0, typecheckers_1.isObject)(v2)) cloneDatesOnObjectRecursivily(v, v2); } }); } /** if an object in this path doesnt exist under parent - creates it.*/ function ensureObjectPath(objectPath, defaultValue = {}, parent = exports.$w) { if ((0, typecheckers_1.isNullOrEmptyString)(objectPath)) return; let parts = objectPath.split('.'); for (let i = 0; i < parts.length; i++) { let partName = parts[i]; if (i === parts.length - 1) //last { if ((0, typecheckers_1.isNullOrUndefined)(parent[partName])) parent[partName] = defaultValue; } else { if ((0, typecheckers_1.isNullOrUndefined)(parent[partName])) parent[partName] = {}; parent = parent[partName]; } } } /** If o has propb and not propa - will copy propb into propa and remove propb */ function keepOne(o, propa, propb) { /* using the unkown type doesn't work in modern apps project */ if ((0, typecheckers_1.isObject)(o)) { if (!hasOwnProperty(o, propa) && hasOwnProperty(o, propb)) { o[propa] = o[propb]; delete o[propb]; } } } /**return all members and functions of an object, including inherited ones from its base class, excluding the constructor * send prototypeLevels to limit the number of prototype climbs to get functions from. 0 means unlimited. */ function getAllMemberNames(instance, prototypeLevels) { let props = []; let obj = instance; let level = 0; let unlimitedLevels = prototypeLevels < 0; do { props.push(...Object.getOwnPropertyNames(obj)); obj = Object.getPrototypeOf(obj); level++; } while (unlimitedLevels ? !!obj : !!obj && level <= prototypeLevels); return (0, collections_base_1.makeUniqueArray)(props.filter(p => p !== 'constructor' && p !== 'dispose')); } /**return all functions of an object, including inherited ones from its base class, excluding the constructor * send prototypeLevels to limit the number of prototype climbs to get functions from. 0 means unlimited. */ function getAllFunctionNames(instance, prototypeLevels) { return getAllMemberNames(instance, prototypeLevels).filter(p => (0, typecheckers_1.isFunction)(instance[p])); } /** generic implementation of Object.values */ function objectValues(obj) { return Object.keys(obj).map((key) => { return obj[key]; }); } class DefaultProp { set value(newValue) { this._value = newValue; } get value() { if (!this.isValid(this._value)) { this._value = (0, typecheckers_1.isFunction)(this._defaultValue) ? this._defaultValue() : this._defaultValue; } return this._value; } constructor(defaultValue, initialValue, isValid) { this._defaultValue = defaultValue; this._value = initialValue; this.isValid = (0, typecheckers_1.isFunction)(isValid) ? isValid : v => !(0, typecheckers_1.isNullOrUndefined)(v); } } exports.DefaultProp = DefaultProp; /** creates a safe property, if the value is null/undefined or empty string - it will return the default value. */ function GetDefaultProp(defaultValue, initialValue, isValid) { return new DefaultProp(defaultValue, initialValue, isValid); } /** Get string error message from an error object */ function GetError(error, defaultError = "Unknown error") { const err = (0, typecheckers_1.isNullOrUndefined)(error) ? defaultError : (0, typecheckers_1.isString)(error) ? error : (0, typecheckers_1.isString)(error.message) ? error.message : defaultError; return err.length > 0 ? err : defaultError; } //# sourceMappingURL=objects.js.map