refactor: immutable -> readonly
This commit is contained in:
parent
e1bbfbba94
commit
589d3c2feb
@ -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)
|
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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'
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user