@e280/stz 0.0.0-3 → 0.0.0-31
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 +285 -0
- package/package.json +14 -7
- package/s/clone/clone.test.ts +123 -123
- package/s/coalesce.ts +1 -0
- package/s/data/base-x.ts +170 -0
- package/s/data/base58.ts +15 -5
- package/s/data/base64.ts +15 -6
- package/s/data/base64url.ts +15 -6
- package/s/data/bytename/bytename.test.ts +49 -0
- package/s/data/{barname/barname.ts → bytename/bytename.ts} +38 -10
- package/s/data/bytename/index.ts +4 -0
- package/s/data/bytename/thumbprint.test.ts +53 -0
- package/s/data/bytename/thumbprint.ts +112 -0
- package/s/data/bytes.ts +12 -2
- package/s/data/data.test.ts +98 -0
- package/s/data/hex.ts +15 -5
- package/s/data/txt.ts +14 -4
- package/s/deadline.ts +5 -6
- package/s/debounce/debounce.test.ts +73 -73
- package/s/deep/deep.test.ts +8 -8
- package/s/deep/parts/equal.test.ts +123 -124
- package/s/{defer-promise.ts → defer.ts} +2 -2
- package/s/drill.ts +2 -4
- package/s/ev.ts +20 -0
- package/s/id-counter.ts +9 -0
- package/s/index.ts +16 -2
- package/s/is.ts +10 -4
- package/s/loopy.ts +12 -0
- package/s/map-g.ts +2 -2
- package/s/nap.ts +1 -0
- package/s/once.ts +14 -0
- package/s/pubsub.ts +24 -6
- package/s/queue/queue.test.ts +67 -0
- package/s/queue/queue.ts +21 -0
- package/s/repeat.ts +25 -0
- package/s/tests.test.ts +21 -0
- package/s/time.ts +22 -0
- package/x/clone/clone.test.d.ts +15 -1
- package/x/clone/clone.test.js +106 -124
- package/x/clone/clone.test.js.map +1 -1
- package/x/coalesce.d.ts +1 -0
- package/x/coalesce.js +1 -0
- package/x/coalesce.js.map +1 -1
- package/x/data/base-x.d.ts +47 -0
- package/x/data/base-x.js +147 -0
- package/x/data/base-x.js.map +1 -0
- package/x/data/base58.d.ts +5 -1
- package/x/data/base58.js +13 -5
- package/x/data/base58.js.map +1 -1
- package/x/data/base64.d.ts +7 -3
- package/x/data/base64.js +13 -5
- package/x/data/base64.js.map +1 -1
- package/x/data/base64url.d.ts +5 -1
- package/x/data/base64url.js +13 -5
- package/x/data/base64url.js.map +1 -1
- package/x/data/bytename/bytename.d.ts +19 -0
- package/x/data/{barname/barname.js → bytename/bytename.js} +27 -11
- package/x/data/bytename/bytename.js.map +1 -0
- package/x/data/bytename/bytename.test.d.ts +17 -0
- package/x/data/bytename/bytename.test.js +41 -0
- package/x/data/bytename/bytename.test.js.map +1 -0
- package/x/data/bytename/index.d.ts +2 -0
- package/x/data/bytename/index.js +3 -0
- package/x/data/bytename/index.js.map +1 -0
- package/x/data/bytename/thumbprint.d.ts +36 -0
- package/x/data/bytename/thumbprint.js +79 -0
- package/x/data/bytename/thumbprint.js.map +1 -0
- package/x/data/bytename/thumbprint.test.d.ts +24 -0
- package/x/data/bytename/thumbprint.test.js +45 -0
- package/x/data/bytename/thumbprint.test.js.map +1 -0
- package/x/data/bytename/utils/prefixes.js.map +1 -0
- package/x/data/bytename/utils/suffixes.js.map +1 -0
- package/x/data/bytes.d.ts +3 -2
- package/x/data/bytes.js +11 -2
- package/x/data/bytes.js.map +1 -1
- package/x/data/data.test.d.ts +69 -0
- package/x/data/data.test.js +77 -0
- package/x/data/data.test.js.map +1 -0
- package/x/data/hex.d.ts +8 -4
- package/x/data/hex.js +13 -5
- package/x/data/hex.js.map +1 -1
- package/x/data/txt.d.ts +6 -2
- package/x/data/txt.js +12 -4
- package/x/data/txt.js.map +1 -1
- package/x/deadline.d.ts +2 -2
- package/x/deadline.js +4 -4
- package/x/deadline.js.map +1 -1
- package/x/debounce/debounce.test.d.ts +8 -1
- package/x/debounce/debounce.test.js +70 -74
- package/x/debounce/debounce.test.js.map +1 -1
- package/x/deep/deep.test.d.ts +21 -1
- package/x/deep/deep.test.js +5 -9
- package/x/deep/deep.test.js.map +1 -1
- package/x/deep/parts/equal.test.d.ts +19 -1
- package/x/deep/parts/equal.test.js +107 -125
- package/x/deep/parts/equal.test.js.map +1 -1
- package/x/{defer-promise.d.ts → defer.d.ts} +2 -2
- package/x/{defer-promise.js → defer.js} +2 -2
- package/x/defer.js.map +1 -0
- package/x/drill.d.ts +1 -3
- package/x/drill.js +2 -4
- package/x/drill.js.map +1 -1
- package/x/ev.d.ts +6 -0
- package/x/ev.js +10 -0
- package/x/ev.js.map +1 -0
- package/x/id-counter.d.ts +5 -0
- package/x/id-counter.js +10 -0
- package/x/id-counter.js.map +1 -0
- package/x/index.d.ts +13 -2
- package/x/index.js +13 -2
- package/x/index.js.map +1 -1
- package/x/is.d.ts +6 -4
- package/x/is.js +6 -4
- package/x/is.js.map +1 -1
- package/x/loopy.d.ts +2 -0
- package/x/loopy.js +10 -0
- package/x/loopy.js.map +1 -0
- package/x/map-g.d.ts +3 -3
- package/x/map-g.js +1 -1
- package/x/map-g.js.map +1 -1
- package/x/nap.d.ts +1 -0
- package/x/nap.js +1 -0
- package/x/nap.js.map +1 -1
- package/x/once.d.ts +1 -0
- package/x/once.js +12 -0
- package/x/once.js.map +1 -0
- package/x/pubsub.d.ts +12 -1
- package/x/pubsub.js +7 -5
- package/x/pubsub.js.map +1 -1
- package/x/queue/queue.d.ts +4 -0
- package/x/queue/queue.js +14 -0
- package/x/queue/queue.js.map +1 -0
- package/x/queue/queue.test.d.ts +8 -0
- package/x/queue/queue.test.js +57 -0
- package/x/queue/queue.test.js.map +1 -0
- package/x/repeat.d.ts +5 -0
- package/x/repeat.js +23 -0
- package/x/repeat.js.map +1 -0
- package/x/tests.test.js +18 -0
- package/x/tests.test.js.map +1 -0
- package/x/time.d.ts +18 -0
- package/x/time.js +19 -0
- package/x/time.js.map +1 -0
- package/readme.md +0 -85
- package/s/data/anka.ts +0 -66
- package/s/data/barname/badge.ts +0 -78
- package/s/data/barname/demo.ts +0 -49
- package/s/data/barname/index.ts +0 -4
- package/x/data/anka.d.ts +0 -5
- package/x/data/anka.js +0 -53
- package/x/data/anka.js.map +0 -1
- package/x/data/barname/badge.d.ts +0 -25
- package/x/data/barname/badge.js +0 -64
- package/x/data/barname/badge.js.map +0 -1
- package/x/data/barname/barname.d.ts +0 -7
- package/x/data/barname/barname.js.map +0 -1
- package/x/data/barname/demo.js +0 -45
- package/x/data/barname/demo.js.map +0 -1
- package/x/data/barname/index.d.ts +0 -2
- package/x/data/barname/index.js +0 -3
- package/x/data/barname/index.js.map +0 -1
- package/x/data/barname/utils/prefixes.js.map +0 -1
- package/x/data/barname/utils/suffixes.js.map +0 -1
- package/x/defer-promise.js.map +0 -1
- /package/{license → LICENSE} +0 -0
- /package/s/data/{barname → bytename}/utils/prefixes.ts +0 -0
- /package/s/data/{barname → bytename}/utils/suffixes.ts +0 -0
- /package/x/data/{barname → bytename}/utils/prefixes.d.ts +0 -0
- /package/x/data/{barname → bytename}/utils/prefixes.js +0 -0
- /package/x/data/{barname → bytename}/utils/suffixes.d.ts +0 -0
- /package/x/data/{barname → bytename}/utils/suffixes.js +0 -0
- /package/x/{data/barname/demo.d.ts → tests.test.d.ts} +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
|
|
2
|
+
# `@e280/stz`
|
|
3
|
+
|
|
4
|
+
**stz** is e280's standard library of environment-agnostic typescript tools.
|
|
5
|
+
|
|
6
|
+
it's our javascript toolkit.
|
|
7
|
+
|
|
8
|
+
zero dependencies.
|
|
9
|
+
|
|
10
|
+
<br/>
|
|
11
|
+
|
|
12
|
+
## 🧰 STZ PRIMITIVES
|
|
13
|
+
> cool concepts we use all over the place
|
|
14
|
+
|
|
15
|
+
### 🍏 MapG
|
|
16
|
+
> extended js map
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import {MapG} from "@e280/stz"
|
|
20
|
+
|
|
21
|
+
const map = new MapG<number, string>([
|
|
22
|
+
[1, "hello"],
|
|
23
|
+
[2, "world"],
|
|
24
|
+
])
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- `map.require(key)` — throws error if the value is undefined
|
|
28
|
+
```ts
|
|
29
|
+
const value = map.require(1)
|
|
30
|
+
// "hello"
|
|
31
|
+
```
|
|
32
|
+
- `map.guarantee(key, make)` — returns the value for `key`, but if undefined, run `make` to set the value
|
|
33
|
+
```ts
|
|
34
|
+
const value = map.guarantee(3, () => "rofl")
|
|
35
|
+
// "rofl"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### nap
|
|
39
|
+
> sleep for some milliseconds
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import {nap} from "@e280/stz"
|
|
43
|
+
|
|
44
|
+
await nap(900)
|
|
45
|
+
// wait for 900 milliseconds
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### defer
|
|
49
|
+
> defer the resolve/reject of a promise to the outside
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import {defer} from "@e280/stz"
|
|
53
|
+
|
|
54
|
+
const deferred = defer()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- resolve the deferred promise
|
|
58
|
+
```ts
|
|
59
|
+
deferred.resolve()
|
|
60
|
+
```
|
|
61
|
+
- reject the deferred promise
|
|
62
|
+
```ts
|
|
63
|
+
deferred.reject(new Error("fail"))
|
|
64
|
+
```
|
|
65
|
+
- await the promise
|
|
66
|
+
```ts
|
|
67
|
+
await deferred.promise
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 🍏 `pub` and `sub`
|
|
71
|
+
> ergonomic event emitters
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import {pub, sub} from "@e280/stz"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- make a publisher fn
|
|
78
|
+
```ts
|
|
79
|
+
// create a pub fn
|
|
80
|
+
const sendMessage = pub<[string]>()
|
|
81
|
+
|
|
82
|
+
// subscribe to it
|
|
83
|
+
sendMessage.sub(m => console.log(m))
|
|
84
|
+
|
|
85
|
+
// publish to it
|
|
86
|
+
sendMessage("hello")
|
|
87
|
+
```
|
|
88
|
+
- make a subscriber fn *(see how it's just the reverse of pub?)*
|
|
89
|
+
```ts
|
|
90
|
+
// create a sub fn
|
|
91
|
+
const onMessage = sub<[string]>()
|
|
92
|
+
|
|
93
|
+
// subscribe to it
|
|
94
|
+
onMessage(m => console.log(m))
|
|
95
|
+
|
|
96
|
+
// publish to it
|
|
97
|
+
onMessage.pub("hello")
|
|
98
|
+
```
|
|
99
|
+
- the pub and sub are the same, but have differing invoke signatures
|
|
100
|
+
- i seem to use `sub` more often
|
|
101
|
+
- both have some extra functionality
|
|
102
|
+
```ts
|
|
103
|
+
// pub fns return a promise, to wait for all async subscribers
|
|
104
|
+
await sendMessage("hello")
|
|
105
|
+
await onMessage.pub("hello")
|
|
106
|
+
|
|
107
|
+
// sub fns return an unsub fn
|
|
108
|
+
const unsub1 = onMessage(m => console.log(m))
|
|
109
|
+
unsub1() // unsubscribe that listener
|
|
110
|
+
|
|
111
|
+
const unsub2 = sendMessage.sub(m => console.log(m))
|
|
112
|
+
unsub2() // unsubscribe that listener
|
|
113
|
+
|
|
114
|
+
// you can clear all subscribers from a pub or a sub
|
|
115
|
+
sendMessage.clear()
|
|
116
|
+
onMessage.clear()
|
|
117
|
+
|
|
118
|
+
// instead of a 'once' fn we simply await next()
|
|
119
|
+
await onMessage.next()
|
|
120
|
+
await sendMessage.next()
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
<br/>
|
|
124
|
+
|
|
125
|
+
## 🧰 FN TOOLS
|
|
126
|
+
> function-oriented tools
|
|
127
|
+
|
|
128
|
+
### 🍏 `queue(fn)`
|
|
129
|
+
> execute calls in sequence (not concurrent)
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import {queue, nap} from "@e280/stz"
|
|
133
|
+
|
|
134
|
+
const fn = queue(async() => nap(100))
|
|
135
|
+
|
|
136
|
+
fn()
|
|
137
|
+
fn()
|
|
138
|
+
await fn() // waits for the previous calls (sequentially)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 🍏 `once(fn)`
|
|
142
|
+
> ensure a fn is only executed one time
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import {once} from "@e280/stz"
|
|
146
|
+
|
|
147
|
+
let count = 0
|
|
148
|
+
const fn = once(() => count++)
|
|
149
|
+
console.log(count) // 0
|
|
150
|
+
|
|
151
|
+
fn()
|
|
152
|
+
console.log(count) // 1
|
|
153
|
+
|
|
154
|
+
fn()
|
|
155
|
+
console.log(count) // 1
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 🍏 `deadline(100, message, fn)`
|
|
159
|
+
> throws an error if the async function takes too long
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import {deadline} from "@e280/stz"
|
|
163
|
+
|
|
164
|
+
const fn = deadline(100, "deadline exceeded", async() => {
|
|
165
|
+
|
|
166
|
+
// example deliberately takes too long
|
|
167
|
+
await nap(200)
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
await fn()
|
|
171
|
+
// DeadlineError: deadline exceeded, timed out in 0.1 seconds
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 🍏 `repeat(fn)`
|
|
175
|
+
> execute a function over and over again, back to back
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import {repeat} from "@e280/stz"
|
|
179
|
+
|
|
180
|
+
let ticks = 0
|
|
181
|
+
|
|
182
|
+
const stop = repeat(async() => {
|
|
183
|
+
|
|
184
|
+
// use a nap to add a delay between each execution
|
|
185
|
+
await nap(200)
|
|
186
|
+
|
|
187
|
+
ticks++
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
// stop repeating whenever you want
|
|
191
|
+
stop()
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
<br/>
|
|
195
|
+
|
|
196
|
+
## 🧰 DATA UTILITIES
|
|
197
|
+
> transforming and representing binary data
|
|
198
|
+
|
|
199
|
+
### 🍏 BaseX
|
|
200
|
+
> represent data in arbitrary encodings
|
|
201
|
+
- make a BaseX instance
|
|
202
|
+
```ts
|
|
203
|
+
import {BaseX} from "@e280/stz"
|
|
204
|
+
|
|
205
|
+
const hex = new BaseX(BaseX.lexicons.hex)
|
|
206
|
+
```
|
|
207
|
+
- convert between strings and binary
|
|
208
|
+
```ts
|
|
209
|
+
hex.toBytes("9960cd633a46acfe8307d8a400e842da0d930a75fb8188e0f5da264e4b6b4e5b")
|
|
210
|
+
// Uint8Array
|
|
211
|
+
|
|
212
|
+
hex.fromBytes(bytes)
|
|
213
|
+
// string
|
|
214
|
+
```
|
|
215
|
+
- you can also convert between strings and integers
|
|
216
|
+
```ts
|
|
217
|
+
hex.fromInteger(Date.now())
|
|
218
|
+
// "197140ac804"
|
|
219
|
+
|
|
220
|
+
hex.toInteger(hex)
|
|
221
|
+
// 1748387940356
|
|
222
|
+
```
|
|
223
|
+
- available lexicons include
|
|
224
|
+
- base2
|
|
225
|
+
- hex
|
|
226
|
+
- base36
|
|
227
|
+
- base58
|
|
228
|
+
- base62
|
|
229
|
+
- base64 (with standard padding)
|
|
230
|
+
- base64url
|
|
231
|
+
- you can make insanely compact timestamps like this:
|
|
232
|
+
```ts
|
|
233
|
+
import {BaseX} from "@e280/stz"
|
|
234
|
+
|
|
235
|
+
const base62 = new BaseX(BaseX.lexicons.base62)
|
|
236
|
+
|
|
237
|
+
base62.fromInteger(Date.now() / 1000)
|
|
238
|
+
// "1uK3au"
|
|
239
|
+
```
|
|
240
|
+
- `1748388028` base10 epoch seconds (10 chars)
|
|
241
|
+
- `1uK3au` base62 epoch seconds (6 chars)
|
|
242
|
+
- *nice*
|
|
243
|
+
|
|
244
|
+
<br/>
|
|
245
|
+
|
|
246
|
+
### 🍏 Bytename
|
|
247
|
+
> friendly string encoding for binary data
|
|
248
|
+
|
|
249
|
+
a bytename looks like `"midsen.picmyn.widrep.baclut dotreg.filtyp.nosnus.siptev"`. that's 16 bytes. each byte maps to a three-letter triplet
|
|
250
|
+
|
|
251
|
+
the bytename parser (`Bytename.toBytes`) ignores all non-alphabetic characters. thus `midsen.picmyn`, `midsenpicmyn`, and `mid@sen$pic@myn` are all equal.
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
import {Bytename} from "@e280/stz"
|
|
255
|
+
```
|
|
256
|
+
- ```ts
|
|
257
|
+
Bytename.fromBytes(new Uint8Array([0xDE, 0xAD, 0xBE, 0xEF]))
|
|
258
|
+
// "ribmug.hilmun"
|
|
259
|
+
```
|
|
260
|
+
- ```ts
|
|
261
|
+
Bytename.toBytes("ribmug.hilmun")
|
|
262
|
+
// Uint8Array, 4 bytes
|
|
263
|
+
```
|
|
264
|
+
- ```ts
|
|
265
|
+
const bytes = new Uint8Array([
|
|
266
|
+
0xDE, 0xAD, 0xBE, 0xEF,
|
|
267
|
+
0xDE, 0xAD, 0xBE, 0xEF,
|
|
268
|
+
])
|
|
269
|
+
|
|
270
|
+
Bytename.fromBytes(bytes, {
|
|
271
|
+
groupSize: 2, // default is 4
|
|
272
|
+
groupSeparator: " ",
|
|
273
|
+
wordSeparator: ".",
|
|
274
|
+
})
|
|
275
|
+
// "ribmug.hilmun ribmug.hilmun"
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
<br/>
|
|
279
|
+
|
|
280
|
+
<br/>
|
|
281
|
+
|
|
282
|
+
## 💖 stz is made with open source love
|
|
283
|
+
reward us with github stars
|
|
284
|
+
build with us at https://e280.org/ but only if you're cool
|
|
285
|
+
|
package/package.json
CHANGED
|
@@ -1,28 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e280/stz",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-31",
|
|
4
4
|
"description": "everyday ts fns for everything",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Chase Moskal <chasemoskal@gmail.com>",
|
|
7
7
|
"type": "module",
|
|
8
|
-
"main": "x/index.js",
|
|
8
|
+
"main": "./x/index.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./x/index.js"
|
|
11
|
+
},
|
|
9
12
|
"files": [
|
|
10
13
|
"x",
|
|
11
14
|
"s"
|
|
12
15
|
],
|
|
13
16
|
"scripts": {
|
|
14
17
|
"build": "run-s _clean _links _tsc",
|
|
18
|
+
"test": "node x/tests.test.js",
|
|
19
|
+
"test-watch": "node --watch x/tests.test.js",
|
|
20
|
+
"test-inspect": "node inspect x/tests.test.js",
|
|
21
|
+
"count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +",
|
|
22
|
+
"watch": "run-p _tscw test-watch",
|
|
15
23
|
"_clean": "rm -rf x && mkdir x",
|
|
16
24
|
"_links": "ln -s \"$(realpath node_modules)\" x/node_modules",
|
|
17
25
|
"_tsc": "tsc",
|
|
18
|
-
"
|
|
19
|
-
"count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +",
|
|
20
|
-
"test": "exit 0"
|
|
26
|
+
"_tscw": "tsc -w"
|
|
21
27
|
},
|
|
22
28
|
"devDependencies": {
|
|
23
|
-
"@
|
|
29
|
+
"@e280/science": "^0.0.5",
|
|
30
|
+
"@types/node": "^24.2.0",
|
|
24
31
|
"npm-run-all": "^4.1.5",
|
|
25
|
-
"typescript": "^5.
|
|
32
|
+
"typescript": "^5.9.2"
|
|
26
33
|
},
|
|
27
34
|
"keywords": [
|
|
28
35
|
"standard",
|
package/s/clone/clone.test.ts
CHANGED
|
@@ -1,124 +1,124 @@
|
|
|
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
|
-
|
|
1
|
+
|
|
2
|
+
import {clone} from "./clone.js"
|
|
3
|
+
import {Science, expect} from "@e280/science"
|
|
4
|
+
|
|
5
|
+
function checkMapOrSetEquality(original: any, cloned: any) {
|
|
6
|
+
const originalEntries = JSON.stringify(Array.from(original))
|
|
7
|
+
const clonedEntries = JSON.stringify(Array.from(cloned))
|
|
8
|
+
expect(clonedEntries).is(originalEntries)
|
|
9
|
+
expect(cloned).not.is(original) // check for deep cloning
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default Science.suite({
|
|
13
|
+
|
|
14
|
+
async "clone primitive types"() {
|
|
15
|
+
expect(clone(123)).is(123)
|
|
16
|
+
expect(clone("abc")).is("abc")
|
|
17
|
+
expect(clone(true)).is(true)
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
async "clone arrays"() {
|
|
21
|
+
const array = [1, 2, 3]
|
|
22
|
+
const clonedArray = clone(array)
|
|
23
|
+
expect(JSON.stringify(clonedArray)).is(JSON.stringify(array))
|
|
24
|
+
expect(clonedArray).not.is(array) // check for deep cloning
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
async "clone plain objects"() {
|
|
28
|
+
const object = {foo: "bar", baz: 123}
|
|
29
|
+
const clonedObject = clone(object)
|
|
30
|
+
expect(JSON.stringify(clonedObject)).is(JSON.stringify(object))
|
|
31
|
+
expect(clonedObject).not.is(object) // check for deep cloning
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
async "clone Map"() {
|
|
35
|
+
const map = new Map()
|
|
36
|
+
map.set("key", "value")
|
|
37
|
+
const clonedMap = clone(map)
|
|
38
|
+
expect(map.get("key")).is("value")
|
|
39
|
+
expect(clonedMap).not.is(map)
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
async "clone Set"() {
|
|
43
|
+
const set = new Set()
|
|
44
|
+
set.add("value")
|
|
45
|
+
const clonedSet = clone(set)
|
|
46
|
+
expect(clonedSet.has("value")).ok()
|
|
47
|
+
expect(clonedSet).not.is(set)
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
async "clone Date"() {
|
|
51
|
+
const date = new Date()
|
|
52
|
+
const clonedDate = clone(date)
|
|
53
|
+
expect(clonedDate.getTime()).is(date.getTime())
|
|
54
|
+
expect(clonedDate).not.is(date) // check for deep cloning
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
async "clone objects with circular reference"() {
|
|
58
|
+
const object: any = {foo: "bar"}
|
|
59
|
+
object.self = object // create circular reference
|
|
60
|
+
let error: any
|
|
61
|
+
try {
|
|
62
|
+
clone(object)
|
|
63
|
+
} catch (e) {
|
|
64
|
+
error = e
|
|
65
|
+
}
|
|
66
|
+
expect(error).not.is(undefined)
|
|
67
|
+
expect(error instanceof Error).ok()
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
async "clone nested objects"() {
|
|
71
|
+
const object = {foo: "bar", inner: {baz: 123, deeper: {qux: true}}}
|
|
72
|
+
const clonedObject = clone(object)
|
|
73
|
+
expect(JSON.stringify(clonedObject)).is(JSON.stringify(object))
|
|
74
|
+
expect(clonedObject).not.is(object) // check for deep cloning
|
|
75
|
+
expect(clonedObject.inner).not.is(object.inner) // check for deep cloning
|
|
76
|
+
expect(clonedObject.inner.deeper).not.is(object.inner.deeper) // check for deep cloning
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
async "clone array of objects"() {
|
|
80
|
+
const array = [{foo: "bar"}, {baz: 123}, {qux: true}]
|
|
81
|
+
const clonedArray = clone(array)
|
|
82
|
+
expect(JSON.stringify(clonedArray)).is(JSON.stringify(array))
|
|
83
|
+
expect(clonedArray).not.is(array) // check for deep cloning
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
async "clone object with array"() {
|
|
87
|
+
const object = {foo: "bar", array: [1, 2, 3]}
|
|
88
|
+
const clonedObject = clone(object)
|
|
89
|
+
expect(JSON.stringify(clonedObject)).is(JSON.stringify(object))
|
|
90
|
+
expect(clonedObject).not.is(object) // check for deep cloning
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
async "clone object with Map"() {
|
|
94
|
+
const map = new Map()
|
|
95
|
+
map.set("key", "value")
|
|
96
|
+
const object = {foo: "bar", map}
|
|
97
|
+
const clonedObject = clone(object)
|
|
98
|
+
expect(JSON.stringify(clonedObject.foo)).is(JSON.stringify(object.foo))
|
|
99
|
+
checkMapOrSetEquality(object.map, clonedObject.map)
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
async "clone object with duplicate sibling references"() {
|
|
103
|
+
const dupeObject = { id: 1, name: "H4CK3RM4N" }
|
|
104
|
+
const data = { obj1: dupeObject, obj2: dupeObject }
|
|
105
|
+
|
|
106
|
+
let didThrow = false
|
|
107
|
+
let clonedData: typeof data = {} as typeof data
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
clonedData = clone(data)
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
didThrow = true
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
expect(didThrow).not.is(true)
|
|
117
|
+
expect(clonedData.obj1).not.is(clonedData.obj2)
|
|
118
|
+
expect(clonedData.obj1.id).is(1)
|
|
119
|
+
expect(clonedData.obj1.name).is("H4CK3RM4N")
|
|
120
|
+
expect(clonedData.obj2.id).is(1)
|
|
121
|
+
expect(clonedData.obj2.name).is("H4CK3RM4N")
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
124
|
|