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,18 +1,18 @@
import { import {
reactive, reactive,
immutable, readonly,
toRaw, toRaw,
isReactive, isReactive,
isImmutable, isReadonly,
markNonReactive, markNonReactive,
markImmutable, markReadonly,
lock, lock,
unlock, unlock,
effect, effect,
ref ref
} from '../src' } from '../src'
describe('reactivity/immutable', () => { describe('reactivity/readonly', () => {
let warn: any let warn: any
beforeEach(() => { beforeEach(() => {
@ -25,18 +25,18 @@ describe('reactivity/immutable', () => {
}) })
describe('Object', () => { describe('Object', () => {
it('should make nested values immutable', () => { it('should make nested values readonly', () => {
const original = { foo: 1, bar: { baz: 2 } } const original = { foo: 1, bar: { baz: 2 } }
const observed = immutable(original) const observed = readonly(original)
expect(observed).not.toBe(original) expect(observed).not.toBe(original)
expect(isReactive(observed)).toBe(true) expect(isReactive(observed)).toBe(true)
expect(isImmutable(observed)).toBe(true) expect(isReadonly(observed)).toBe(true)
expect(isReactive(original)).toBe(false) expect(isReactive(original)).toBe(false)
expect(isImmutable(original)).toBe(false) expect(isReadonly(original)).toBe(false)
expect(isReactive(observed.bar)).toBe(true) expect(isReactive(observed.bar)).toBe(true)
expect(isImmutable(observed.bar)).toBe(true) expect(isReadonly(observed.bar)).toBe(true)
expect(isReactive(original.bar)).toBe(false) expect(isReactive(original.bar)).toBe(false)
expect(isImmutable(original.bar)).toBe(false) expect(isReadonly(original.bar)).toBe(false)
// get // get
expect(observed.foo).toBe(1) expect(observed.foo).toBe(1)
// has // has
@ -46,7 +46,7 @@ describe('reactivity/immutable', () => {
}) })
it('should not allow mutation', () => { it('should not allow mutation', () => {
const observed: any = immutable({ foo: 1, bar: { baz: 2 } }) const observed: any = readonly({ foo: 1, bar: { baz: 2 } })
observed.foo = 2 observed.foo = 2
expect(observed.foo).toBe(1) expect(observed.foo).toBe(1)
expect(warn).toHaveBeenCalledTimes(1) expect(warn).toHaveBeenCalledTimes(1)
@ -62,7 +62,7 @@ describe('reactivity/immutable', () => {
}) })
it('should allow mutation when unlocked', () => { it('should allow mutation when unlocked', () => {
const observed: any = immutable({ foo: 1, bar: { baz: 2 } }) const observed: any = readonly({ foo: 1, bar: { baz: 2 } })
unlock() unlock()
observed.prop = 2 observed.prop = 2
observed.bar.qux = 3 observed.bar.qux = 3
@ -77,7 +77,7 @@ describe('reactivity/immutable', () => {
}) })
it('should not trigger effects when locked', () => { it('should not trigger effects when locked', () => {
const observed: any = immutable({ a: 1 }) const observed: any = readonly({ a: 1 })
let dummy let dummy
effect(() => { effect(() => {
dummy = observed.a dummy = observed.a
@ -89,7 +89,7 @@ describe('reactivity/immutable', () => {
}) })
it('should trigger effects when unlocked', () => { it('should trigger effects when unlocked', () => {
const observed: any = immutable({ a: 1 }) const observed: any = readonly({ a: 1 })
let dummy let dummy
effect(() => { effect(() => {
dummy = observed.a dummy = observed.a
@ -104,18 +104,18 @@ describe('reactivity/immutable', () => {
}) })
describe('Array', () => { describe('Array', () => {
it('should make nested values immutable', () => { it('should make nested values readonly', () => {
const original: any[] = [{ foo: 1 }] const original: any[] = [{ foo: 1 }]
const observed = immutable(original) const observed = readonly(original)
expect(observed).not.toBe(original) expect(observed).not.toBe(original)
expect(isReactive(observed)).toBe(true) expect(isReactive(observed)).toBe(true)
expect(isImmutable(observed)).toBe(true) expect(isReadonly(observed)).toBe(true)
expect(isReactive(original)).toBe(false) expect(isReactive(original)).toBe(false)
expect(isImmutable(original)).toBe(false) expect(isReadonly(original)).toBe(false)
expect(isReactive(observed[0])).toBe(true) expect(isReactive(observed[0])).toBe(true)
expect(isImmutable(observed[0])).toBe(true) expect(isReadonly(observed[0])).toBe(true)
expect(isReactive(original[0])).toBe(false) expect(isReactive(original[0])).toBe(false)
expect(isImmutable(original[0])).toBe(false) expect(isReadonly(original[0])).toBe(false)
// get // get
expect(observed[0].foo).toBe(1) expect(observed[0].foo).toBe(1)
// has // has
@ -125,7 +125,7 @@ describe('reactivity/immutable', () => {
}) })
it('should not allow mutation', () => { it('should not allow mutation', () => {
const observed: any = immutable([{ foo: 1 }]) const observed: any = readonly([{ foo: 1 }])
observed[0] = 1 observed[0] = 1
expect(observed[0]).not.toBe(1) expect(observed[0]).not.toBe(1)
expect(warn).toHaveBeenCalledTimes(1) expect(warn).toHaveBeenCalledTimes(1)
@ -147,7 +147,7 @@ describe('reactivity/immutable', () => {
}) })
it('should allow mutation when unlocked', () => { it('should allow mutation when unlocked', () => {
const observed: any = immutable([{ foo: 1, bar: { baz: 2 } }]) const observed: any = readonly([{ foo: 1, bar: { baz: 2 } }])
unlock() unlock()
observed[1] = 2 observed[1] = 2
observed.push(3) observed.push(3)
@ -163,7 +163,7 @@ describe('reactivity/immutable', () => {
}) })
it('should not trigger effects when locked', () => { it('should not trigger effects when locked', () => {
const observed: any = immutable([{ a: 1 }]) const observed: any = readonly([{ a: 1 }])
let dummy let dummy
effect(() => { effect(() => {
dummy = observed[0].a dummy = observed[0].a
@ -178,7 +178,7 @@ describe('reactivity/immutable', () => {
}) })
it('should trigger effects when unlocked', () => { it('should trigger effects when unlocked', () => {
const observed: any = immutable([{ a: 1 }]) const observed: any = readonly([{ a: 1 }])
let dummy let dummy
effect(() => { effect(() => {
dummy = observed[0].a dummy = observed[0].a
@ -205,24 +205,24 @@ describe('reactivity/immutable', () => {
const maps = [Map, WeakMap] const maps = [Map, WeakMap]
maps.forEach((Collection: any) => { maps.forEach((Collection: any) => {
describe(Collection.name, () => { describe(Collection.name, () => {
test('should make nested values immutable', () => { test('should make nested values readonly', () => {
const key1 = {} const key1 = {}
const key2 = {} const key2 = {}
const original = new Collection([[key1, {}], [key2, {}]]) const original = new Collection([[key1, {}], [key2, {}]])
const observed = immutable(original) const observed = readonly(original)
expect(observed).not.toBe(original) expect(observed).not.toBe(original)
expect(isReactive(observed)).toBe(true) expect(isReactive(observed)).toBe(true)
expect(isImmutable(observed)).toBe(true) expect(isReadonly(observed)).toBe(true)
expect(isReactive(original)).toBe(false) expect(isReactive(original)).toBe(false)
expect(isImmutable(original)).toBe(false) expect(isReadonly(original)).toBe(false)
expect(isReactive(observed.get(key1))).toBe(true) expect(isReactive(observed.get(key1))).toBe(true)
expect(isImmutable(observed.get(key1))).toBe(true) expect(isReadonly(observed.get(key1))).toBe(true)
expect(isReactive(original.get(key1))).toBe(false) expect(isReactive(original.get(key1))).toBe(false)
expect(isImmutable(original.get(key1))).toBe(false) expect(isReadonly(original.get(key1))).toBe(false)
}) })
test('should not allow mutation & not trigger effect', () => { test('should not allow mutation & not trigger effect', () => {
const map = immutable(new Collection()) const map = readonly(new Collection())
const key = {} const key = {}
let dummy let dummy
effect(() => { effect(() => {
@ -236,7 +236,7 @@ describe('reactivity/immutable', () => {
}) })
test('should allow mutation & trigger effect when unlocked', () => { test('should allow mutation & trigger effect when unlocked', () => {
const map = immutable(new Collection()) const map = readonly(new Collection())
const isWeak = Collection === WeakMap const isWeak = Collection === WeakMap
const key = {} const key = {}
let dummy let dummy
@ -253,20 +253,20 @@ describe('reactivity/immutable', () => {
}) })
if (Collection === Map) { if (Collection === Map) {
test('should retrive immutable values on iteration', () => { test('should retrive readonly values on iteration', () => {
const key1 = {} const key1 = {}
const key2 = {} const key2 = {}
const original = new Collection([[key1, {}], [key2, {}]]) const original = new Collection([[key1, {}], [key2, {}]])
const observed: any = immutable(original) const observed: any = readonly(original)
for (const [key, value] of observed) { for (const [key, value] of observed) {
expect(isImmutable(key)).toBe(true) expect(isReadonly(key)).toBe(true)
expect(isImmutable(value)).toBe(true) expect(isReadonly(value)).toBe(true)
} }
observed.forEach((value: any) => { observed.forEach((value: any) => {
expect(isImmutable(value)).toBe(true) expect(isReadonly(value)).toBe(true)
}) })
for (const value of observed.values()) { for (const value of observed.values()) {
expect(isImmutable(value)).toBe(true) expect(isReadonly(value)).toBe(true)
} }
}) })
} }
@ -276,22 +276,22 @@ describe('reactivity/immutable', () => {
const sets = [Set, WeakSet] const sets = [Set, WeakSet]
sets.forEach((Collection: any) => { sets.forEach((Collection: any) => {
describe(Collection.name, () => { describe(Collection.name, () => {
test('should make nested values immutable', () => { test('should make nested values readonly', () => {
const key1 = {} const key1 = {}
const key2 = {} const key2 = {}
const original = new Collection([key1, key2]) const original = new Collection([key1, key2])
const observed = immutable(original) const observed = readonly(original)
expect(observed).not.toBe(original) expect(observed).not.toBe(original)
expect(isReactive(observed)).toBe(true) expect(isReactive(observed)).toBe(true)
expect(isImmutable(observed)).toBe(true) expect(isReadonly(observed)).toBe(true)
expect(isReactive(original)).toBe(false) expect(isReactive(original)).toBe(false)
expect(isImmutable(original)).toBe(false) expect(isReadonly(original)).toBe(false)
expect(observed.has(reactive(key1))).toBe(true) expect(observed.has(reactive(key1))).toBe(true)
expect(original.has(reactive(key1))).toBe(false) expect(original.has(reactive(key1))).toBe(false)
}) })
test('should not allow mutation & not trigger effect', () => { test('should not allow mutation & not trigger effect', () => {
const set = immutable(new Collection()) const set = readonly(new Collection())
const key = {} const key = {}
let dummy let dummy
effect(() => { effect(() => {
@ -305,7 +305,7 @@ describe('reactivity/immutable', () => {
}) })
test('should allow mutation & trigger effect when unlocked', () => { test('should allow mutation & trigger effect when unlocked', () => {
const set = immutable(new Collection()) const set = readonly(new Collection())
const key = {} const key = {}
let dummy let dummy
effect(() => { effect(() => {
@ -321,59 +321,59 @@ describe('reactivity/immutable', () => {
}) })
if (Collection === Set) { if (Collection === Set) {
test('should retrive immutable values on iteration', () => { test('should retrive readonly values on iteration', () => {
const original = new Collection([{}, {}]) const original = new Collection([{}, {}])
const observed: any = immutable(original) const observed: any = readonly(original)
for (const value of observed) { for (const value of observed) {
expect(isImmutable(value)).toBe(true) expect(isReadonly(value)).toBe(true)
} }
observed.forEach((value: any) => { observed.forEach((value: any) => {
expect(isImmutable(value)).toBe(true) expect(isReadonly(value)).toBe(true)
}) })
for (const value of observed.values()) { for (const value of observed.values()) {
expect(isImmutable(value)).toBe(true) expect(isReadonly(value)).toBe(true)
} }
for (const [v1, v2] of observed.entries()) { for (const [v1, v2] of observed.entries()) {
expect(isImmutable(v1)).toBe(true) expect(isReadonly(v1)).toBe(true)
expect(isImmutable(v2)).toBe(true) expect(isReadonly(v2)).toBe(true)
} }
}) })
} }
}) })
}) })
test('calling reactive on an immutable should return immutable', () => { test('calling reactive on an readonly should return readonly', () => {
const a = immutable({}) const a = readonly({})
const b = reactive(a) const b = reactive(a)
expect(isImmutable(b)).toBe(true) expect(isReadonly(b)).toBe(true)
// should point to same original // should point to same original
expect(toRaw(a)).toBe(toRaw(b)) expect(toRaw(a)).toBe(toRaw(b))
}) })
test('calling immutable on a reactive object should return immutable', () => { test('calling readonly on a reactive object should return readonly', () => {
const a = reactive({}) const a = reactive({})
const b = immutable(a) const b = readonly(a)
expect(isImmutable(b)).toBe(true) expect(isReadonly(b)).toBe(true)
// should point to same original // should point to same original
expect(toRaw(a)).toBe(toRaw(b)) expect(toRaw(a)).toBe(toRaw(b))
}) })
test('observing already observed value should return same Proxy', () => { test('observing already observed value should return same Proxy', () => {
const original = { foo: 1 } const original = { foo: 1 }
const observed = immutable(original) const observed = readonly(original)
const observed2 = immutable(observed) const observed2 = readonly(observed)
expect(observed2).toBe(observed) expect(observed2).toBe(observed)
}) })
test('observing the same value multiple times should return same Proxy', () => { test('observing the same value multiple times should return same Proxy', () => {
const original = { foo: 1 } const original = { foo: 1 }
const observed = immutable(original) const observed = readonly(original)
const observed2 = immutable(original) const observed2 = readonly(original)
expect(observed2).toBe(observed) expect(observed2).toBe(observed)
}) })
test('markNonReactive', () => { test('markNonReactive', () => {
const obj = immutable({ const obj = readonly({
foo: { a: 1 }, foo: { a: 1 },
bar: markNonReactive({ b: 2 }) bar: markNonReactive({ b: 2 })
}) })
@ -381,19 +381,19 @@ describe('reactivity/immutable', () => {
expect(isReactive(obj.bar)).toBe(false) expect(isReactive(obj.bar)).toBe(false)
}) })
test('markImmutable', () => { test('markReadonly', () => {
const obj = reactive({ const obj = reactive({
foo: { a: 1 }, foo: { a: 1 },
bar: markImmutable({ b: 2 }) bar: markReadonly({ b: 2 })
}) })
expect(isReactive(obj.foo)).toBe(true) expect(isReactive(obj.foo)).toBe(true)
expect(isReactive(obj.bar)).toBe(true) expect(isReactive(obj.bar)).toBe(true)
expect(isImmutable(obj.foo)).toBe(false) expect(isReadonly(obj.foo)).toBe(false)
expect(isImmutable(obj.bar)).toBe(true) expect(isReadonly(obj.bar)).toBe(true)
}) })
test('should make ref immutable', () => { test('should make ref readonly', () => {
const n: any = immutable(ref(1)) const n: any = readonly(ref(1))
n.value = 2 n.value = 2
expect(n.value).toBe(1) expect(n.value).toBe(1)
expect(warn).toHaveBeenCalledTimes(1) expect(warn).toHaveBeenCalledTimes(1)

View File

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

View File

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

View File

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

View File

@ -4,10 +4,10 @@ export {
toRefs, toRefs,
reactive, reactive,
isReactive, isReactive,
immutable, readonly,
isImmutable, isReadonly,
toRaw, toRaw,
markImmutable, markReadonly,
markNonReactive, markNonReactive,
effect, effect,
// types // types

View File

@ -1,5 +1,5 @@
import { VNode, normalizeVNode, VNodeChild } from './vnode' import { VNode, normalizeVNode, VNodeChild } from './vnode'
import { ReactiveEffect, UnwrapRef, reactive, immutable } from '@vue/reactivity' import { ReactiveEffect, UnwrapRef, reactive, readonly } from '@vue/reactivity'
import { EMPTY_OBJ, isFunction, capitalize, invokeHandlers } from '@vue/shared' import { EMPTY_OBJ, isFunction, capitalize, invokeHandlers } from '@vue/shared'
import { RenderProxyHandlers } from './componentProxy' import { RenderProxyHandlers } from './componentProxy'
import { ComponentPropsOptions, ExtractPropTypes } from './componentProps' import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
@ -233,7 +233,7 @@ export function setupStatefulComponent(instance: ComponentInstance) {
// so props change can be tracked by watchers // so props change can be tracked by watchers
// it will be updated in resolveProps() on updates before render // it will be updated in resolveProps() on updates before render
const propsProxy = (instance.propsProxy = setup.length const propsProxy = (instance.propsProxy = setup.length
? immutable(instance.props) ? readonly(instance.props)
: null) : null)
const setupContext = (instance.setupContext = const setupContext = (instance.setupContext =
setup.length > 1 ? createSetupContext(instance) : null) setup.length > 1 ? createSetupContext(instance) : null)

View File

@ -1,4 +1,4 @@
import { immutable, toRaw, lock, unlock } from '@vue/reactivity' import { readonly, toRaw, lock, unlock } from '@vue/reactivity'
import { import {
EMPTY_OBJ, EMPTY_OBJ,
camelize, camelize,
@ -114,7 +114,7 @@ export function resolveProps(
props[key] = val props[key] = val
} }
// allow mutation of propsProxy (which is immutable by default) // allow mutation of propsProxy (which is readonly by default)
unlock() unlock()
if (rawProps != null) { if (rawProps != null) {
@ -179,13 +179,13 @@ export function resolveProps(
} }
} }
// lock immutable // lock readonly
lock() lock()
instance.props = __DEV__ ? immutable(props) : props instance.props = __DEV__ ? readonly(props) : props
instance.attrs = options instance.attrs = options
? __DEV__ ? __DEV__
? immutable(attrs) ? readonly(attrs)
: attrs : attrs
: instance.props : instance.props
} }