@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
131 lines • 4.32 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isObjectOrArray = isObjectOrArray;
exports.deepMergeObject = deepMergeObject;
exports.deepMergeObjectInPlace = deepMergeObjectInPlace;
exports.compactRecord = compactRecord;
exports.deepClonePreserveUnclonable = deepClonePreserveUnclonable;
const json_1 = require("./json");
/**
* checks if `item` is an object (it may be an array, ...)
*/
function isObjectOrArray(item) {
return typeof item === 'object';
}
function deepMergeObject(base, addon) {
if (!base) {
return addon;
}
else if (!addon) {
return base;
}
else if (typeof base !== 'object' || typeof addon !== 'object') {
// this case should be guarded by type guards, but in case we do not know
throw new Error('illegal types for deepMergeObject!');
}
assertSameType(base, addon);
const result = { ...base };
const baseIsArray = Array.isArray(base);
const addonIsArray = Array.isArray(addon);
if (!baseIsArray && !addonIsArray) {
deepMergeObjectWithResult(addon, base, result);
}
else if (baseIsArray && addonIsArray) {
return base.concat(addon);
}
else {
throw new Error('cannot merge object with array!');
}
return result;
}
function deepMergeObjectWithResult(addon, base, result) {
for (const key of Object.keys(addon)) {
// values that are undefined (like from a partial object) should NOT be overwritten
if (addon[key] === undefined) {
continue;
}
if (typeof addon[key] === 'object') {
if (key in base) {
result[key] = deepMergeObject(base[key], addon[key]);
}
else {
result[key] = addon[key];
}
}
else {
assertSameType(result[key], addon[key]);
result[key] = addon[key];
}
}
}
function deepMergeObjectInPlace(base, addon) {
if (!base) {
return addon;
}
else if (!addon) {
return base;
}
else if (typeof base !== 'object' || typeof addon !== 'object') {
// this case should be guarded by type guards, but in case we do not know
throw new Error('illegal types for deepMergeObjectInPlace!');
}
assertSameType(base, addon);
const baseIsArray = Array.isArray(base);
const addonIsArray = Array.isArray(addon);
if (!baseIsArray && !addonIsArray) {
deepMergeObjectWithResult(addon, base, base);
}
else if (baseIsArray && addonIsArray) {
(base).push(...addon);
}
else {
throw new Error('cannot merge object with array!');
}
return base;
}
function assertSameType(base, addon) {
if (base !== undefined && addon !== undefined && typeof base !== typeof addon) {
throw new Error(`cannot merge different types! ${typeof base} (${JSON.stringify(base, json_1.jsonReplacer)}) !== ${typeof addon} (${JSON.stringify(addon, json_1.jsonReplacer)})`);
}
}
/** from a record take only the keys that are not undefined */
function compactRecord(record) {
if (record === undefined) {
return undefined;
}
const result = {};
for (const key of Object.keys(record)) {
if (record[key] !== undefined) {
result[key] = record[key];
}
}
return result;
}
/**
* This is a version of a deep clone that preserves unclonable values (like functions, symbols, ...) by keeping the same reference to them.
*/
function deepClonePreserveUnclonable(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
else if (Array.isArray(obj)) {
return obj.map(deepClonePreserveUnclonable);
}
else if (obj instanceof Date) {
return new Date(obj.getTime());
}
else if (obj instanceof Map) {
return new Map(obj.entries().map(([k, v]) => [deepClonePreserveUnclonable(k), deepClonePreserveUnclonable(v)]));
}
else if (obj instanceof Set) {
return new Set(obj.values().map(deepClonePreserveUnclonable));
}
else {
const result = {};
for (const key of Object.keys(obj)) {
result[key] = deepClonePreserveUnclonable(obj[key]);
}
return result;
}
}
//# sourceMappingURL=objects.js.map