import isArray from '../is-array.js'; import {isBuiltinWithMutableMethods} from '../is-builtin.js'; import isObject from '../is-object.js'; import CloneObject from './clone/clone-object.js'; import CloneArray from './clone/clone-array.js'; import CloneDate from './clone/clone-date.js'; import CloneSet from './clone/clone-set.js'; import CloneMap from './clone/clone-map.js'; import CloneWeakSet from './clone/clone-weakset.js'; import CloneWeakMap from './clone/clone-weakmap.js'; export default class SmartClone { constructor(hasOnValidate) { this._stack = []; this._hasOnValidate = hasOnValidate; } static isHandledType(value) { return isObject(value) || isArray(value) || isBuiltinWithMutableMethods(value); } static isHandledMethod(target, name) { if (isObject(target)) { return CloneObject.isHandledMethod(name); } if (isArray(target)) { return CloneArray.isHandledMethod(name); } if (target instanceof Set) { return CloneSet.isHandledMethod(name); } if (target instanceof Map) { return CloneMap.isHandledMethod(name); } return isBuiltinWithMutableMethods(target); } get isCloning() { return this._stack.length > 0; } start(value, path, argumentsList) { let CloneClass = CloneObject; if (isArray(value)) { CloneClass = CloneArray; } else if (value instanceof Date) { CloneClass = CloneDate; } else if (value instanceof Set) { CloneClass = CloneSet; } else if (value instanceof Map) { CloneClass = CloneMap; } else if (value instanceof WeakSet) { CloneClass = CloneWeakSet; } else if (value instanceof WeakMap) { CloneClass = CloneWeakMap; } this._stack.push(new CloneClass(value, path, argumentsList, this._hasOnValidate)); } update(fullPath, property, value) { this._stack.at(-1).update(fullPath, property, value); } preferredThisArg(target, thisArgument, thisProxyTarget) { const {name} = target; const isHandledMethod = SmartClone.isHandledMethod(thisProxyTarget, name); return this._stack.at(-1) .preferredThisArg(isHandledMethod, name, thisArgument, thisProxyTarget); } isChanged(isMutable, value, equals) { return this._stack.at(-1).isChanged(isMutable, value, equals); } isPartOfClone(changePath) { return this._stack.at(-1).isPathApplicable(changePath); } undo(object) { if (this._previousClone !== undefined) { this._previousClone.undo(object); } } stop() { this._previousClone = this._stack.pop(); return this._previousClone.clone; } }