@kwiz/common
Version:
KWIZ common utilities and helpers for M365 platform
283 lines • 11.2 kB
JavaScript
;
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