UNPKG

@mikro-orm/core

Version:

TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.

138 lines (137 loc) 4.73 kB
/** * Inspired by https://github.com/pvorb/clone but simplified and never tries to * clone `EventEmitter`s to get around https://github.com/mikro-orm/mikro-orm/issues/2748 * @internal */ /** * Get the property descriptor of a property on an object or its prototype chain. * * @param obj - The object to get the property descriptor from. * @param prop - The property to get the descriptor for. */ function getPropertyDescriptor(obj, prop) { const descriptor = Object.getOwnPropertyDescriptor(obj, prop); if (descriptor) { return descriptor; } const proto = Object.getPrototypeOf(obj); if (proto) { return getPropertyDescriptor(proto, prop); } return null; } const TypedArray = Object.getPrototypeOf(Uint8Array); export function clone(parent, respectCustomCloneMethod = true) { const allParents = []; const allChildren = []; function _clone(parent) { // cloning null always returns null if (parent === null) { return null; } if (typeof parent !== 'object') { return parent; } if (respectCustomCloneMethod && 'clone' in parent && typeof parent.clone === 'function') { // an async `clone()` signals a live stateful resource (e.g. a PGlite instance // in `driverOptions`, whose `clone()` boots a second WASM database) — this sync // function cannot await it, so keep the instance by reference instead if (parent.clone.constructor.name === 'AsyncFunction') { return parent; } return parent.clone(); } let child; let proto; if (parent instanceof Map) { child = new Map(); } else if (parent instanceof Set) { child = new Set(); } else if (parent instanceof Promise) { child = new Promise((resolve, reject) => { parent.then(resolve.bind(null, _clone), reject.bind(null, _clone)); }); } else if (Array.isArray(parent)) { child = []; } else if (parent instanceof RegExp) { let flags = ''; if (parent.global) { flags += 'g'; } if (parent.ignoreCase) { flags += 'i'; } if (parent.multiline) { flags += 'm'; } child = new RegExp(parent.source, flags); if (parent.lastIndex) { child.lastIndex = parent.lastIndex; } } else if (parent instanceof Date) { child = new Date(parent.getTime()); } else if (Buffer.isBuffer(parent)) { child = Buffer.allocUnsafe(parent.length); parent.copy(child); return child; } else if (parent instanceof TypedArray) { child = parent.slice(); return child; } else if (parent instanceof Error) { child = new parent.constructor(parent.message); } else { proto = Object.getPrototypeOf(parent); child = Object.create(proto); } const index = allParents.indexOf(parent); if (index !== -1) { return allChildren[index]; } allParents.push(parent); allChildren.push(child); if (parent instanceof Map) { parent.forEach((value, key) => { const keyChild = _clone(key); const valueChild = _clone(value); child.set(keyChild, valueChild); }); } if (parent instanceof Set) { parent.forEach((value) => { const entryChild = _clone(value); child.add(entryChild); }); } for (const i in parent) { let attrs; if (proto) { attrs = getPropertyDescriptor(proto, i); } if (attrs && typeof attrs.get === 'function' && attrs.set == null) { continue; } child[i] = _clone(parent[i]); } const symbols = Object.getOwnPropertySymbols(parent); for (let i = 0; i < symbols.length; i++) { const symbol = symbols[i]; const descriptor = Object.getOwnPropertyDescriptor(parent, symbol); if (descriptor && !descriptor.enumerable) { Object.defineProperty(child, symbol, { ...descriptor, value: _clone(descriptor.value) }); continue; } child[symbol] = _clone(parent[symbol]); } return child; } return _clone(parent); }