eyelang 1.6.0 → 1.6.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/package.json +1 -1
- package/src/builtins/n3.js +3 -3
- package/src/hash.js +294 -0
- package/test/run-regression.js +52 -0
package/package.json
CHANGED
package/src/builtins/n3.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// RDF parser lowers body triples with math:, string:, list:, crypto:, time:, and
|
|
3
3
|
// selected log: predicates to n3_* eyelang builtins. The handlers work on the
|
|
4
4
|
// explicit RDF term representation from src/rdf.js.
|
|
5
|
-
import
|
|
5
|
+
import { hashHex } from '../hash.js';
|
|
6
6
|
import { compareLexicalOrNumeric } from './arithmetic.js';
|
|
7
7
|
import { deref, isDecimalInteger, listFromItems, parseFiniteNumber, properListItems, termToString, unify } from '../term.js';
|
|
8
8
|
import { RDF_DIR_LANG_STRING, RDF_LANG_STRING, XSD_BOOLEAN, XSD_DECIMAL, XSD_DOUBLE, XSD_INTEGER, XSD_STRING, rdfIri, rdfLiteral } from '../rdf.js';
|
|
@@ -423,7 +423,7 @@ function cryptoHash(name) {
|
|
|
423
423
|
return function* ({ goal, env }) {
|
|
424
424
|
const s = jsString(goal.args[0], env);
|
|
425
425
|
if (s == null) return;
|
|
426
|
-
const out =
|
|
426
|
+
const out = hashHex(algo, s);
|
|
427
427
|
yield* bindOrCheck(goal.args[1], rdfLiteral(out, XSD_STRING, '', ''), env);
|
|
428
428
|
};
|
|
429
429
|
}
|
|
@@ -445,7 +445,7 @@ function timeComponent(name) {
|
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
function* localTime({ goal, env }) {
|
|
448
|
-
const fixed = process.env
|
|
448
|
+
const fixed = typeof process !== 'undefined' ? process.env?.EYELANG_LOCAL_TIME : null;
|
|
449
449
|
const now = fixed || new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
450
450
|
yield* bindOrCheck(goal.args[1], rdfLiteral(now, XSD_DATE_TIME, '', ''), env);
|
|
451
451
|
}
|
package/src/hash.js
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
// Small dependency-free hashing helpers shared by Node and browser builds.
|
|
2
|
+
// They intentionally avoid node:crypto so src/index.js remains importable by the
|
|
3
|
+
// browser playground when the N3 crypto builtins are registered.
|
|
4
|
+
|
|
5
|
+
const textEncoder = new TextEncoder();
|
|
6
|
+
|
|
7
|
+
export function hashHex(algorithm, text) {
|
|
8
|
+
const name = String(algorithm).toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
9
|
+
const bytes = textEncoder.encode(String(text));
|
|
10
|
+
if (name === 'md5') return md5Hex(bytes);
|
|
11
|
+
if (name === 'sha' || name === 'sha1') return sha1Hex(bytes);
|
|
12
|
+
if (name === 'sha256') return sha256Hex(bytes);
|
|
13
|
+
if (name === 'sha512') return sha512Hex(bytes);
|
|
14
|
+
throw new Error(`Unsupported hash algorithm: ${algorithm}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function hex32(x) {
|
|
18
|
+
return (x >>> 0).toString(16).padStart(8, '0');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function rotr32(x, n) {
|
|
22
|
+
return (x >>> n) | (x << (32 - n));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function rotl32(x, n) {
|
|
26
|
+
return (x << n) | (x >>> (32 - n));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function bytesToHex(bytes) {
|
|
30
|
+
let out = '';
|
|
31
|
+
for (const b of bytes) out += b.toString(16).padStart(2, '0');
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function paddedBytes(bytes, blockBytes, lengthBytes, littleLength = false) {
|
|
36
|
+
const bitLength = BigInt(bytes.length) * 8n;
|
|
37
|
+
const withOne = bytes.length + 1;
|
|
38
|
+
const zeroCount = (blockBytes - ((withOne + lengthBytes) % blockBytes)) % blockBytes;
|
|
39
|
+
const out = new Uint8Array(withOne + zeroCount + lengthBytes);
|
|
40
|
+
out.set(bytes, 0);
|
|
41
|
+
out[bytes.length] = 0x80;
|
|
42
|
+
for (let i = 0; i < lengthBytes; i++) {
|
|
43
|
+
const shift = BigInt(littleLength ? i * 8 : (lengthBytes - 1 - i) * 8);
|
|
44
|
+
out[out.length - lengthBytes + i] = Number((bitLength >> shift) & 0xffn);
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function sha1Hex(bytes) {
|
|
50
|
+
const msg = paddedBytes(bytes, 64, 8);
|
|
51
|
+
let h0 = 0x67452301;
|
|
52
|
+
let h1 = 0xefcdab89;
|
|
53
|
+
let h2 = 0x98badcfe;
|
|
54
|
+
let h3 = 0x10325476;
|
|
55
|
+
let h4 = 0xc3d2e1f0;
|
|
56
|
+
const w = new Array(80);
|
|
57
|
+
|
|
58
|
+
for (let offset = 0; offset < msg.length; offset += 64) {
|
|
59
|
+
for (let i = 0; i < 16; i++) {
|
|
60
|
+
const j = offset + i * 4;
|
|
61
|
+
w[i] = ((msg[j] << 24) | (msg[j + 1] << 16) | (msg[j + 2] << 8) | msg[j + 3]) >>> 0;
|
|
62
|
+
}
|
|
63
|
+
for (let i = 16; i < 80; i++) w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1) >>> 0;
|
|
64
|
+
|
|
65
|
+
let a = h0, b = h1, c = h2, d = h3, e = h4;
|
|
66
|
+
for (let i = 0; i < 80; i++) {
|
|
67
|
+
let f, k;
|
|
68
|
+
if (i < 20) { f = (b & c) | (~b & d); k = 0x5a827999; }
|
|
69
|
+
else if (i < 40) { f = b ^ c ^ d; k = 0x6ed9eba1; }
|
|
70
|
+
else if (i < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8f1bbcdc; }
|
|
71
|
+
else { f = b ^ c ^ d; k = 0xca62c1d6; }
|
|
72
|
+
const temp = (rotl32(a, 5) + f + e + k + w[i]) >>> 0;
|
|
73
|
+
e = d;
|
|
74
|
+
d = c;
|
|
75
|
+
c = rotl32(b, 30) >>> 0;
|
|
76
|
+
b = a;
|
|
77
|
+
a = temp;
|
|
78
|
+
}
|
|
79
|
+
h0 = (h0 + a) >>> 0;
|
|
80
|
+
h1 = (h1 + b) >>> 0;
|
|
81
|
+
h2 = (h2 + c) >>> 0;
|
|
82
|
+
h3 = (h3 + d) >>> 0;
|
|
83
|
+
h4 = (h4 + e) >>> 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return [h0, h1, h2, h3, h4].map(hex32).join('');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const SHA256_K = [
|
|
90
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
91
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
92
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
93
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
94
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
95
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
96
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
97
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
function sha256Hex(bytes) {
|
|
101
|
+
const msg = paddedBytes(bytes, 64, 8);
|
|
102
|
+
let h0 = 0x6a09e667;
|
|
103
|
+
let h1 = 0xbb67ae85;
|
|
104
|
+
let h2 = 0x3c6ef372;
|
|
105
|
+
let h3 = 0xa54ff53a;
|
|
106
|
+
let h4 = 0x510e527f;
|
|
107
|
+
let h5 = 0x9b05688c;
|
|
108
|
+
let h6 = 0x1f83d9ab;
|
|
109
|
+
let h7 = 0x5be0cd19;
|
|
110
|
+
const w = new Array(64);
|
|
111
|
+
|
|
112
|
+
for (let offset = 0; offset < msg.length; offset += 64) {
|
|
113
|
+
for (let i = 0; i < 16; i++) {
|
|
114
|
+
const j = offset + i * 4;
|
|
115
|
+
w[i] = ((msg[j] << 24) | (msg[j + 1] << 16) | (msg[j + 2] << 8) | msg[j + 3]) >>> 0;
|
|
116
|
+
}
|
|
117
|
+
for (let i = 16; i < 64; i++) {
|
|
118
|
+
const s0 = (rotr32(w[i - 15], 7) ^ rotr32(w[i - 15], 18) ^ (w[i - 15] >>> 3)) >>> 0;
|
|
119
|
+
const s1 = (rotr32(w[i - 2], 17) ^ rotr32(w[i - 2], 19) ^ (w[i - 2] >>> 10)) >>> 0;
|
|
120
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;
|
|
124
|
+
for (let i = 0; i < 64; i++) {
|
|
125
|
+
const S1 = (rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25)) >>> 0;
|
|
126
|
+
const ch = ((e & f) ^ (~e & g)) >>> 0;
|
|
127
|
+
const temp1 = (h + S1 + ch + SHA256_K[i] + w[i]) >>> 0;
|
|
128
|
+
const S0 = (rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22)) >>> 0;
|
|
129
|
+
const maj = ((a & b) ^ (a & c) ^ (b & c)) >>> 0;
|
|
130
|
+
const temp2 = (S0 + maj) >>> 0;
|
|
131
|
+
h = g;
|
|
132
|
+
g = f;
|
|
133
|
+
f = e;
|
|
134
|
+
e = (d + temp1) >>> 0;
|
|
135
|
+
d = c;
|
|
136
|
+
c = b;
|
|
137
|
+
b = a;
|
|
138
|
+
a = (temp1 + temp2) >>> 0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
h0 = (h0 + a) >>> 0;
|
|
142
|
+
h1 = (h1 + b) >>> 0;
|
|
143
|
+
h2 = (h2 + c) >>> 0;
|
|
144
|
+
h3 = (h3 + d) >>> 0;
|
|
145
|
+
h4 = (h4 + e) >>> 0;
|
|
146
|
+
h5 = (h5 + f) >>> 0;
|
|
147
|
+
h6 = (h6 + g) >>> 0;
|
|
148
|
+
h7 = (h7 + h) >>> 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return [h0, h1, h2, h3, h4, h5, h6, h7].map(hex32).join('');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const MD5_S = [
|
|
155
|
+
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
|
156
|
+
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
|
157
|
+
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
|
158
|
+
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
|
|
159
|
+
];
|
|
160
|
+
const MD5_K = Array.from({ length: 64 }, (_, i) => Math.floor(Math.abs(Math.sin(i + 1)) * 2 ** 32) >>> 0);
|
|
161
|
+
|
|
162
|
+
function md5Hex(bytes) {
|
|
163
|
+
const msg = paddedBytes(bytes, 64, 8, true);
|
|
164
|
+
let a0 = 0x67452301;
|
|
165
|
+
let b0 = 0xefcdab89;
|
|
166
|
+
let c0 = 0x98badcfe;
|
|
167
|
+
let d0 = 0x10325476;
|
|
168
|
+
const m = new Array(16);
|
|
169
|
+
|
|
170
|
+
for (let offset = 0; offset < msg.length; offset += 64) {
|
|
171
|
+
for (let i = 0; i < 16; i++) {
|
|
172
|
+
const j = offset + i * 4;
|
|
173
|
+
m[i] = (msg[j] | (msg[j + 1] << 8) | (msg[j + 2] << 16) | (msg[j + 3] << 24)) >>> 0;
|
|
174
|
+
}
|
|
175
|
+
let a = a0, b = b0, c = c0, d = d0;
|
|
176
|
+
|
|
177
|
+
for (let i = 0; i < 64; i++) {
|
|
178
|
+
let f, g;
|
|
179
|
+
if (i < 16) { f = (b & c) | (~b & d); g = i; }
|
|
180
|
+
else if (i < 32) { f = (d & b) | (~d & c); g = (5 * i + 1) % 16; }
|
|
181
|
+
else if (i < 48) { f = b ^ c ^ d; g = (3 * i + 5) % 16; }
|
|
182
|
+
else { f = c ^ (b | ~d); g = (7 * i) % 16; }
|
|
183
|
+
f = (f + a + MD5_K[i] + m[g]) >>> 0;
|
|
184
|
+
a = d;
|
|
185
|
+
d = c;
|
|
186
|
+
c = b;
|
|
187
|
+
b = (b + rotl32(f, MD5_S[i])) >>> 0;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
a0 = (a0 + a) >>> 0;
|
|
191
|
+
b0 = (b0 + b) >>> 0;
|
|
192
|
+
c0 = (c0 + c) >>> 0;
|
|
193
|
+
d0 = (d0 + d) >>> 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const out = new Uint8Array(16);
|
|
197
|
+
for (const [i, word] of [a0, b0, c0, d0].entries()) {
|
|
198
|
+
out[i * 4] = word & 0xff;
|
|
199
|
+
out[i * 4 + 1] = (word >>> 8) & 0xff;
|
|
200
|
+
out[i * 4 + 2] = (word >>> 16) & 0xff;
|
|
201
|
+
out[i * 4 + 3] = (word >>> 24) & 0xff;
|
|
202
|
+
}
|
|
203
|
+
return bytesToHex(out);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const MASK64 = (1n << 64n) - 1n;
|
|
207
|
+
const SHA512_H0 = [
|
|
208
|
+
0x6a09e667f3bcc908n, 0xbb67ae8584caa73bn, 0x3c6ef372fe94f82bn, 0xa54ff53a5f1d36f1n,
|
|
209
|
+
0x510e527fade682d1n, 0x9b05688c2b3e6c1fn, 0x1f83d9abfb41bd6bn, 0x5be0cd19137e2179n,
|
|
210
|
+
];
|
|
211
|
+
const SHA512_K = [
|
|
212
|
+
0x428a2f98d728ae22n, 0x7137449123ef65cdn, 0xb5c0fbcfec4d3b2fn, 0xe9b5dba58189dbbcn,
|
|
213
|
+
0x3956c25bf348b538n, 0x59f111f1b605d019n, 0x923f82a4af194f9bn, 0xab1c5ed5da6d8118n,
|
|
214
|
+
0xd807aa98a3030242n, 0x12835b0145706fben, 0x243185be4ee4b28cn, 0x550c7dc3d5ffb4e2n,
|
|
215
|
+
0x72be5d74f27b896fn, 0x80deb1fe3b1696b1n, 0x9bdc06a725c71235n, 0xc19bf174cf692694n,
|
|
216
|
+
0xe49b69c19ef14ad2n, 0xefbe4786384f25e3n, 0x0fc19dc68b8cd5b5n, 0x240ca1cc77ac9c65n,
|
|
217
|
+
0x2de92c6f592b0275n, 0x4a7484aa6ea6e483n, 0x5cb0a9dcbd41fbd4n, 0x76f988da831153b5n,
|
|
218
|
+
0x983e5152ee66dfabn, 0xa831c66d2db43210n, 0xb00327c898fb213fn, 0xbf597fc7beef0ee4n,
|
|
219
|
+
0xc6e00bf33da88fc2n, 0xd5a79147930aa725n, 0x06ca6351e003826fn, 0x142929670a0e6e70n,
|
|
220
|
+
0x27b70a8546d22ffcn, 0x2e1b21385c26c926n, 0x4d2c6dfc5ac42aedn, 0x53380d139d95b3dfn,
|
|
221
|
+
0x650a73548baf63den, 0x766a0abb3c77b2a8n, 0x81c2c92e47edaee6n, 0x92722c851482353bn,
|
|
222
|
+
0xa2bfe8a14cf10364n, 0xa81a664bbc423001n, 0xc24b8b70d0f89791n, 0xc76c51a30654be30n,
|
|
223
|
+
0xd192e819d6ef5218n, 0xd69906245565a910n, 0xf40e35855771202an, 0x106aa07032bbd1b8n,
|
|
224
|
+
0x19a4c116b8d2d0c8n, 0x1e376c085141ab53n, 0x2748774cdf8eeb99n, 0x34b0bcb5e19b48a8n,
|
|
225
|
+
0x391c0cb3c5c95a63n, 0x4ed8aa4ae3418acbn, 0x5b9cca4f7763e373n, 0x682e6ff3d6b2b8a3n,
|
|
226
|
+
0x748f82ee5defb2fcn, 0x78a5636f43172f60n, 0x84c87814a1f0ab72n, 0x8cc702081a6439ecn,
|
|
227
|
+
0x90befffa23631e28n, 0xa4506cebde82bde9n, 0xbef9a3f7b2c67915n, 0xc67178f2e372532bn,
|
|
228
|
+
0xca273eceea26619cn, 0xd186b8c721c0c207n, 0xeada7dd6cde0eb1en, 0xf57d4f7fee6ed178n,
|
|
229
|
+
0x06f067aa72176fban, 0x0a637dc5a2c898a6n, 0x113f9804bef90daen, 0x1b710b35131c471bn,
|
|
230
|
+
0x28db77f523047d84n, 0x32caab7b40c72493n, 0x3c9ebe0a15c9bebcn, 0x431d67c49c100d4cn,
|
|
231
|
+
0x4cc5d4becb3e42b6n, 0x597f299cfc657e2an, 0x5fcb6fab3ad6faecn, 0x6c44198c4a475817n,
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
function rotr64(x, n) {
|
|
235
|
+
return ((x >> BigInt(n)) | (x << BigInt(64 - n))) & MASK64;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function shr64(x, n) {
|
|
239
|
+
return x >> BigInt(n);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function add64(...xs) {
|
|
243
|
+
let out = 0n;
|
|
244
|
+
for (const x of xs) out = (out + x) & MASK64;
|
|
245
|
+
return out;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function sha512Hex(bytes) {
|
|
249
|
+
const msg = paddedBytes(bytes, 128, 16);
|
|
250
|
+
const h = [...SHA512_H0];
|
|
251
|
+
const w = new Array(80).fill(0n);
|
|
252
|
+
|
|
253
|
+
for (let offset = 0; offset < msg.length; offset += 128) {
|
|
254
|
+
for (let i = 0; i < 16; i++) {
|
|
255
|
+
let word = 0n;
|
|
256
|
+
for (let j = 0; j < 8; j++) word = (word << 8n) | BigInt(msg[offset + i * 8 + j]);
|
|
257
|
+
w[i] = word;
|
|
258
|
+
}
|
|
259
|
+
for (let i = 16; i < 80; i++) {
|
|
260
|
+
const s0 = rotr64(w[i - 15], 1) ^ rotr64(w[i - 15], 8) ^ shr64(w[i - 15], 7);
|
|
261
|
+
const s1 = rotr64(w[i - 2], 19) ^ rotr64(w[i - 2], 61) ^ shr64(w[i - 2], 6);
|
|
262
|
+
w[i] = add64(w[i - 16], s0, w[i - 7], s1);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let [a, b, c, d, e, f, g, hh] = h;
|
|
266
|
+
for (let i = 0; i < 80; i++) {
|
|
267
|
+
const S1 = rotr64(e, 14) ^ rotr64(e, 18) ^ rotr64(e, 41);
|
|
268
|
+
const ch = (e & f) ^ (~e & g);
|
|
269
|
+
const temp1 = add64(hh, S1, ch, SHA512_K[i], w[i]);
|
|
270
|
+
const S0 = rotr64(a, 28) ^ rotr64(a, 34) ^ rotr64(a, 39);
|
|
271
|
+
const maj = (a & b) ^ (a & c) ^ (b & c);
|
|
272
|
+
const temp2 = add64(S0, maj);
|
|
273
|
+
hh = g;
|
|
274
|
+
g = f;
|
|
275
|
+
f = e;
|
|
276
|
+
e = add64(d, temp1);
|
|
277
|
+
d = c;
|
|
278
|
+
c = b;
|
|
279
|
+
b = a;
|
|
280
|
+
a = add64(temp1, temp2);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
h[0] = add64(h[0], a);
|
|
284
|
+
h[1] = add64(h[1], b);
|
|
285
|
+
h[2] = add64(h[2], c);
|
|
286
|
+
h[3] = add64(h[3], d);
|
|
287
|
+
h[4] = add64(h[4], e);
|
|
288
|
+
h[5] = add64(h[5], f);
|
|
289
|
+
h[6] = add64(h[6], g);
|
|
290
|
+
h[7] = add64(h[7], hh);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return h.map((x) => x.toString(16).padStart(16, '0')).join('');
|
|
294
|
+
}
|
package/test/run-regression.js
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
import { parseGoalText } from '../src/parser.js';
|
|
36
36
|
import { selectClauseCandidates } from '../src/program.js';
|
|
37
37
|
import { TestReporter, isMainModule } from './test-style.js';
|
|
38
|
+
import { hashHex } from '../src/hash.js';
|
|
38
39
|
|
|
39
40
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
40
41
|
const bin = path.join(root, 'bin', 'eyelang');
|
|
@@ -196,6 +197,21 @@ why(
|
|
|
196
197
|
assertEqual(playgroundExamples.join('\n'), examples.join('\n'), 'playground examples');
|
|
197
198
|
},
|
|
198
199
|
},
|
|
200
|
+
{
|
|
201
|
+
name: 'playground import graph is browser-safe',
|
|
202
|
+
run: () => {
|
|
203
|
+
const files = playgroundImportGraph();
|
|
204
|
+
assertEqual(files.includes(path.join(root, 'src', 'index.js')), true, 'src/index.js reachable');
|
|
205
|
+
for (const file of files) {
|
|
206
|
+
const rel = path.relative(root, file).replace(/\\/g, '/');
|
|
207
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
208
|
+
for (const spec of moduleSpecifiers(text)) {
|
|
209
|
+
if (spec.startsWith('node:')) throw new Error(`${rel} imports ${spec}`);
|
|
210
|
+
if (!spec.startsWith('.')) throw new Error(`${rel} has browser-unresolved bare import ${spec}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
},
|
|
199
215
|
{
|
|
200
216
|
name: 'stdin input is accepted',
|
|
201
217
|
run: () => {
|
|
@@ -332,6 +348,16 @@ function apiCases() {
|
|
|
332
348
|
},
|
|
333
349
|
},
|
|
334
350
|
|
|
351
|
+
{
|
|
352
|
+
name: 'portable hash helpers match standard vectors',
|
|
353
|
+
run: () => {
|
|
354
|
+
assertEqual(hashHex('md5', 'abc'), '900150983cd24fb0d6963f7d28e17f72', 'md5');
|
|
355
|
+
assertEqual(hashHex('sha', 'abc'), 'a9993e364706816aba3e25717850c26c9cd0d89d', 'sha1');
|
|
356
|
+
assertEqual(hashHex('sha256', 'abc'), 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', 'sha256');
|
|
357
|
+
assertEqual(hashHex('sha512', 'abc'), 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f', 'sha512');
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
|
|
335
361
|
|
|
336
362
|
{
|
|
337
363
|
name: 'run materialization can enable proof explanations',
|
|
@@ -558,6 +584,32 @@ function playgroundExampleNames() {
|
|
|
558
584
|
.sort();
|
|
559
585
|
}
|
|
560
586
|
|
|
587
|
+
function playgroundImportGraph() {
|
|
588
|
+
const entry = path.join(root, 'playground-worker.mjs');
|
|
589
|
+
const seen = new Set();
|
|
590
|
+
const stack = [entry];
|
|
591
|
+
while (stack.length > 0) {
|
|
592
|
+
const file = stack.pop();
|
|
593
|
+
if (seen.has(file)) continue;
|
|
594
|
+
seen.add(file);
|
|
595
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
596
|
+
for (const spec of moduleSpecifiers(text)) {
|
|
597
|
+
if (spec.startsWith('node:')) throw new Error(`${path.relative(root, file)} imports ${spec}`);
|
|
598
|
+
if (!spec.startsWith('.')) continue;
|
|
599
|
+
const next = path.resolve(path.dirname(file), spec);
|
|
600
|
+
if (next.startsWith(root) && fs.existsSync(next)) stack.push(next);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return [...seen].sort();
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
function moduleSpecifiers(text) {
|
|
607
|
+
const specs = [];
|
|
608
|
+
for (const match of text.matchAll(/(?:import|export)\s+(?:[^'"]*?\s+from\s+)?['"]([^'"]+)['"]/g)) specs.push(match[1]);
|
|
609
|
+
for (const match of text.matchAll(/import\(\s*['"]([^'"]+)['"]\s*\)/g)) specs.push(match[1]);
|
|
610
|
+
return specs;
|
|
611
|
+
}
|
|
612
|
+
|
|
561
613
|
function between(text, startMarker, endMarker) {
|
|
562
614
|
const start = text.indexOf(startMarker);
|
|
563
615
|
if (start === -1) throw new Error(`${startMarker} not found`);
|