functionalscript 0.30.0 → 0.31.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 (181) hide show
  1. package/fs/asn.1/module.f.js +18 -22
  2. package/fs/asn.1/proof.f.d.ts +5 -0
  3. package/fs/asn.1/proof.f.js +38 -2
  4. package/fs/base64/module.f.d.ts +9 -0
  5. package/fs/base64/module.f.js +60 -0
  6. package/fs/base64/proof.f.d.ts +11 -0
  7. package/fs/base64/proof.f.js +117 -0
  8. package/fs/base_n/module.f.d.ts +44 -0
  9. package/fs/base_n/module.f.js +54 -0
  10. package/fs/base_n/proof.f.d.ts +10 -0
  11. package/fs/base_n/proof.f.js +86 -0
  12. package/fs/bnf/data/module.f.d.ts +4 -9
  13. package/fs/bnf/data/module.f.js +4 -3
  14. package/fs/bnf/module.f.d.ts +3 -4
  15. package/fs/bnf/module.f.js +3 -2
  16. package/fs/bnf/proof.f.d.ts +9 -0
  17. package/fs/bnf/proof.f.js +98 -1
  18. package/fs/cas/mcp/module.f.d.ts +40 -0
  19. package/fs/cas/mcp/module.f.js +223 -0
  20. package/fs/cas/mcp/proof.f.d.ts +30 -0
  21. package/fs/cas/mcp/proof.f.js +310 -0
  22. package/fs/cas/module.f.d.ts +9 -3
  23. package/fs/cas/module.f.js +104 -69
  24. package/fs/cas/proof.f.d.ts +2 -0
  25. package/fs/cas/proof.f.js +30 -1
  26. package/fs/cbase32/module.f.d.ts +1 -1
  27. package/fs/cbase32/module.f.js +19 -40
  28. package/fs/cbase32/proof.f.d.ts +1 -0
  29. package/fs/cbase32/proof.f.js +15 -0
  30. package/fs/ci/config/module.f.d.ts +6 -6
  31. package/fs/ci/config/module.f.js +6 -6
  32. package/fs/ci/deno/module.f.js +2 -2
  33. package/fs/ci/module.f.d.ts +5 -0
  34. package/fs/ci/module.f.js +2 -3
  35. package/fs/ci/proof.f.d.ts +1 -0
  36. package/fs/ci/proof.f.js +9 -3
  37. package/fs/cli/module.f.d.ts +3 -1
  38. package/fs/cli/module.f.js +22 -12
  39. package/fs/cli/proof.f.d.ts +5 -0
  40. package/fs/cli/proof.f.js +76 -0
  41. package/fs/crypto/hmac/proof.f.d.ts +1 -0
  42. package/fs/crypto/hmac/proof.f.js +8 -0
  43. package/fs/crypto/secp/proof.f.d.ts +1 -0
  44. package/fs/crypto/secp/proof.f.js +10 -0
  45. package/fs/crypto/sign/module.f.js +1 -4
  46. package/fs/dev/module.f.d.ts +5 -3
  47. package/fs/dev/module.f.js +13 -2
  48. package/fs/dev/package_json/proof.f.d.ts +1 -0
  49. package/fs/dev/package_json/proof.f.js +5 -0
  50. package/fs/dev/proof.f.d.ts +1 -0
  51. package/fs/dev/proof.f.js +12 -1
  52. package/fs/djs/ast/module.f.d.ts +1 -1
  53. package/fs/djs/ast/proof.f.d.ts +5 -0
  54. package/fs/djs/ast/proof.f.js +17 -0
  55. package/fs/djs/module.f.d.ts +1 -1
  56. package/fs/djs/module.f.js +2 -3
  57. package/fs/djs/serializer/module.f.js +24 -11
  58. package/fs/djs/transpiler/module.f.js +3 -4
  59. package/fs/effects/memory/module.f.d.ts +37 -0
  60. package/fs/effects/memory/module.f.js +24 -0
  61. package/fs/effects/memory/proof.f.d.ts +6 -0
  62. package/fs/effects/memory/proof.f.js +64 -0
  63. package/fs/effects/mock/module.f.d.ts +7 -2
  64. package/fs/effects/mock/module.f.js +12 -8
  65. package/fs/effects/module.d.ts +1 -1
  66. package/fs/effects/module.f.d.ts +41 -0
  67. package/fs/effects/module.f.js +25 -0
  68. package/fs/effects/module.js +6 -7
  69. package/fs/effects/node/memory/module.d.ts +20 -0
  70. package/fs/effects/node/memory/module.js +44 -0
  71. package/fs/effects/node/memory/proof.d.ts +10 -0
  72. package/fs/effects/node/memory/proof.js +35 -0
  73. package/fs/effects/node/module.d.ts +1 -1
  74. package/fs/effects/node/module.f.d.ts +54 -8
  75. package/fs/effects/node/module.f.js +55 -4
  76. package/fs/effects/node/module.js +166 -135
  77. package/fs/effects/node/proof.f.d.ts +10 -0
  78. package/fs/effects/node/proof.f.js +88 -21
  79. package/fs/effects/node/virtual/module.f.d.ts +6 -0
  80. package/fs/effects/node/virtual/module.f.js +48 -16
  81. package/fs/effects/node/virtual/proof.f.d.ts +17 -0
  82. package/fs/effects/node/virtual/proof.f.js +79 -0
  83. package/fs/effects/proof.f.d.ts +5 -0
  84. package/fs/effects/proof.f.js +54 -34
  85. package/fs/emergent_testing/module.f.d.ts +6 -1
  86. package/fs/emergent_testing/module.f.js +8 -3
  87. package/fs/emergent_testing/proof.f.d.ts +11 -0
  88. package/fs/emergent_testing/proof.f.js +52 -16
  89. package/fs/fjs/module.f.js +2 -2
  90. package/fs/fjs/proof.f.d.ts +8 -0
  91. package/fs/fjs/proof.f.js +39 -0
  92. package/fs/fsc/module.f.d.ts +5 -0
  93. package/fs/fsc/module.f.js +17 -27
  94. package/fs/fsc/proof.f.d.ts +8 -0
  95. package/fs/fsc/proof.f.js +48 -2
  96. package/fs/fsm/module.f.d.ts +2 -3
  97. package/fs/fsm/module.f.js +1 -1
  98. package/fs/html/module.f.d.ts +2 -3
  99. package/fs/html/module.f.js +7 -6
  100. package/fs/html/proof.f.d.ts +1 -0
  101. package/fs/html/proof.f.js +7 -0
  102. package/fs/js/tokenizer/module.f.js +1 -1
  103. package/fs/js/tokenizer/proof.f.js +7 -0
  104. package/fs/json/module.f.d.ts +9 -2
  105. package/fs/json/module.f.js +9 -7
  106. package/fs/json/parser/module.f.js +4 -6
  107. package/fs/json/parser/proof.f.js +19 -10
  108. package/fs/json/proof.f.d.ts +2 -1
  109. package/fs/json/proof.f.js +33 -6
  110. package/fs/json/rpc/module.f.d.ts +5 -0
  111. package/fs/json/rpc/module.f.js +16 -11
  112. package/fs/json/schema/module.f.d.ts +15 -14
  113. package/fs/json/schema/proof.f.d.ts +3 -0
  114. package/fs/json/schema/proof.f.js +16 -1
  115. package/fs/mcp/module.f.d.ts +103 -5
  116. package/fs/mcp/module.f.js +139 -2
  117. package/fs/mcp/proof.f.d.ts +34 -0
  118. package/fs/mcp/proof.f.js +207 -0
  119. package/fs/mcp/stdio/module.f.d.ts +39 -0
  120. package/fs/mcp/stdio/module.f.js +54 -0
  121. package/fs/mcp/stdio/proof.f.d.ts +10 -0
  122. package/fs/mcp/stdio/proof.f.js +92 -0
  123. package/fs/mime/module.f.d.ts +39 -0
  124. package/fs/mime/module.f.js +78 -0
  125. package/fs/mime/proof.f.d.ts +15 -0
  126. package/fs/mime/proof.f.js +30 -0
  127. package/fs/path/module.f.d.ts +8 -0
  128. package/fs/path/module.f.js +10 -3
  129. package/fs/path/proof.f.d.ts +1 -0
  130. package/fs/path/proof.f.js +40 -2
  131. package/fs/text/sgr/proof.f.js +30 -2
  132. package/fs/text/utf8/module.f.d.ts +7 -0
  133. package/fs/text/utf8/module.f.js +85 -31
  134. package/fs/text/utf8/proof.f.d.ts +1 -0
  135. package/fs/text/utf8/proof.f.js +60 -1
  136. package/fs/types/bigfloat/module.f.d.ts +3 -0
  137. package/fs/types/bigfloat/module.f.js +30 -31
  138. package/fs/types/bigint/module.f.d.ts +24 -2
  139. package/fs/types/bigint/module.f.js +30 -2
  140. package/fs/types/bigint/proof.f.d.ts +7 -0
  141. package/fs/types/bigint/proof.f.js +47 -16
  142. package/fs/types/bit_vec/module.f.d.ts +18 -0
  143. package/fs/types/bit_vec/module.f.js +18 -0
  144. package/fs/types/bit_vec/proof.f.d.ts +1 -0
  145. package/fs/types/bit_vec/proof.f.js +13 -1
  146. package/fs/types/function/operator/proof.f.d.ts +2 -0
  147. package/fs/types/function/operator/proof.f.js +20 -2
  148. package/fs/types/list/module.f.js +1 -4
  149. package/fs/types/list/proof.f.d.ts +1 -1
  150. package/fs/types/list/proof.f.js +14 -6
  151. package/fs/types/map/proof.f.d.ts +1 -0
  152. package/fs/types/map/proof.f.js +10 -1
  153. package/fs/types/nibble_set/module.f.d.ts +13 -0
  154. package/fs/types/nibble_set/module.f.js +16 -0
  155. package/fs/types/object/module.f.d.ts +12 -8
  156. package/fs/types/object/module.f.js +9 -2
  157. package/fs/types/object/proof.f.d.ts +14 -0
  158. package/fs/types/object/proof.f.js +4 -0
  159. package/fs/types/ordered_map/proof.f.d.ts +1 -0
  160. package/fs/types/ordered_map/proof.f.js +39 -79
  161. package/fs/types/phantom/module.f.d.ts +22 -0
  162. package/fs/types/phantom/module.f.js +11 -0
  163. package/fs/types/prime_field/proof.f.d.ts +7 -0
  164. package/fs/types/prime_field/proof.f.js +63 -122
  165. package/fs/types/rtti/common/module.f.d.ts +4 -4
  166. package/fs/types/rtti/common/module.f.js +1 -1
  167. package/fs/types/rtti/module.f.d.ts +2 -3
  168. package/fs/types/rtti/parse/module.f.js +0 -1
  169. package/fs/types/rtti/ts/module.f.d.ts +26 -32
  170. package/fs/types/rtti/ts/module.f.js +2 -2
  171. package/fs/types/rtti/ts/proof.f.js +3 -3
  172. package/fs/types/rtti/validate/module.f.js +0 -1
  173. package/fs/types/sorted_list/module.f.d.ts +6 -0
  174. package/fs/types/sorted_list/module.f.js +11 -0
  175. package/fs/types/sorted_set/module.f.js +2 -8
  176. package/fs/types/ts/module.f.d.ts +1 -1
  177. package/fs/types/ts/module.f.js +3 -1
  178. package/fs/types/ts/proof.f.js +3 -2
  179. package/fs/website/proof.f.d.ts +1 -0
  180. package/fs/website/proof.f.js +8 -1
  181. package/package.json +3 -3
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * @module
6
6
  */
7
- import { bitLength } from "../types/bigint/module.f.js";
7
+ import { bitLength, divUp8 } from "../types/bigint/module.f.js";
8
8
  import { empty, isVec, length, msb, uint, unpack, vec, vec8 } from "../types/bit_vec/module.f.js";
9
9
  import { identity } from "../types/function/module.f.js";
10
10
  import { max } from "../types/function/compare/module.f.js";
@@ -28,7 +28,7 @@ const parsedTagDecode = (v) => {
28
28
  : b128decode(rest);
29
29
  return [[classPc, number], rest1];
30
30
  };
31
- const tagEncode = (tag) => vec(max((bitLength(tag) + 7n) >> 3n)(1n) << 3n)(tag);
31
+ const tagEncode = (tag) => vec(max(divUp8(bitLength(tag)))(1n) << 3n)(tag);
32
32
  const tagDecode = (v) => {
33
33
  const [parsedTag, rest] = parsedTagDecode(v);
34
34
  return [uint(parsedTagEncode(parsedTag)), rest];
@@ -78,7 +78,7 @@ const constructed = 0x20;
78
78
  export const constructedSequence = 0x30n; // constructed | sequence
79
79
  export const constructedSet = 0x31n; // constructed | set
80
80
  const round8 = ({ length, uint }) => {
81
- const byteLen = (length + 7n) >> 3n;
81
+ const byteLen = divUp8(length);
82
82
  return { byteLen, v: vec(byteLen << 3n)(uint) };
83
83
  };
84
84
  const lenEncode = (uint) => {
@@ -141,33 +141,29 @@ export const encodeObjectIdentifier = (oid) => {
141
141
  const firstByte = first * 40n + second;
142
142
  return listToVec([vec8(firstByte), ...rest.map(b128encode)]);
143
143
  };
144
+ /**
145
+ * Drains a bit vector by repeatedly applying a step until the vector is empty,
146
+ * collecting every decoded item into an array.
147
+ */
148
+ const decodeAll = (step) => (v) => {
149
+ let result = [];
150
+ while (length(v) !== 0n) {
151
+ const [item, rest] = step(v);
152
+ result = [...result, item];
153
+ v = rest;
154
+ }
155
+ return result;
156
+ };
144
157
  /** Decodes an OBJECT IDENTIFIER value. */
145
158
  export const decodeObjectIdentifier = (v) => {
146
159
  const [firstByte, rest] = pop8(v);
147
- const first = firstByte / 40n;
148
- const second = firstByte % 40n;
149
- let result = [first, second];
150
- let tail = rest;
151
- while (length(tail) > 0n) {
152
- const [value, next] = b128decode(tail);
153
- result = [...result, value];
154
- tail = next;
155
- }
156
- return result;
160
+ return [firstByte / 40n, firstByte % 40n, ...decodeAll(b128decode)(rest)];
157
161
  };
158
162
  const genericEncodeSequence = (map) => (...records) => listToVec(map(records.map(encode)));
159
163
  /** Encodes a SEQUENCE payload from ordered records. */
160
164
  export const encodeSequence = genericEncodeSequence(identity);
161
165
  /** Decodes a SEQUENCE payload into records. */
162
- export const decodeSequence = (v) => {
163
- let result = [];
164
- while (length(v) !== 0n) {
165
- const [record, rest] = decode(v);
166
- result = [...result, record];
167
- v = rest;
168
- }
169
- return result;
170
- };
166
+ export const decodeSequence = (v) => decodeAll(decode)(v);
171
167
  /** Encodes a SET payload with canonical byte ordering. */
172
168
  export const encodeSet = genericEncodeSequence(v => v.toSorted((a, b) => msb.cmp(a)(b)));
173
169
  /** Decodes a SET payload. */
@@ -39,5 +39,10 @@ export declare const proof: {
39
39
  sequence: () => void;
40
40
  set: () => void;
41
41
  };
42
+ objectIdentifier: {
43
+ simple: () => void;
44
+ withArc: () => void;
45
+ };
46
+ unknownTag: () => void;
42
47
  raw: (() => void)[];
43
48
  };
@@ -1,6 +1,7 @@
1
- import { empty, length, msb, uint, unpack, vec, vec8 } from "../types/bit_vec/module.f.js";
1
+ import { empty, isVec, length, msb, uint, unpack, vec, vec8 } from "../types/bit_vec/module.f.js";
2
2
  import { asBase } from "../types/nominal/module.f.js";
3
- import { decodeRaw, decodeInteger, encodeRaw, encodeInteger, integer, encode, decode, constructedSequence, octetString, boolean, constructedSet } from "./module.f.js";
3
+ import { decodeRaw, decodeInteger, encodeRaw, encodeInteger, integer, encode, decode, constructedSequence, octetString, boolean, constructedSet, encodeObjectIdentifier, decodeObjectIdentifier, } from "./module.f.js";
4
+ import { assertEq } from "../asserts/module.f.js";
4
5
  const { concat, popFront: pop, listToVec } = msb;
5
6
  const pop8 = pop(8n);
6
7
  const check = (tag, v, rest) => {
@@ -272,6 +273,41 @@ export const proof = {
272
273
  ]));
273
274
  },
274
275
  },
276
+ objectIdentifier: {
277
+ simple: () => {
278
+ const oid = [1n, 2n];
279
+ const encoded = encodeObjectIdentifier(oid);
280
+ const decoded = decodeObjectIdentifier(encoded);
281
+ assertEq(decoded.length, 2);
282
+ assertEq(decoded[0], 1n);
283
+ assertEq(decoded[1], 2n);
284
+ },
285
+ withArc: () => {
286
+ // OID 1.2.840.113549 (RSA)
287
+ const oid = [1n, 2n, 840n, 113549n];
288
+ const decoded = decodeObjectIdentifier(encodeObjectIdentifier(oid));
289
+ assertEq(decoded.length, 4);
290
+ assertEq(decoded[0], 1n);
291
+ assertEq(decoded[1], 2n);
292
+ assertEq(decoded[2], 840n);
293
+ assertEq(decoded[3], 113549n);
294
+ },
295
+ },
296
+ unknownTag: () => {
297
+ // bitString (0x03) is not in SupportedRecord, exercises the default case in rawToRecord
298
+ const raw = encodeRaw([0x03n, vec8(0x42n)]);
299
+ const [decoded, rest] = decode(raw);
300
+ if (!isVec(decoded)) {
301
+ throw 'expected UnsupportedRecord (Vec)';
302
+ }
303
+ if (rest !== empty) {
304
+ throw 'expected empty rest';
305
+ }
306
+ // Re-encoding an UnsupportedRecord returns it unchanged (it is already the TLV bytes)
307
+ if (encode(decoded) !== raw) {
308
+ throw 'encode should round-trip UnsupportedRecord';
309
+ }
310
+ },
275
311
  raw: [
276
312
  () => {
277
313
  const e = encodeRaw([0x00n, vec8(0x23n)]);
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Standard Base64 encoding and decoding (RFC 4648).
3
+ *
4
+ * @module
5
+ */
6
+ import { type Vec } from "../types/bit_vec/module.f.ts";
7
+ import type { Nullable } from "../types/nullable/module.f.ts";
8
+ export declare const encode: (input: Vec) => Nullable<string>;
9
+ export declare const decode: (input: string) => Nullable<Vec>;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Standard Base64 encoding and decoding (RFC 4648).
3
+ *
4
+ * @module
5
+ */
6
+ import { msb, length, vec, empty } from "../types/bit_vec/module.f.js";
7
+ import { baseN } from "../base_n/module.f.js";
8
+ const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
9
+ const { popFront, concat } = msb;
10
+ const { vecToString, stringToVec } = baseN(6n, alphabet);
11
+ export const encode = (input) => {
12
+ const len = length(input);
13
+ // Base64 is a byte codec; reject non-octet-aligned inputs.
14
+ if (len % 8n !== 0n) {
15
+ return null;
16
+ }
17
+ const rem = len % 24n;
18
+ const padBits = rem === 0n ? 0n : 6n - rem % 6n;
19
+ const v = padBits > 0n ? concat(input)(vec(padBits)(0n)) : input;
20
+ let result = vecToString(v);
21
+ // Append `=` padding to make total length a multiple of 4.
22
+ while (result.length % 4 !== 0) {
23
+ result += '=';
24
+ }
25
+ return result;
26
+ };
27
+ export const decode = (input) => {
28
+ // Count and strip trailing `=` padding (0, 1, or 2).
29
+ let padChars = 0;
30
+ for (let i = input.length - 1; i >= 0 && input[i] === '='; i--) {
31
+ padChars++;
32
+ }
33
+ if (padChars > 2) {
34
+ return null;
35
+ }
36
+ const body = input.slice(0, input.length - padChars);
37
+ // Total chars must make a multiple of 4 with the padding.
38
+ if ((body.length + padChars) % 4 !== 0) {
39
+ return null;
40
+ }
41
+ // Decode each character to 6 bits.
42
+ const result = stringToVec(body);
43
+ if (result === null) {
44
+ return null;
45
+ }
46
+ // Remove the zero-padding bits introduced during encode.
47
+ // padChars=1 → 2 padding bits removed, padChars=2 → 4 padding bits removed.
48
+ const removeBits = BigInt(padChars * 2);
49
+ const totalBits = length(result);
50
+ const targetLen = totalBits - removeBits;
51
+ if (targetLen === 0n) {
52
+ return empty;
53
+ }
54
+ const [kept, padVec] = popFront(targetLen)(result);
55
+ // Padding bits must be zero (RFC 4648 §3.5).
56
+ if (removeBits > 0n && padVec !== vec(removeBits)(0n)) {
57
+ return null;
58
+ }
59
+ return vec(targetLen)(kept);
60
+ };
@@ -0,0 +1,11 @@
1
+ export declare const proof: {
2
+ empty: () => void;
3
+ oneByte: () => void;
4
+ twoBytes: () => void;
5
+ threeBytes: () => void;
6
+ roundtrip: () => void;
7
+ nonOctet: () => void;
8
+ invalidInput: () => void;
9
+ validPadding: () => void;
10
+ knownVectors: () => void;
11
+ };
@@ -0,0 +1,117 @@
1
+ import { empty, vec } from "../types/bit_vec/module.f.js";
2
+ import { encode, decode } from "./module.f.js";
3
+ const check = (s, v) => {
4
+ const sr = encode(v);
5
+ if (sr !== s) {
6
+ throw ['encode', sr, s];
7
+ }
8
+ const vr = decode(s);
9
+ if (vr !== v) {
10
+ throw ['decode', vr, v];
11
+ }
12
+ };
13
+ export const proof = {
14
+ empty: () => {
15
+ check('', empty);
16
+ },
17
+ oneByte: () => {
18
+ // 0x00 → 0b00000000, padded to 12 bits → AA==
19
+ check('AA==', vec(8n)(0n));
20
+ // 0x48 'H' → 0b01001000 → SA==
21
+ check('SA==', vec(8n)(72n));
22
+ // 0xFF → 0b11111111, padded 12: 111111110000 → /w==
23
+ check('/w==', vec(8n)(255n));
24
+ },
25
+ twoBytes: () => {
26
+ // 0x0000 → AAAA with == stripped → 16 bits: AA==? No: 16 bits → 18 bits with 2 pad → 3 chars + =
27
+ // 0b0000000000000000 padded 2 bits → 18 bits: 000000 000000 000000 → AAA=
28
+ check('AAA=', vec(16n)(0n));
29
+ // 0xFFFF → 0b1111111111111111 padded 2 bits → 111111 111111 111100 → //8=
30
+ check('//8=', vec(16n)(65535n));
31
+ },
32
+ threeBytes: () => {
33
+ // 24 bits, no padding
34
+ check('AAAA', vec(24n)(0n));
35
+ check('////', vec(24n)(16777215n));
36
+ },
37
+ roundtrip: () => {
38
+ // Various bit lengths
39
+ check('AA==', vec(8n)(0n));
40
+ check('AAA=', vec(16n)(0n));
41
+ check('AAAA', vec(24n)(0n));
42
+ // 32 bits
43
+ check('AAAAAA==', vec(32n)(0n));
44
+ // 40 bits (5 bytes: AAAA + AAA=)
45
+ check('AAAAAAA=', vec(40n)(0n));
46
+ },
47
+ nonOctet: () => {
48
+ // encode rejects bit vectors whose length is not a multiple of 8
49
+ if (encode(vec(1n)(0n)) !== null) {
50
+ throw '1-bit input should return null';
51
+ }
52
+ if (encode(vec(6n)(0n)) !== null) {
53
+ throw '6-bit input should return null';
54
+ }
55
+ if (encode(vec(12n)(0n)) !== null) {
56
+ throw '12-bit input should return null';
57
+ }
58
+ },
59
+ invalidInput: () => {
60
+ if (decode('!') !== null) {
61
+ throw 'invalid char should return null';
62
+ }
63
+ if (decode('A!AA') !== null) {
64
+ throw 'invalid char mid-string should return null';
65
+ }
66
+ if (decode('A===') !== null) {
67
+ throw 'three equals signs should return null';
68
+ }
69
+ if (decode('A') !== null) {
70
+ throw 'length 1 (not multiple of 4) should return null';
71
+ }
72
+ if (decode('AA') !== null) {
73
+ throw 'length 2 (no padding) should return null';
74
+ }
75
+ if (decode('AAA') !== null) {
76
+ throw 'length 3 (no padding) should return null';
77
+ }
78
+ if (decode('=AAA') !== null) {
79
+ throw 'padding not at end should return null';
80
+ }
81
+ // Non-zero padding bits must be rejected (RFC 4648 §3.5)
82
+ if (decode('AB==') !== null) {
83
+ throw 'non-zero 4-pad-bit should return null';
84
+ }
85
+ if (decode('AAB=') !== null) {
86
+ throw 'non-zero 2-pad-bit should return null';
87
+ }
88
+ },
89
+ validPadding: () => {
90
+ // "==" padding
91
+ const v2 = decode('AA==');
92
+ if (v2 !== vec(8n)(0n)) {
93
+ throw ['AA== should decode to 8-bit zero', v2];
94
+ }
95
+ // "=" padding
96
+ const v1 = decode('AAA=');
97
+ if (v1 !== vec(16n)(0n)) {
98
+ throw ['AAA= should decode to 16-bit zero', v1];
99
+ }
100
+ // No padding
101
+ const v0 = decode('AAAA');
102
+ if (v0 !== vec(24n)(0n)) {
103
+ throw ['AAAA should decode to 24-bit zero', v0];
104
+ }
105
+ },
106
+ knownVectors: () => {
107
+ // RFC 4648 §10 test vectors (byte-aligned, treating bytes as 8-bit MSB vectors)
108
+ // '' → ''
109
+ check('', empty);
110
+ // 0x66 ('f') → Zg==
111
+ check('Zg==', vec(8n)(0x66n));
112
+ // 0x66 0x6f ('fo') → Zm8=
113
+ check('Zm8=', vec(16n)(0x666fn));
114
+ // 0x66 0x6f 0x6f ('foo') → Zm9v
115
+ check('Zm9v', vec(24n)(0x666f6fn));
116
+ },
117
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Shared bit-codec factory for alphabet-based encodings such as `base64` and
3
+ * `cbase32`.
4
+ *
5
+ * Each call returns the raw `Vec ↔ string` codec parameterised by the chunk
6
+ * width (`bits`) and the alphabet (and an optional input-character
7
+ * normalisation step on the decode side). Padding strategies — RFC 4648 `=`
8
+ * octet-alignment, Crockford-style stop-bit sentinels, etc. — are deliberately
9
+ * out of scope: they vary per format and are handled by the caller around
10
+ * `vecToString` / `stringToVec`.
11
+ *
12
+ * @module
13
+ */
14
+ import { type Vec } from '../types/bit_vec/module.f.ts';
15
+ import type { Nullable } from '../types/nullable/module.f.ts';
16
+ /**
17
+ * The encode/decode pair returned by {@link baseN}.
18
+ */
19
+ export type BaseN = {
20
+ /**
21
+ * Encodes a bit vector by repeatedly popping `bits`-wide MSB chunks and
22
+ * indexing them into the alphabet. A trailing partial chunk shorter than
23
+ * `bits` is left-padded with zeros (the underlying `popFront` semantics).
24
+ */
25
+ readonly vecToString: (v: Vec) => string;
26
+ /**
27
+ * Decodes a string by mapping each character to its alphabet index and
28
+ * concatenating the resulting `bits`-wide chunks. Returns `null` on the
29
+ * first character that is not in the alphabet (after `normalize`, when
30
+ * provided).
31
+ */
32
+ readonly stringToVec: (s: string) => Nullable<Vec>;
33
+ };
34
+ /**
35
+ * Builds a {@link BaseN} codec for a fixed chunk width and alphabet.
36
+ *
37
+ * @param bits The chunk width in bits. `alphabet.length` must equal `2 ** bits`.
38
+ * @param alphabet The character used for each unsigned `bits`-bit value, in
39
+ * ascending order (index `0` → first character).
40
+ * @param normalize Optional pre-lookup transform applied to each input
41
+ * character on decode — e.g. Crockford base32 lowercases and folds
42
+ * `i`/`l`→`1`, `o`→`0`.
43
+ */
44
+ export declare const baseN: (bits: bigint, alphabet: string, normalize?: (c: string) => string) => BaseN;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Shared bit-codec factory for alphabet-based encodings such as `base64` and
3
+ * `cbase32`.
4
+ *
5
+ * Each call returns the raw `Vec ↔ string` codec parameterised by the chunk
6
+ * width (`bits`) and the alphabet (and an optional input-character
7
+ * normalisation step on the decode side). Padding strategies — RFC 4648 `=`
8
+ * octet-alignment, Crockford-style stop-bit sentinels, etc. — are deliberately
9
+ * out of scope: they vary per format and are handled by the caller around
10
+ * `vecToString` / `stringToVec`.
11
+ *
12
+ * @module
13
+ */
14
+ import { msb, length, vec, empty } from "../types/bit_vec/module.f.js";
15
+ const { popFront, concat } = msb;
16
+ /**
17
+ * Builds a {@link BaseN} codec for a fixed chunk width and alphabet.
18
+ *
19
+ * @param bits The chunk width in bits. `alphabet.length` must equal `2 ** bits`.
20
+ * @param alphabet The character used for each unsigned `bits`-bit value, in
21
+ * ascending order (index `0` → first character).
22
+ * @param normalize Optional pre-lookup transform applied to each input
23
+ * character on decode — e.g. Crockford base32 lowercases and folds
24
+ * `i`/`l`→`1`, `o`→`0`.
25
+ */
26
+ export const baseN = (bits, alphabet, normalize) => {
27
+ const popFrontN = popFront(bits);
28
+ const vecN = vec(bits);
29
+ const toIndex = normalize === undefined
30
+ ? (c) => alphabet.indexOf(c)
31
+ : (c) => alphabet.indexOf(normalize(c));
32
+ return {
33
+ vecToString: v => {
34
+ let result = '';
35
+ while (length(v) > 0n) {
36
+ const [r, rest] = popFrontN(v);
37
+ result += alphabet[Number(r)];
38
+ v = rest;
39
+ }
40
+ return result;
41
+ },
42
+ stringToVec: s => {
43
+ let result = empty;
44
+ for (const c of s) {
45
+ const index = toIndex(c);
46
+ if (index < 0) {
47
+ return null;
48
+ }
49
+ result = concat(result)(vecN(BigInt(index)));
50
+ }
51
+ return result;
52
+ },
53
+ };
54
+ };
@@ -0,0 +1,10 @@
1
+ export declare const proof: {
2
+ encodeEmpty: () => void;
3
+ encodeAligned: () => void;
4
+ encodeUnaligned: () => void;
5
+ decodeEmpty: () => void;
6
+ decodeRoundTrip: () => void;
7
+ decodeInvalid: () => void;
8
+ normalizeHit: () => void;
9
+ normalizeMiss: () => void;
10
+ };
@@ -0,0 +1,86 @@
1
+ import { empty, vec } from "../types/bit_vec/module.f.js";
2
+ import { baseN } from "./module.f.js";
3
+ const hex = baseN(4n, '0123456789abcdef');
4
+ const cb32 = baseN(5n, '0123456789abcdefghjkmnpqrstvwxyz', c => {
5
+ const lower = c.toLowerCase();
6
+ switch (lower) {
7
+ case 'i': {
8
+ return '1';
9
+ }
10
+ case 'l': {
11
+ return '1';
12
+ }
13
+ case 'o': {
14
+ return '0';
15
+ }
16
+ default: {
17
+ return lower;
18
+ }
19
+ }
20
+ });
21
+ export const proof = {
22
+ encodeEmpty: () => {
23
+ const s = hex.vecToString(empty);
24
+ if (s !== '') {
25
+ throw [s];
26
+ }
27
+ },
28
+ encodeAligned: () => {
29
+ // Two 4-bit chunks → two hex digits
30
+ const s = hex.vecToString(vec(8n)(0xa5n));
31
+ if (s !== 'a5') {
32
+ throw [s];
33
+ }
34
+ },
35
+ encodeUnaligned: () => {
36
+ // 6 bits → first 4-bit chunk + a 2-bit tail that popFront pads with
37
+ // trailing zeros (the standard `popFront` behaviour the codec inherits).
38
+ const s = hex.vecToString(vec(6n)(41n));
39
+ if (s !== 'a4') {
40
+ throw [s];
41
+ }
42
+ },
43
+ decodeEmpty: () => {
44
+ const v = hex.stringToVec('');
45
+ if (v !== empty) {
46
+ throw [v];
47
+ }
48
+ },
49
+ decodeRoundTrip: () => {
50
+ const v = hex.stringToVec('ab');
51
+ if (v !== vec(8n)(0xabn)) {
52
+ throw [v];
53
+ }
54
+ },
55
+ decodeInvalid: () => {
56
+ if (hex.stringToVec('z') !== null) {
57
+ throw 'invalid char should return null';
58
+ }
59
+ if (hex.stringToVec('aZ') !== null) {
60
+ throw 'mixed invalid char should return null';
61
+ }
62
+ },
63
+ normalizeHit: () => {
64
+ // 'A' lowercases to 'a' — same vector as the lowercase input.
65
+ const a = cb32.stringToVec('A');
66
+ const b = cb32.stringToVec('a');
67
+ if (a !== b) {
68
+ throw [a, b];
69
+ }
70
+ // Crockford folds: i,l → 1 and o → 0.
71
+ if (cb32.stringToVec('I') !== cb32.stringToVec('1')) {
72
+ throw 'I→1';
73
+ }
74
+ if (cb32.stringToVec('l') !== cb32.stringToVec('1')) {
75
+ throw 'l→1';
76
+ }
77
+ if (cb32.stringToVec('o') !== cb32.stringToVec('0')) {
78
+ throw 'o→0';
79
+ }
80
+ },
81
+ normalizeMiss: () => {
82
+ if (cb32.stringToVec('u') !== null) {
83
+ throw 'unknown char should return null';
84
+ }
85
+ },
86
+ };
@@ -7,6 +7,7 @@
7
7
  import { type CodePoint } from '../../text/utf16/module.f.ts';
8
8
  import { type RangeMapArray } from '../../types/range_map/module.f.ts';
9
9
  import { type Rule as FRule } from '../module.f.ts';
10
+ import { type StringMap } from '../../types/object/module.f.ts';
10
11
  /**
11
12
  * Encoded terminal range value used by BNF data rules.
12
13
  *
@@ -18,9 +19,7 @@ export type TerminalRange = number;
18
19
  */
19
20
  export type Sequence = readonly string[];
20
21
  /** A variant of rule names. */
21
- export type Variant = {
22
- readonly [k in string]: string;
23
- };
22
+ export type Variant = StringMap<string, string>;
24
23
  /**
25
24
  * Grammar rule definition.
26
25
  *
@@ -45,12 +44,8 @@ type DispatchRuleCollection = {
45
44
  readonly tag: string | undefined;
46
45
  readonly rules: DispatchRuleOrName[];
47
46
  };
48
- type DispatchMap = {
49
- readonly [id in string]: DispatchRule;
50
- };
51
- type EmptyTagMap = {
52
- readonly [id in string]: EmptyTagEntry;
53
- };
47
+ type DispatchMap = StringMap<string, DispatchRule>;
48
+ type EmptyTagMap = StringMap<string, EmptyTagEntry>;
54
49
  /**
55
50
  * Recursive descent matcher for a single named rule.
56
51
  */
@@ -11,6 +11,7 @@ import { rangeMap } from "../../types/range_map/module.f.js";
11
11
  import { contains, set } from "../../types/string_set/module.f.js";
12
12
  import { contains as rangeContains } from "../../types/range/module.f.js";
13
13
  import { oneEncode, rangeDecode, } from "../module.f.js";
14
+ import { definedEntries } from "../../types/object/module.f.js";
14
15
  const { entries } = Object;
15
16
  const find = (map) => (fr) => {
16
17
  for (const [k, v] of entries(map)) {
@@ -151,7 +152,7 @@ export const dispatchMap = (ruleSet) => {
151
152
  return { ...dm, [name]: dr };
152
153
  }
153
154
  else {
154
- const entries = Object.entries(rule);
155
+ const entries = definedEntries(rule);
155
156
  let result = [];
156
157
  let emptyTag = undefined;
157
158
  for (const [tag, item] of entries) {
@@ -197,7 +198,7 @@ const emptyTagMapAdd = (ruleSet) => (map) => (name) => {
197
198
  }
198
199
  else {
199
200
  map = { ...map, [name]: true };
200
- const entries = Object.entries(rule);
201
+ const entries = definedEntries(rule);
201
202
  let emptyTag = false;
202
203
  for (const [tag, item] of entries) {
203
204
  const [, newMap, itemEmptyTag] = emptyTagMapAdd(ruleSet)(map)(item);
@@ -258,7 +259,7 @@ export const descentParser = (fr) => {
258
259
  return mrSuccess(tag, seq, tidx);
259
260
  }
260
261
  else {
261
- const entries = Object.entries(rule);
262
+ const entries = definedEntries(rule);
262
263
  const emptyTag = getEmptyTag(name);
263
264
  let emptyResult = mrFail(emptyTag, [], idx);
264
265
  for (const [tag, item] of entries) {
@@ -1,3 +1,4 @@
1
+ import { type StringMap } from '../types/object/module.f.ts';
1
2
  import { type Array2 } from '../types/array/module.f.ts';
2
3
  /**
3
4
  * A range of symbols. Two 24-bit numbers are stored in one JS number (48 bits).
@@ -27,7 +28,7 @@ export declare const unicodeMax: string;
27
28
  export type Sequence = readonly Rule[];
28
29
  /** A variant */
29
30
  export type Variant = {
30
- readonly [k in string]: Rule;
31
+ readonly [k in string]?: Rule;
31
32
  };
32
33
  /**
33
34
  * Data-only grammar rule.
@@ -74,9 +75,7 @@ export declare const range: (ab: string) => TerminalRange;
74
75
  /**
75
76
  * A set of terminal ranges compatible with the `Variant` rule.
76
77
  */
77
- export type RangeVariant = {
78
- readonly [k in string]: TerminalRange;
79
- };
78
+ export type RangeVariant = StringMap<string, TerminalRange>;
80
79
  export declare const remove: (range: TerminalRange, v: RangeVariant) => RangeVariant;
81
80
  /**
82
81
  * Returns the complement set of the provided ranges over {@link fullRange}.
@@ -7,6 +7,7 @@
7
7
  * @module
8
8
  */
9
9
  import { codePointListToString, stringToCodePointList } from "../text/utf16/module.f.js";
10
+ import { definedValues } from "../types/object/module.f.js";
10
11
  import { isArray2 } from "../types/array/module.f.js";
11
12
  import { map, toArray, repeat as listRepeat } from "../types/list/module.f.js";
12
13
  /**
@@ -26,7 +27,7 @@ export const max = codePointListToString([0xFFFFFF]);
26
27
  */
27
28
  export const unicodeMax = codePointListToString([0x10FFFF]);
28
29
  // Internals:
29
- const { fromEntries, values } = Object;
30
+ const { fromEntries } = Object;
30
31
  const { fromCodePoint } = String;
31
32
  /**
32
33
  * Two 24 bit numbers can be fit into one JS number (53 bit).
@@ -102,7 +103,7 @@ const removeOne = (list, ab) => {
102
103
  };
103
104
  export const remove = (range, v) => {
104
105
  let result = [range];
105
- for (const r of values(v)) {
106
+ for (const r of definedValues(v)) {
106
107
  result = removeOne(result, r);
107
108
  }
108
109
  return toVariantRangeSet(result);
@@ -1,3 +1,12 @@
1
1
  export declare const proof: {
2
2
  test: () => void;
3
+ throw: {
4
+ rangeEncodeInvalid: (() => void)[];
5
+ rangeInvalid: (() => void)[];
6
+ };
7
+ str: (() => void)[];
8
+ set: () => void;
9
+ commaJoin0Plus: () => void;
10
+ isEmpty: (() => void)[];
11
+ repeat1Plus: (() => void)[];
3
12
  };