@wtasnorg/node-lib 0.0.10 → 0.0.12

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 (62) hide show
  1. package/changelog.txt +14 -0
  2. package/docs/README.md +17 -0
  3. package/docs/docs.json +2148 -413
  4. package/docs/functions/countOnes.md +31 -0
  5. package/docs/functions/countZeroes.md +32 -0
  6. package/docs/functions/countZeroesWithWidth.md +37 -0
  7. package/docs/functions/createFindDirectories.md +3 -3
  8. package/docs/functions/decode.md +3 -3
  9. package/docs/functions/decode32.md +49 -0
  10. package/docs/functions/decode58.md +49 -0
  11. package/docs/functions/decode85.md +49 -0
  12. package/docs/functions/encode.md +3 -3
  13. package/docs/functions/encode32.md +45 -0
  14. package/docs/functions/encode58.md +45 -0
  15. package/docs/functions/encode85.md +45 -0
  16. package/docs/functions/hello.md +1 -1
  17. package/docs/functions/parseUserAgent.md +1 -1
  18. package/docs/functions/pojo.md +1 -1
  19. package/docs/functions/popcount32.md +27 -0
  20. package/docs/functions/popcount64.md +31 -0
  21. package/docs/interfaces/FileSystemDependencies.md +3 -3
  22. package/docs/interfaces/FindDirectoriesOptions.md +5 -5
  23. package/docs/interfaces/UserAgentInfo.md +6 -6
  24. package/docs/type-aliases/Base32CharsetType.md +13 -0
  25. package/docs/type-aliases/Base58CharsetType.md +13 -0
  26. package/docs/type-aliases/Base64CharsetType.md +1 -1
  27. package/docs/type-aliases/Base85CharsetType.md +13 -0
  28. package/docs/variables/Base32Charset.md +16 -0
  29. package/docs/variables/Base58Charset.md +16 -0
  30. package/docs/variables/Base64Charset.md +1 -1
  31. package/docs/variables/Base85Charset.md +16 -0
  32. package/package.json +52 -8
  33. package/readme.txt +30 -4
  34. package/src/base32.d.ts +58 -0
  35. package/src/base32.js +143 -0
  36. package/src/base32.test.d.ts +2 -0
  37. package/src/base32.test.js +121 -0
  38. package/src/base32.test.ts +144 -0
  39. package/src/base32.ts +169 -0
  40. package/src/base58.d.ts +58 -0
  41. package/src/base58.js +155 -0
  42. package/src/base58.test.d.ts +2 -0
  43. package/src/base58.test.js +108 -0
  44. package/src/base58.test.ts +128 -0
  45. package/src/base58.ts +177 -0
  46. package/src/base85.d.ts +58 -0
  47. package/src/base85.js +173 -0
  48. package/src/base85.test.d.ts +2 -0
  49. package/src/base85.test.js +107 -0
  50. package/src/base85.test.ts +125 -0
  51. package/src/base85.ts +199 -0
  52. package/src/bits.d.ts +43 -0
  53. package/src/bits.js +117 -0
  54. package/src/bits.test.d.ts +2 -0
  55. package/src/bits.test.js +62 -0
  56. package/src/bits.test.ts +77 -0
  57. package/src/bits.ts +135 -0
  58. package/src/index.d.ts +9 -2
  59. package/src/index.js +5 -1
  60. package/src/index.ts +26 -2
  61. package/.github/workflows/npm-publish.yml +0 -36
  62. package/.github/workflows/npm-test-on-pr.yml +0 -30
@@ -0,0 +1,128 @@
1
+ import { describe, it } from "node:test";
2
+ import { strictEqual, throws } from "node:assert";
3
+ import { encode58, decode58, Base58Charset } from "./base58.js";
4
+ import type { Base58CharsetType } from "./base58.js";
5
+
6
+ describe("Base58 encode58", () => {
7
+ it("encodes empty string", () => {
8
+ strictEqual(encode58(""), "");
9
+ });
10
+
11
+ it("encodes 'Hello World' with bitcoin charset", () => {
12
+ strictEqual(encode58("Hello World"), "JxF12TrwUP45BMd");
13
+ });
14
+
15
+ it("encodes single character", () => {
16
+ // Verify round-trip rather than hardcoded value
17
+ const encoded = encode58("A");
18
+ strictEqual(encoded.length > 0, true);
19
+ strictEqual(decode58(encoded), "A");
20
+ });
21
+
22
+ it("encodes 'abc'", () => {
23
+ strictEqual(encode58("abc"), "ZiCa");
24
+ });
25
+
26
+ it("encodes with flickr charset", () => {
27
+ const bitcoin = encode58("Hello World", "bitcoin");
28
+ const flickr = encode58("Hello World", "flickr");
29
+ // Flickr swaps case
30
+ strictEqual(bitcoin !== flickr, true);
31
+ });
32
+
33
+ it("encodes with ripple charset", () => {
34
+ const bitcoin = encode58("Hello World", "bitcoin");
35
+ const ripple = encode58("Hello World", "ripple");
36
+ strictEqual(bitcoin !== ripple, true);
37
+ });
38
+
39
+ it("encodes UTF-8 characters", () => {
40
+ const input = "こんにちは";
41
+ const encoded = encode58(input);
42
+ const decoded = decode58(encoded);
43
+ strictEqual(decoded, input);
44
+ });
45
+
46
+ it("preserves leading zero bytes", () => {
47
+ const input = "\x00\x00Hello";
48
+ const encoded = encode58(input);
49
+ const decoded = decode58(encoded);
50
+ strictEqual(decoded, input);
51
+ });
52
+ });
53
+
54
+ describe("Base58 decode58", () => {
55
+ it("decodes empty string", () => {
56
+ strictEqual(decode58(""), "");
57
+ });
58
+
59
+ it("decodes 'JxF12TrwUP45BMd' to 'Hello World'", () => {
60
+ strictEqual(decode58("JxF12TrwUP45BMd"), "Hello World");
61
+ });
62
+
63
+ it("decodes single character", () => {
64
+ const encoded = encode58("A");
65
+ strictEqual(decode58(encoded), "A");
66
+ });
67
+
68
+ it("decodes 'ZiCa' to 'abc'", () => {
69
+ strictEqual(decode58("ZiCa"), "abc");
70
+ });
71
+
72
+ it("throws on invalid character (0)", () => {
73
+ throws(() => decode58("0invalid"), /Invalid Base58 character/);
74
+ });
75
+
76
+ it("throws on invalid character (O)", () => {
77
+ throws(() => decode58("OOO"), /Invalid Base58 character/);
78
+ });
79
+
80
+ it("throws on invalid character (I)", () => {
81
+ throws(() => decode58("III"), /Invalid Base58 character/);
82
+ });
83
+
84
+ it("throws on invalid character (l)", () => {
85
+ throws(() => decode58("lll"), /Invalid Base58 character/);
86
+ });
87
+ });
88
+
89
+ describe("Base58 round-trip", () => {
90
+ const testCases = [
91
+ "",
92
+ "a",
93
+ "ab",
94
+ "abc",
95
+ "abcd",
96
+ "Hello, World!",
97
+ "The quick brown fox jumps over the lazy dog",
98
+ "こんにちは世界",
99
+ "🎉🚀✨",
100
+ "\x00\x00\x00abc"
101
+ ];
102
+
103
+ for (const charset of Base58Charset) {
104
+ describe(`charset: ${charset}`, () => {
105
+ for (const input of testCases) {
106
+ it(`round-trips: ${JSON.stringify(input)}`, () => {
107
+ const encoded = encode58(input, charset);
108
+ const decoded = decode58(encoded, charset);
109
+ strictEqual(decoded, input);
110
+ });
111
+ }
112
+ });
113
+ }
114
+ });
115
+
116
+ describe("Base58Charset", () => {
117
+ it("exports array with three charsets", () => {
118
+ strictEqual(Base58Charset.length, 3);
119
+ strictEqual(Base58Charset[0], "bitcoin");
120
+ strictEqual(Base58Charset[1], "flickr");
121
+ strictEqual(Base58Charset[2], "ripple");
122
+ });
123
+
124
+ it("charset type works correctly", () => {
125
+ const cs: Base58CharsetType = "flickr";
126
+ strictEqual(encode58("test", cs), encode58("test", "flickr"));
127
+ });
128
+ });
package/src/base58.ts ADDED
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Base58 encoding/decoding with multiple charset variants.
3
+ * Base58 excludes visually ambiguous characters (0, O, I, l).
4
+ * @module base58
5
+ */
6
+
7
+ /**
8
+ * Available Base58 charset variants.
9
+ * - `bitcoin`: Bitcoin/IPFS alphabet (default)
10
+ * - `flickr`: Flickr short URLs (swaps case)
11
+ * - `ripple`: Ripple addresses
12
+ */
13
+ const Base58Charset = ["bitcoin", "flickr", "ripple"] as const;
14
+
15
+ /**
16
+ * Base58 charset type.
17
+ */
18
+ type Base58CharsetType = (typeof Base58Charset)[number];
19
+
20
+ /**
21
+ * Charset alphabets for Base58 variants.
22
+ */
23
+ const CHARSETS: Record<Base58CharsetType, string> = {
24
+ bitcoin: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
25
+ flickr: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ",
26
+ ripple: "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"
27
+ };
28
+
29
+ /**
30
+ * Build a reverse lookup table for decoding.
31
+ * @param alphabet - The 58-character alphabet string.
32
+ * @returns Map of character to index.
33
+ */
34
+ function buildDecodeTable(alphabet: string): Map<string, number> {
35
+ const table = new Map<string, number>();
36
+ for (let i = 0; i < alphabet.length; i++) {
37
+ const char = alphabet[i];
38
+ if (char !== undefined) {
39
+ table.set(char, i);
40
+ }
41
+ }
42
+ return table;
43
+ }
44
+
45
+ /**
46
+ * Pre-built decode tables for each charset.
47
+ */
48
+ const DECODE_TABLES: Record<Base58CharsetType, Map<string, number>> = {
49
+ bitcoin: buildDecodeTable(CHARSETS.bitcoin),
50
+ flickr: buildDecodeTable(CHARSETS.flickr),
51
+ ripple: buildDecodeTable(CHARSETS.ripple)
52
+ };
53
+
54
+ /**
55
+ * Encode a string to Base58.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * import { encode58 } from "./base58.js";
60
+ *
61
+ * encode58("Hello World");
62
+ * // => "JxF12TrwUP45BMd"
63
+ *
64
+ * encode58("Hello World", "flickr");
65
+ * // => "jXf12sRWto45bmD"
66
+ * ```
67
+ *
68
+ * @param input - The string to encode.
69
+ * @param charset - The charset variant to use (default: "bitcoin").
70
+ * @returns The Base58 encoded string.
71
+ */
72
+ function encode58(input: string, charset: Base58CharsetType = "bitcoin"): string {
73
+ if (input === "") {
74
+ return "";
75
+ }
76
+
77
+ const alphabet = CHARSETS[charset];
78
+ const bytes = new TextEncoder().encode(input);
79
+
80
+ // Count leading zeros
81
+ let leadingZeros = 0;
82
+ for (const byte of bytes) {
83
+ if (byte === 0) {
84
+ leadingZeros++;
85
+ } else {
86
+ break;
87
+ }
88
+ }
89
+
90
+ // Convert bytes to a big integer
91
+ let num = 0n;
92
+ for (const byte of bytes) {
93
+ num = num * 256n + BigInt(byte);
94
+ }
95
+
96
+ // Convert to Base58
97
+ let result = "";
98
+ while (num > 0n) {
99
+ const remainder = Number(num % 58n);
100
+ num = num / 58n;
101
+ result = alphabet[remainder] + result;
102
+ }
103
+
104
+ // Add leading '1's for leading zero bytes
105
+ const leadChar = alphabet[0];
106
+ for (let i = 0; i < leadingZeros; i++) {
107
+ result = leadChar + result;
108
+ }
109
+
110
+ return result;
111
+ }
112
+
113
+ /**
114
+ * Decode a Base58 string.
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * import { decode58 } from "./base58.js";
119
+ *
120
+ * decode58("JxF12TrwUP45BMd");
121
+ * // => "Hello World"
122
+ *
123
+ * decode58("jXf12sRWto45bmD", "flickr");
124
+ * // => "Hello World"
125
+ * ```
126
+ *
127
+ * @param input - The Base58 encoded string.
128
+ * @param charset - The charset variant to use (default: "bitcoin").
129
+ * @returns The decoded string.
130
+ * @throws Error if the input contains invalid characters.
131
+ */
132
+ function decode58(input: string, charset: Base58CharsetType = "bitcoin"): string {
133
+ if (input === "") {
134
+ return "";
135
+ }
136
+
137
+ const alphabet = CHARSETS[charset];
138
+ const decodeTable = DECODE_TABLES[charset];
139
+ const leadChar = alphabet[0];
140
+
141
+ // Count leading '1's (or equivalent)
142
+ let leadingOnes = 0;
143
+ for (const char of input) {
144
+ if (char === leadChar) {
145
+ leadingOnes++;
146
+ } else {
147
+ break;
148
+ }
149
+ }
150
+
151
+ // Convert from Base58 to big integer
152
+ let num = 0n;
153
+ for (const char of input) {
154
+ const value = decodeTable.get(char);
155
+ if (value === undefined) {
156
+ throw new Error(`Invalid Base58 character: ${char}`);
157
+ }
158
+ num = num * 58n + BigInt(value);
159
+ }
160
+
161
+ // Convert big integer to bytes
162
+ const bytes: number[] = [];
163
+ while (num > 0n) {
164
+ bytes.unshift(Number(num % 256n));
165
+ num = num / 256n;
166
+ }
167
+
168
+ // Add leading zeros
169
+ for (let i = 0; i < leadingOnes; i++) {
170
+ bytes.unshift(0);
171
+ }
172
+
173
+ return new TextDecoder().decode(new Uint8Array(bytes));
174
+ }
175
+
176
+ export { encode58, decode58, Base58Charset };
177
+ export type { Base58CharsetType };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Base85 encoding/decoding with multiple charset variants.
3
+ * Base85 provides ~25% better efficiency than Base64 (4:5 vs 3:4 ratio).
4
+ * @module base85
5
+ */
6
+ /**
7
+ * Available Base85 charset variants.
8
+ * - `ascii85`: Adobe Ascii85 (btoa format)
9
+ * - `z85`: ZeroMQ Base85 (no quotes or backslash)
10
+ * - `rfc1924`: RFC 1924 IPv6 encoding
11
+ */
12
+ declare const Base85Charset: readonly ["ascii85", "z85", "rfc1924"];
13
+ /**
14
+ * Base85 charset type.
15
+ */
16
+ type Base85CharsetType = (typeof Base85Charset)[number];
17
+ /**
18
+ * Encode a string to Base85.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * import { encode85 } from "./base85.js";
23
+ *
24
+ * encode85("Hello");
25
+ * // => "87cURDZ"
26
+ *
27
+ * encode85("test", "z85");
28
+ * // => "wrx.P"
29
+ * ```
30
+ *
31
+ * @param input - The string to encode.
32
+ * @param charset - The charset variant to use (default: "ascii85").
33
+ * @returns The Base85 encoded string.
34
+ */
35
+ declare function encode85(input: string, charset?: Base85CharsetType): string;
36
+ /**
37
+ * Decode a Base85 string.
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * import { decode85 } from "./base85.js";
42
+ *
43
+ * decode85("87cURDZ");
44
+ * // => "Hello"
45
+ *
46
+ * decode85("wrx.P", "z85");
47
+ * // => "test"
48
+ * ```
49
+ *
50
+ * @param input - The Base85 encoded string.
51
+ * @param charset - The charset variant to use (default: "ascii85").
52
+ * @returns The decoded string.
53
+ * @throws Error if the input contains invalid characters.
54
+ */
55
+ declare function decode85(input: string, charset?: Base85CharsetType): string;
56
+ export { encode85, decode85, Base85Charset };
57
+ export type { Base85CharsetType };
58
+ //# sourceMappingURL=base85.d.ts.map
package/src/base85.js ADDED
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Base85 encoding/decoding with multiple charset variants.
3
+ * Base85 provides ~25% better efficiency than Base64 (4:5 vs 3:4 ratio).
4
+ * @module base85
5
+ */
6
+ /**
7
+ * Available Base85 charset variants.
8
+ * - `ascii85`: Adobe Ascii85 (btoa format)
9
+ * - `z85`: ZeroMQ Base85 (no quotes or backslash)
10
+ * - `rfc1924`: RFC 1924 IPv6 encoding
11
+ */
12
+ const Base85Charset = ["ascii85", "z85", "rfc1924"];
13
+ /**
14
+ * Charset alphabets for Base85 variants.
15
+ * Each has exactly 85 printable ASCII characters.
16
+ */
17
+ const CHARSETS = {
18
+ ascii85: "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu",
19
+ z85: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#",
20
+ rfc1924: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
21
+ };
22
+ /**
23
+ * Build a reverse lookup table for decoding.
24
+ * @param alphabet - The 85-character alphabet string.
25
+ * @returns Map of character to index.
26
+ */
27
+ function buildDecodeTable(alphabet) {
28
+ const table = new Map();
29
+ for (let i = 0; i < alphabet.length; i++) {
30
+ const char = alphabet[i];
31
+ if (char !== undefined) {
32
+ table.set(char, i);
33
+ }
34
+ }
35
+ return table;
36
+ }
37
+ /**
38
+ * Pre-built decode tables for each charset.
39
+ */
40
+ const DECODE_TABLES = {
41
+ ascii85: buildDecodeTable(CHARSETS.ascii85),
42
+ z85: buildDecodeTable(CHARSETS.z85),
43
+ rfc1924: buildDecodeTable(CHARSETS.rfc1924)
44
+ };
45
+ /**
46
+ * Encode a string to Base85.
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * import { encode85 } from "./base85.js";
51
+ *
52
+ * encode85("Hello");
53
+ * // => "87cURDZ"
54
+ *
55
+ * encode85("test", "z85");
56
+ * // => "wrx.P"
57
+ * ```
58
+ *
59
+ * @param input - The string to encode.
60
+ * @param charset - The charset variant to use (default: "ascii85").
61
+ * @returns The Base85 encoded string.
62
+ */
63
+ function encode85(input, charset = "ascii85") {
64
+ if (input === "") {
65
+ return "";
66
+ }
67
+ const alphabet = CHARSETS[charset];
68
+ const bytes = new TextEncoder().encode(input);
69
+ let result = "";
70
+ // Process 4 bytes at a time
71
+ for (let i = 0; i < bytes.length; i += 4) {
72
+ const chunkSize = Math.min(4, bytes.length - i);
73
+ // Pack up to 4 bytes into a value using multiplication to avoid
74
+ // 32-bit signed integer overflow from bitwise operations
75
+ let value = 0;
76
+ for (let j = 0; j < chunkSize; j++) {
77
+ value = value * 256 + (bytes[i + j] ?? 0);
78
+ }
79
+ // Pad with zeros for incomplete chunks
80
+ for (let j = chunkSize; j < 4; j++) {
81
+ value = value * 256;
82
+ }
83
+ // Convert to 5 base-85 digits
84
+ const encoded = [];
85
+ for (let j = 0; j < 5; j++) {
86
+ encoded.unshift(alphabet[value % 85] ?? "");
87
+ value = Math.floor(value / 85);
88
+ }
89
+ // For the last chunk, only output as many characters as needed
90
+ // (chunkSize bytes -> chunkSize + 1 characters)
91
+ if (i + 4 > bytes.length) {
92
+ result += encoded.slice(0, chunkSize + 1).join("");
93
+ }
94
+ else {
95
+ result += encoded.join("");
96
+ }
97
+ }
98
+ return result;
99
+ }
100
+ /**
101
+ * Decode a Base85 string.
102
+ *
103
+ * @example
104
+ * ```typescript
105
+ * import { decode85 } from "./base85.js";
106
+ *
107
+ * decode85("87cURDZ");
108
+ * // => "Hello"
109
+ *
110
+ * decode85("wrx.P", "z85");
111
+ * // => "test"
112
+ * ```
113
+ *
114
+ * @param input - The Base85 encoded string.
115
+ * @param charset - The charset variant to use (default: "ascii85").
116
+ * @returns The decoded string.
117
+ * @throws Error if the input contains invalid characters.
118
+ */
119
+ function decode85(input, charset = "ascii85") {
120
+ if (input === "") {
121
+ return "";
122
+ }
123
+ const decodeTable = DECODE_TABLES[charset];
124
+ const bytes = [];
125
+ const inputLen = input.length;
126
+ // Calculate expected output length
127
+ // Full groups of 5 chars -> 4 bytes each
128
+ // Partial group: n chars -> n-1 bytes
129
+ const fullGroups = Math.floor(inputLen / 5);
130
+ const remainder = inputLen % 5;
131
+ const totalBytes = fullGroups * 4 + (remainder > 0 ? remainder - 1 : 0);
132
+ // Process 5 characters at a time
133
+ let byteCount = 0;
134
+ for (let i = 0; i < inputLen; i += 5) {
135
+ const chunkSize = Math.min(5, inputLen - i);
136
+ // Decode up to 5 characters into a 32-bit value
137
+ let value = 0;
138
+ for (let j = 0; j < chunkSize; j++) {
139
+ const char = input[i + j];
140
+ if (char === undefined) {
141
+ break;
142
+ }
143
+ const digit = decodeTable.get(char);
144
+ if (digit === undefined) {
145
+ throw new Error(`Invalid Base85 character: ${char}`);
146
+ }
147
+ value = value * 85 + digit;
148
+ }
149
+ // Pad with 84 (highest digit) for incomplete chunks
150
+ for (let j = chunkSize; j < 5; j++) {
151
+ value = value * 85 + 84;
152
+ }
153
+ // Calculate how many bytes this chunk should produce
154
+ const bytesToExtract = chunkSize === 5 ? 4 : chunkSize - 1;
155
+ // Extract bytes from high to low
156
+ const extracted = [];
157
+ for (let j = 0; j < 4; j++) {
158
+ extracted.unshift(value & 0xff);
159
+ value = value >>> 8;
160
+ }
161
+ // Only push the bytes we need
162
+ for (let j = 0; j < bytesToExtract && byteCount < totalBytes; j++) {
163
+ const byte = extracted[j];
164
+ if (byte !== undefined) {
165
+ bytes.push(byte);
166
+ byteCount++;
167
+ }
168
+ }
169
+ }
170
+ return new TextDecoder().decode(new Uint8Array(bytes));
171
+ }
172
+ export { encode85, decode85, Base85Charset };
173
+ //# sourceMappingURL=base85.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=base85.test.d.ts.map
@@ -0,0 +1,107 @@
1
+ import { describe, it } from "node:test";
2
+ import { strictEqual, throws } from "node:assert";
3
+ import { encode85, decode85, Base85Charset } from "./base85.js";
4
+ describe("Base85 encode85", () => {
5
+ it("encodes empty string", () => {
6
+ strictEqual(encode85(""), "");
7
+ });
8
+ it("encodes 'Hello' with ascii85 charset", () => {
9
+ const encoded = encode85("Hello");
10
+ strictEqual(encoded.length > 0, true);
11
+ });
12
+ it("encodes single character", () => {
13
+ const encoded = encode85("A");
14
+ strictEqual(encoded.length, 2);
15
+ });
16
+ it("encodes 4 characters (full block)", () => {
17
+ const encoded = encode85("test");
18
+ strictEqual(encoded.length, 5);
19
+ });
20
+ it("encodes 5 characters (4 + 1)", () => {
21
+ const encoded = encode85("tests");
22
+ strictEqual(encoded.length, 7);
23
+ });
24
+ it("encodes with z85 charset", () => {
25
+ const ascii85 = encode85("test", "ascii85");
26
+ const z85 = encode85("test", "z85");
27
+ strictEqual(ascii85 !== z85, true);
28
+ });
29
+ it("encodes with rfc1924 charset", () => {
30
+ const ascii85 = encode85("test", "ascii85");
31
+ const rfc1924 = encode85("test", "rfc1924");
32
+ strictEqual(ascii85 !== rfc1924, true);
33
+ });
34
+ it("encodes UTF-8 characters", () => {
35
+ const input = "こんにちは";
36
+ const encoded = encode85(input);
37
+ const decoded = decode85(encoded);
38
+ strictEqual(decoded, input);
39
+ });
40
+ });
41
+ describe("Base85 decode85", () => {
42
+ it("decodes empty string", () => {
43
+ strictEqual(decode85(""), "");
44
+ });
45
+ it("decodes encoded 'Hello'", () => {
46
+ const encoded = encode85("Hello");
47
+ strictEqual(decode85(encoded), "Hello");
48
+ });
49
+ it("decodes single character encoded", () => {
50
+ const encoded = encode85("A");
51
+ strictEqual(decode85(encoded), "A");
52
+ });
53
+ it("decodes 4-char block correctly", () => {
54
+ const encoded = encode85("test");
55
+ strictEqual(decode85(encoded), "test");
56
+ });
57
+ it("throws on invalid character", () => {
58
+ // Use a character not in ascii85 alphabet
59
+ throws(() => decode85("\x7F"), /Invalid Base85 character/);
60
+ });
61
+ });
62
+ describe("Base85 round-trip", () => {
63
+ const testCases = [
64
+ "",
65
+ "a",
66
+ "ab",
67
+ "abc",
68
+ "abcd",
69
+ "abcde",
70
+ "Hello, World!",
71
+ "The quick brown fox jumps over the lazy dog",
72
+ "こんにちは世界",
73
+ "🎉🚀✨",
74
+ "1234567890"
75
+ ];
76
+ for (const charset of Base85Charset) {
77
+ describe(`charset: ${charset}`, () => {
78
+ for (const input of testCases) {
79
+ it(`round-trips: ${JSON.stringify(input)}`, () => {
80
+ const encoded = encode85(input, charset);
81
+ const decoded = decode85(encoded, charset);
82
+ strictEqual(decoded, input);
83
+ });
84
+ }
85
+ });
86
+ }
87
+ });
88
+ describe("Base85Charset", () => {
89
+ it("exports array with three charsets", () => {
90
+ strictEqual(Base85Charset.length, 3);
91
+ strictEqual(Base85Charset[0], "ascii85");
92
+ strictEqual(Base85Charset[1], "z85");
93
+ strictEqual(Base85Charset[2], "rfc1924");
94
+ });
95
+ it("charset type works correctly", () => {
96
+ const cs = "z85";
97
+ strictEqual(encode85("test", cs), encode85("test", "z85"));
98
+ });
99
+ it("each charset has exactly 85 characters", () => {
100
+ // This is a compile-time guarantee, but let's verify at runtime too
101
+ for (const charset of Base85Charset) {
102
+ const encoded = encode85("test", charset);
103
+ strictEqual(encoded.length > 0, true);
104
+ }
105
+ });
106
+ });
107
+ //# sourceMappingURL=base85.test.js.map