@e280/stz 0.0.0-20 → 0.0.0-21

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 (54) hide show
  1. package/README.md +56 -7
  2. package/package.json +5 -4
  3. package/s/data/base-x.ts +164 -0
  4. package/s/data/base58.ts +15 -5
  5. package/s/data/base64.ts +15 -6
  6. package/s/data/base64url.ts +15 -6
  7. package/s/data/bytename/bytename.ts +2 -2
  8. package/s/data/bytename/thumbprint.test.ts +1 -1
  9. package/s/data/bytename/thumbprint.ts +5 -5
  10. package/s/data/bytes.ts +2 -2
  11. package/s/data/data.test.ts +93 -0
  12. package/s/data/hex.ts +15 -5
  13. package/s/data/txt.ts +14 -4
  14. package/s/index.ts +1 -0
  15. package/s/tests.test.ts +12 -10
  16. package/x/data/base-x.d.ts +44 -0
  17. package/x/data/base-x.js +142 -0
  18. package/x/data/base-x.js.map +1 -0
  19. package/x/data/base58.d.ts +5 -1
  20. package/x/data/base58.js +13 -5
  21. package/x/data/base58.js.map +1 -1
  22. package/x/data/base64.d.ts +7 -3
  23. package/x/data/base64.js +13 -5
  24. package/x/data/base64.js.map +1 -1
  25. package/x/data/base64url.d.ts +5 -1
  26. package/x/data/base64url.js +13 -5
  27. package/x/data/base64url.js.map +1 -1
  28. package/x/data/bytename/bytename.js +2 -2
  29. package/x/data/bytename/bytename.js.map +1 -1
  30. package/x/data/bytename/thumbprint.js +5 -5
  31. package/x/data/bytename/thumbprint.js.map +1 -1
  32. package/x/data/bytename/thumbprint.test.js +1 -1
  33. package/x/data/bytename/thumbprint.test.js.map +1 -1
  34. package/x/data/bytes.d.ts +2 -2
  35. package/x/data/bytes.js +2 -2
  36. package/x/data/bytes.js.map +1 -1
  37. package/x/data/data.test.d.ts +68 -0
  38. package/x/data/data.test.js +72 -0
  39. package/x/data/data.test.js.map +1 -0
  40. package/x/data/hex.d.ts +8 -4
  41. package/x/data/hex.js +13 -5
  42. package/x/data/hex.js.map +1 -1
  43. package/x/data/txt.d.ts +6 -2
  44. package/x/data/txt.js +12 -4
  45. package/x/data/txt.js.map +1 -1
  46. package/x/index.d.ts +1 -0
  47. package/x/index.js +1 -0
  48. package/x/index.js.map +1 -1
  49. package/x/tests.test.js +12 -10
  50. package/x/tests.test.js.map +1 -1
  51. package/s/data/anka.ts +0 -66
  52. package/x/data/anka.d.ts +0 -5
  53. package/x/data/anka.js +0 -53
  54. package/x/data/anka.js.map +0 -1
package/README.md CHANGED
@@ -81,8 +81,57 @@ standard library of environment-agnostic typescript functions we use basically e
81
81
 
82
82
  <br/>
83
83
 
84
+ ## Data utilities
85
+ > codecs for representing data in different ways
86
+
87
+ ### BaseX
88
+ - make a BaseX instance
89
+ ```ts
90
+ import {BaseX} from "@e280/stz"
91
+
92
+ const hex = new BaseX(BaseX.lexicons.hex)
93
+ ```
94
+ - convert between strings and binary
95
+ ```ts
96
+ hex.toBytes("9960cd633a46acfe8307d8a400e842da0d930a75fb8188e0f5da264e4b6b4e5b")
97
+ // Uint8Array
98
+
99
+ hex.fromBytes(bytes)
100
+ // string
101
+ ```
102
+ - you can also convert between strings and integers
103
+ ```ts
104
+ hex.fromInteger(Date.now())
105
+ // "197140ac804"
106
+
107
+ hex.toInteger(hex)
108
+ // 1748387940356
109
+ ```
110
+ - available lexicons include
111
+ - base2
112
+ - hex
113
+ - base36
114
+ - base58
115
+ - base62
116
+ - base64 (with standard padding)
117
+ - base64url
118
+ - you can make insanely compact timestamps like this:
119
+ ```ts
120
+ import {BaseX} from "@e280/stz"
121
+
122
+ const base62 = new BaseX(BaseX.lexicons.base62)
123
+
124
+ base62.fromInteger(Date.now() / 1000)
125
+ // "1uK3au"
126
+ ```
127
+ - `1748388028` base10 epoch seconds (10 chars)
128
+ - `1uK3au` base62 epoch seconds (6 chars)
129
+ - *nice*
130
+
131
+ <br/>
132
+
84
133
  ## Bytename
85
- ### friendly string encoding for binary data
134
+ > friendly string encoding for binary data
86
135
 
87
136
  a bytename looks like `"midsen.picmyn.widrep.baclut dotreg.filtyp.nosnus.siptev"`. that's 16 bytes. each byte maps to a three-letter triplet
88
137
 
@@ -105,12 +154,12 @@ import {Bytename} from "@e280/stz"
105
154
  0xDE, 0xAD, 0xBE, 0xEF,
106
155
  ])
107
156
 
108
- Bytename.fromBytes(bytes, {
109
- groupSize: 2, // default is 4
110
- groupSeparator: " ",
111
- wordSeparator: ".",
112
- })
113
- // "ribmug.hilmun ribmug.hilmun"
157
+ Bytename.fromBytes(bytes, {
158
+ groupSize: 2, // default is 4
159
+ groupSeparator: " ",
160
+ wordSeparator: ".",
161
+ })
162
+ // "ribmug.hilmun ribmug.hilmun"
114
163
  ```
115
164
 
116
165
  <br/>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e280/stz",
3
- "version": "0.0.0-20",
3
+ "version": "0.0.0-21",
4
4
  "description": "everyday ts fns for everything",
5
5
  "license": "MIT",
6
6
  "author": "Chase Moskal <chasemoskal@gmail.com>",
@@ -13,13 +13,14 @@
13
13
  "scripts": {
14
14
  "build": "run-s _clean _links _tsc",
15
15
  "test": "node x/tests.test.js",
16
+ "test-watch": "node --watch x/tests.test.js",
17
+ "test-inspect": "node inspect x/tests.test.js",
16
18
  "count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +",
17
- "start": "run-p _tscw _testw",
19
+ "watch": "run-p _tscw test-watch",
18
20
  "_clean": "rm -rf x && mkdir x",
19
21
  "_links": "ln -s \"$(realpath node_modules)\" x/node_modules",
20
22
  "_tsc": "tsc",
21
- "_tscw": "tsc -w",
22
- "_testw": "node --watch x/tests.test.js"
23
+ "_tscw": "tsc -w"
23
24
  },
24
25
  "devDependencies": {
25
26
  "@e280/science": "^0.0.4",
@@ -0,0 +1,164 @@
1
+
2
+ import {Bytes} from "./bytes.js"
3
+
4
+ export type Lexicon = {
5
+ characters: string
6
+ padding?: {
7
+ character: string
8
+ size: number
9
+ }
10
+ }
11
+
12
+ export class BaseX {
13
+ static lexicons = Object.freeze({
14
+ base2: {characters: "01"},
15
+ hex: {characters: "0123456789abcdef"},
16
+ base36: {characters: "0123456789abcdefghijklmnopqrstuvwxyz"},
17
+ base58: {characters: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"},
18
+ base62: {characters: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"},
19
+ base64url: {characters: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"},
20
+ base64: {
21
+ characters: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
22
+ padding: {character: "=", size: 4},
23
+ },
24
+ })
25
+
26
+ private lookup: Record<string, number>
27
+
28
+ constructor(public lexicon: Lexicon) {
29
+ this.lookup = Object.fromEntries(
30
+ [...lexicon.characters].map((char, i) => [char, i])
31
+ )
32
+ }
33
+
34
+ toBytes(s: string): Uint8Array {
35
+ const bitsPerChar = Math.log2(this.lexicon.characters.length)
36
+ if (Number.isInteger(bitsPerChar)) {
37
+ // Bitstream mode (for power-of-2 lexicons)
38
+ let bitBuffer = 0
39
+ let bitCount = 0
40
+ const output: number[] = []
41
+
42
+ for (const char of s) {
43
+ if (char === this.lexicon.padding?.character) continue
44
+ const val = this.lookup[char]
45
+ if (val === undefined) throw new Error(`Invalid character: ${char}`)
46
+ bitBuffer = (bitBuffer << bitsPerChar) | val
47
+ bitCount += bitsPerChar
48
+
49
+ while (bitCount >= 8) {
50
+ bitCount -= 8
51
+ output.push((bitBuffer >> bitCount) & 0xFF)
52
+ }
53
+ }
54
+
55
+ return new Uint8Array(output)
56
+ }
57
+
58
+ // Radix mode fallback
59
+ let num = 0n
60
+ const base = BigInt(this.lexicon.characters.length)
61
+ let negative = false
62
+ if (s.startsWith("-")) {
63
+ s = s.slice(1)
64
+ negative = true
65
+ }
66
+ for (const char of s) {
67
+ const val = this.lookup[char]
68
+ if (val === undefined) throw new Error(`Invalid character: ${char}`)
69
+ num = num * base + BigInt(val)
70
+ }
71
+ const out: number[] = []
72
+ while (num > 0n) {
73
+ out.unshift(Number(num % 256n))
74
+ num = num / 256n
75
+ }
76
+ return new Uint8Array(out)
77
+ }
78
+
79
+ fromBytes(bytes: Uint8Array): string {
80
+ const bitsPerChar = Math.log2(this.lexicon.characters.length)
81
+ if (Number.isInteger(bitsPerChar)) {
82
+ // Bitstream mode (for power-of-2 lexicons)
83
+ let bitBuffer = 0
84
+ let bitCount = 0
85
+ let out = ""
86
+
87
+ for (const byte of bytes) {
88
+ bitBuffer = (bitBuffer << 8) | byte
89
+ bitCount += 8
90
+
91
+ while (bitCount >= bitsPerChar) {
92
+ bitCount -= bitsPerChar
93
+ const index = (bitBuffer >> bitCount) & ((1 << bitsPerChar) - 1)
94
+ out += this.lexicon.characters[index]
95
+ }
96
+ }
97
+
98
+ // 🩹 flush remaining bits
99
+ if (bitCount > 0) {
100
+ const index = (bitBuffer << (bitsPerChar - bitCount)) & ((1 << bitsPerChar) - 1)
101
+ out += this.lexicon.characters[index]
102
+ }
103
+
104
+ // Add padding if applicable
105
+ if (this.lexicon.padding) {
106
+ while (out.length % this.lexicon.padding.size !== 0)
107
+ out += this.lexicon.padding.character
108
+ }
109
+
110
+ return out
111
+ }
112
+
113
+ // Radix mode fallback
114
+ let num = 0n
115
+ for (const byte of bytes)
116
+ num = (num << 8n) + BigInt(byte)
117
+
118
+ if (num === 0n) return this.lexicon.characters[0]
119
+
120
+ const base = BigInt(this.lexicon.characters.length)
121
+ let out = ""
122
+ while (num > 0n) {
123
+ out = this.lexicon.characters[Number(num % base)] + out
124
+ num = num / base
125
+ }
126
+ return out
127
+ }
128
+
129
+ toInteger(s: string) {
130
+ if (!s) return 0
131
+ let n = 0n
132
+ let negative = false
133
+ const base = BigInt(this.lexicon.characters.length)
134
+ if (s.startsWith("-")) {
135
+ s = s.slice(1)
136
+ negative = true
137
+ }
138
+ for (const char of s) {
139
+ const value = this.lookup[char]
140
+ if (value === undefined) throw new Error(`Invalid character: ${char}`)
141
+ n = n * base + BigInt(value)
142
+ }
143
+ return Number(negative ? -n : n)
144
+ }
145
+
146
+ fromInteger(n: number) {
147
+ n = Math.floor(n)
148
+ const negative = n < 0
149
+ let num = BigInt(negative ? -n : n)
150
+ if (num === 0n) return this.lexicon.characters[0]
151
+ const base = BigInt(this.lexicon.characters.length)
152
+ let out = ""
153
+ while (num > 0n) {
154
+ out = this.lexicon.characters[Number(num % base)] + out
155
+ num = num / base
156
+ }
157
+ return negative ? `-${out}` : out
158
+ }
159
+
160
+ random(count = 32) {
161
+ return this.fromBytes(Bytes.random(count))
162
+ }
163
+ }
164
+
package/s/data/base58.ts CHANGED
@@ -16,8 +16,8 @@ const base = 58
16
16
  const characters = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
17
17
 
18
18
  export const Base58 = Object.freeze({
19
- string(bytes: Uint8Array) {
20
- let intVal = BigInt("0x" + Hex.string(bytes))
19
+ fromBytes(bytes: Uint8Array) {
20
+ let intVal = BigInt("0x" + Hex.fromBytes(bytes))
21
21
  let encoded = ""
22
22
 
23
23
  while (intVal > 0) {
@@ -34,7 +34,7 @@ export const Base58 = Object.freeze({
34
34
  return encoded
35
35
  },
36
36
 
37
- bytes(string: string) {
37
+ toBytes(string: string) {
38
38
  let intVal = BigInt(0)
39
39
 
40
40
  for (const char of string) {
@@ -45,7 +45,7 @@ export const Base58 = Object.freeze({
45
45
 
46
46
  let hex = intVal.toString(16)
47
47
  if (hex.length % 2 !== 0) hex = "0" + hex
48
- const bytes = Hex.bytes(hex)
48
+ const bytes = Hex.toBytes(hex)
49
49
 
50
50
  let leadingZeroes = 0
51
51
  for (const char of string) {
@@ -59,7 +59,17 @@ export const Base58 = Object.freeze({
59
59
  },
60
60
 
61
61
  random(count = 32) {
62
- return this.string(Bytes.random(count))
62
+ return this.fromBytes(Bytes.random(count))
63
+ },
64
+
65
+ /** @deprecated renamed to `fromBytes` */
66
+ string(bytes: Uint8Array) {
67
+ return Base58.fromBytes(bytes)
68
+ },
69
+
70
+ /** @deprecated renamed to `toBytes` */
71
+ bytes(string: string) {
72
+ return Base58.toBytes(string)
63
73
  },
64
74
  })
65
75
 
package/s/data/base64.ts CHANGED
@@ -1,22 +1,31 @@
1
1
 
2
2
  import {Bytes} from "./bytes.js"
3
3
 
4
- export const Base64 = {
5
-
6
- string(bytes: Uint8Array) {
4
+ export const Base64 = Object.freeze({
5
+ fromBytes(bytes: Uint8Array) {
7
6
  return (typeof btoa === "function")
8
7
  ? btoa(String.fromCharCode(...bytes))
9
8
  : Buffer.from(bytes).toString("base64")
10
9
  },
11
10
 
12
- bytes(string: string) {
11
+ toBytes(string: string) {
13
12
  return (typeof atob === "function")
14
13
  ? Uint8Array.from(atob(string), char => char.charCodeAt(0))
15
14
  : Uint8Array.from(Buffer.from(string, "base64"))
16
15
  },
17
16
 
18
17
  random(count = 32) {
19
- return this.string(Bytes.random(count))
18
+ return this.fromBytes(Bytes.random(count))
19
+ },
20
+
21
+ /** @deprecated rename to "fromBytes" */
22
+ string(bytes: Uint8Array) {
23
+ return Base64.fromBytes(bytes)
24
+ },
25
+
26
+ /** @deprecated rename to "toBytes" */
27
+ bytes(string: string) {
28
+ return Base64.toBytes(string)
20
29
  },
21
- }
30
+ })
22
31
 
@@ -3,25 +3,34 @@ import {Bytes} from "./bytes.js"
3
3
  import {Base64} from "./base64.js"
4
4
 
5
5
  export const Base64url = {
6
-
7
- string(bytes: Uint8Array) {
8
- return Base64.string(bytes)
6
+ fromBytes(bytes: Uint8Array) {
7
+ return Base64.fromBytes(bytes)
9
8
  .replace(/\+/g, "-")
10
9
  .replace(/\//g, "_")
11
10
  .replace(/=+$/g, "")
12
11
  },
13
12
 
14
- bytes(string: string) {
13
+ toBytes(string: string) {
15
14
  let b64 = string
16
15
  .replace(/-/g, "+")
17
16
  .replace(/_/g, "/")
18
17
  if (b64.length % 4 !== 0)
19
18
  b64 = b64.padEnd(b64.length + (4 - b64.length % 4) % 4, "=")
20
- return Base64.bytes(b64)
19
+ return Base64.toBytes(b64)
21
20
  },
22
21
 
23
22
  random(count = 32) {
24
- return this.string(Bytes.random(count))
23
+ return this.fromBytes(Bytes.random(count))
24
+ },
25
+
26
+ /** @deprecated renamed to "fromBytes" */
27
+ string(bytes: Uint8Array) {
28
+ return Base64url.fromBytes(bytes)
29
+ },
30
+
31
+ /** @deprecated renamed to "toBytes" */
32
+ bytes(string: string) {
33
+ return Base64url.toBytes(string)
25
34
  },
26
35
  }
27
36
 
@@ -80,11 +80,11 @@ export const Bytename = {
80
80
  },
81
81
 
82
82
  toHex(bytename: string) {
83
- return Hex.string(Bytename.toBytes(bytename))
83
+ return Hex.fromBytes(Bytename.toBytes(bytename))
84
84
  },
85
85
 
86
86
  fromHex(hex: string, options?: Partial<BytenameOptions>) {
87
- return Bytename.fromBytes(Hex.bytes(hex), options)
87
+ return Bytename.fromBytes(Hex.toBytes(hex), options)
88
88
  },
89
89
  }
90
90
 
@@ -6,7 +6,7 @@ import {Thumbprint} from "./thumbprint.js"
6
6
 
7
7
  const sampleThumbprint = "nodlyn.fasrep.habbud.ralwel.Avo7gFmdWMRHkwsD149mcaBoZdS69iXuJ"
8
8
  const sampleHex = "88e8c3fad1028fcf6ce5ac491578850f4d833336feca03b608265501c3019d59"
9
- const sampleBytes = Hex.bytes(sampleHex)
9
+ const sampleBytes = Hex.toBytes(sampleHex)
10
10
 
11
11
  function good(bytes: Uint8Array) {
12
12
  expect(Bytes.eq(bytes, sampleBytes)).ok()
@@ -46,7 +46,7 @@ export const Thumbprint = {
46
46
 
47
47
  return new Uint8Array([
48
48
  ...Bytename.toBytes(preview),
49
- ...Base58.bytes(bulk),
49
+ ...Base58.toBytes(bulk),
50
50
  ])
51
51
  },
52
52
 
@@ -71,7 +71,7 @@ export const Thumbprint = {
71
71
  const preview = yoink(previewBytes)
72
72
 
73
73
  const bulk = (bytes.length > previewBytes)
74
- ? Base58.string(bytes.slice(previewBytes))
74
+ ? Base58.fromBytes(bytes.slice(previewBytes))
75
75
  : ""
76
76
 
77
77
  const thumbprint = [preview, bulk]
@@ -82,14 +82,14 @@ export const Thumbprint = {
82
82
  },
83
83
 
84
84
  fromHex(hex: string, options?: Partial<ThumbprintOptions>) {
85
- const bytes = Hex.bytes(hex)
85
+ const bytes = Hex.toBytes(hex)
86
86
  return Thumbprint.build.fromBytes(bytes, options)
87
87
  },
88
88
  },
89
89
 
90
90
  toHex(thumbprint: string) {
91
91
  const bytes = Thumbprint.toBytes(thumbprint)
92
- return Hex.string(bytes)
92
+ return Hex.fromBytes(bytes)
93
93
  },
94
94
 
95
95
  fromBytes(bytes: Uint8Array, options?: Partial<ThumbprintOptions>) {
@@ -97,7 +97,7 @@ export const Thumbprint = {
97
97
  },
98
98
 
99
99
  fromHex(hex: string, options?: Partial<ThumbprintOptions>) {
100
- return Thumbprint.fromBytes(Hex.bytes(hex), options)
100
+ return Thumbprint.fromBytes(Hex.toBytes(hex), options)
101
101
  },
102
102
 
103
103
  sigil: {
package/s/data/bytes.ts CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- export const Bytes = {
2
+ export const Bytes = Object.freeze({
3
3
  eq(a: Uint8Array, b: Uint8Array) {
4
4
  if (a.length !== b.length)
5
5
  return false
@@ -13,5 +13,5 @@ export const Bytes = {
13
13
  random(count: number) {
14
14
  return crypto.getRandomValues(new Uint8Array(count))
15
15
  },
16
- }
16
+ })
17
17
 
@@ -0,0 +1,93 @@
1
+
2
+ import {Science, test, expect} from "@e280/science"
3
+ import {ob} from "../ob.js"
4
+ import {Txt} from "./txt.js"
5
+ import {Hex} from "./hex.js"
6
+ import {Bytes} from "./bytes.js"
7
+ import {BaseX} from "./base-x.js"
8
+ import {Base58} from "./base58.js"
9
+ import {Base64} from "./base64.js"
10
+ import {Base64url} from "./base64url.js"
11
+
12
+ const sampleBytes = Hex.toBytes("9960cd633a46acfe8307d8a400e842da0d930a75fb8188e0f5da264e4b6b4e5b")
13
+
14
+ type ByteUtil = {
15
+ toBytes: (string: string) => Uint8Array
16
+ fromBytes: (bytes: Uint8Array) => string
17
+ }
18
+
19
+ type NumberUtil = {
20
+ toInteger: (s: string) => number
21
+ fromInteger: (n: number) => string
22
+ }
23
+
24
+ function testBytes(util: ByteUtil) {
25
+ return async() => {
26
+ const string = util.fromBytes(sampleBytes)
27
+ const recreated = util.toBytes(string)
28
+ expect(Bytes.eq(sampleBytes, recreated)).ok()
29
+ }
30
+ }
31
+
32
+ function testNumbers(util: NumberUtil) {
33
+ return {
34
+ positive: async() => {
35
+ const original = 123456789
36
+ const string = util.fromInteger(original)
37
+ const recreated = util.toInteger(string)
38
+ expect(original).is(recreated)
39
+ expect(util.toInteger("")).is(0)
40
+ },
41
+ negative: async() => {
42
+ const original = -123456789
43
+ const string = util.fromInteger(original)
44
+ const recreated = util.toInteger(string)
45
+ expect(original).is(recreated)
46
+ expect(util.toInteger("")).is(0)
47
+ },
48
+ }
49
+ }
50
+
51
+ function testBoth(util: ByteUtil & NumberUtil) {
52
+ return {
53
+ bytes: testBytes(util),
54
+ numbers: testNumbers(util),
55
+ }
56
+ }
57
+
58
+ function testCompat(alpha: ByteUtil, bravo: ByteUtil) {
59
+ return async() => {
60
+ expect(alpha.fromBytes(sampleBytes))
61
+ .is(bravo.fromBytes(sampleBytes))
62
+ }
63
+ }
64
+
65
+ export default Science.suite({
66
+ "Base58": testBytes(Base58),
67
+ "Base64": testBytes(Base64),
68
+ "Base64url": testBytes(Base64url),
69
+ "Hex": testBytes(Hex),
70
+
71
+ "Txt": test(async() => {
72
+ const original = `build or die. 💻>☠️ 命火工`
73
+ const bytes = Txt.toBytes(original)
74
+ const recreated = Txt.fromBytes(bytes)
75
+ expect(original).is(recreated)
76
+ }),
77
+
78
+ "BaseX": Science.suite({
79
+ lexicons: Science.suite(
80
+ ob(BaseX.lexicons).map(lex => testBoth(new BaseX(lex)))
81
+ ),
82
+ compat: Science.suite({
83
+ "Hex": testCompat(Hex, new BaseX(BaseX.lexicons.hex)),
84
+ "Base64": testCompat(Base64, new BaseX(BaseX.lexicons.base64)),
85
+ "Base64url": testCompat(Base64url, new BaseX(BaseX.lexicons.base64url)),
86
+ }),
87
+ "base64 has padding": test(async() => {
88
+ const s = new BaseX(BaseX.lexicons.base64).fromBytes(sampleBytes)
89
+ expect(s.endsWith("=")).ok()
90
+ }),
91
+ }),
92
+ })
93
+
package/s/data/hex.ts CHANGED
@@ -11,14 +11,14 @@
11
11
 
12
12
  import {Bytes} from "./bytes.js"
13
13
 
14
- export const Hex = {
15
- string(bytes: Uint8Array) {
14
+ export const Hex = Object.freeze({
15
+ fromBytes(bytes: Uint8Array) {
16
16
  return [...bytes]
17
17
  .map(byte => byte.toString(16).padStart(2, "0"))
18
18
  .join("")
19
19
  },
20
20
 
21
- bytes(string: string) {
21
+ toBytes(string: string) {
22
22
  if (string.length % 2 !== 0)
23
23
  throw new Error("must have even number of hex characters")
24
24
  const bytes = new Uint8Array(string.length / 2)
@@ -29,7 +29,17 @@ export const Hex = {
29
29
 
30
30
  /** generate a random hex string. byteCount defaults to 32. */
31
31
  random(byteCount = 32) {
32
- return this.string(Bytes.random(byteCount))
32
+ return this.fromBytes(Bytes.random(byteCount))
33
+ },
34
+
35
+ /** @deprecated renamed to `fromBytes` */
36
+ string(bytes: Uint8Array) {
37
+ return Hex.fromBytes(bytes)
38
+ },
39
+
40
+ /** @deprecated renamed to `toBytes` */
41
+ bytes(string: string) {
42
+ return Hex.toBytes(string)
33
43
  },
34
- }
44
+ })
35
45
 
package/s/data/txt.ts CHANGED
@@ -1,11 +1,21 @@
1
1
 
2
- export const Txt = {
3
- string(bytes: Uint8Array) {
2
+ export const Txt = Object.freeze({
3
+ fromBytes(bytes: Uint8Array) {
4
4
  return new TextDecoder().decode(bytes)
5
5
  },
6
6
 
7
- bytes(string: string) {
7
+ toBytes(string: string) {
8
8
  return new TextEncoder().encode(string)
9
9
  },
10
- }
10
+
11
+ /** @deprecated renamed to `fromBytes` */
12
+ string(bytes: Uint8Array) {
13
+ return Txt.fromBytes(bytes)
14
+ },
15
+
16
+ /** @deprecated renamed to `toBytes` */
17
+ bytes(string: string) {
18
+ return Txt.toBytes(string)
19
+ },
20
+ })
11
21
 
package/s/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
 
2
2
  export * from "./data/bytename/index.js"
3
+ export * from "./data/base-x.js"
3
4
  export * from "./data/base58.js"
4
5
  export * from "./data/base64.js"
5
6
  export * from "./data/base64url.js"
package/s/tests.test.ts CHANGED
@@ -1,17 +1,19 @@
1
1
 
2
2
  import {Science} from "@e280/science"
3
3
 
4
- import cloneTest from "./clone/clone.test.js"
5
- import thumbprintTest from "./data/bytename/thumbprint.test.js"
6
- import debounceTest from "./debounce/debounce.test.js"
7
- import bytenameTest from "./data/bytename/bytename.test.js"
8
- import deepTest from "./deep/deep.test.js"
4
+ import clone from "./clone/clone.test.js"
5
+ import thumbprint from "./data/bytename/thumbprint.test.js"
6
+ import debounce from "./debounce/debounce.test.js"
7
+ import bytename from "./data/bytename/bytename.test.js"
8
+ import deep from "./deep/deep.test.js"
9
+ import data from "./data/data.test.js"
9
10
 
10
11
  await Science.run({
11
- clone: cloneTest,
12
- bytename: bytenameTest,
13
- thumbprint: thumbprintTest,
14
- debounce: debounceTest,
15
- deep: deepTest,
12
+ clone,
13
+ bytename,
14
+ thumbprint,
15
+ debounce,
16
+ deep,
17
+ data,
16
18
  })
17
19