import {
reactive,
- immutable,
+ readonly,
toRaw,
isReactive,
- isImmutable,
+ isReadonly,
markNonReactive,
- markImmutable,
+ markReadonly,
lock,
unlock,
effect,
ref
} from '../src'
-describe('reactivity/immutable', () => {
+describe('reactivity/readonly', () => {
let warn: any
beforeEach(() => {
})
describe('Object', () => {
- it('should make nested values immutable', () => {
+ it('should make nested values readonly', () => {
const original = { foo: 1, bar: { baz: 2 } }
- const observed = immutable(original)
+ const observed = readonly(original)
expect(observed).not.toBe(original)
expect(isReactive(observed)).toBe(true)
- expect(isImmutable(observed)).toBe(true)
+ expect(isReadonly(observed)).toBe(true)
expect(isReactive(original)).toBe(false)
- expect(isImmutable(original)).toBe(false)
+ expect(isReadonly(original)).toBe(false)
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(isImmutable(original.bar)).toBe(false)
+ expect(isReadonly(original.bar)).toBe(false)
// get
expect(observed.foo).toBe(1)
// has
})
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
expect(observed.foo).toBe(1)
expect(warn).toHaveBeenCalledTimes(1)
})
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()
observed.prop = 2
observed.bar.qux = 3
})
it('should not trigger effects when locked', () => {
- const observed: any = immutable({ a: 1 })
+ const observed: any = readonly({ a: 1 })
let dummy
effect(() => {
dummy = observed.a
})
it('should trigger effects when unlocked', () => {
- const observed: any = immutable({ a: 1 })
+ const observed: any = readonly({ a: 1 })
let dummy
effect(() => {
dummy = observed.a
})
describe('Array', () => {
- it('should make nested values immutable', () => {
+ it('should make nested values readonly', () => {
const original: any[] = [{ foo: 1 }]
- const observed = immutable(original)
+ const observed = readonly(original)
expect(observed).not.toBe(original)
expect(isReactive(observed)).toBe(true)
- expect(isImmutable(observed)).toBe(true)
+ expect(isReadonly(observed)).toBe(true)
expect(isReactive(original)).toBe(false)
- expect(isImmutable(original)).toBe(false)
+ expect(isReadonly(original)).toBe(false)
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(isImmutable(original[0])).toBe(false)
+ expect(isReadonly(original[0])).toBe(false)
// get
expect(observed[0].foo).toBe(1)
// has
})
it('should not allow mutation', () => {
- const observed: any = immutable([{ foo: 1 }])
+ const observed: any = readonly([{ foo: 1 }])
observed[0] = 1
expect(observed[0]).not.toBe(1)
expect(warn).toHaveBeenCalledTimes(1)
})
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()
observed[1] = 2
observed.push(3)
})
it('should not trigger effects when locked', () => {
- const observed: any = immutable([{ a: 1 }])
+ const observed: any = readonly([{ a: 1 }])
let dummy
effect(() => {
dummy = observed[0].a
})
it('should trigger effects when unlocked', () => {
- const observed: any = immutable([{ a: 1 }])
+ const observed: any = readonly([{ a: 1 }])
let dummy
effect(() => {
dummy = observed[0].a
const maps = [Map, WeakMap]
maps.forEach((Collection: any) => {
describe(Collection.name, () => {
- test('should make nested values immutable', () => {
+ test('should make nested values readonly', () => {
const key1 = {}
const key2 = {}
const original = new Collection([[key1, {}], [key2, {}]])
- const observed = immutable(original)
+ const observed = readonly(original)
expect(observed).not.toBe(original)
expect(isReactive(observed)).toBe(true)
- expect(isImmutable(observed)).toBe(true)
+ expect(isReadonly(observed)).toBe(true)
expect(isReactive(original)).toBe(false)
- expect(isImmutable(original)).toBe(false)
+ expect(isReadonly(original)).toBe(false)
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(isImmutable(original.get(key1))).toBe(false)
+ expect(isReadonly(original.get(key1))).toBe(false)
})
test('should not allow mutation & not trigger effect', () => {
- const map = immutable(new Collection())
+ const map = readonly(new Collection())
const key = {}
let dummy
effect(() => {
})
test('should allow mutation & trigger effect when unlocked', () => {
- const map = immutable(new Collection())
+ const map = readonly(new Collection())
const isWeak = Collection === WeakMap
const key = {}
let dummy
})
if (Collection === Map) {
- test('should retrive immutable values on iteration', () => {
+ test('should retrive readonly values on iteration', () => {
const key1 = {}
const key2 = {}
const original = new Collection([[key1, {}], [key2, {}]])
- const observed: any = immutable(original)
+ const observed: any = readonly(original)
for (const [key, value] of observed) {
- expect(isImmutable(key)).toBe(true)
- expect(isImmutable(value)).toBe(true)
+ expect(isReadonly(key)).toBe(true)
+ expect(isReadonly(value)).toBe(true)
}
observed.forEach((value: any) => {
- expect(isImmutable(value)).toBe(true)
+ expect(isReadonly(value)).toBe(true)
})
for (const value of observed.values()) {
- expect(isImmutable(value)).toBe(true)
+ expect(isReadonly(value)).toBe(true)
}
})
}
const sets = [Set, WeakSet]
sets.forEach((Collection: any) => {
describe(Collection.name, () => {
- test('should make nested values immutable', () => {
+ test('should make nested values readonly', () => {
const key1 = {}
const key2 = {}
const original = new Collection([key1, key2])
- const observed = immutable(original)
+ const observed = readonly(original)
expect(observed).not.toBe(original)
expect(isReactive(observed)).toBe(true)
- expect(isImmutable(observed)).toBe(true)
+ expect(isReadonly(observed)).toBe(true)
expect(isReactive(original)).toBe(false)
- expect(isImmutable(original)).toBe(false)
+ expect(isReadonly(original)).toBe(false)
expect(observed.has(reactive(key1))).toBe(true)
expect(original.has(reactive(key1))).toBe(false)
})
test('should not allow mutation & not trigger effect', () => {
- const set = immutable(new Collection())
+ const set = readonly(new Collection())
const key = {}
let dummy
effect(() => {
})
test('should allow mutation & trigger effect when unlocked', () => {
- const set = immutable(new Collection())
+ const set = readonly(new Collection())
const key = {}
let dummy
effect(() => {
})
if (Collection === Set) {
- test('should retrive immutable values on iteration', () => {
+ test('should retrive readonly values on iteration', () => {
const original = new Collection([{}, {}])
- const observed: any = immutable(original)
+ const observed: any = readonly(original)
for (const value of observed) {
- expect(isImmutable(value)).toBe(true)
+ expect(isReadonly(value)).toBe(true)
}
observed.forEach((value: any) => {
- expect(isImmutable(value)).toBe(true)
+ expect(isReadonly(value)).toBe(true)
})
for (const value of observed.values()) {
- expect(isImmutable(value)).toBe(true)
+ expect(isReadonly(value)).toBe(true)
}
for (const [v1, v2] of observed.entries()) {
- expect(isImmutable(v1)).toBe(true)
- expect(isImmutable(v2)).toBe(true)
+ expect(isReadonly(v1)).toBe(true)
+ expect(isReadonly(v2)).toBe(true)
}
})
}
})
})
- test('calling reactive on an immutable should return immutable', () => {
- const a = immutable({})
+ test('calling reactive on an readonly should return readonly', () => {
+ const a = readonly({})
const b = reactive(a)
- expect(isImmutable(b)).toBe(true)
+ expect(isReadonly(b)).toBe(true)
// should point to same original
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 b = immutable(a)
- expect(isImmutable(b)).toBe(true)
+ const b = readonly(a)
+ expect(isReadonly(b)).toBe(true)
// should point to same original
expect(toRaw(a)).toBe(toRaw(b))
})
test('observing already observed value should return same Proxy', () => {
const original = { foo: 1 }
- const observed = immutable(original)
- const observed2 = immutable(observed)
+ const observed = readonly(original)
+ const observed2 = readonly(observed)
expect(observed2).toBe(observed)
})
test('observing the same value multiple times should return same Proxy', () => {
const original = { foo: 1 }
- const observed = immutable(original)
- const observed2 = immutable(original)
+ const observed = readonly(original)
+ const observed2 = readonly(original)
expect(observed2).toBe(observed)
})
test('markNonReactive', () => {
- const obj = immutable({
+ const obj = readonly({
foo: { a: 1 },
bar: markNonReactive({ b: 2 })
})
expect(isReactive(obj.bar)).toBe(false)
})
- test('markImmutable', () => {
+ test('markReadonly', () => {
const obj = reactive({
foo: { a: 1 },
- bar: markImmutable({ b: 2 })
+ bar: markReadonly({ b: 2 })
})
expect(isReactive(obj.foo)).toBe(true)
expect(isReactive(obj.bar)).toBe(true)
- expect(isImmutable(obj.foo)).toBe(false)
- expect(isImmutable(obj.bar)).toBe(true)
+ expect(isReadonly(obj.foo)).toBe(false)
+ expect(isReadonly(obj.bar)).toBe(true)
})
- test('should make ref immutable', () => {
- const n: any = immutable(ref(1))
+ test('should make ref readonly', () => {
+ const n: any = readonly(ref(1))
n.value = 2
expect(n.value).toBe(1)
expect(warn).toHaveBeenCalledTimes(1)
-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)
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)
}
}
}
-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)
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
}
}
-function createImmutableMethod(
+function createReadonlyMethod(
method: Function,
type: OperationTypes
): Function {
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)
)
}
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) {
get: createInstrumentationGetter(mutableInstrumentations)
}
-export const immutableCollectionHandlers: ProxyHandler<any> = {
- get: createInstrumentationGetter(immutableInstrumentations)
+export const readonlyCollectionHandlers: ProxyHandler<any> = {
+ get: createInstrumentationGetter(readonlyInstrumentations)
}
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'
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])
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
)
}
}
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
}