@e280/stz 0.0.0-4 → 0.0.0-6

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 (78) hide show
  1. package/package.json +8 -5
  2. package/s/clone/clone.test.ts +123 -123
  3. package/s/data/bytename/badge.test.ts +52 -0
  4. package/s/data/bytename/badge.ts +72 -0
  5. package/s/data/bytename/bytename.test.ts +49 -0
  6. package/s/data/{barname/barname.ts → bytename/bytename.ts} +20 -8
  7. package/s/data/bytename/index.ts +4 -0
  8. package/s/data/bytes.ts +10 -0
  9. package/s/debounce/debounce.test.ts +73 -73
  10. package/s/deep/deep.test.ts +8 -8
  11. package/s/deep/parts/equal.test.ts +123 -124
  12. package/s/index.ts +2 -1
  13. package/s/loopy.ts +12 -0
  14. package/s/tests.test.ts +17 -0
  15. package/x/clone/clone.test.d.ts +15 -1
  16. package/x/clone/clone.test.js +106 -124
  17. package/x/clone/clone.test.js.map +1 -1
  18. package/x/data/bytename/badge.d.ts +25 -0
  19. package/x/data/bytename/badge.js +50 -0
  20. package/x/data/bytename/badge.js.map +1 -0
  21. package/x/data/bytename/badge.test.d.ts +23 -0
  22. package/x/data/bytename/badge.test.js +44 -0
  23. package/x/data/bytename/badge.test.js.map +1 -0
  24. package/x/data/bytename/bytename.d.ts +11 -0
  25. package/x/data/{barname/barname.js → bytename/bytename.js} +11 -9
  26. package/x/data/bytename/bytename.js.map +1 -0
  27. package/x/data/bytename/bytename.test.d.ts +17 -0
  28. package/x/data/bytename/bytename.test.js +41 -0
  29. package/x/data/bytename/bytename.test.js.map +1 -0
  30. package/x/data/bytename/index.d.ts +2 -0
  31. package/x/data/bytename/index.js +3 -0
  32. package/x/data/bytename/index.js.map +1 -0
  33. package/x/data/bytename/utils/prefixes.js.map +1 -0
  34. package/x/data/bytename/utils/suffixes.js.map +1 -0
  35. package/x/data/bytes.d.ts +1 -0
  36. package/x/data/bytes.js +9 -0
  37. package/x/data/bytes.js.map +1 -1
  38. package/x/debounce/debounce.test.d.ts +8 -1
  39. package/x/debounce/debounce.test.js +70 -74
  40. package/x/debounce/debounce.test.js.map +1 -1
  41. package/x/deep/deep.test.d.ts +21 -1
  42. package/x/deep/deep.test.js +5 -9
  43. package/x/deep/deep.test.js.map +1 -1
  44. package/x/deep/parts/equal.test.d.ts +19 -1
  45. package/x/deep/parts/equal.test.js +107 -125
  46. package/x/deep/parts/equal.test.js.map +1 -1
  47. package/x/index.d.ts +2 -1
  48. package/x/index.js +2 -1
  49. package/x/index.js.map +1 -1
  50. package/x/loopy.d.ts +2 -0
  51. package/x/loopy.js +10 -0
  52. package/x/loopy.js.map +1 -0
  53. package/x/tests.test.js +14 -0
  54. package/x/tests.test.js.map +1 -0
  55. package/s/data/barname/badge.ts +0 -78
  56. package/s/data/barname/demo.ts +0 -49
  57. package/s/data/barname/index.ts +0 -4
  58. package/x/data/barname/badge.d.ts +0 -25
  59. package/x/data/barname/badge.js +0 -64
  60. package/x/data/barname/badge.js.map +0 -1
  61. package/x/data/barname/barname.d.ts +0 -7
  62. package/x/data/barname/barname.js.map +0 -1
  63. package/x/data/barname/demo.js +0 -45
  64. package/x/data/barname/demo.js.map +0 -1
  65. package/x/data/barname/index.d.ts +0 -2
  66. package/x/data/barname/index.js +0 -3
  67. package/x/data/barname/index.js.map +0 -1
  68. package/x/data/barname/utils/prefixes.js.map +0 -1
  69. package/x/data/barname/utils/suffixes.js.map +0 -1
  70. /package/{license → LICENSE} +0 -0
  71. /package/{readme.md → README.md} +0 -0
  72. /package/s/data/{barname → bytename}/utils/prefixes.ts +0 -0
  73. /package/s/data/{barname → bytename}/utils/suffixes.ts +0 -0
  74. /package/x/data/{barname → bytename}/utils/prefixes.d.ts +0 -0
  75. /package/x/data/{barname → bytename}/utils/prefixes.js +0 -0
  76. /package/x/data/{barname → bytename}/utils/suffixes.d.ts +0 -0
  77. /package/x/data/{barname → bytename}/utils/suffixes.js +0 -0
  78. /package/x/{data/barname/demo.d.ts → tests.test.d.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e280/stz",
3
- "version": "0.0.0-4",
3
+ "version": "0.0.0-6",
4
4
  "description": "everyday ts fns for everything",
5
5
  "license": "MIT",
6
6
  "author": "Chase Moskal <chasemoskal@gmail.com>",
@@ -12,15 +12,18 @@
12
12
  ],
13
13
  "scripts": {
14
14
  "build": "run-s _clean _links _tsc",
15
+ "test": "node x/tests.test.js --verbose",
16
+ "count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +",
17
+ "start": "run-p _tscw _testw",
15
18
  "_clean": "rm -rf x && mkdir x",
16
19
  "_links": "ln -s \"$(realpath node_modules)\" x/node_modules",
17
20
  "_tsc": "tsc",
18
- "start": "exit 0",
19
- "count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +",
20
- "test": "exit 0"
21
+ "_tscw": "tsc -w",
22
+ "_testw": "node --watch x/tests.test.js --verbose"
21
23
  },
22
24
  "devDependencies": {
23
- "@types/node": "^22.14.1",
25
+ "@e280/science": "^0.0.4",
26
+ "@types/node": "^22.15.3",
24
27
  "npm-run-all": "^4.1.5",
25
28
  "typescript": "^5.8.3"
26
29
  },
@@ -1,124 +1,124 @@
1
- //
2
- // import {Suite, expect} from "cynic"
3
- // import {clone} from "./clone.js"
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).equals(originalEntries)
9
- // expect(cloned).not.equals(original) // check for deep cloning
10
- // }
11
- //
12
- // export default <Suite>{
13
- //
14
- // async "clone primitive types"() {
15
- // expect(clone(123)).equals(123)
16
- // expect(clone("abc")).equals("abc")
17
- // expect(clone(true)).equals(true)
18
- // },
19
- //
20
- // async "clone arrays"() {
21
- // const array = [1, 2, 3]
22
- // const clonedArray = clone(array)
23
- // expect(JSON.stringify(clonedArray)).equals(JSON.stringify(array))
24
- // expect(clonedArray).not.equals(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)).equals(JSON.stringify(object))
31
- // expect(clonedObject).not.equals(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")).equals("value")
39
- // expect(clonedMap).not.equals(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.equals(set)
48
- // },
49
- //
50
- // async "clone Date"() {
51
- // const date = new Date()
52
- // const clonedDate = clone(date)
53
- // expect(clonedDate.getTime()).equals(date.getTime())
54
- // expect(clonedDate).not.equals(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.equals(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)).equals(JSON.stringify(object))
74
- // expect(clonedObject).not.equals(object) // check for deep cloning
75
- // expect(clonedObject.inner).not.equals(object.inner) // check for deep cloning
76
- // expect(clonedObject.inner.deeper).not.equals(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)).equals(JSON.stringify(array))
83
- // expect(clonedArray).not.equals(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)).equals(JSON.stringify(object))
90
- // expect(clonedObject).not.equals(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)).equals(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.equals(true)
117
- // expect(clonedData.obj1).not.equals(clonedData.obj2)
118
- // expect(clonedData.obj1.id).equals(1)
119
- // expect(clonedData.obj1.name).equals("H4CK3RM4N")
120
- // expect(clonedData.obj2.id).equals(1)
121
- // expect(clonedData.obj2.name).equals("H4CK3RM4N")
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
 
@@ -0,0 +1,52 @@
1
+
2
+ import {Hex} from "../hex.js"
3
+ import {Badge} from "./badge.js"
4
+ import {Bytes} from "../bytes.js"
5
+ import {Science, test, expect} from "@e280/science"
6
+
7
+ const sampleBadge = "nodlyn.fasrep:39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k"
8
+ const sampleHex = "88e8c3fad1028fcf6ce5ac491578850f4d833336feca03b608265501c3019d59"
9
+ const sampleBytes = Hex.bytes(sampleHex)
10
+
11
+ function good(bytes: Uint8Array) {
12
+ expect(Bytes.eq(bytes, sampleBytes)).ok()
13
+ }
14
+
15
+ export default Science.suite({
16
+ "bytes->string->bytes": test(async() => {
17
+ const text = Badge.string(sampleBytes)
18
+ expect(text).is(sampleBadge)
19
+ good(Badge.bytes(text))
20
+ }),
21
+
22
+ "zero bytes": test(async() => {
23
+ const text = Badge.string(new Uint8Array([]))
24
+ expect(text).is("")
25
+ expect(Bytes.eq(Badge.bytes(text), new Uint8Array([]))).ok()
26
+ }),
27
+
28
+ "one byte": test(async() => {
29
+ const text = Badge.string(new Uint8Array([0x00]))
30
+ expect(text).is("doz")
31
+ expect(Bytes.eq(Badge.bytes(text), new Uint8Array([0x00]))).ok()
32
+ }),
33
+
34
+ "partially": Science.suite({
35
+ "normal": test(async() => expect(Badge.bytes("nodlyn.fasrep:39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k").length).ok()),
36
+ "nothing": test(async() => expect(Badge.bytes("").length).is(0)),
37
+ "no-rest": test(async() => expect(Badge.bytes("nodlyn.fasrep").length).ok()),
38
+ "one-byte": test(async() => expect(Badge.bytes("nod").length).is(1)),
39
+ "three-byte": test(async() => expect(Badge.bytes("nodlynfas").length).is(3)),
40
+ "one-byte-lead": test(async() => expect(Badge.bytes("nod:39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k").length).ok()),
41
+ }),
42
+
43
+ "tolerance": Science.suite({
44
+ "normal": test(async() => good(Badge.bytes("nodlyn.fasrep:39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k"))),
45
+ "spaces": test(async() => good(Badge.bytes("nodlyn fasrep 39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k"))),
46
+ "dots": test(async() => good(Badge.bytes("nodlyn.fasrep.39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k"))),
47
+ "one-space": test(async() => good(Badge.bytes("nodlynfasrep 39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k"))),
48
+ "one-newline": test(async() => good(Badge.bytes("nodlynfasrep\n39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k"))),
49
+ "whitespace": test(async() => good(Badge.bytes("\t\n nodlyn\n fasrep \n\n\t\n 39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k\n\t"))),
50
+ }),
51
+ })
52
+
@@ -0,0 +1,72 @@
1
+
2
+ import {Base58} from "../base58.js"
3
+ import {Bytename} from "./bytename.js"
4
+
5
+ export type BadgeOptions = {
6
+ leadBytes: number
7
+ leadSeparator: string
8
+ restSeparator: string
9
+ }
10
+
11
+ export type ParsedBadge = {
12
+ lead: string
13
+ rest: string
14
+ bytes: Uint8Array
15
+ }
16
+
17
+ /**
18
+ * Badge is a human-friendly presentation format for arbitrary binary data.
19
+ * - looks like "nodlyn.fasrep:39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k"
20
+ * - the first lead bytes are shown in bytename format
21
+ * - the rest of the data is in base58
22
+ * - designed to be a nice way to present 256-bit passport thumbprints
23
+ * - can actually represent any number of bytes
24
+ * - "nodlyn.fasrep:39gfeGFAAnBzH5pkT7EdoETMUMAekG9h1iymk6k"
25
+ */
26
+ export const Badge = {
27
+ defaults: (<BadgeOptions>{
28
+ leadBytes: 4,
29
+ leadSeparator: ".",
30
+ restSeparator: ":",
31
+ }),
32
+
33
+ string(bytes: Uint8Array, options: Partial<BadgeOptions> = {}) {
34
+ const {leadBytes, leadSeparator, restSeparator}
35
+ = {...Badge.defaults, ...options}
36
+
37
+ const appetizer = Bytename.string(bytes.slice(0, leadBytes), {
38
+ wordSeparator: leadSeparator,
39
+ groupSeparator: leadSeparator,
40
+ })
41
+
42
+ return (bytes.length > leadBytes)
43
+ ? `${appetizer}${restSeparator}${Base58.string(bytes.slice(leadBytes))}`
44
+ : appetizer
45
+ },
46
+
47
+ parse(badge: string): ParsedBadge {
48
+ badge = badge.trim()
49
+ const parts = badge.split(/[^a-zA-Z0-9]+/m)
50
+ .filter(Boolean)
51
+ .map(s => s.trim())
52
+
53
+ if (parts.length < 2) {
54
+ const lead = parts.join(".")
55
+ const bytes = Bytename.bytes(lead)
56
+ return {lead, rest: "", bytes}
57
+ }
58
+
59
+ const rest = parts.pop()!
60
+ const lead = parts.join(".")
61
+ const bytes = new Uint8Array([
62
+ ...Bytename.bytes(lead),
63
+ ...Base58.bytes(rest),
64
+ ])
65
+ return {lead, rest, bytes}
66
+ },
67
+
68
+ bytes(badge: string) {
69
+ return Badge.parse(badge).bytes
70
+ },
71
+ }
72
+
@@ -0,0 +1,49 @@
1
+
2
+ import {Bytes} from "../bytes.js"
3
+ import {Bytename} from "./bytename.js"
4
+ import {Science, test, expect} from "@e280/science"
5
+
6
+ const deadbeef = new Uint8Array([0xDE, 0xAD, 0xBE, 0xEF])
7
+
8
+ function good(bytes: Uint8Array) {
9
+ expect(Bytes.eq(bytes, deadbeef)).ok()
10
+ }
11
+
12
+ export default Science.suite({
13
+ "bytes->string->bytes": test(async() => {
14
+ const text = Bytename.string(deadbeef)
15
+ expect(text).is("ribmug.hilmun")
16
+ good(Bytename.bytes(text))
17
+ }),
18
+
19
+ "zero bytes": test(async() => {
20
+ const text = Bytename.string(new Uint8Array([]))
21
+ expect(text).is("")
22
+ }),
23
+
24
+ "one byte": test(async() => {
25
+ const text = Bytename.string(new Uint8Array([0x00]))
26
+ expect(text).is("doz")
27
+ }),
28
+
29
+ "groupings": test(async() => {
30
+ const bytes = new Uint8Array([...deadbeef, ...deadbeef])
31
+ const text = Bytename.string(bytes, {
32
+ groupSize: 2,
33
+ groupSeparator: " ",
34
+ wordSeparator: ".",
35
+ })
36
+ expect(text).is("ribmug.hilmun ribmug.hilmun")
37
+ }),
38
+
39
+ "wordsep": Science.suite({
40
+ "underscore": test(async() => good(Bytename.bytes("ribmug_hilmun"))),
41
+ "uppercase": test(async() => good(Bytename.bytes("RIBMUG_HILMUN"))),
42
+ "dots": test(async() => good(Bytename.bytes("ribmug.hilmun"))),
43
+ "crushed": test(async() => good(Bytename.bytes("ribmughilmun"))),
44
+ "space": test(async() => good(Bytename.bytes("ribmug hilmun"))),
45
+ "spaces": test(async() => good(Bytename.bytes("ribmug hilmun"))),
46
+ "whitespace": test(async() => good(Bytename.bytes("\n ribmug \n \t \n hilmun \n"))),
47
+ }),
48
+ })
49
+
@@ -3,17 +3,29 @@ import {Bytes} from "../bytes.js"
3
3
  import {prefixes} from "./utils/prefixes.js"
4
4
  import {suffixes} from "./utils/suffixes.js"
5
5
 
6
- const wordSeparator = "_"
7
- const groupSeparator = " "
8
- const defaultWordsPerGroup = 4
6
+ export type BytenameOptions = {
7
+ groupSize: number
8
+ wordSeparator: string
9
+ groupSeparator: string
10
+ }
11
+
12
+ export const Bytename = {
13
+ defaults: (<BytenameOptions>{
14
+ groupSize: 4,
15
+ wordSeparator: ".",
16
+ groupSeparator: " ",
17
+ }),
9
18
 
10
- export const Barname = {
11
- random(byteCount: number) {
12
- return this.string(Bytes.random(byteCount))
19
+ random(byteCount: number, options: Partial<BytenameOptions> = {}) {
20
+ return this.string(Bytes.random(byteCount), options)
13
21
  },
14
22
 
15
- string(bytes: Uint8Array, options?: {wordsPerGroup?: number}) {
16
- const groupSize = options?.wordsPerGroup ?? defaultWordsPerGroup
23
+ string(bytes: Uint8Array, options: Partial<BytenameOptions> = {}) {
24
+ const {
25
+ groupSize = Bytename.defaults.groupSize,
26
+ wordSeparator = Bytename.defaults.wordSeparator,
27
+ groupSeparator = Bytename.defaults.groupSeparator,
28
+ } = options
17
29
 
18
30
  const words: string[] = []
19
31
  let currentWord: string[] = []
@@ -0,0 +1,4 @@
1
+
2
+ export * from "./bytename.js"
3
+ export * from "./badge.js"
4
+
package/s/data/bytes.ts CHANGED
@@ -1,5 +1,15 @@
1
1
 
2
2
  export const Bytes = {
3
+ eq(a: Uint8Array, b: Uint8Array) {
4
+ if (a.length !== b.length)
5
+ return false
6
+ for (let i = 0; i <= a.length; i++) {
7
+ if (a.at(i) !== b.at(i))
8
+ return false
9
+ }
10
+ return true
11
+ },
12
+
3
13
  random(count: number) {
4
14
  return crypto.getRandomValues(new Uint8Array(count))
5
15
  },
@@ -1,73 +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
- //
1
+
2
+ import {nap} from "../nap.js"
3
+ import {Science, expect} from "@e280/science"
4
+ import {debounce as debounce} from "./debounce.js"
5
+
6
+ export default Science.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).is(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).is(0)
33
+ await nap(101)
34
+ expect(count).is(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).is(false)
53
+ await nap(201)
54
+ expect(done).is(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).is(1)
63
+ await increment()
64
+ expect(count).is(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()).throwsAsync()
71
+ },
72
+ })
73
+