@e280/stz 0.0.0-0

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.
Files changed (175) hide show
  1. package/license +23 -0
  2. package/package.json +40 -0
  3. package/readme.md +85 -0
  4. package/s/clone/clone.test.ts +124 -0
  5. package/s/clone/clone.ts +41 -0
  6. package/s/concurrent.ts +12 -0
  7. package/s/data/anka.ts +66 -0
  8. package/s/data/barname/badge.ts +78 -0
  9. package/s/data/barname/barname.ts +62 -0
  10. package/s/data/barname/demo.ts +49 -0
  11. package/s/data/barname/index.ts +4 -0
  12. package/s/data/barname/utils/prefixes.ts +20 -0
  13. package/s/data/barname/utils/suffixes.ts +20 -0
  14. package/s/data/base58.ts +65 -0
  15. package/s/data/base64.ts +22 -0
  16. package/s/data/base64url.ts +27 -0
  17. package/s/data/bytes.ts +7 -0
  18. package/s/data/hex.ts +35 -0
  19. package/s/data/nomen/demo.ts +8 -0
  20. package/s/data/nomen/grammar.ts +41 -0
  21. package/s/data/nomen/index.ts +5 -0
  22. package/s/data/nomen/nomen.ts +34 -0
  23. package/s/data/nomen/presets/falrysk.ts +112 -0
  24. package/s/data/nomen/types.ts +9 -0
  25. package/s/data/txt.ts +11 -0
  26. package/s/deadline.ts +24 -0
  27. package/s/debounce/debounce.test.ts +73 -0
  28. package/s/debounce/debounce.ts +54 -0
  29. package/s/debounce/types.ts +8 -0
  30. package/s/dedupe.ts +5 -0
  31. package/s/deep/deep.test.ts +8 -0
  32. package/s/deep/deep.ts +11 -0
  33. package/s/deep/parts/equal.test.ts +124 -0
  34. package/s/deep/parts/equal.ts +49 -0
  35. package/s/deep/parts/freeze.ts +34 -0
  36. package/s/defer-promise.ts +29 -0
  37. package/s/escape-regex.ts +5 -0
  38. package/s/hat.ts +17 -0
  39. package/s/index.ts +23 -0
  40. package/s/is.ts +27 -0
  41. package/s/map-g.ts +52 -0
  42. package/s/nap.ts +5 -0
  43. package/s/ob.ts +66 -0
  44. package/s/pipe.ts +24 -0
  45. package/s/pubsub.ts +68 -0
  46. package/s/trash.ts +30 -0
  47. package/x/clone/clone.d.ts +1 -0
  48. package/x/clone/clone.js +26 -0
  49. package/x/clone/clone.js.map +1 -0
  50. package/x/clone/clone.test.d.ts +1 -0
  51. package/x/clone/clone.test.js +125 -0
  52. package/x/clone/clone.test.js.map +1 -0
  53. package/x/concurrent.d.ts +1 -0
  54. package/x/concurrent.js +7 -0
  55. package/x/concurrent.js.map +1 -0
  56. package/x/data/anka.d.ts +5 -0
  57. package/x/data/anka.js +53 -0
  58. package/x/data/anka.js.map +1 -0
  59. package/x/data/barname/badge.d.ts +25 -0
  60. package/x/data/barname/badge.js +64 -0
  61. package/x/data/barname/badge.js.map +1 -0
  62. package/x/data/barname/barname.d.ts +7 -0
  63. package/x/data/barname/barname.js +49 -0
  64. package/x/data/barname/barname.js.map +1 -0
  65. package/x/data/barname/demo.d.ts +1 -0
  66. package/x/data/barname/demo.js +45 -0
  67. package/x/data/barname/demo.js.map +1 -0
  68. package/x/data/barname/index.d.ts +2 -0
  69. package/x/data/barname/index.js +3 -0
  70. package/x/data/barname/index.js.map +1 -0
  71. package/x/data/barname/utils/prefixes.d.ts +1 -0
  72. package/x/data/barname/utils/prefixes.js +19 -0
  73. package/x/data/barname/utils/prefixes.js.map +1 -0
  74. package/x/data/barname/utils/suffixes.d.ts +1 -0
  75. package/x/data/barname/utils/suffixes.js +19 -0
  76. package/x/data/barname/utils/suffixes.js.map +1 -0
  77. package/x/data/base58.d.ts +5 -0
  78. package/x/data/base58.js +58 -0
  79. package/x/data/base58.js.map +1 -0
  80. package/x/data/base64.d.ts +5 -0
  81. package/x/data/base64.js +17 -0
  82. package/x/data/base64.js.map +1 -0
  83. package/x/data/base64url.d.ts +5 -0
  84. package/x/data/base64url.js +22 -0
  85. package/x/data/base64url.js.map +1 -0
  86. package/x/data/bytes.d.ts +3 -0
  87. package/x/data/bytes.js +6 -0
  88. package/x/data/bytes.js.map +1 -0
  89. package/x/data/hex.d.ts +6 -0
  90. package/x/data/hex.js +30 -0
  91. package/x/data/hex.js.map +1 -0
  92. package/x/data/nomen/demo.d.ts +1 -0
  93. package/x/data/nomen/demo.js +5 -0
  94. package/x/data/nomen/demo.js.map +1 -0
  95. package/x/data/nomen/grammar.d.ts +11 -0
  96. package/x/data/nomen/grammar.js +32 -0
  97. package/x/data/nomen/grammar.js.map +1 -0
  98. package/x/data/nomen/index.d.ts +3 -0
  99. package/x/data/nomen/index.js +4 -0
  100. package/x/data/nomen/index.js.map +1 -0
  101. package/x/data/nomen/nomen.d.ts +11 -0
  102. package/x/data/nomen/nomen.js +29 -0
  103. package/x/data/nomen/nomen.js.map +1 -0
  104. package/x/data/nomen/presets/falrysk.d.ts +5 -0
  105. package/x/data/nomen/presets/falrysk.js +99 -0
  106. package/x/data/nomen/presets/falrysk.js.map +1 -0
  107. package/x/data/nomen/types.d.ts +6 -0
  108. package/x/data/nomen/types.js +2 -0
  109. package/x/data/nomen/types.js.map +1 -0
  110. package/x/data/txt.d.ts +4 -0
  111. package/x/data/txt.js +9 -0
  112. package/x/data/txt.js.map +1 -0
  113. package/x/deadline.d.ts +6 -0
  114. package/x/deadline.js +17 -0
  115. package/x/deadline.js.map +1 -0
  116. package/x/debounce/debounce.d.ts +2 -0
  117. package/x/debounce/debounce.js +37 -0
  118. package/x/debounce/debounce.js.map +1 -0
  119. package/x/debounce/debounce.test.d.ts +1 -0
  120. package/x/debounce/debounce.test.js +75 -0
  121. package/x/debounce/debounce.test.js.map +1 -0
  122. package/x/debounce/types.d.ts +2 -0
  123. package/x/debounce/types.js +2 -0
  124. package/x/debounce/types.js.map +1 -0
  125. package/x/dedupe.d.ts +1 -0
  126. package/x/dedupe.js +4 -0
  127. package/x/dedupe.js.map +1 -0
  128. package/x/deep/deep.d.ts +7 -0
  129. package/x/deep/deep.js +9 -0
  130. package/x/deep/deep.js.map +1 -0
  131. package/x/deep/deep.test.d.ts +1 -0
  132. package/x/deep/deep.test.js +10 -0
  133. package/x/deep/deep.test.js.map +1 -0
  134. package/x/deep/parts/equal.d.ts +1 -0
  135. package/x/deep/parts/equal.js +39 -0
  136. package/x/deep/parts/equal.js.map +1 -0
  137. package/x/deep/parts/equal.test.d.ts +1 -0
  138. package/x/deep/parts/equal.test.js +126 -0
  139. package/x/deep/parts/equal.test.js.map +1 -0
  140. package/x/deep/parts/freeze.d.ts +1 -0
  141. package/x/deep/parts/freeze.js +24 -0
  142. package/x/deep/parts/freeze.js.map +1 -0
  143. package/x/defer-promise.d.ts +10 -0
  144. package/x/defer-promise.js +15 -0
  145. package/x/defer-promise.js.map +1 -0
  146. package/x/escape-regex.d.ts +1 -0
  147. package/x/escape-regex.js +4 -0
  148. package/x/escape-regex.js.map +1 -0
  149. package/x/hat.d.ts +6 -0
  150. package/x/hat.js +16 -0
  151. package/x/hat.js.map +1 -0
  152. package/x/index.d.ts +20 -0
  153. package/x/index.js +21 -0
  154. package/x/index.js.map +1 -0
  155. package/x/is.d.ts +10 -0
  156. package/x/is.js +11 -0
  157. package/x/is.js.map +1 -0
  158. package/x/map-g.d.ts +17 -0
  159. package/x/map-g.js +40 -0
  160. package/x/map-g.js.map +1 -0
  161. package/x/nap.d.ts +1 -0
  162. package/x/nap.js +2 -0
  163. package/x/nap.js.map +1 -0
  164. package/x/ob.d.ts +14 -0
  165. package/x/ob.js +21 -0
  166. package/x/ob.js.map +1 -0
  167. package/x/pipe.d.ts +8 -0
  168. package/x/pipe.js +16 -0
  169. package/x/pipe.js.map +1 -0
  170. package/x/pubsub.d.ts +18 -0
  171. package/x/pubsub.js +40 -0
  172. package/x/pubsub.js.map +1 -0
  173. package/x/trash.d.ts +14 -0
  174. package/x/trash.js +25 -0
  175. package/x/trash.js.map +1 -0
@@ -0,0 +1,65 @@
1
+
2
+ /*
3
+
4
+ 256-bit base58 ids look like this:
5
+
6
+ 9X1D9rdkDgRdykzmogNcxfopRc7TnbS869ow1E2ehCFS
7
+ AmRKyNfq6jhhsd9qda1Y6rAVS2NLUqyTUvfcB2wUiiAC
8
+ 8skYcqBAXsejDcJzsZMo19PErt43DHP3bykaXBtMvdu
9
+
10
+ */
11
+
12
+ import {Hex} from "./hex.js"
13
+ import {Bytes} from "./bytes.js"
14
+
15
+ const base = 58
16
+ const characters = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
17
+
18
+ export const Base58 = Object.freeze({
19
+ string(bytes: Uint8Array) {
20
+ let intVal = BigInt("0x" + Hex.string(bytes))
21
+ let encoded = ""
22
+
23
+ while (intVal > 0) {
24
+ const remainder = intVal % BigInt(base)
25
+ intVal = intVal / BigInt(base)
26
+ encoded = characters[Number(remainder)] + encoded
27
+ }
28
+
29
+ for (const byte of bytes) {
30
+ if (byte === 0) encoded = characters[0] + encoded
31
+ else break
32
+ }
33
+
34
+ return encoded
35
+ },
36
+
37
+ bytes(string: string) {
38
+ let intVal = BigInt(0)
39
+
40
+ for (const char of string) {
41
+ const index = characters.indexOf(char)
42
+ if (index === -1) throw new Error(`Invalid character '${char}' in base58 string`)
43
+ intVal = intVal * BigInt(base) + BigInt(index)
44
+ }
45
+
46
+ let hex = intVal.toString(16)
47
+ if (hex.length % 2 !== 0) hex = "0" + hex
48
+ const bytes = Hex.bytes(hex)
49
+
50
+ let leadingZeroes = 0
51
+ for (const char of string) {
52
+ if (char === characters[0]) leadingZeroes++
53
+ else break
54
+ }
55
+
56
+ const decoded = new Uint8Array(leadingZeroes + bytes.length)
57
+ decoded.set(bytes, leadingZeroes)
58
+ return decoded
59
+ },
60
+
61
+ random(count = 32) {
62
+ return this.string(Bytes.random(count))
63
+ },
64
+ })
65
+
@@ -0,0 +1,22 @@
1
+
2
+ import {Bytes} from "./bytes.js"
3
+
4
+ export const Base64 = {
5
+
6
+ string(bytes: Uint8Array) {
7
+ return (typeof btoa === "function")
8
+ ? btoa(String.fromCharCode(...bytes))
9
+ : Buffer.from(bytes).toString("base64")
10
+ },
11
+
12
+ bytes(string: string) {
13
+ return (typeof atob === "function")
14
+ ? Uint8Array.from(atob(string), char => char.charCodeAt(0))
15
+ : Uint8Array.from(Buffer.from(string, "base64"))
16
+ },
17
+
18
+ random(count = 32) {
19
+ return this.string(Bytes.random(count))
20
+ },
21
+ }
22
+
@@ -0,0 +1,27 @@
1
+
2
+ import {Bytes} from "./bytes.js"
3
+ import {Base64} from "./base64.js"
4
+
5
+ export const Base64url = {
6
+
7
+ string(bytes: Uint8Array) {
8
+ return Base64.string(bytes)
9
+ .replace(/\+/g, "-")
10
+ .replace(/\//g, "_")
11
+ .replace(/=+$/g, "")
12
+ },
13
+
14
+ bytes(string: string) {
15
+ let b64 = string
16
+ .replace(/-/g, "+")
17
+ .replace(/_/g, "/")
18
+ if (b64.length % 4 !== 0)
19
+ b64 = b64.padEnd(b64.length + (4 - b64.length % 4) % 4, "=")
20
+ return Base64.bytes(b64)
21
+ },
22
+
23
+ random(count = 32) {
24
+ return this.string(Bytes.random(count))
25
+ },
26
+ }
27
+
@@ -0,0 +1,7 @@
1
+
2
+ export const Bytes = {
3
+ random(count: number) {
4
+ return crypto.getRandomValues(new Uint8Array(count))
5
+ },
6
+ }
7
+
package/s/data/hex.ts ADDED
@@ -0,0 +1,35 @@
1
+
2
+ /*
3
+
4
+ 256-bit hex ids look like this:
5
+
6
+ 8ff8dfbc7c994c5439d2dd327b9898aa6796f97fb396e262985f03f868707e32
7
+ 6b99284a2c4a1c5f101502bd009f9fb592ca4427e4375155e411ddd07ed9da6b
8
+ 2eb73fb00a2b9e38c855b5aa353b530d820a3a2dcea5013b7e4e277ddfe9d0ad
9
+
10
+ */
11
+
12
+ import {Bytes} from "./bytes.js"
13
+
14
+ export const Hex = {
15
+ string(bytes: Uint8Array) {
16
+ return [...bytes]
17
+ .map(byte => byte.toString(16).padStart(2, "0"))
18
+ .join("")
19
+ },
20
+
21
+ bytes(string: string) {
22
+ if (string.length % 2 !== 0)
23
+ throw new Error("must have even number of hex characters")
24
+ const bytes = new Uint8Array(string.length / 2)
25
+ for (let i = 0; i < string.length; i += 2)
26
+ bytes[i / 2] = parseInt(string.slice(i, i + 2), 16)
27
+ return bytes
28
+ },
29
+
30
+ /** generate a random hex string. byteCount defaults to 32. */
31
+ random(byteCount = 32) {
32
+ return this.string(Bytes.random(byteCount))
33
+ },
34
+ }
35
+
@@ -0,0 +1,8 @@
1
+
2
+ import {falryskNameGrammar} from "./presets/falrysk.js"
3
+
4
+ const grammar = falryskNameGrammar()
5
+
6
+ for (const _ of Array(20))
7
+ console.log(grammar.random())
8
+
@@ -0,0 +1,41 @@
1
+
2
+ import {ob} from "../../ob.js"
3
+ import {Bytes} from "../bytes.js"
4
+ import {GrammarTemplate, PhraseFns} from "./types.js"
5
+
6
+ export class Grammar<P extends PhraseFns> {
7
+ constructor(
8
+ public phraseFns: P,
9
+ public templates: GrammarTemplate<P>[],
10
+ ) {}
11
+
12
+ static phrases = <P extends PhraseFns>(phrases: P) => ({
13
+ templates: (templates: GrammarTemplate<P>[]) => (
14
+ new this<P>(phrases, templates)
15
+ ),
16
+ })
17
+
18
+ generate([firstByte, ...bytes]: Uint8Array) {
19
+ const template = this.templates[firstByte % this.templates.length]
20
+ const phraseCount = Object.keys(this.phraseFns).length
21
+ const bytesPerPhrase = Math.floor(bytes.length / phraseCount)
22
+
23
+ let indexCounter = 0
24
+
25
+ const phrases = ob(this.phraseFns).map(fn => {
26
+ const index = indexCounter++
27
+ const start = index * bytesPerPhrase
28
+ const end = Math.min(start + bytesPerPhrase, bytes.length - 1)
29
+ const buffer = new Uint8Array(bytes.slice(start, end))
30
+ return fn(buffer)
31
+ })
32
+
33
+ return template(phrases)
34
+ }
35
+
36
+ random() {
37
+ const buffer = Bytes.random(32)
38
+ return this.generate(buffer)
39
+ }
40
+ }
41
+
@@ -0,0 +1,5 @@
1
+
2
+ export * from "./nomen.js"
3
+ export * from "./grammar.js"
4
+ export * from "./presets/falrysk.js"
5
+
@@ -0,0 +1,34 @@
1
+
2
+ import {Bytes} from "../bytes.js"
3
+ import {Dictionary, Pattern} from "./types.js"
4
+
5
+ export class Nomen<D extends Dictionary> {
6
+ constructor(public dictionary: D, public patterns: Pattern<D>[]) {}
7
+
8
+ static dictionary = <D extends Dictionary>(dictionary: D) => ({
9
+ patterns: (patterns: Pattern<D>[]) => (
10
+ new this<D>(dictionary, patterns)
11
+ ),
12
+ })
13
+
14
+ generate([firstByte, ...bytes]: Uint8Array) {
15
+ const pattern = this.patterns[firstByte % this.patterns.length]
16
+ let index = 0
17
+
18
+ const obtainWordChunk = (key: keyof D) => {
19
+ const dictionary = this.dictionary[key]
20
+ const byte = bytes[(index++) % bytes.length]
21
+ return dictionary[byte % dictionary.length]
22
+ }
23
+
24
+ return pattern
25
+ .map(wordpattern => wordpattern.map(obtainWordChunk).join(""))
26
+ .join(" ")
27
+ }
28
+
29
+ random() {
30
+ const buffer = Bytes.random(32)
31
+ return this.generate(buffer)
32
+ }
33
+ }
34
+
@@ -0,0 +1,112 @@
1
+
2
+ import {Nomen} from "../nomen.js"
3
+ import {Grammar} from "../grammar.js"
4
+
5
+ export function falryskNameGrammar() {
6
+ const person = Nomen
7
+ .dictionary({
8
+ prefix: [
9
+ "Aed", "Ael", "Aer", "Aeg",
10
+ "Aes", "Aet", "Aeon", "Aek",
11
+ "Årg", "Ard", "Arn", "Ayn",
12
+ "Ar", "Ad", "Atl", "An",
13
+ "And", "Anr", "Ain", "Ayn",
14
+ "End", "Esk", "Eld", "Ŏln",
15
+ "Elg", "Erd", "Eyn", "Esn",
16
+ "Olf", "Of", "Oy", "Oc",
17
+ "War", "Wer", "Wot", "Wal",
18
+ "Gäl", "Gar", "Gaer", "Gir",
19
+ "Gor", "Gil", "Ger", "Gan",
20
+ "Thós", "Thès", "Tír", "Tal",
21
+ "Fâl", "Fen", "Fel", "Fol",
22
+ "Fír", "For", "Feyt", "Fern",
23
+ "Feyn", "Fayn", "Feln", "Faln",
24
+ "Ven", "Van", "Vèl", "Val",
25
+ "Veyn", "Vayn", "Veyl", "Vayl",
26
+ "Nýz", "Nor", "Nal", "Nyn",
27
+ "Mór", "Mar", "Myor", "Mor",
28
+ "Lom", "Lem", "Lorn", "Leyn",
29
+ "Kal", "Kel", "Kyel", "Kol",
30
+ "Shel", "Shen", "Shal", "Shey",
31
+ "Pip", "Par", "Pyot", "Poy",
32
+ "Thar", "Ther", "Thor", "Thel",
33
+ "Uyn", "Uer", "Usn", "Uin",
34
+ "Yön", "Yès", "Yol", "Yel",
35
+ "Xen", "Zael", "Zaer", "Zod",
36
+ "Aʼ", "Oʼ",
37
+ ],
38
+
39
+ suffix: [
40
+ "th", "st", "yt", "ft",
41
+ "sk", "rk", "rd", "nd",
42
+ "by", "cy", "ry", "ny",
43
+ "yn", "vn", "vy", "ly",
44
+ "rik", "rek", "nok", "rôk",
45
+ "bie", "rie", "lie",
46
+ "nar", "råg", "lg", "rn",
47
+ ],
48
+
49
+ o: [..."aaeeiou"],
50
+ x: [..."bcdfghklmnprstvwxyz"],
51
+
52
+ oo: [
53
+ "au", "ea", "ía", "oa",
54
+ "áe", "ës", "ie", "oé",
55
+ "aí", "ei", "iû", "uî",
56
+ "al", "eo", "io", "us",
57
+ ],
58
+
59
+ ox: [
60
+ "ës", "us", "is", "os",
61
+ "as", "ar", "er", "or",
62
+ "ad", "ed", "id", "od",
63
+ "aw", "ew", "iw", "ow",
64
+ ],
65
+
66
+ xox: [
67
+ "nak", "nëk", "nud", "nok",
68
+ "rár", "råth", "ýeg", "rin",
69
+ "wég", "wug", "wøg",
70
+ ],
71
+
72
+ oxo: [
73
+ "ana", "ëna", "anu", "irá",
74
+ "arna", "erna", "arnû", "irna",
75
+ "ánla", "ënla", "arlu", "irla",
76
+ "ára", "atho", "oýo", "ina",
77
+ "éwe", "uwa", "øga",
78
+ ],
79
+ })
80
+ .patterns([
81
+ [["prefix", "o"]],
82
+ [["prefix", "oo"]],
83
+ [["prefix", "ox"]],
84
+ [["prefix", "oxo"]],
85
+
86
+ [["prefix", "o", "suffix"]],
87
+ [["prefix", "o", "suffix"]],
88
+ [["prefix", "o", "suffix"]],
89
+ [["prefix", "o", "suffix"]],
90
+
91
+ [["prefix", "oo", "suffix"]],
92
+ [["prefix", "oxo", "suffix"]],
93
+
94
+ // // long names
95
+ // [["prefix", "oo", "x", "oo", "suffix"]],
96
+ // [["prefix", "o", "x", "oo", "suffix"]],
97
+ ])
98
+
99
+ return Grammar
100
+ .phrases({
101
+ first: b => person.generate(b),
102
+ last: b => person.generate(b),
103
+ })
104
+ .templates([
105
+ o => `${o.first} ${o.last}`,
106
+
107
+ // // long names
108
+ // o => `${o.first} of ${o.last}`,
109
+ // o => `${o.first} from ${o.last}`,
110
+ ])
111
+ }
112
+
@@ -0,0 +1,9 @@
1
+
2
+ export type Dictionary = Record<string, string[]>
3
+ export type Pattern<D extends Dictionary> = (keyof D)[][]
4
+
5
+ export type PhraseFn = (bytes: Uint8Array) => string
6
+ export type PhraseFns = Record<string, PhraseFn>
7
+ export type Phrases<P extends PhraseFns> = Record<keyof P, string>
8
+ export type GrammarTemplate<P extends PhraseFns> = (phrases: Phrases<P>) => string
9
+
package/s/data/txt.ts ADDED
@@ -0,0 +1,11 @@
1
+
2
+ export const Txt = {
3
+ string(bytes: Uint8Array) {
4
+ return new TextDecoder().decode(bytes)
5
+ },
6
+
7
+ bytes(string: string) {
8
+ return new TextEncoder().encode(string)
9
+ },
10
+ }
11
+
package/s/deadline.ts ADDED
@@ -0,0 +1,24 @@
1
+
2
+ export class DeadlineError extends Error {
3
+ name = this.constructor.name
4
+ constructor(milliseconds: number) {
5
+ super(`deadline exceeded (${milliseconds.toLocaleString()} ms)`)
6
+ }
7
+ }
8
+
9
+ /** set a deadline for a fn to do something, will reject with a `DeadlineError` if it takes too long */
10
+ export function deadline<R>(milliseconds: number, fn: () => Promise<R>) {
11
+ return new Promise<R>((resolve, reject) => {
12
+
13
+ const id = setTimeout(
14
+ () => reject(new DeadlineError(milliseconds)),
15
+ milliseconds,
16
+ )
17
+
18
+ fn()
19
+ .then(resolve)
20
+ .catch(reject)
21
+ .finally(() => clearTimeout(id))
22
+ })
23
+ }
24
+
@@ -0,0 +1,73 @@
1
+ //
2
+ // import {nap} from "../nap.js"
3
+ // import {Suite, expect} from "cynic"
4
+ // import {debounce as debounce} from "./debounce.js"
5
+ //
6
+ // export default <Suite>{
7
+ // async "reduces many calls into one"() {
8
+ // let count = 0
9
+ // const increment = debounce(100, () => {
10
+ // count += 1
11
+ // })
12
+ // increment()
13
+ // increment()
14
+ // increment()
15
+ // await nap(200)
16
+ // expect(count).equals(1)
17
+ // },
18
+ // async "timer gets reset on each call"() {
19
+ // let count = 0
20
+ // const increment = debounce(100, () => {
21
+ // count += 1
22
+ // })
23
+ // increment()
24
+ // await nap(50)
25
+ // increment()
26
+ // await nap(50)
27
+ // increment()
28
+ // await nap(50)
29
+ // increment()
30
+ // await nap(50)
31
+ // increment()
32
+ // expect(count).equals(0)
33
+ // await nap(101)
34
+ // expect(count).equals(1)
35
+ // },
36
+ // async "provides a promise that resolves when done"() {
37
+ // let count = 0
38
+ // const increment = debounce(100, () => {
39
+ // count += 1
40
+ // })
41
+ // let done = false
42
+ // increment()
43
+ // .then(() => done = true)
44
+ // await nap(50)
45
+ // increment()
46
+ // await nap(50)
47
+ // increment()
48
+ // await nap(50)
49
+ // increment()
50
+ // await nap(50)
51
+ // increment()
52
+ // expect(done).equals(false)
53
+ // await nap(201)
54
+ // expect(done).equals(true)
55
+ // },
56
+ // async "can wait multiple rounds"() {
57
+ // let count = 0
58
+ // const increment = debounce(100, () => {
59
+ // count += 1
60
+ // })
61
+ // await increment()
62
+ // expect(count).equals(1)
63
+ // await increment()
64
+ // expect(count).equals(2)
65
+ // },
66
+ // async "errors are passed into promise chain"() {
67
+ // const err = debounce(1, () => {
68
+ // throw new Error()
69
+ // })
70
+ // await expect(async() => err()).throws()
71
+ // },
72
+ // }
73
+ //
@@ -0,0 +1,54 @@
1
+
2
+ import {AnyFunction, DebounceReturn} from "./types.js"
3
+
4
+ export function debounce<xAction extends AnyFunction>(
5
+ delay: number,
6
+ action: xAction,
7
+ ): DebounceReturn<xAction> {
8
+
9
+ let latestArgs: any[]
10
+ let timeout: any
11
+
12
+ let waitingQueue: {
13
+ resolve: (r: ReturnType<xAction>) => void
14
+ reject: (reason: any) => void
15
+ }[] = []
16
+
17
+ function reset() {
18
+ latestArgs = []
19
+ if (timeout)
20
+ clearTimeout(timeout)
21
+ timeout = undefined
22
+ waitingQueue = []
23
+ }
24
+
25
+ reset()
26
+
27
+ return <DebounceReturn<xAction>>((...args) => {
28
+ latestArgs = args
29
+
30
+ if (timeout)
31
+ clearTimeout(timeout)
32
+
33
+ const promise = new Promise((resolve, reject) => {
34
+ waitingQueue.push({resolve, reject})
35
+ })
36
+
37
+ timeout = setTimeout(() => {
38
+ Promise.resolve()
39
+ .then(() => action(...latestArgs))
40
+ .then(r => {
41
+ for (const {resolve} of waitingQueue)
42
+ resolve(r)
43
+ reset()
44
+ })
45
+ .catch(err => {
46
+ for (const {reject} of waitingQueue)
47
+ reject(err)
48
+ reset()
49
+ })
50
+ }, delay)
51
+
52
+ return promise
53
+ })
54
+ }
@@ -0,0 +1,8 @@
1
+
2
+ export type AnyFunction = (...args: any[]) => any
3
+
4
+ export type DebounceReturn<xAction extends AnyFunction> =
5
+ (...args: Parameters<xAction>) =>
6
+ ReturnType<xAction> extends Promise<any>
7
+ ? ReturnType<xAction>
8
+ : Promise<ReturnType<xAction>>
package/s/dedupe.ts ADDED
@@ -0,0 +1,5 @@
1
+
2
+ export function dedupe<T>(array: T[]) {
3
+ return [...new Set(array)]
4
+ }
5
+
@@ -0,0 +1,8 @@
1
+ //
2
+ // import {Suite} from "cynic"
3
+ // import deepEqual from "./parts/equal.test.js"
4
+ //
5
+ // export default <Suite>{
6
+ // deepEqual,
7
+ // }
8
+ //
package/s/deep/deep.ts ADDED
@@ -0,0 +1,11 @@
1
+
2
+ import {clone} from "../clone/clone.js"
3
+ import {deepEqual} from "./parts/equal.js"
4
+ import {deepFreeze} from "./parts/freeze.js"
5
+
6
+ export const deep = {
7
+ clone,
8
+ equal: deepEqual,
9
+ freeze: deepFreeze,
10
+ }
11
+