| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- import { isObject, toRawType, def, hasOwn } from '@vue/shared'
- import {
- mutableHandlers,
- readonlyHandlers,
- shallowReactiveHandlers,
- shallowReadonlyHandlers
- } from './baseHandlers'
- import {
- mutableCollectionHandlers,
- readonlyCollectionHandlers,
- shallowCollectionHandlers
- } from './collectionHandlers'
- import { UnwrapRef, Ref } from './ref'
- export const enum ReactiveFlags {
- SKIP = '__v_skip',
- IS_REACTIVE = '__v_isReactive',
- IS_READONLY = '__v_isReadonly',
- RAW = '__v_raw',
- REACTIVE = '__v_reactive',
- READONLY = '__v_readonly'
- }
- export interface Target {
- [ReactiveFlags.SKIP]?: boolean
- [ReactiveFlags.IS_REACTIVE]?: boolean
- [ReactiveFlags.IS_READONLY]?: boolean
- [ReactiveFlags.RAW]?: any
- [ReactiveFlags.REACTIVE]?: any
- [ReactiveFlags.READONLY]?: any
- }
- const enum TargetType {
- INVALID = 0,
- COMMON = 1,
- COLLECTION = 2
- }
- function targetTypeMap(rawType: string) {
- switch (rawType) {
- case 'Object':
- case 'Array':
- return TargetType.COMMON
- case 'Map':
- case 'Set':
- case 'WeakMap':
- case 'WeakSet':
- return TargetType.COLLECTION
- default:
- return TargetType.INVALID
- }
- }
- function getTargetType(value: Target) {
- return value[ReactiveFlags.SKIP] || !Object.isExtensible(value)
- ? TargetType.INVALID
- : targetTypeMap(toRawType(value))
- }
- // only unwrap nested ref
- type UnwrapNestedRefs<T> = T extends Ref ? T : UnwrapRef<T>
- export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
- export function reactive(target: object) {
- // if trying to observe a readonly proxy, return the readonly version.
- if (target && (target as Target)[ReactiveFlags.IS_READONLY]) {
- return target
- }
- return createReactiveObject(
- target,
- false,
- mutableHandlers,
- mutableCollectionHandlers
- )
- }
- // Return a reactive-copy of the original object, where only the root level
- // properties are reactive, and does NOT unwrap refs nor recursively convert
- // returned properties.
- export function shallowReactive<T extends object>(target: T): T {
- return createReactiveObject(
- target,
- false,
- shallowReactiveHandlers,
- shallowCollectionHandlers
- )
- }
- 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 {}
- ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
- : Readonly<T>
- export function readonly<T extends object>(
- target: T
- ): DeepReadonly<UnwrapNestedRefs<T>> {
- return createReactiveObject(
- target,
- true,
- readonlyHandlers,
- readonlyCollectionHandlers
- )
- }
- // Return 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<{ [K in keyof T]: UnwrapNestedRefs<T[K]> }> {
- return createReactiveObject(
- target,
- true,
- shallowReadonlyHandlers,
- readonlyCollectionHandlers
- )
- }
- function createReactiveObject(
- target: Target,
- isReadonly: boolean,
- baseHandlers: ProxyHandler<any>,
- collectionHandlers: ProxyHandler<any>
- ) {
- if (!isObject(target)) {
- if (__DEV__) {
- console.warn(`value cannot be made reactive: ${String(target)}`)
- }
- return target
- }
- // target is already a Proxy, return it.
- // exception: calling readonly() on a reactive object
- if (
- target[ReactiveFlags.RAW] &&
- !(isReadonly && target[ReactiveFlags.IS_REACTIVE])
- ) {
- return target
- }
- // target already has corresponding Proxy
- const reactiveFlag = isReadonly
- ? ReactiveFlags.READONLY
- : ReactiveFlags.REACTIVE
- if (hasOwn(target, reactiveFlag)) {
- return target[reactiveFlag]
- }
- // only a whitelist of value types can be observed.
- const targetType = getTargetType(target)
- if (targetType === TargetType.INVALID) {
- return target
- }
- const observed = new Proxy(
- target,
- targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
- )
- def(target, reactiveFlag, observed)
- return observed
- }
- export function isReactive(value: unknown): boolean {
- if (isReadonly(value)) {
- return isReactive((value as Target)[ReactiveFlags.RAW])
- }
- return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE])
- }
- export function isReadonly(value: unknown): boolean {
- return !!(value && (value as Target)[ReactiveFlags.IS_READONLY])
- }
- export function isProxy(value: unknown): boolean {
- return isReactive(value) || isReadonly(value)
- }
- export function toRaw<T>(observed: T): T {
- return (
- (observed && toRaw((observed as Target)[ReactiveFlags.RAW])) || observed
- )
- }
- export function markRaw<T extends object>(value: T): T {
- def(value, ReactiveFlags.SKIP, true)
- return value
- }
|