2020-05-04 03:32:37 +08:00
|
|
|
import { isObject, toRawType, def, hasOwn } from '@vue/shared'
|
2019-11-07 01:51:06 +08:00
|
|
|
import {
|
|
|
|
mutableHandlers,
|
|
|
|
readonlyHandlers,
|
2020-04-15 11:49:46 +08:00
|
|
|
shallowReactiveHandlers,
|
|
|
|
shallowReadonlyHandlers
|
2019-11-07 01:51:06 +08:00
|
|
|
} from './baseHandlers'
|
2019-06-12 00:03:50 +08:00
|
|
|
import {
|
|
|
|
mutableCollectionHandlers,
|
2019-08-23 21:38:32 +08:00
|
|
|
readonlyCollectionHandlers
|
2019-06-12 00:03:50 +08:00
|
|
|
} from './collectionHandlers'
|
2020-04-15 10:18:58 +08:00
|
|
|
import { UnwrapRef, Ref } from './ref'
|
2019-10-19 00:11:58 +08:00
|
|
|
import { makeMap } from '@vue/shared'
|
2018-09-19 23:35:38 +08:00
|
|
|
|
2020-05-03 04:16:51 +08:00
|
|
|
export const enum ReactiveFlags {
|
|
|
|
skip = '__v_skip',
|
|
|
|
isReactive = '__v_isReactive',
|
|
|
|
isReadonly = '__v_isReadonly',
|
|
|
|
raw = '__v_raw',
|
|
|
|
reactive = '__v_reactive',
|
|
|
|
readonly = '__v_readonly'
|
|
|
|
}
|
|
|
|
|
|
|
|
interface Target {
|
|
|
|
__v_skip?: boolean
|
|
|
|
__v_isReactive?: boolean
|
|
|
|
__v_isReadonly?: boolean
|
|
|
|
__v_raw?: any
|
|
|
|
__v_reactive?: any
|
|
|
|
__v_readonly?: any
|
|
|
|
}
|
2019-06-12 00:03:50 +08:00
|
|
|
|
2019-10-06 23:22:32 +08:00
|
|
|
const collectionTypes = new Set<Function>([Set, Map, WeakMap, WeakSet])
|
2019-10-19 00:11:58 +08:00
|
|
|
const isObservableType = /*#__PURE__*/ makeMap(
|
2019-10-25 23:15:04 +08:00
|
|
|
'Object,Array,Map,Set,WeakMap,WeakSet'
|
2019-10-19 00:11:58 +08:00
|
|
|
)
|
2019-06-12 00:03:50 +08:00
|
|
|
|
2020-05-03 04:16:51 +08:00
|
|
|
const canObserve = (value: Target): boolean => {
|
2019-06-12 00:03:50 +08:00
|
|
|
return (
|
2020-05-03 04:16:51 +08:00
|
|
|
!value.__v_skip &&
|
2019-10-25 23:15:04 +08:00
|
|
|
isObservableType(toRawType(value)) &&
|
2020-03-23 23:28:20 +08:00
|
|
|
!Object.isFrozen(value)
|
2019-06-12 00:03:50 +08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-10-14 23:21:09 +08:00
|
|
|
// only unwrap nested ref
|
|
|
|
type UnwrapNestedRefs<T> = T extends Ref ? T : UnwrapRef<T>
|
|
|
|
|
2019-08-22 00:01:05 +08:00
|
|
|
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
|
|
|
|
export function reactive(target: object) {
|
2019-08-23 21:38:32 +08:00
|
|
|
// if trying to observe a readonly proxy, return the readonly version.
|
2020-05-03 04:16:51 +08:00
|
|
|
if (target && (target as Target).__v_isReadonly) {
|
2019-06-12 00:03:50 +08:00
|
|
|
return target
|
|
|
|
}
|
2019-08-20 21:58:10 +08:00
|
|
|
return createReactiveObject(
|
2019-06-12 00:03:50 +08:00
|
|
|
target,
|
2020-05-03 04:16:51 +08:00
|
|
|
false,
|
2019-06-12 00:03:50 +08:00
|
|
|
mutableHandlers,
|
|
|
|
mutableCollectionHandlers
|
|
|
|
)
|
2019-08-22 00:01:05 +08:00
|
|
|
}
|
2019-06-12 00:03:50 +08:00
|
|
|
|
2020-04-15 11:49:46 +08:00
|
|
|
// 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,
|
2020-05-03 04:16:51 +08:00
|
|
|
false,
|
2020-04-15 11:49:46 +08:00
|
|
|
shallowReactiveHandlers,
|
|
|
|
mutableCollectionHandlers
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-08-23 21:38:32 +08:00
|
|
|
export function readonly<T extends object>(
|
2019-08-22 00:01:05 +08:00
|
|
|
target: T
|
2019-10-10 02:01:53 +08:00
|
|
|
): Readonly<UnwrapNestedRefs<T>> {
|
2019-08-20 21:58:10 +08:00
|
|
|
return createReactiveObject(
|
2019-06-12 00:03:50 +08:00
|
|
|
target,
|
2020-05-03 04:16:51 +08:00
|
|
|
true,
|
2019-08-23 21:38:32 +08:00
|
|
|
readonlyHandlers,
|
|
|
|
readonlyCollectionHandlers
|
2019-06-12 00:03:50 +08:00
|
|
|
)
|
2019-08-22 00:01:05 +08:00
|
|
|
}
|
2019-06-12 00:03:50 +08:00
|
|
|
|
2019-12-03 03:11:12 +08:00
|
|
|
// Return a reactive-copy of the original object, where only the root level
|
2020-01-28 04:15:13 +08:00
|
|
|
// properties are readonly, and does NOT unwrap refs nor recursively convert
|
|
|
|
// returned properties.
|
2019-12-03 03:11:12 +08:00
|
|
|
// This is used for creating the props proxy object for stateful components.
|
|
|
|
export function shallowReadonly<T extends object>(
|
2019-11-07 01:51:06 +08:00
|
|
|
target: T
|
|
|
|
): Readonly<{ [K in keyof T]: UnwrapNestedRefs<T[K]> }> {
|
|
|
|
return createReactiveObject(
|
|
|
|
target,
|
2020-05-03 04:16:51 +08:00
|
|
|
true,
|
2019-12-03 03:11:12 +08:00
|
|
|
shallowReadonlyHandlers,
|
2019-11-07 01:51:06 +08:00
|
|
|
readonlyCollectionHandlers
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-08-20 21:58:10 +08:00
|
|
|
function createReactiveObject(
|
2020-05-03 04:16:51 +08:00
|
|
|
target: Target,
|
|
|
|
isReadonly: boolean,
|
2019-06-12 00:03:50 +08:00
|
|
|
baseHandlers: ProxyHandler<any>,
|
|
|
|
collectionHandlers: ProxyHandler<any>
|
|
|
|
) {
|
|
|
|
if (!isObject(target)) {
|
|
|
|
if (__DEV__) {
|
2019-08-20 21:58:10 +08:00
|
|
|
console.warn(`value cannot be made reactive: ${String(target)}`)
|
2019-06-12 00:03:50 +08:00
|
|
|
}
|
|
|
|
return target
|
|
|
|
}
|
2020-05-03 04:16:51 +08:00
|
|
|
// target is already a Proxy, return it.
|
|
|
|
// excpetion: calling readonly() on a reactive object
|
|
|
|
if (target.__v_raw && !(isReadonly && target.__v_isReactive)) {
|
|
|
|
return target
|
|
|
|
}
|
2019-06-12 00:03:50 +08:00
|
|
|
// target already has corresponding Proxy
|
2020-05-04 03:32:37 +08:00
|
|
|
if (
|
|
|
|
hasOwn(target, isReadonly ? ReactiveFlags.readonly : ReactiveFlags.reactive)
|
|
|
|
) {
|
|
|
|
return isReadonly ? target.__v_readonly : target.__v_reactive
|
2019-06-12 00:03:50 +08:00
|
|
|
}
|
|
|
|
// only a whitelist of value types can be observed.
|
|
|
|
if (!canObserve(target)) {
|
|
|
|
return target
|
|
|
|
}
|
2020-05-04 03:32:37 +08:00
|
|
|
const observed = new Proxy(
|
|
|
|
target,
|
|
|
|
collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers
|
|
|
|
)
|
2020-05-03 04:16:51 +08:00
|
|
|
def(
|
|
|
|
target,
|
|
|
|
isReadonly ? ReactiveFlags.readonly : ReactiveFlags.reactive,
|
|
|
|
observed
|
|
|
|
)
|
2019-06-12 00:03:50 +08:00
|
|
|
return observed
|
|
|
|
}
|
|
|
|
|
2019-10-22 23:26:48 +08:00
|
|
|
export function isReactive(value: unknown): boolean {
|
2020-05-03 04:16:51 +08:00
|
|
|
if (isReadonly(value)) {
|
|
|
|
return isReactive((value as Target).__v_raw)
|
|
|
|
}
|
|
|
|
return !!(value && (value as Target).__v_isReactive)
|
2019-06-12 00:03:50 +08:00
|
|
|
}
|
|
|
|
|
2019-10-22 23:26:48 +08:00
|
|
|
export function isReadonly(value: unknown): boolean {
|
2020-05-03 04:16:51 +08:00
|
|
|
return !!(value && (value as Target).__v_isReadonly)
|
2019-06-12 00:03:50 +08:00
|
|
|
}
|
|
|
|
|
2020-04-16 04:45:20 +08:00
|
|
|
export function isProxy(value: unknown): boolean {
|
2020-05-03 04:16:51 +08:00
|
|
|
return isReactive(value) || isReadonly(value)
|
2020-04-16 04:45:20 +08:00
|
|
|
}
|
|
|
|
|
2019-06-12 00:03:50 +08:00
|
|
|
export function toRaw<T>(observed: T): T {
|
2020-05-03 04:16:51 +08:00
|
|
|
return (observed && toRaw((observed as Target).__v_raw)) || observed
|
2019-06-12 00:03:50 +08:00
|
|
|
}
|
|
|
|
|
2020-04-16 04:45:20 +08:00
|
|
|
export function markRaw<T extends object>(value: T): T {
|
2020-05-03 04:16:51 +08:00
|
|
|
def(value, ReactiveFlags.skip, true)
|
2019-06-12 00:03:50 +08:00
|
|
|
return value
|
|
|
|
}
|