@webreflection/utils 0.2.13 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +11 -1
- package/src/README.md +20 -0
- package/src/json-storage.js +167 -0
- package/types/json-storage.d.ts +78 -0
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ A [collection](./src/) of utility functions:
|
|
|
11
11
|
* **[ascii](https://github.com/WebReflection/utils/tree/main/src#ascii)** - basic string to buffer conversion (without validation)
|
|
12
12
|
* **[bound-once](https://github.com/WebReflection/utils/tree/main/src#bound-once)** - to retrieve unique bound methods per realm
|
|
13
13
|
* **[bound](https://github.com/WebReflection/utils/tree/main/src#bound)** - to retrieve one-off bound methods
|
|
14
|
+
* **[json-storage](https://github.com/WebReflection/utils/tree/main/src#json-storage)** - to handle with ease both `localStorage` and `sessionStorage` via a *Map* friendly API
|
|
14
15
|
* **[shared-array-buffer](https://github.com/WebReflection/utils/tree/main/src#shared-array-buffer)** - to simulate *SAB* when not available
|
|
15
16
|
* **[sticky](https://github.com/WebReflection/utils/tree/main/src#sticky)** - to stick once per realm anything useful
|
|
16
17
|
* **[with-resolvers](https://github.com/WebReflection/utils/tree/main/src#with-resolvers)** - a self bound `Promise.withResolver()` for older runtimes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webreflection/utils",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"types": {
|
|
6
6
|
"./all": "./types/all.d.ts",
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
"types": "./types/bound.d.ts",
|
|
29
29
|
"import": "./src/bound.js"
|
|
30
30
|
},
|
|
31
|
+
"./json-storage": {
|
|
32
|
+
"types": "./types/json-storage.d.ts",
|
|
33
|
+
"import": "./src/json-storage.js"
|
|
34
|
+
},
|
|
31
35
|
"./shared-array-buffer": {
|
|
32
36
|
"types": "./types/shared-array-buffer.d.ts",
|
|
33
37
|
"import": "./src/shared-array-buffer.js"
|
|
@@ -47,6 +51,7 @@
|
|
|
47
51
|
"ascii",
|
|
48
52
|
"bound-once",
|
|
49
53
|
"bound",
|
|
54
|
+
"json-storage",
|
|
50
55
|
"shared-array-buffer",
|
|
51
56
|
"sticky",
|
|
52
57
|
"with-resolvers"
|
|
@@ -79,6 +84,11 @@
|
|
|
79
84
|
"url": "https://github.com/WebReflection/utils/issues"
|
|
80
85
|
},
|
|
81
86
|
"homepage": "https://github.com/WebReflection/utils#readme",
|
|
87
|
+
"overrides": {
|
|
88
|
+
"c8": {
|
|
89
|
+
"yargs": "^18.0.0"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
82
92
|
"devDependencies": {
|
|
83
93
|
"c8": "^11.0.0",
|
|
84
94
|
"typescript": "^6.0.3"
|
package/src/README.md
CHANGED
|
@@ -70,6 +70,26 @@ resolve(4);
|
|
|
70
70
|
|
|
71
71
|
The **bound-once** variant ensures that repeated accesses, such as `boundOnce(Promise).all`, always return the same bound method.
|
|
72
72
|
|
|
73
|
+
|
|
74
|
+
## json-storage
|
|
75
|
+
|
|
76
|
+
A *Map* like API that is compatible out of the box with *JSON API*.
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
import JSONStorage from '@webreflection/utils/json-storage';
|
|
80
|
+
|
|
81
|
+
const localJSONStorage = new JSONStorage;
|
|
82
|
+
|
|
83
|
+
// insert if not present an object and returns it
|
|
84
|
+
localJSONStorage.getOrInsert('key', { complex: true }).complex;
|
|
85
|
+
|
|
86
|
+
localJSONStorage.get('key').complex; // true
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The storage can be a session one via `new JSONStorage(JSONStorage.SESSION)` and it can optionally accept a different api from native *JSON* as long as both `parse` and `stringify` are implemented.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
73
93
|
## shared-array-buffer
|
|
74
94
|
|
|
75
95
|
This utility provides an unobtrusive *SAB* (*SharedArrayBuffer*) shim based on the default *ArrayBuffer*, with `grow(length)` and `growable` additions.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
const { entries, keys, values } = Object;
|
|
4
|
+
|
|
5
|
+
/** @type {typeof Symbol.iterator} */
|
|
6
|
+
const iterator = Symbol.iterator;
|
|
7
|
+
|
|
8
|
+
const LOCAL = 'local';
|
|
9
|
+
const SESSION = 'session';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {typeof LOCAL | typeof SESSION} JSONStorageKind
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @template Value
|
|
17
|
+
* @typedef {{
|
|
18
|
+
* parse(source: string): Value,
|
|
19
|
+
* stringify(value: Value): string
|
|
20
|
+
* }} JSONStorageAPI
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {{
|
|
25
|
+
* clear(): void,
|
|
26
|
+
* getItem(key: string): string | null,
|
|
27
|
+
* removeItem(key: string): void,
|
|
28
|
+
* setItem(key: string, value: string): void,
|
|
29
|
+
* [Symbol.iterator](): Generator<[string, string], void, unknown>,
|
|
30
|
+
* }} StorageAPI
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @template Value
|
|
35
|
+
* @param {JSONStorage<Value>} self
|
|
36
|
+
* @param {string} key
|
|
37
|
+
* @param {Value} value
|
|
38
|
+
* @returns {Value}
|
|
39
|
+
*/
|
|
40
|
+
const add = (self, key, value) => {
|
|
41
|
+
self.set(key, value);
|
|
42
|
+
return value;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Map-like facade over `localStorage` or `sessionStorage` that stores values
|
|
47
|
+
* through a JSON-compatible `parse`/`stringify` pair.
|
|
48
|
+
*
|
|
49
|
+
* @template [Value=unknown]
|
|
50
|
+
* @implements {Iterable<[string, Value]>}
|
|
51
|
+
*/
|
|
52
|
+
export default class JSONStorage {
|
|
53
|
+
/** @type {typeof LOCAL} */
|
|
54
|
+
static LOCAL = LOCAL;
|
|
55
|
+
|
|
56
|
+
/** @type {typeof SESSION} */
|
|
57
|
+
static SESSION = SESSION;
|
|
58
|
+
|
|
59
|
+
/** @type {StorageAPI} */
|
|
60
|
+
#storage;
|
|
61
|
+
|
|
62
|
+
/** @type {(value: Value) => string} */
|
|
63
|
+
#stringify;
|
|
64
|
+
|
|
65
|
+
/** @type {(source: string) => Value} */
|
|
66
|
+
#parse;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @param {JSONStorageKind} [storage=LOCAL]
|
|
70
|
+
* @param {JSONStorageAPI<Value>} [json=JSON]
|
|
71
|
+
*/
|
|
72
|
+
constructor(storage = LOCAL, { parse, stringify } = /** @type {JSONStorageAPI<Value>} */ (JSON)) {
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
this.#storage = storage === LOCAL ? localStorage : sessionStorage;
|
|
75
|
+
this.#stringify = stringify;
|
|
76
|
+
this.#parse = parse;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** @returns {void} */
|
|
80
|
+
clear() {
|
|
81
|
+
this.#storage.clear();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @param {string} key
|
|
86
|
+
* @returns {boolean}
|
|
87
|
+
*/
|
|
88
|
+
delete(key) {
|
|
89
|
+
const had = this.has(key);
|
|
90
|
+
if (had) this.#storage.removeItem(key);
|
|
91
|
+
return had;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {string} key
|
|
96
|
+
* @returns {Value | undefined}
|
|
97
|
+
*/
|
|
98
|
+
get(key) {
|
|
99
|
+
const value = this.#storage.getItem(key);
|
|
100
|
+
return typeof value === 'string' ? this.#parse(value) : void 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @param {string} key
|
|
105
|
+
* @param {Value} value
|
|
106
|
+
* @returns {Value}
|
|
107
|
+
*/
|
|
108
|
+
getOrInsert(key, value) {
|
|
109
|
+
const current = this.get(key);
|
|
110
|
+
return current !== void 0 ? current : add(this, key, value);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @template {string} Key
|
|
115
|
+
* @param {Key} key
|
|
116
|
+
* @param {(key: Key) => Value} callback
|
|
117
|
+
* @returns {Value}
|
|
118
|
+
*/
|
|
119
|
+
getOrInsertComputed(key, callback) {
|
|
120
|
+
const current = this.get(key);
|
|
121
|
+
return current !== void 0 ? current : add(this, key, callback(key));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @param {string} key
|
|
126
|
+
* @returns {boolean}
|
|
127
|
+
*/
|
|
128
|
+
has(key) {
|
|
129
|
+
return this.#storage.getItem(key) != null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @param {string} key
|
|
134
|
+
* @param {Value} value
|
|
135
|
+
* @returns {this}
|
|
136
|
+
*/
|
|
137
|
+
set(key, value) {
|
|
138
|
+
this.#storage.setItem(key, this.#stringify(value));
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** @returns {Generator<[string, Value], void, unknown>} */
|
|
143
|
+
*entries() {
|
|
144
|
+
yield* this[iterator]();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** @returns {Generator<string, void, unknown>} */
|
|
148
|
+
*keys() {
|
|
149
|
+
yield* keys(this.#storage);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** @returns {Generator<Value, void, unknown>} */
|
|
153
|
+
*values() {
|
|
154
|
+
for (const value of values(this.#storage)) {
|
|
155
|
+
// @ts-ignore
|
|
156
|
+
yield this.#parse(value);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** @returns {Generator<[string, Value], void, unknown>} */
|
|
161
|
+
*[iterator]() {
|
|
162
|
+
for (const [key, value] of entries(this.#storage)) {
|
|
163
|
+
// @ts-ignore
|
|
164
|
+
yield [key, this.#parse(value)];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map-like facade over `localStorage` or `sessionStorage` that stores values
|
|
3
|
+
* through a JSON-compatible `parse`/`stringify` pair.
|
|
4
|
+
*
|
|
5
|
+
* @template [Value=unknown]
|
|
6
|
+
* @implements {Iterable<[string, Value]>}
|
|
7
|
+
*/
|
|
8
|
+
export default class JSONStorage<Value = unknown> implements Iterable<[string, Value]> {
|
|
9
|
+
/** @type {typeof LOCAL} */
|
|
10
|
+
static LOCAL: typeof LOCAL;
|
|
11
|
+
/** @type {typeof SESSION} */
|
|
12
|
+
static SESSION: typeof SESSION;
|
|
13
|
+
/**
|
|
14
|
+
* @param {JSONStorageKind} [storage=LOCAL]
|
|
15
|
+
* @param {JSONStorageAPI<Value>} [json=JSON]
|
|
16
|
+
*/
|
|
17
|
+
constructor(storage?: JSONStorageKind, { parse, stringify }?: JSONStorageAPI<Value>);
|
|
18
|
+
/** @returns {void} */
|
|
19
|
+
clear(): void;
|
|
20
|
+
/**
|
|
21
|
+
* @param {string} key
|
|
22
|
+
* @returns {boolean}
|
|
23
|
+
*/
|
|
24
|
+
delete(key: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* @param {string} key
|
|
27
|
+
* @returns {Value | undefined}
|
|
28
|
+
*/
|
|
29
|
+
get(key: string): Value | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} key
|
|
32
|
+
* @param {Value} value
|
|
33
|
+
* @returns {Value}
|
|
34
|
+
*/
|
|
35
|
+
getOrInsert(key: string, value: Value): Value;
|
|
36
|
+
/**
|
|
37
|
+
* @template {string} Key
|
|
38
|
+
* @param {Key} key
|
|
39
|
+
* @param {(key: Key) => Value} callback
|
|
40
|
+
* @returns {Value}
|
|
41
|
+
*/
|
|
42
|
+
getOrInsertComputed<Key extends string>(key: Key, callback: (key: Key) => Value): Value;
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} key
|
|
45
|
+
* @returns {boolean}
|
|
46
|
+
*/
|
|
47
|
+
has(key: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* @param {string} key
|
|
50
|
+
* @param {Value} value
|
|
51
|
+
* @returns {this}
|
|
52
|
+
*/
|
|
53
|
+
set(key: string, value: Value): this;
|
|
54
|
+
/** @returns {Generator<[string, Value], void, unknown>} */
|
|
55
|
+
entries(): Generator<[string, Value], void, unknown>;
|
|
56
|
+
/** @returns {Generator<string, void, unknown>} */
|
|
57
|
+
keys(): Generator<string, void, unknown>;
|
|
58
|
+
/** @returns {Generator<Value, void, unknown>} */
|
|
59
|
+
values(): Generator<Value, void, unknown>;
|
|
60
|
+
/** @returns {Generator<[string, Value], void, unknown>} */
|
|
61
|
+
[Symbol.iterator](): Generator<[string, Value], void, unknown>;
|
|
62
|
+
#private;
|
|
63
|
+
}
|
|
64
|
+
export type JSONStorageKind = typeof LOCAL | typeof SESSION;
|
|
65
|
+
export type JSONStorageAPI<Value> = {
|
|
66
|
+
parse(source: string): Value;
|
|
67
|
+
stringify(value: Value): string;
|
|
68
|
+
};
|
|
69
|
+
export type StorageAPI = {
|
|
70
|
+
clear(): void;
|
|
71
|
+
getItem(key: string): string | null;
|
|
72
|
+
removeItem(key: string): void;
|
|
73
|
+
setItem(key: string, value: string): void;
|
|
74
|
+
[Symbol.iterator](): Generator<[string, string], void, unknown>;
|
|
75
|
+
};
|
|
76
|
+
declare const LOCAL: "local";
|
|
77
|
+
declare const SESSION: "session";
|
|
78
|
+
export {};
|