domain-objects
Version:
A simple, convenient way to represent domain objects, leverage domain knowledge, and add runtime validation in your code base.
63 lines • 2.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.clone = void 0;
/**
* .what = deep clones domain objects safely
* .why = preserves instance types, methods, and nested structures
*/
const clone = (dobj, updates = {}) => {
// clone and merge
const merged = deepMerge(deepClone(dobj), updates);
// instantiate, if can
const ctor = dobj?.constructor;
const hasConstructor = typeof ctor === 'function' &&
ctor !== Object &&
ctor.prototype &&
ctor.prototype.constructor === ctor;
if (!hasConstructor)
return merged;
return new ctor(merged);
};
exports.clone = clone;
function deepClone(value) {
if (value === null || typeof value !== 'object')
return value;
if (Array.isArray(value)) {
return value.map(deepClone);
}
if (value instanceof Date)
return new Date(value.getTime());
const proto = Object.getPrototypeOf(value);
const cloneObj = Object.create(proto);
for (const key of Reflect.ownKeys(value)) {
const desc = Object.getOwnPropertyDescriptor(value, key);
if (desc) {
Object.defineProperty(cloneObj, key, {
...desc,
value: deepClone(value[key]),
});
}
}
return cloneObj;
}
function deepMerge(base, updates) {
const result = Array.isArray(base) ? [...base] : { ...base };
for (const key in updates) {
const baseVal = base[key];
const updateVal = updates[key];
const isMergeableObject = typeof baseVal === 'object' &&
baseVal !== null &&
typeof updateVal === 'object' &&
updateVal !== null &&
!Array.isArray(baseVal) &&
!Array.isArray(updateVal);
if (isMergeableObject) {
result[key] = deepMerge(baseVal, updateVal);
}
else if (updateVal !== undefined) {
result[key] = updateVal;
}
}
return result;
}
//# sourceMappingURL=clone.js.map