forked from magicoflolis/Userscript-Plus
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstorage.js
More file actions
101 lines (88 loc) · 2.42 KB
/
Copy pathstorage.js
File metadata and controls
101 lines (88 loc) · 2.42 KB
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
'use strict';
let api = webext.storage.local;
/** @type {{ [prefix: string]: StorageArea }} */
export const storageByPrefix = {};
/**
* @param {function} [fnValue] - (value, newKey, obj) => newValue
* @param {function} [fnKey] - (key, val, obj) => newKey (if newKey is falsy the key is skipped)
* @param {Object} [thisObj] - passed as `this` to both functions
* @return {Object}
*/
function mapEntry(fnValue, fnKey, thisObj) {
const res = {};
for (let key of Object.keys(this)) {
const val = this[key];
if (!fnKey || (key = thisObj[fnKey](key, val, this))) {
res[key] = fnValue ? thisObj[fnValue](val, key, this) : val;
}
}
return res;
}
class StorageArea {
constructor(name, prefix) {
storageByPrefix[prefix] = this;
this.name = name;
this.prefix = prefix;
}
/** @return {string} */
toKey(id) {
return this.prefix + id;
}
/** @return {string} */
toId(key) {
return key.startsWith(this.prefix) ? key.slice(this.prefix.length) : '';
}
/**
* @param {string|number} id
* @return {Promise<?>}
*/
async getOne(id) {
const key = this.toKey(id);
return (await api.get([key]))[key];
}
/**
* @param {?string[]} [ids] - if null/absent, the entire storage is returned
* @param {function(val:?,key:string):?} [transform]
* @return {Promise<?>} - single value or object of id:value
*/
async getMulti(ids, transform) {
const keys = ids?.map(this.toKey, this);
const data = await api.get(keys);
return transform || this.prefix
? mapEntry.call(data, transform, 'toId', this)
: data;
}
/**
* @param {string|number|Array<string|number>} id
* @return {Promise<void>}
*/
async remove(id) {
const keys = (Array.isArray(id) ? id : [id]).filter(Boolean).map(this.toKey, this);
if (keys.length) await api.remove(keys);
}
async setOne(id, value) {
if (id) return this.set({ [id]: value });
}
/**
* @param {Object} data
* @return {Promise<Object>} same object
*/
async set(data) {
await api.set(this.prefix ? mapEntry.call(data, null, 'toKey', this) : data);
return data;
}
}
const storage = {
get api() {
return api;
},
set api(val) {
api = val;
},
/** @return {?StorageArea} */
forKey: key => storageByPrefix[/^\w+:|$/.exec(key)[0]],
base: new StorageArea('base', ''),
config: new StorageArea('config', 'cfg:'),
cache: new StorageArea('cache', 'cac:'),
};
export default storage;