@beenotung/tslib
Version:
utils library in Typescript
261 lines • 8.24 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.valuesToObject = exports.objectToValues = exports.deleteUndefined = exports.ensureNonCyclic = exports.removeNull = exports.isNull = exports.updateObject = exports.createSafeObject = exports.SafeObjectOptions = exports.replaceObject = exports.deepEqual = exports.deepClone = exports.hasFunction = exports.isObject = void 0;
const array_1 = require("./array");
const map_1 = require("./iterative/map");
const type_1 = require("./type");
function isObject(o) {
return typeof o === 'object';
}
exports.isObject = isObject;
function hasFunction(o, name) {
return typeof o[name] === 'function';
}
exports.hasFunction = hasFunction;
function deepClone(o) {
if (!isObject(o)) {
return o;
}
if (o instanceof Array) {
return o.map(deepClone);
}
else {
const res = {};
Object.keys(o).forEach(x => (res[x] = deepClone(o[x])));
return res;
}
}
exports.deepClone = deepClone;
function deepEqual(a, b) {
if (a === b) {
return true;
}
const aType = type_1.getObjectType(a);
const bType = type_1.getObjectType(b);
if (aType !== bType) {
return false;
}
switch (aType) {
case 'AsyncFunction':
case 'Function':
return a.toString() === b.toString();
case 'Array':
if (a.length !== b.length) {
return false;
}
return a.every((_, i) => deepEqual(a[i], b[i]));
case 'Uint8Array':
if (a.length !== b.length) {
return false;
}
return a.every((_, i) => deepEqual(a[i], b[i]));
case 'Boolean':
case 'Number':
case 'String':
return a === b;
case 'Null':
case 'Undefined':
return true;
case 'Map':
const aMap = a;
const bMap = b;
for (const key of aMap.keys()) {
if (!bMap.has(key)) {
return false;
}
if (!deepEqual(aMap.get(key), bMap.get(key))) {
return false;
}
}
return true;
case 'Set':
const aSet = a;
const bSet = b;
if (aSet.size !== bSet.size) {
return false;
}
for (const value of aSet.values()) {
if (!bSet.has(value)) {
return false;
}
}
return true;
case 'Date':
return a.getTime() === b.getTime();
case 'Object':
const aKeys = Object.keys(a);
const bKeys = Object.keys(b);
if (aKeys.length !== bKeys.length) {
return false;
}
return aKeys.every(key => deepEqual(a[key], b[key]));
default:
throw Error('unsupported data type');
}
}
exports.deepEqual = deepEqual;
function replaceObject(dest, src) {
Object.keys(dest).forEach(x => delete dest[x]);
return Object.assign(dest, src);
}
exports.replaceObject = replaceObject;
const SafeObject = Symbol.for('SafeObject');
exports.SafeObjectOptions = {
throwError: false,
};
const safeProxyHandler = {
get: (target, p, receiver) => {
let value = Reflect.get(target, p, receiver);
if (typeof p === 'symbol' || p === 'inspect') {
return value;
}
if (exports.SafeObjectOptions.throwError && !Reflect.has(target, p)) {
throw new TypeError(JSON.stringify(p) + ' is not defined in ' + target.toString());
}
if (value === null || value === undefined) {
value = createSafeObject();
target[p] = value;
return value;
}
if (typeof value === 'object') {
if (value[SafeObject] === true) {
return value;
}
value = createSafeObject(value);
target[p] = value;
return value;
}
else {
return value;
}
},
};
/**
* make a loss object, very forgiving
* */
function createSafeObject(target = {}) {
;
target[SafeObject] = true;
return new Proxy(target, safeProxyHandler);
}
exports.createSafeObject = createSafeObject;
exports.updateObject = (dest) => (x) => Object.assign(dest, x);
exports.isNull = (x) => !(x === null || x === undefined || x === '');
function removeNull(o) {
if (Array.isArray(o)) {
return o
.filter(x => !(x === null || x === undefined || x === ''))
.map(x => removeNull(x));
}
if (o instanceof Set) {
return new Set(removeNull(Array.from(o)));
}
if (o instanceof Date) {
return o;
}
if (typeof o === 'object' && o !== null) {
o = Object.assign({}, o);
for (const k of Object.keys(o)) {
const v = o[k];
if (v === null || v === undefined || v === '') {
delete o[k];
}
}
}
return o;
}
exports.removeNull = removeNull;
/**
* @param {any} o : value to be checked
* @param {boolean} skip : true will remove duplicated value silently;
* false will throw an error upon duplication
* @param {any} placeholder : custom value to replace duplicated object
* @param {function} mapper : optional map function
* @param {Set} visited : internal book keeping seen objects
* */
function ensureNonCyclic(o, skip = true, placeholder = void 0, mapper, visited = new Set()) {
switch (type_1.getObjectType(o)) {
case 'Number':
case 'String':
case 'Null':
case 'Undefined':
case 'Function':
case 'AsyncFunction':
/* these types can be duplicated */
return mapper ? mapper(o) : o;
default:
/* array, set, map, object */
if (visited.has(o)) {
/* duplicated object */
if (skip) {
return placeholder;
}
throw new Error('circular structure, duplicated value: ' + o);
}
/* non-duplicated object */
/* clone the set, to allow sibling duplication */
visited = map_1.map_set(visited, x => x);
visited.add(o);
return map_1.map_any(o, x => ensureNonCyclic(x, skip, placeholder, mapper, visited));
}
}
exports.ensureNonCyclic = ensureNonCyclic;
function deleteUndefined(o) {
if (Array.isArray(o)) {
array_1.replaceArray(o, o.filter(x => x !== undefined));
o.forEach(x => deleteUndefined(x));
return;
}
if (o instanceof Map) {
o.forEach((value, key) => {
if (value === undefined) {
o.delete(key);
}
deleteUndefined(value);
});
return;
}
if (typeof o === 'object') {
for (const s of Object.keys(o)) {
if (o[s] === undefined) {
delete o[s];
continue;
}
deleteUndefined(o[s]);
}
return;
}
// e.g. number, string
return;
}
exports.deleteUndefined = deleteUndefined;
/**
* to encode json data in csv-style
* i.e. only need to store the keys once for a large collection (e.g. Array / Set)
* */
function objectToValues(o, keys = Object.keys(o).sort()) {
return keys.map(key => o[key]);
}
exports.objectToValues = objectToValues;
/**
* to decode json data from csv-style
* i.e. populate values and keys to a collection (e.g. Array / Set)
* */
function valuesToObject(values, keys) {
const res = {};
if (values.length !== keys.length) {
console.error('length of values and keys mismatch:', {
keys: keys.length,
values: values.length,
});
throw new Error('invalid values');
}
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = values[i];
res[key] = value;
}
return res;
}
exports.valuesToObject = valuesToObject;
//# sourceMappingURL=object.js.map