import { def, warn, isPlainObject, isArray } from 'core/util' import { isCollectionType, isReadonly, isShallow, ReactiveFlags, UnwrapNestedRefs } from './reactive' import { isRef, Ref, RefFlag } from './ref' type Primitive = string | number | boolean | bigint | symbol | undefined | null type Builtin = Primitive | Function | Date | Error | RegExp export type DeepReadonly = T extends Builtin ? T : T extends Map ? ReadonlyMap, DeepReadonly> : T extends ReadonlyMap ? ReadonlyMap, DeepReadonly> : T extends WeakMap ? WeakMap, DeepReadonly> : T extends Set ? ReadonlySet> : T extends ReadonlySet ? ReadonlySet> : T extends WeakSet ? WeakSet> : T extends Promise ? Promise> : T extends Ref ? Readonly>> : T extends {} ? { readonly [K in keyof T]: DeepReadonly } : Readonly const rawToReadonlyFlag = `__v_rawToReadonly` const rawToShallowReadonlyFlag = `__v_rawToShallowReadonly` export function readonly( target: T ): DeepReadonly> { return createReadonly(target, false) } function createReadonly(target: any, shallow: boolean) { if (!isPlainObject(target)) { if (__DEV__) { if (isArray(target)) { warn(`Vue 2 does not support readonly arrays.`) } else if (isCollectionType(target)) { warn( `Vue 2 does not support readonly collection types such as Map or Set.` ) } else { warn(`value cannot be made readonly: ${typeof target}`) } } return target as any } if (__DEV__ && !Object.isExtensible(target)) { warn( `Vue 2 does not support creating readonly proxy for non-extensible object.` ) } // already a readonly object if (isReadonly(target)) { return target as any } // already has a readonly proxy const existingFlag = shallow ? rawToShallowReadonlyFlag : rawToReadonlyFlag const existingProxy = target[existingFlag] if (existingProxy) { return existingProxy } const proxy = Object.create(Object.getPrototypeOf(target)) def(target, existingFlag, proxy) def(proxy, ReactiveFlags.IS_READONLY, true) def(proxy, ReactiveFlags.RAW, target) if (isRef(target)) { def(proxy, RefFlag, true) } if (shallow || isShallow(target)) { def(proxy, ReactiveFlags.IS_SHALLOW, true) } const keys = Object.keys(target) for (let i = 0; i < keys.length; i++) { defineReadonlyProperty(proxy, target, keys[i], shallow) } return proxy as any } function defineReadonlyProperty( proxy: any, target: any, key: string, shallow: boolean ) { Object.defineProperty(proxy, key, { enumerable: true, configurable: true, get() { const val = target[key] return shallow || !isPlainObject(val) ? val : readonly(val) }, set() { __DEV__ && warn(`Set operation on key "${key}" failed: target is readonly.`) } }) } /** * Returns a reactive-copy of the original object, where only the root level * properties are readonly, and does NOT unwrap refs nor recursively convert * returned properties. * This is used for creating the props proxy object for stateful components. */ export function shallowReadonly(target: T): Readonly { return createReadonly(target, true) }