mh-two-thousand-and-two
2024-03-25 b8c93990f3fa5e50a8aca16bdc9c2758168aa0fd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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> = T extends Builtin
  ? T
  : T extends Map<infer K, infer V>
  ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>
  : T extends ReadonlyMap<infer K, infer V>
  ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>
  : T extends WeakMap<infer K, infer V>
  ? WeakMap<DeepReadonly<K>, DeepReadonly<V>>
  : T extends Set<infer U>
  ? ReadonlySet<DeepReadonly<U>>
  : T extends ReadonlySet<infer U>
  ? ReadonlySet<DeepReadonly<U>>
  : T extends WeakSet<infer U>
  ? WeakSet<DeepReadonly<U>>
  : T extends Promise<infer U>
  ? Promise<DeepReadonly<U>>
  : T extends Ref<infer U>
  ? Readonly<Ref<DeepReadonly<U>>>
  : T extends {}
  ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
  : Readonly<T>
 
const rawToReadonlyFlag = `__v_rawToReadonly`
const rawToShallowReadonlyFlag = `__v_rawToShallowReadonly`
 
export function readonly<T extends object>(
  target: T
): DeepReadonly<UnwrapNestedRefs<T>> {
  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<T extends object>(target: T): Readonly<T> {
  return createReadonly(target, true)
}