-
Notifications
You must be signed in to change notification settings - Fork 14
/
storage.ts
132 lines (116 loc) · 3.58 KB
/
storage.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { getExpires, removeExpires, setExpires } from '../extends/expires';
import { activeEffect, createExpiredFunc, EffectFn, expiresType, prefix, proxyMap, shouldTrack, StorageLike } from '../shared';
import { hasChanged, hasOwn, propertyIsInPrototype } from '../utils';
import { emit, off, on, once } from '../extends/watch';
import { decode, encode } from './transform';
function createInstrumentations(
target: object,
receiver: any
) {
const instrumentations: Record<string, Function> = {};
(['clear', 'key'] as const).forEach(key => {
instrumentations[key] = target[key].bind(target);
});
instrumentations.getItem = function(keyName: string) {
return get(target, keyName, receiver);
};
instrumentations.removeItem = function(keyName: string) {
return deleteProperty(target, keyName);
};
instrumentations.setItem = function(keyName: string, keyValue: any) {
return set(target, keyName, keyValue, receiver);
};
instrumentations.getExpires = function(keyName: string) {
return getExpires(target, keyName);
}
instrumentations.removeExpires = function(keyName: string) {
return removeExpires(target, keyName, receiver);
}
instrumentations.setExpires = function(keyName: string, keyValue: expiresType) {
return setExpires(target, keyName, keyValue, receiver);
}
instrumentations.off = function(key?: string, fn?: EffectFn) {
off(target, key, fn);
}
instrumentations.on = function(key: string, fn: EffectFn) {
on(target, key, fn);
}
instrumentations.once = function(key: string, fn: EffectFn) {
once(target, key, fn);
}
return instrumentations;
}
let instrumentations: Record<string, Function>;
function get(
target: object,
property: string,
receiver: any
) {
// records the parent of array and object
if(shouldTrack) {
activeEffect.storage = target;
activeEffect.key = property;
activeEffect.proxy = receiver;
}
if(!instrumentations) {
instrumentations = createInstrumentations(target, receiver);
}
if(hasOwn(instrumentations, property)) {
return Reflect.get(instrumentations, property, receiver);
}
if(!has(target, property)) {
return undefined;
}
const key = `${prefix}${property}`;
const value = target[key] || target[property];
if(!value) {
return value;
}
return decode(value, createExpiredFunc(target, key));
}
function set(
target: object,
property: string,
value: any,
receiver: any
) {
const key = `${prefix}${property}`;
let oldValue = decode(target[key], createExpiredFunc(target, key));
oldValue = proxyMap.get(oldValue) || oldValue;
const encodeValue = encode(value);
const result = Reflect.set(target, key, encodeValue, receiver);
if(result && hasChanged(value, oldValue) && shouldTrack) {
emit(target, property, value, oldValue);
}
return result;
}
// only prefixed properties are accepted in the instance
function has(
target: object,
property: string
): boolean {
return target.hasOwnProperty(`${prefix}${property}`) || propertyIsInPrototype(target, property);
}
function deleteProperty(
target: object,
property: string
) {
const key = `${prefix}${property}`;
const hadKey = hasOwn(target, key);
let oldValue = decode(target[key], createExpiredFunc(target, key));
oldValue = proxyMap.get(oldValue) || oldValue;
const result = Reflect.deleteProperty(target, key);
if(result && hadKey) {
emit(target, property, undefined, oldValue);
}
return result;
}
export function createProxyStorage(storage: StorageLike) {
const proxy = new Proxy(storage, {
get,
set,
has,
deleteProperty,
});
return proxy;
}