refactor: immutable -> readonly

This commit is contained in:
Evan You
2019-08-23 09:38:32 -04:00
parent e1bbfbba94
commit 589d3c2feb
8 changed files with 137 additions and 137 deletions

View File

@@ -1,4 +1,4 @@
import { reactive, immutable, toRaw } from './reactive'
import { reactive, readonly, toRaw } from './reactive'
import { OperationTypes } from './operations'
import { track, trigger } from './effect'
import { LOCKED } from './lock'
@@ -13,7 +13,7 @@ const builtInSymbols = new Set(
.filter(value => typeof value === 'symbol')
)
function createGetter(isImmutable: boolean) {
function createGetter(isReadonly: boolean) {
return function get(target: any, key: string | symbol, receiver: any) {
const res = Reflect.get(target, key, receiver)
if (typeof key === 'symbol' && builtInSymbols.has(key)) {
@@ -24,10 +24,10 @@ function createGetter(isImmutable: boolean) {
}
track(target, OperationTypes.GET, key)
return isObject(res)
? isImmutable
? // need to lazy access immutable and reactive here to avoid
? isReadonly
? // need to lazy access readonly and reactive here to avoid
// circular dependency
immutable(res)
readonly(res)
: reactive(res)
: res
}
@@ -102,14 +102,14 @@ export const mutableHandlers: ProxyHandler<any> = {
ownKeys
}
export const immutableHandlers: ProxyHandler<any> = {
export const readonlyHandlers: ProxyHandler<any> = {
get: createGetter(true),
set(target: any, key: string | symbol, value: any, receiver: any): boolean {
if (LOCKED) {
if (__DEV__) {
console.warn(
`Set operation on key "${key as any}" failed: target is immutable.`,
`Set operation on key "${key as any}" failed: target is readonly.`,
target
)
}
@@ -123,7 +123,7 @@ export const immutableHandlers: ProxyHandler<any> = {
if (LOCKED) {
if (__DEV__) {
console.warn(
`Delete operation on key "${key as any}" failed: target is immutable.`,
`Delete operation on key "${key as any}" failed: target is readonly.`,
target
)
}

View File

@@ -1,11 +1,11 @@
import { toRaw, reactive, immutable } from './reactive'
import { toRaw, reactive, readonly } from './reactive'
import { track, trigger } from './effect'
import { OperationTypes } from './operations'
import { LOCKED } from './lock'
import { isObject } from '@vue/shared'
const toReactive = (value: any) => (isObject(value) ? reactive(value) : value)
const toImmutable = (value: any) => (isObject(value) ? immutable(value) : value)
const toReadonly = (value: any) => (isObject(value) ? readonly(value) : value)
function get(target: any, key: any, wrap: (t: any) => any): any {
target = toRaw(target)
@@ -111,16 +111,16 @@ function clear() {
return result
}
function createForEach(isImmutable: boolean) {
function createForEach(isReadonly: boolean) {
return function forEach(callback: Function, thisArg?: any) {
const observed = this
const target = toRaw(observed)
const proto: any = Reflect.getPrototypeOf(target)
const wrap = isImmutable ? toImmutable : toReactive
const wrap = isReadonly ? toReadonly : toReactive
track(target, OperationTypes.ITERATE)
// important: create sure the callback is
// 1. invoked with the observable map as `this` and 3rd arg
// 2. the value received should be a corresponding observable/immutable.
// 1. invoked with the reactive map as `this` and 3rd arg
// 2. the value received should be a corresponding reactive/readonly.
function wrappedCallback(value: any, key: any) {
return callback.call(observed, wrap(value), wrap(key), observed)
}
@@ -128,7 +128,7 @@ function createForEach(isImmutable: boolean) {
}
}
function createIterableMethod(method: string | symbol, isImmutable: boolean) {
function createIterableMethod(method: string | symbol, isReadonly: boolean) {
return function(...args: any[]) {
const target = toRaw(this)
const proto: any = Reflect.getPrototypeOf(target)
@@ -136,7 +136,7 @@ function createIterableMethod(method: string | symbol, isImmutable: boolean) {
method === 'entries' ||
(method === Symbol.iterator && target instanceof Map)
const innerIterator = proto[method].apply(target, args)
const wrap = isImmutable ? toImmutable : toReactive
const wrap = isReadonly ? toReadonly : toReactive
track(target, OperationTypes.ITERATE)
// return a wrapped iterator which returns observed versions of the
// values emitted from the real iterator
@@ -159,7 +159,7 @@ function createIterableMethod(method: string | symbol, isImmutable: boolean) {
}
}
function createImmutableMethod(
function createReadonlyMethod(
method: Function,
type: OperationTypes
): Function {
@@ -168,7 +168,7 @@ function createImmutableMethod(
if (__DEV__) {
const key = args[0] ? `on key "${args[0]}"` : ``
console.warn(
`${type} operation ${key}failed: target is immutable.`,
`${type} operation ${key}failed: target is readonly.`,
toRaw(this)
)
}
@@ -194,25 +194,25 @@ const mutableInstrumentations: any = {
forEach: createForEach(false)
}
const immutableInstrumentations: any = {
const readonlyInstrumentations: any = {
get(key: any) {
return get(this, key, toImmutable)
return get(this, key, toReadonly)
},
get size() {
return size(this)
},
has,
add: createImmutableMethod(add, OperationTypes.ADD),
set: createImmutableMethod(set, OperationTypes.SET),
delete: createImmutableMethod(deleteEntry, OperationTypes.DELETE),
clear: createImmutableMethod(clear, OperationTypes.CLEAR),
add: createReadonlyMethod(add, OperationTypes.ADD),
set: createReadonlyMethod(set, OperationTypes.SET),
delete: createReadonlyMethod(deleteEntry, OperationTypes.DELETE),
clear: createReadonlyMethod(clear, OperationTypes.CLEAR),
forEach: createForEach(true)
}
const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]
iteratorMethods.forEach(method => {
mutableInstrumentations[method] = createIterableMethod(method, false)
immutableInstrumentations[method] = createIterableMethod(method, true)
readonlyInstrumentations[method] = createIterableMethod(method, true)
})
function createInstrumentationGetter(instrumentations: any) {
@@ -233,6 +233,6 @@ export const mutableCollectionHandlers: ProxyHandler<any> = {
get: createInstrumentationGetter(mutableInstrumentations)
}
export const immutableCollectionHandlers: ProxyHandler<any> = {
get: createInstrumentationGetter(immutableInstrumentations)
export const readonlyCollectionHandlers: ProxyHandler<any> = {
get: createInstrumentationGetter(readonlyInstrumentations)
}

View File

@@ -2,10 +2,10 @@ export { ref, isRef, toRefs, Ref, UnwrapRef } from './ref'
export {
reactive,
isReactive,
immutable,
isImmutable,
readonly,
isReadonly,
toRaw,
markImmutable,
markReadonly,
markNonReactive
} from './reactive'
export { computed, ComputedRef, ComputedOptions } from './computed'

View File

@@ -1,9 +1,9 @@
import { isObject } from '@vue/shared'
import { mutableHandlers, immutableHandlers } from './baseHandlers'
import { mutableHandlers, readonlyHandlers } from './baseHandlers'
import {
mutableCollectionHandlers,
immutableCollectionHandlers
readonlyCollectionHandlers
} from './collectionHandlers'
import { UnwrapNestedRefs } from './ref'
@@ -18,14 +18,14 @@ export type KeyToDepMap = Map<string | symbol, Dep>
export const targetMap: WeakMap<any, KeyToDepMap> = new WeakMap()
// WeakMaps that store {raw <-> observed} pairs.
const rawToObserved: WeakMap<any, any> = new WeakMap()
const observedToRaw: WeakMap<any, any> = new WeakMap()
const rawToImmutable: WeakMap<any, any> = new WeakMap()
const immutableToRaw: WeakMap<any, any> = new WeakMap()
const rawToReactive: WeakMap<any, any> = new WeakMap()
const reactiveToRaw: WeakMap<any, any> = new WeakMap()
const rawToReadonly: WeakMap<any, any> = new WeakMap()
const readonlyToRaw: WeakMap<any, any> = new WeakMap()
// WeakSets for values that are marked immutable or non-reactive during
// WeakSets for values that are marked readonly or non-reactive during
// observable creation.
const immutableValues: WeakSet<any> = new WeakSet()
const readonlyValues: WeakSet<any> = new WeakSet()
const nonReactiveValues: WeakSet<any> = new WeakSet()
const collectionTypes: Set<any> = new Set([Set, Map, WeakMap, WeakSet])
@@ -42,38 +42,38 @@ const canObserve = (value: any): boolean => {
export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
export function reactive(target: object) {
// if trying to observe an immutable proxy, return the immutable version.
if (immutableToRaw.has(target)) {
// if trying to observe a readonly proxy, return the readonly version.
if (readonlyToRaw.has(target)) {
return target
}
// target is explicitly marked as immutable by user
if (immutableValues.has(target)) {
return immutable(target)
// target is explicitly marked as readonly by user
if (readonlyValues.has(target)) {
return readonly(target)
}
return createReactiveObject(
target,
rawToObserved,
observedToRaw,
rawToReactive,
reactiveToRaw,
mutableHandlers,
mutableCollectionHandlers
)
}
export function immutable<T extends object>(
export function readonly<T extends object>(
target: T
): Readonly<UnwrapNestedRefs<T>>
export function immutable(target: object) {
export function readonly(target: object) {
// value is a mutable observable, retrive its original and return
// a readonly version.
if (observedToRaw.has(target)) {
target = observedToRaw.get(target)
if (reactiveToRaw.has(target)) {
target = reactiveToRaw.get(target)
}
return createReactiveObject(
target,
rawToImmutable,
immutableToRaw,
immutableHandlers,
immutableCollectionHandlers
rawToReadonly,
readonlyToRaw,
readonlyHandlers,
readonlyCollectionHandlers
)
}
@@ -116,19 +116,19 @@ function createReactiveObject(
}
export function isReactive(value: any): boolean {
return observedToRaw.has(value) || immutableToRaw.has(value)
return reactiveToRaw.has(value) || readonlyToRaw.has(value)
}
export function isImmutable(value: any): boolean {
return immutableToRaw.has(value)
export function isReadonly(value: any): boolean {
return readonlyToRaw.has(value)
}
export function toRaw<T>(observed: T): T {
return observedToRaw.get(observed) || immutableToRaw.get(observed) || observed
return reactiveToRaw.get(observed) || readonlyToRaw.get(observed) || observed
}
export function markImmutable<T>(value: T): T {
immutableValues.add(value)
export function markReadonly<T>(value: T): T {
readonlyValues.add(value)
return value
}