1/* 2 * Copyright (c) 2022-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { getObservableTarget } from "./observable" 17 18/* 19 When decorating variables of complex types, 20 @Prop makes a deep copy, during which all types, 21 except primitive types, Map, Set, Date, and Array, will be lost. 22 */ 23 24export function propDeepCopy<T>(sourceObject: T): T { 25 if (!sourceObject || typeof sourceObject !== 'object') { 26 return sourceObject 27 } 28 29 const copiedObjects = new Map<Object, Object>() 30 return recursiveDeepCopy(sourceObject) as T 31 32 function recursiveDeepCopy(sourceObject: Object): Object { 33 if (!sourceObject || typeof sourceObject !== 'object') { 34 return sourceObject 35 } 36 37 const storedObject = copiedObjects.get(sourceObject) 38 if (storedObject !== undefined) { 39 return storedObject 40 } 41 42 const copy: any = copyDeepTrackable(sourceObject) 43 44 const objectToCopyFrom = getObservableTarget(sourceObject) 45 Object.keys(objectToCopyFrom) 46 .forEach((key) => { 47 const property = objectToCopyFrom[key as keyof Object] 48 49 if (typeof property === "function") { 50 Reflect.set(copy, key, property) 51 copy[key] = copy[key].bind(copy) 52 return 53 } 54 Reflect.set(copy, key, recursiveDeepCopy(property)); 55 }) 56 57 return copy 58 } 59 60 function copyDeepTrackable<T>(sourceObject: T): T { 61 if (sourceObject instanceof Set) { 62 const copy = new Set<any>() 63 Object.setPrototypeOf(copy, Object.getPrototypeOf(sourceObject)) 64 copiedObjects.set(sourceObject, copy) 65 for (const setKey of sourceObject.keys()) { 66 copy.add(recursiveDeepCopy(setKey)) 67 } 68 return copy as T 69 } 70 if (sourceObject instanceof Map) { 71 const copy = new Map<any, any>() 72 Object.setPrototypeOf(copy, Object.getPrototypeOf(sourceObject)) 73 copiedObjects.set(sourceObject, copy) 74 for (const mapKey of sourceObject.keys()) { 75 copy.set(mapKey, recursiveDeepCopy(sourceObject.get(mapKey))) 76 } 77 return copy as T 78 } 79 if (sourceObject instanceof Date) { 80 const copy = new Date() 81 copy.setTime(sourceObject.getTime()) 82 Object.setPrototypeOf(copy, Object.getPrototypeOf(sourceObject)) 83 copiedObjects.set(sourceObject, copy) 84 return copy as T 85 } 86 if (sourceObject instanceof Object) { 87 const copy = Array.isArray(sourceObject) ? [] : {} 88 Object.setPrototypeOf(copy, Object.getPrototypeOf(sourceObject)) 89 copiedObjects.set(sourceObject, copy) 90 return copy as T 91 } 92 93 return sourceObject 94 } 95} 96