functionalscript 0.30.0 → 0.31.1
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.
- package/fs/asn.1/module.f.js +18 -22
- package/fs/asn.1/proof.f.d.ts +5 -0
- package/fs/asn.1/proof.f.js +38 -2
- package/fs/base64/module.f.d.ts +9 -0
- package/fs/base64/module.f.js +60 -0
- package/fs/base64/proof.f.d.ts +11 -0
- package/fs/base64/proof.f.js +117 -0
- package/fs/base_n/module.f.d.ts +44 -0
- package/fs/base_n/module.f.js +54 -0
- package/fs/base_n/proof.f.d.ts +10 -0
- package/fs/base_n/proof.f.js +86 -0
- package/fs/bnf/data/module.f.d.ts +4 -9
- package/fs/bnf/data/module.f.js +4 -3
- package/fs/bnf/module.f.d.ts +3 -4
- package/fs/bnf/module.f.js +3 -2
- package/fs/bnf/proof.f.d.ts +9 -0
- package/fs/bnf/proof.f.js +98 -1
- package/fs/cas/mcp/module.f.d.ts +40 -0
- package/fs/cas/mcp/module.f.js +223 -0
- package/fs/cas/mcp/proof.f.d.ts +30 -0
- package/fs/cas/mcp/proof.f.js +310 -0
- package/fs/cas/module.f.d.ts +9 -3
- package/fs/cas/module.f.js +104 -69
- package/fs/cas/proof.f.d.ts +2 -0
- package/fs/cas/proof.f.js +30 -1
- package/fs/cbase32/module.f.d.ts +1 -1
- package/fs/cbase32/module.f.js +19 -40
- package/fs/cbase32/proof.f.d.ts +1 -0
- package/fs/cbase32/proof.f.js +15 -0
- package/fs/ci/config/module.f.d.ts +6 -6
- package/fs/ci/config/module.f.js +6 -6
- package/fs/ci/deno/module.f.js +2 -2
- package/fs/ci/module.f.d.ts +5 -0
- package/fs/ci/module.f.js +2 -3
- package/fs/ci/proof.f.d.ts +1 -0
- package/fs/ci/proof.f.js +9 -3
- package/fs/cli/module.f.d.ts +3 -1
- package/fs/cli/module.f.js +22 -12
- package/fs/cli/proof.f.d.ts +5 -0
- package/fs/cli/proof.f.js +76 -0
- package/fs/crypto/hmac/proof.f.d.ts +1 -0
- package/fs/crypto/hmac/proof.f.js +8 -0
- package/fs/crypto/secp/proof.f.d.ts +1 -0
- package/fs/crypto/secp/proof.f.js +10 -0
- package/fs/crypto/sign/module.f.js +1 -4
- package/fs/dev/module.f.d.ts +5 -3
- package/fs/dev/module.f.js +13 -2
- package/fs/dev/package_json/proof.f.d.ts +1 -0
- package/fs/dev/package_json/proof.f.js +5 -0
- package/fs/dev/proof.f.d.ts +1 -0
- package/fs/dev/proof.f.js +12 -1
- package/fs/djs/ast/module.f.d.ts +1 -1
- package/fs/djs/ast/proof.f.d.ts +5 -0
- package/fs/djs/ast/proof.f.js +17 -0
- package/fs/djs/module.f.d.ts +1 -1
- package/fs/djs/module.f.js +2 -3
- package/fs/djs/serializer/module.f.js +24 -11
- package/fs/djs/transpiler/module.f.js +3 -4
- package/fs/effects/memory/module.f.d.ts +37 -0
- package/fs/effects/memory/module.f.js +24 -0
- package/fs/effects/memory/proof.f.d.ts +6 -0
- package/fs/effects/memory/proof.f.js +64 -0
- package/fs/effects/mock/module.f.d.ts +7 -2
- package/fs/effects/mock/module.f.js +12 -8
- package/fs/effects/module.d.ts +1 -1
- package/fs/effects/module.f.d.ts +41 -0
- package/fs/effects/module.f.js +25 -0
- package/fs/effects/module.js +6 -7
- package/fs/effects/node/memory/module.d.ts +20 -0
- package/fs/effects/node/memory/module.js +44 -0
- package/fs/effects/node/memory/proof.d.ts +10 -0
- package/fs/effects/node/memory/proof.js +35 -0
- package/fs/effects/node/module.d.ts +1 -1
- package/fs/effects/node/module.f.d.ts +54 -8
- package/fs/effects/node/module.f.js +55 -4
- package/fs/effects/node/module.js +167 -137
- package/fs/effects/node/proof.f.d.ts +10 -0
- package/fs/effects/node/proof.f.js +88 -21
- package/fs/effects/node/virtual/module.f.d.ts +6 -0
- package/fs/effects/node/virtual/module.f.js +48 -16
- package/fs/effects/node/virtual/proof.f.d.ts +17 -0
- package/fs/effects/node/virtual/proof.f.js +79 -0
- package/fs/effects/proof.f.d.ts +5 -0
- package/fs/effects/proof.f.js +54 -34
- package/fs/emergent_testing/module.f.d.ts +6 -1
- package/fs/emergent_testing/module.f.js +8 -3
- package/fs/emergent_testing/proof.f.d.ts +11 -0
- package/fs/emergent_testing/proof.f.js +52 -16
- package/fs/fjs/module.f.js +2 -2
- package/fs/fjs/proof.f.d.ts +8 -0
- package/fs/fjs/proof.f.js +39 -0
- package/fs/fsc/module.f.d.ts +5 -0
- package/fs/fsc/module.f.js +17 -27
- package/fs/fsc/proof.f.d.ts +8 -0
- package/fs/fsc/proof.f.js +48 -2
- package/fs/fsm/module.f.d.ts +2 -3
- package/fs/fsm/module.f.js +1 -1
- package/fs/html/module.f.d.ts +2 -3
- package/fs/html/module.f.js +7 -6
- package/fs/html/proof.f.d.ts +1 -0
- package/fs/html/proof.f.js +7 -0
- package/fs/js/tokenizer/module.f.js +1 -1
- package/fs/js/tokenizer/proof.f.js +7 -0
- package/fs/json/module.f.d.ts +9 -2
- package/fs/json/module.f.js +9 -7
- package/fs/json/parser/module.f.js +4 -6
- package/fs/json/parser/proof.f.js +19 -10
- package/fs/json/proof.f.d.ts +2 -1
- package/fs/json/proof.f.js +33 -6
- package/fs/json/rpc/module.f.d.ts +5 -0
- package/fs/json/rpc/module.f.js +16 -11
- package/fs/json/schema/module.f.d.ts +15 -14
- package/fs/json/schema/proof.f.d.ts +3 -0
- package/fs/json/schema/proof.f.js +16 -1
- package/fs/mcp/module.f.d.ts +103 -5
- package/fs/mcp/module.f.js +139 -2
- package/fs/mcp/proof.f.d.ts +34 -0
- package/fs/mcp/proof.f.js +207 -0
- package/fs/mcp/stdio/module.f.d.ts +39 -0
- package/fs/mcp/stdio/module.f.js +54 -0
- package/fs/mcp/stdio/proof.f.d.ts +10 -0
- package/fs/mcp/stdio/proof.f.js +92 -0
- package/fs/mime/module.f.d.ts +39 -0
- package/fs/mime/module.f.js +78 -0
- package/fs/mime/proof.f.d.ts +15 -0
- package/fs/mime/proof.f.js +30 -0
- package/fs/path/module.f.d.ts +8 -0
- package/fs/path/module.f.js +10 -3
- package/fs/path/proof.f.d.ts +1 -0
- package/fs/path/proof.f.js +40 -2
- package/fs/text/sgr/proof.f.js +30 -2
- package/fs/text/utf8/module.f.d.ts +7 -0
- package/fs/text/utf8/module.f.js +85 -31
- package/fs/text/utf8/proof.f.d.ts +1 -0
- package/fs/text/utf8/proof.f.js +60 -1
- package/fs/types/bigfloat/module.f.d.ts +3 -0
- package/fs/types/bigfloat/module.f.js +30 -31
- package/fs/types/bigint/module.f.d.ts +24 -2
- package/fs/types/bigint/module.f.js +30 -2
- package/fs/types/bigint/proof.f.d.ts +7 -0
- package/fs/types/bigint/proof.f.js +47 -16
- package/fs/types/bit_vec/module.f.d.ts +18 -0
- package/fs/types/bit_vec/module.f.js +18 -0
- package/fs/types/bit_vec/proof.f.d.ts +1 -0
- package/fs/types/bit_vec/proof.f.js +13 -1
- package/fs/types/function/operator/proof.f.d.ts +2 -0
- package/fs/types/function/operator/proof.f.js +20 -2
- package/fs/types/list/module.f.js +1 -4
- package/fs/types/list/proof.f.d.ts +1 -1
- package/fs/types/list/proof.f.js +14 -6
- package/fs/types/map/proof.f.d.ts +1 -0
- package/fs/types/map/proof.f.js +10 -1
- package/fs/types/nibble_set/module.f.d.ts +13 -0
- package/fs/types/nibble_set/module.f.js +16 -0
- package/fs/types/object/module.f.d.ts +12 -8
- package/fs/types/object/module.f.js +9 -2
- package/fs/types/object/proof.f.d.ts +14 -0
- package/fs/types/object/proof.f.js +4 -0
- package/fs/types/ordered_map/proof.f.d.ts +1 -0
- package/fs/types/ordered_map/proof.f.js +39 -79
- package/fs/types/phantom/module.f.d.ts +22 -0
- package/fs/types/phantom/module.f.js +11 -0
- package/fs/types/prime_field/proof.f.d.ts +7 -0
- package/fs/types/prime_field/proof.f.js +63 -122
- package/fs/types/rtti/common/module.f.d.ts +4 -4
- package/fs/types/rtti/common/module.f.js +1 -1
- package/fs/types/rtti/module.f.d.ts +2 -3
- package/fs/types/rtti/parse/module.f.js +0 -1
- package/fs/types/rtti/ts/module.f.d.ts +26 -32
- package/fs/types/rtti/ts/module.f.js +2 -2
- package/fs/types/rtti/ts/proof.f.js +3 -3
- package/fs/types/rtti/validate/module.f.js +0 -1
- package/fs/types/sorted_list/module.f.d.ts +6 -0
- package/fs/types/sorted_list/module.f.js +11 -0
- package/fs/types/sorted_set/module.f.js +2 -8
- package/fs/types/ts/module.f.d.ts +1 -1
- package/fs/types/ts/module.f.js +3 -1
- package/fs/types/ts/proof.f.js +3 -2
- package/fs/website/proof.f.d.ts +1 -0
- package/fs/website/proof.f.js +8 -1
- package/package.json +3 -3
package/fs/asn.1/module.f.js
CHANGED
|
@@ -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)
|
|
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
|
|
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
|
-
|
|
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. */
|
package/fs/asn.1/proof.f.d.ts
CHANGED
package/fs/asn.1/proof.f.js
CHANGED
|
@@ -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
|
-
|
|
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
|
*/
|
package/fs/bnf/data/module.f.js
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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) {
|
package/fs/bnf/module.f.d.ts
CHANGED
|
@@ -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]
|
|
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}.
|
package/fs/bnf/module.f.js
CHANGED
|
@@ -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
|
|
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
|
|
106
|
+
for (const r of definedValues(v)) {
|
|
106
107
|
result = removeOne(result, r);
|
|
107
108
|
}
|
|
108
109
|
return toVariantRangeSet(result);
|
package/fs/bnf/proof.f.d.ts
CHANGED
|
@@ -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
|
};
|