WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Set default behavior to automatically convert line endings
|
||||
* text=auto eol=lf
|
||||
@@ -0,0 +1,401 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.argon2idAsync = exports.argon2iAsync = exports.argon2dAsync = exports.argon2id = exports.argon2i = exports.argon2d = void 0;
|
||||
/**
|
||||
* Argon2 KDF from RFC 9106. Can be used to create a key from password and salt.
|
||||
* We suggest to use Scrypt. JS Argon is 2-10x slower than native code because of 64-bitness:
|
||||
* * argon uses uint64, but JS doesn't have fast uint64array
|
||||
* * uint64 multiplication is 1/3 of time
|
||||
* * `P` function would be very nice with u64, because most of value will be in registers,
|
||||
* hovewer with u32 it will require 32 registers, which is too much.
|
||||
* * JS arrays do slow bound checks, so reading from `A2_BUF` slows it down
|
||||
* @module
|
||||
*/
|
||||
const _u64_ts_1 = require("./_u64.js");
|
||||
const blake2_ts_1 = require("./blake2.js");
|
||||
const utils_ts_1 = require("./utils.js");
|
||||
const AT = { Argond2d: 0, Argon2i: 1, Argon2id: 2 };
|
||||
const ARGON2_SYNC_POINTS = 4;
|
||||
const abytesOrZero = (buf) => {
|
||||
if (buf === undefined)
|
||||
return Uint8Array.of();
|
||||
return (0, utils_ts_1.kdfInputToBytes)(buf);
|
||||
};
|
||||
// u32 * u32 = u64
|
||||
function mul(a, b) {
|
||||
const aL = a & 0xffff;
|
||||
const aH = a >>> 16;
|
||||
const bL = b & 0xffff;
|
||||
const bH = b >>> 16;
|
||||
const ll = Math.imul(aL, bL);
|
||||
const hl = Math.imul(aH, bL);
|
||||
const lh = Math.imul(aL, bH);
|
||||
const hh = Math.imul(aH, bH);
|
||||
const carry = (ll >>> 16) + (hl & 0xffff) + lh;
|
||||
const high = (hh + (hl >>> 16) + (carry >>> 16)) | 0;
|
||||
const low = (carry << 16) | (ll & 0xffff);
|
||||
return { h: high, l: low };
|
||||
}
|
||||
function mul2(a, b) {
|
||||
// 2 * a * b (via shifts)
|
||||
const { h, l } = mul(a, b);
|
||||
return { h: ((h << 1) | (l >>> 31)) & 4294967295, l: (l << 1) & 4294967295 };
|
||||
}
|
||||
// BlaMka permutation for Argon2
|
||||
// A + B + (2 * u32(A) * u32(B))
|
||||
function blamka(Ah, Al, Bh, Bl) {
|
||||
const { h: Ch, l: Cl } = mul2(Al, Bl);
|
||||
// A + B + (2 * A * B)
|
||||
const Rll = (0, _u64_ts_1.add3L)(Al, Bl, Cl);
|
||||
return { h: (0, _u64_ts_1.add3H)(Rll, Ah, Bh, Ch), l: Rll | 0 };
|
||||
}
|
||||
// Temporary block buffer
|
||||
const A2_BUF = new Uint32Array(256); // 1024 bytes (matrix 16x16)
|
||||
function G(a, b, c, d) {
|
||||
let Al = A2_BUF[2 * a], Ah = A2_BUF[2 * a + 1]; // prettier-ignore
|
||||
let Bl = A2_BUF[2 * b], Bh = A2_BUF[2 * b + 1]; // prettier-ignore
|
||||
let Cl = A2_BUF[2 * c], Ch = A2_BUF[2 * c + 1]; // prettier-ignore
|
||||
let Dl = A2_BUF[2 * d], Dh = A2_BUF[2 * d + 1]; // prettier-ignore
|
||||
({ h: Ah, l: Al } = blamka(Ah, Al, Bh, Bl));
|
||||
({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al });
|
||||
({ Dh, Dl } = { Dh: (0, _u64_ts_1.rotr32H)(Dh, Dl), Dl: (0, _u64_ts_1.rotr32L)(Dh, Dl) });
|
||||
({ h: Ch, l: Cl } = blamka(Ch, Cl, Dh, Dl));
|
||||
({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl });
|
||||
({ Bh, Bl } = { Bh: (0, _u64_ts_1.rotrSH)(Bh, Bl, 24), Bl: (0, _u64_ts_1.rotrSL)(Bh, Bl, 24) });
|
||||
({ h: Ah, l: Al } = blamka(Ah, Al, Bh, Bl));
|
||||
({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al });
|
||||
({ Dh, Dl } = { Dh: (0, _u64_ts_1.rotrSH)(Dh, Dl, 16), Dl: (0, _u64_ts_1.rotrSL)(Dh, Dl, 16) });
|
||||
({ h: Ch, l: Cl } = blamka(Ch, Cl, Dh, Dl));
|
||||
({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl });
|
||||
({ Bh, Bl } = { Bh: (0, _u64_ts_1.rotrBH)(Bh, Bl, 63), Bl: (0, _u64_ts_1.rotrBL)(Bh, Bl, 63) });
|
||||
(A2_BUF[2 * a] = Al), (A2_BUF[2 * a + 1] = Ah);
|
||||
(A2_BUF[2 * b] = Bl), (A2_BUF[2 * b + 1] = Bh);
|
||||
(A2_BUF[2 * c] = Cl), (A2_BUF[2 * c + 1] = Ch);
|
||||
(A2_BUF[2 * d] = Dl), (A2_BUF[2 * d + 1] = Dh);
|
||||
}
|
||||
// prettier-ignore
|
||||
function P(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14, v15) {
|
||||
G(v00, v04, v08, v12);
|
||||
G(v01, v05, v09, v13);
|
||||
G(v02, v06, v10, v14);
|
||||
G(v03, v07, v11, v15);
|
||||
G(v00, v05, v10, v15);
|
||||
G(v01, v06, v11, v12);
|
||||
G(v02, v07, v08, v13);
|
||||
G(v03, v04, v09, v14);
|
||||
}
|
||||
function block(x, xPos, yPos, outPos, needXor) {
|
||||
for (let i = 0; i < 256; i++)
|
||||
A2_BUF[i] = x[xPos + i] ^ x[yPos + i];
|
||||
// columns (8)
|
||||
for (let i = 0; i < 128; i += 16) {
|
||||
// prettier-ignore
|
||||
P(i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, i + 10, i + 11, i + 12, i + 13, i + 14, i + 15);
|
||||
}
|
||||
// rows (8)
|
||||
for (let i = 0; i < 16; i += 2) {
|
||||
// prettier-ignore
|
||||
P(i, i + 1, i + 16, i + 17, i + 32, i + 33, i + 48, i + 49, i + 64, i + 65, i + 80, i + 81, i + 96, i + 97, i + 112, i + 113);
|
||||
}
|
||||
if (needXor)
|
||||
for (let i = 0; i < 256; i++)
|
||||
x[outPos + i] ^= A2_BUF[i] ^ x[xPos + i] ^ x[yPos + i];
|
||||
else
|
||||
for (let i = 0; i < 256; i++)
|
||||
x[outPos + i] = A2_BUF[i] ^ x[xPos + i] ^ x[yPos + i];
|
||||
(0, utils_ts_1.clean)(A2_BUF);
|
||||
}
|
||||
// Variable-Length Hash Function H'
|
||||
function Hp(A, dkLen) {
|
||||
const A8 = (0, utils_ts_1.u8)(A);
|
||||
const T = new Uint32Array(1);
|
||||
const T8 = (0, utils_ts_1.u8)(T);
|
||||
T[0] = dkLen;
|
||||
// Fast path
|
||||
if (dkLen <= 64)
|
||||
return blake2_ts_1.blake2b.create({ dkLen }).update(T8).update(A8).digest();
|
||||
const out = new Uint8Array(dkLen);
|
||||
let V = blake2_ts_1.blake2b.create({}).update(T8).update(A8).digest();
|
||||
let pos = 0;
|
||||
// First block
|
||||
out.set(V.subarray(0, 32));
|
||||
pos += 32;
|
||||
// Rest blocks
|
||||
for (; dkLen - pos > 64; pos += 32) {
|
||||
const Vh = blake2_ts_1.blake2b.create({}).update(V);
|
||||
Vh.digestInto(V);
|
||||
Vh.destroy();
|
||||
out.set(V.subarray(0, 32), pos);
|
||||
}
|
||||
// Last block
|
||||
out.set((0, blake2_ts_1.blake2b)(V, { dkLen: dkLen - pos }), pos);
|
||||
(0, utils_ts_1.clean)(V, T);
|
||||
return (0, utils_ts_1.u32)(out);
|
||||
}
|
||||
// Used only inside process block!
|
||||
function indexAlpha(r, s, laneLen, segmentLen, index, randL, sameLane = false) {
|
||||
// This is ugly, but close enough to reference implementation.
|
||||
let area;
|
||||
if (r === 0) {
|
||||
if (s === 0)
|
||||
area = index - 1;
|
||||
else if (sameLane)
|
||||
area = s * segmentLen + index - 1;
|
||||
else
|
||||
area = s * segmentLen + (index == 0 ? -1 : 0);
|
||||
}
|
||||
else if (sameLane)
|
||||
area = laneLen - segmentLen + index - 1;
|
||||
else
|
||||
area = laneLen - segmentLen + (index == 0 ? -1 : 0);
|
||||
const startPos = r !== 0 && s !== ARGON2_SYNC_POINTS - 1 ? (s + 1) * segmentLen : 0;
|
||||
const rel = area - 1 - mul(area, mul(randL, randL).h).h;
|
||||
return (startPos + rel) % laneLen;
|
||||
}
|
||||
const maxUint32 = Math.pow(2, 32);
|
||||
function isU32(num) {
|
||||
return Number.isSafeInteger(num) && num >= 0 && num < maxUint32;
|
||||
}
|
||||
function argon2Opts(opts) {
|
||||
const merged = {
|
||||
version: 0x13,
|
||||
dkLen: 32,
|
||||
maxmem: maxUint32 - 1,
|
||||
asyncTick: 10,
|
||||
};
|
||||
for (let [k, v] of Object.entries(opts))
|
||||
if (v != null)
|
||||
merged[k] = v;
|
||||
const { dkLen, p, m, t, version, onProgress } = merged;
|
||||
if (!isU32(dkLen) || dkLen < 4)
|
||||
throw new Error('dkLen should be at least 4 bytes');
|
||||
if (!isU32(p) || p < 1 || p >= Math.pow(2, 24))
|
||||
throw new Error('p should be 1 <= p < 2^24');
|
||||
if (!isU32(m))
|
||||
throw new Error('m should be 0 <= m < 2^32');
|
||||
if (!isU32(t) || t < 1)
|
||||
throw new Error('t (iterations) should be 1 <= t < 2^32');
|
||||
if (onProgress !== undefined && typeof onProgress !== 'function')
|
||||
throw new Error('progressCb should be function');
|
||||
/*
|
||||
Memory size m MUST be an integer number of kibibytes from 8*p to 2^(32)-1. The actual number of blocks is m', which is m rounded down to the nearest multiple of 4*p.
|
||||
*/
|
||||
if (!isU32(m) || m < 8 * p)
|
||||
throw new Error('memory should be at least 8*p bytes');
|
||||
if (version !== 0x10 && version !== 0x13)
|
||||
throw new Error('unknown version=' + version);
|
||||
return merged;
|
||||
}
|
||||
function argon2Init(password, salt, type, opts) {
|
||||
password = (0, utils_ts_1.kdfInputToBytes)(password);
|
||||
salt = (0, utils_ts_1.kdfInputToBytes)(salt);
|
||||
(0, utils_ts_1.abytes)(password);
|
||||
(0, utils_ts_1.abytes)(salt);
|
||||
if (!isU32(password.length))
|
||||
throw new Error('password should be less than 4 GB');
|
||||
if (!isU32(salt.length) || salt.length < 8)
|
||||
throw new Error('salt should be at least 8 bytes and less than 4 GB');
|
||||
if (!Object.values(AT).includes(type))
|
||||
throw new Error('invalid type');
|
||||
let { p, dkLen, m, t, version, key, personalization, maxmem, onProgress, asyncTick } = argon2Opts(opts);
|
||||
// Validation
|
||||
key = abytesOrZero(key);
|
||||
personalization = abytesOrZero(personalization);
|
||||
// H_0 = H^(64)(LE32(p) || LE32(T) || LE32(m) || LE32(t) ||
|
||||
// LE32(v) || LE32(y) || LE32(length(P)) || P ||
|
||||
// LE32(length(S)) || S || LE32(length(K)) || K ||
|
||||
// LE32(length(X)) || X)
|
||||
const h = blake2_ts_1.blake2b.create({});
|
||||
const BUF = new Uint32Array(1);
|
||||
const BUF8 = (0, utils_ts_1.u8)(BUF);
|
||||
for (let item of [p, dkLen, m, t, version, type]) {
|
||||
BUF[0] = item;
|
||||
h.update(BUF8);
|
||||
}
|
||||
for (let i of [password, salt, key, personalization]) {
|
||||
BUF[0] = i.length; // BUF is u32 array, this is valid
|
||||
h.update(BUF8).update(i);
|
||||
}
|
||||
const H0 = new Uint32Array(18);
|
||||
const H0_8 = (0, utils_ts_1.u8)(H0);
|
||||
h.digestInto(H0_8);
|
||||
// 256 u32 = 1024 (BLOCK_SIZE), fills A2_BUF on processing
|
||||
// Params
|
||||
const lanes = p;
|
||||
// m' = 4 * p * floor (m / 4p)
|
||||
const mP = 4 * p * Math.floor(m / (ARGON2_SYNC_POINTS * p));
|
||||
//q = m' / p columns
|
||||
const laneLen = Math.floor(mP / p);
|
||||
const segmentLen = Math.floor(laneLen / ARGON2_SYNC_POINTS);
|
||||
const memUsed = mP * 256;
|
||||
if (!isU32(maxmem) || memUsed > maxmem)
|
||||
throw new Error('mem should be less than 2**32, got: maxmem=' + maxmem + ', memused=' + memUsed);
|
||||
const B = new Uint32Array(memUsed);
|
||||
// Fill first blocks
|
||||
for (let l = 0; l < p; l++) {
|
||||
const i = 256 * laneLen * l;
|
||||
// B[i][0] = H'^(1024)(H_0 || LE32(0) || LE32(i))
|
||||
H0[17] = l;
|
||||
H0[16] = 0;
|
||||
B.set(Hp(H0, 1024), i);
|
||||
// B[i][1] = H'^(1024)(H_0 || LE32(1) || LE32(i))
|
||||
H0[16] = 1;
|
||||
B.set(Hp(H0, 1024), i + 256);
|
||||
}
|
||||
let perBlock = () => { };
|
||||
if (onProgress) {
|
||||
const totalBlock = t * ARGON2_SYNC_POINTS * p * segmentLen;
|
||||
// Invoke callback if progress changes from 10.01 to 10.02
|
||||
// Allows to draw smooth progress bar on up to 8K screen
|
||||
const callbackPer = Math.max(Math.floor(totalBlock / 10000), 1);
|
||||
let blockCnt = 0;
|
||||
perBlock = () => {
|
||||
blockCnt++;
|
||||
if (onProgress && (!(blockCnt % callbackPer) || blockCnt === totalBlock))
|
||||
onProgress(blockCnt / totalBlock);
|
||||
};
|
||||
}
|
||||
(0, utils_ts_1.clean)(BUF, H0);
|
||||
return { type, mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock, asyncTick };
|
||||
}
|
||||
function argon2Output(B, p, laneLen, dkLen) {
|
||||
const B_final = new Uint32Array(256);
|
||||
for (let l = 0; l < p; l++)
|
||||
for (let j = 0; j < 256; j++)
|
||||
B_final[j] ^= B[256 * (laneLen * l + laneLen - 1) + j];
|
||||
const res = (0, utils_ts_1.u8)(Hp(B_final, dkLen));
|
||||
(0, utils_ts_1.clean)(B_final);
|
||||
return res;
|
||||
}
|
||||
function processBlock(B, address, l, r, s, index, laneLen, segmentLen, lanes, offset, prev, dataIndependent, needXor) {
|
||||
if (offset % laneLen)
|
||||
prev = offset - 1;
|
||||
let randL, randH;
|
||||
if (dataIndependent) {
|
||||
let i128 = index % 128;
|
||||
if (i128 === 0) {
|
||||
address[256 + 12]++;
|
||||
block(address, 256, 2 * 256, 0, false);
|
||||
block(address, 0, 2 * 256, 0, false);
|
||||
}
|
||||
randL = address[2 * i128];
|
||||
randH = address[2 * i128 + 1];
|
||||
}
|
||||
else {
|
||||
const T = 256 * prev;
|
||||
randL = B[T];
|
||||
randH = B[T + 1];
|
||||
}
|
||||
// address block
|
||||
const refLane = r === 0 && s === 0 ? l : randH % lanes;
|
||||
const refPos = indexAlpha(r, s, laneLen, segmentLen, index, randL, refLane == l);
|
||||
const refBlock = laneLen * refLane + refPos;
|
||||
// B[i][j] = G(B[i][j-1], B[l][z])
|
||||
block(B, 256 * prev, 256 * refBlock, offset * 256, needXor);
|
||||
}
|
||||
function argon2(type, password, salt, opts) {
|
||||
const { mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock } = argon2Init(password, salt, type, opts);
|
||||
// Pre-loop setup
|
||||
// [address, input, zero_block] format so we can pass single U32 to block function
|
||||
const address = new Uint32Array(3 * 256);
|
||||
address[256 + 6] = mP;
|
||||
address[256 + 8] = t;
|
||||
address[256 + 10] = type;
|
||||
for (let r = 0; r < t; r++) {
|
||||
const needXor = r !== 0 && version === 0x13;
|
||||
address[256 + 0] = r;
|
||||
for (let s = 0; s < ARGON2_SYNC_POINTS; s++) {
|
||||
address[256 + 4] = s;
|
||||
const dataIndependent = type == AT.Argon2i || (type == AT.Argon2id && r === 0 && s < 2);
|
||||
for (let l = 0; l < p; l++) {
|
||||
address[256 + 2] = l;
|
||||
address[256 + 12] = 0;
|
||||
let startPos = 0;
|
||||
if (r === 0 && s === 0) {
|
||||
startPos = 2;
|
||||
if (dataIndependent) {
|
||||
address[256 + 12]++;
|
||||
block(address, 256, 2 * 256, 0, false);
|
||||
block(address, 0, 2 * 256, 0, false);
|
||||
}
|
||||
}
|
||||
// current block postion
|
||||
let offset = l * laneLen + s * segmentLen + startPos;
|
||||
// previous block position
|
||||
let prev = offset % laneLen ? offset - 1 : offset + laneLen - 1;
|
||||
for (let index = startPos; index < segmentLen; index++, offset++, prev++) {
|
||||
perBlock();
|
||||
processBlock(B, address, l, r, s, index, laneLen, segmentLen, lanes, offset, prev, dataIndependent, needXor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(0, utils_ts_1.clean)(address);
|
||||
return argon2Output(B, p, laneLen, dkLen);
|
||||
}
|
||||
/** argon2d GPU-resistant version. */
|
||||
const argon2d = (password, salt, opts) => argon2(AT.Argond2d, password, salt, opts);
|
||||
exports.argon2d = argon2d;
|
||||
/** argon2i side-channel-resistant version. */
|
||||
const argon2i = (password, salt, opts) => argon2(AT.Argon2i, password, salt, opts);
|
||||
exports.argon2i = argon2i;
|
||||
/** argon2id, combining i+d, the most popular version from RFC 9106 */
|
||||
const argon2id = (password, salt, opts) => argon2(AT.Argon2id, password, salt, opts);
|
||||
exports.argon2id = argon2id;
|
||||
async function argon2Async(type, password, salt, opts) {
|
||||
const { mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock, asyncTick } = argon2Init(password, salt, type, opts);
|
||||
// Pre-loop setup
|
||||
// [address, input, zero_block] format so we can pass single U32 to block function
|
||||
const address = new Uint32Array(3 * 256);
|
||||
address[256 + 6] = mP;
|
||||
address[256 + 8] = t;
|
||||
address[256 + 10] = type;
|
||||
let ts = Date.now();
|
||||
for (let r = 0; r < t; r++) {
|
||||
const needXor = r !== 0 && version === 0x13;
|
||||
address[256 + 0] = r;
|
||||
for (let s = 0; s < ARGON2_SYNC_POINTS; s++) {
|
||||
address[256 + 4] = s;
|
||||
const dataIndependent = type == AT.Argon2i || (type == AT.Argon2id && r === 0 && s < 2);
|
||||
for (let l = 0; l < p; l++) {
|
||||
address[256 + 2] = l;
|
||||
address[256 + 12] = 0;
|
||||
let startPos = 0;
|
||||
if (r === 0 && s === 0) {
|
||||
startPos = 2;
|
||||
if (dataIndependent) {
|
||||
address[256 + 12]++;
|
||||
block(address, 256, 2 * 256, 0, false);
|
||||
block(address, 0, 2 * 256, 0, false);
|
||||
}
|
||||
}
|
||||
// current block postion
|
||||
let offset = l * laneLen + s * segmentLen + startPos;
|
||||
// previous block position
|
||||
let prev = offset % laneLen ? offset - 1 : offset + laneLen - 1;
|
||||
for (let index = startPos; index < segmentLen; index++, offset++, prev++) {
|
||||
perBlock();
|
||||
processBlock(B, address, l, r, s, index, laneLen, segmentLen, lanes, offset, prev, dataIndependent, needXor);
|
||||
// Date.now() is not monotonic, so in case if clock goes backwards we return return control too
|
||||
const diff = Date.now() - ts;
|
||||
if (!(diff >= 0 && diff < asyncTick)) {
|
||||
await (0, utils_ts_1.nextTick)();
|
||||
ts += diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(0, utils_ts_1.clean)(address);
|
||||
return argon2Output(B, p, laneLen, dkLen);
|
||||
}
|
||||
/** argon2d async GPU-resistant version. */
|
||||
const argon2dAsync = (password, salt, opts) => argon2Async(AT.Argond2d, password, salt, opts);
|
||||
exports.argon2dAsync = argon2dAsync;
|
||||
/** argon2i async side-channel-resistant version. */
|
||||
const argon2iAsync = (password, salt, opts) => argon2Async(AT.Argon2i, password, salt, opts);
|
||||
exports.argon2iAsync = argon2iAsync;
|
||||
/** argon2id async, combining i+d, the most popular version from RFC 9106 */
|
||||
const argon2idAsync = (password, salt, opts) => argon2Async(AT.Argon2id, password, salt, opts);
|
||||
exports.argon2idAsync = argon2idAsync;
|
||||
//# sourceMappingURL=argon2.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scriptKind.enum.js","sourceRoot":"","sources":["../../src/enums/scriptKind.enum.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,UASX;AATD,WAAY,UAAU;IAClB,iDAAW,CAAA;IACX,uCAAM,CAAA;IACN,yCAAO,CAAA;IACP,uCAAM,CAAA;IACN,yCAAO,CAAA;IACP,mDAAY,CAAA;IACZ,2CAAQ,CAAA;IACR,mDAAY,CAAA;AAChB,CAAC,EATW,UAAU,KAAV,UAAU,QASrB"}
|
||||
@@ -0,0 +1,711 @@
|
||||
import { inspect } from "node:util";
|
||||
import { expect, test } from "vitest";
|
||||
import * as z from "zod/v4";
|
||||
|
||||
test("error creation", () => {
|
||||
const err1 = new z.ZodError([]);
|
||||
|
||||
err1.issues.push({
|
||||
code: "invalid_type",
|
||||
expected: "object",
|
||||
path: [],
|
||||
message: "",
|
||||
input: "adf",
|
||||
});
|
||||
err1.isEmpty;
|
||||
|
||||
const err2 = new z.ZodError(err1.issues);
|
||||
const err3 = new z.ZodError([]);
|
||||
err3.addIssues(err1.issues);
|
||||
err3.addIssue(err1.issues[0]);
|
||||
err1.message;
|
||||
err2.message;
|
||||
err3.message;
|
||||
});
|
||||
|
||||
test("do not allow error and message together", () => {
|
||||
expect(() =>
|
||||
z.string().refine((_) => true, {
|
||||
message: "override",
|
||||
error: (iss) => (iss.input === undefined ? "asdf" : null),
|
||||
})
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
const errorMap: z.ZodErrorMap = (issue) => {
|
||||
if (issue.code === "invalid_type") {
|
||||
if (issue.expected === "string") {
|
||||
return { message: "bad type!" };
|
||||
}
|
||||
}
|
||||
if (issue.code === "custom") {
|
||||
return { message: `less-than-${issue.params?.minimum}` };
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
test("type error with custom error map", () => {
|
||||
const result = z.string().safeParse(234, { error: errorMap });
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [],
|
||||
"message": "bad type!"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("refinement fail with params", () => {
|
||||
const result = z
|
||||
.number()
|
||||
.refine((val) => val >= 3, {
|
||||
params: { minimum: 3 },
|
||||
})
|
||||
.safeParse(2, { error: errorMap });
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [],
|
||||
"params": {
|
||||
"minimum": 3
|
||||
},
|
||||
"message": "less-than-3"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("hard coded error with custom errormap", () => {
|
||||
const result = z
|
||||
.string()
|
||||
.refine((val) => val.length > 12, {
|
||||
params: { minimum: 13 },
|
||||
message: "override",
|
||||
})
|
||||
.safeParse("asdf", { error: () => "contextual" });
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [],
|
||||
"params": {
|
||||
"minimum": 13
|
||||
},
|
||||
"message": "override"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("default error message", () => {
|
||||
const result = z
|
||||
.number()
|
||||
.refine((x) => x > 3)
|
||||
.safeParse(2);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [],
|
||||
"message": "Invalid input"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("override error in refine", () => {
|
||||
const result = z
|
||||
.number()
|
||||
.refine((x) => x > 3, "override")
|
||||
.safeParse(2);
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error!.issues.length).toEqual(1);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [],
|
||||
"message": "override"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("override error in refinement", () => {
|
||||
const result = z
|
||||
.number()
|
||||
.refine((x) => x > 3, {
|
||||
message: "override",
|
||||
})
|
||||
.safeParse(2);
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error!.issues.length).toEqual(1);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [],
|
||||
"message": "override"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("array minimum", () => {
|
||||
let result = z.array(z.string()).min(3, "tooshort").safeParse(["asdf", "qwer"]);
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error!.issues[0].code).toEqual("too_small");
|
||||
expect(result.error!.issues[0].message).toEqual("tooshort");
|
||||
|
||||
result = z.array(z.string()).min(3).safeParse(["asdf", "qwer"]);
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error!.issues[0].code).toEqual("too_small");
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"origin": "array",
|
||||
"code": "too_small",
|
||||
"minimum": 3,
|
||||
"inclusive": true,
|
||||
"path": [],
|
||||
"message": "Too small: expected array to have >=3 items"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("literal bigint default error message", () => {
|
||||
const result = z.literal(BigInt(12)).safeParse(BigInt(13));
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error!.issues.length).toEqual(1);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "invalid_value",
|
||||
"values": [
|
||||
"12"
|
||||
],
|
||||
"path": [],
|
||||
"message": "Invalid input: expected 12n"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("custom path in custom error map", () => {
|
||||
const schema = z.object({
|
||||
items: z.array(z.string()).refine((data) => data.length > 3, {
|
||||
path: ["items-too-few"],
|
||||
}),
|
||||
});
|
||||
|
||||
const errorMap: z.ZodErrorMap = (issue) => {
|
||||
expect((issue.path ?? []).length).toBe(2);
|
||||
return { message: "doesnt matter" };
|
||||
};
|
||||
const result = schema.safeParse({ items: ["first"] }, { error: errorMap });
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [
|
||||
"items",
|
||||
"items-too-few"
|
||||
],
|
||||
"message": "doesnt matter"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
// test("error metadata from value", () => {
|
||||
// const dynamicRefine = z.string().refine(
|
||||
// (val) => val === val.toUpperCase(),
|
||||
// (val) => ({ params: { val } })
|
||||
// );
|
||||
|
||||
// const result = dynamicRefine.safeParse("asdf");
|
||||
// expect(result.success).toEqual(false);
|
||||
// if (!result.success) {
|
||||
// const sub = result.error.issues[0];
|
||||
// expect(result.error.issues[0].code).toEqual("custom");
|
||||
// if (sub.code === "custom") {
|
||||
// expect(sub.params?.val).toEqual("asdf");
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// test("don't call refine after validation failed", () => {
|
||||
// const asdf = z
|
||||
// .union([
|
||||
// z.number(),
|
||||
// z.string().transform(z.number(), (val) => {
|
||||
// return parseFloat(val);
|
||||
// }),
|
||||
// ])
|
||||
// .refine((v) => v >= 1);
|
||||
|
||||
// expect(() => asdf.safeParse("foo")).not.toThrow();
|
||||
// });
|
||||
|
||||
test("root level formatting", () => {
|
||||
const schema = z.string().email();
|
||||
const result = schema.safeParse("asdfsdf");
|
||||
expect(result.success).toBe(false);
|
||||
|
||||
expect(result.error!.format()).toMatchInlineSnapshot(`
|
||||
{
|
||||
"_errors": [
|
||||
"Invalid email address",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("custom path", () => {
|
||||
const schema = z
|
||||
.object({
|
||||
password: z.string(),
|
||||
confirm: z.string(),
|
||||
})
|
||||
.refine((val) => val.confirm === val.password, { path: ["confirm"] });
|
||||
|
||||
const result = schema.safeParse({
|
||||
password: "peanuts",
|
||||
confirm: "qeanuts",
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
const error = result.error!.format();
|
||||
expect(error._errors).toEqual([]);
|
||||
expect(error.password?._errors).toEqual(undefined);
|
||||
expect(error.confirm?._errors).toEqual(["Invalid input"]);
|
||||
});
|
||||
|
||||
test("custom path", () => {
|
||||
const schema = z
|
||||
.object({
|
||||
password: z.string().min(6),
|
||||
confirm: z.string().min(6),
|
||||
})
|
||||
.refine((val) => val.confirm === val.password);
|
||||
|
||||
const result = schema.safeParse({
|
||||
password: "qwer",
|
||||
confirm: "asdf",
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error!.issues.length).toEqual(3);
|
||||
});
|
||||
|
||||
const schema = z.object({
|
||||
inner: z.object({
|
||||
name: z
|
||||
.string()
|
||||
.refine((val) => val.length > 5)
|
||||
.array()
|
||||
.refine((val) => val.length <= 1),
|
||||
}),
|
||||
});
|
||||
|
||||
test("no abort early on refinements", () => {
|
||||
const invalidItem = {
|
||||
inner: { name: ["aasd", "asdfasdfasfd"] },
|
||||
};
|
||||
|
||||
const result1 = schema.safeParse(invalidItem);
|
||||
expect(result1.success).toBe(false);
|
||||
expect(result1.error!.issues.length).toEqual(2);
|
||||
});
|
||||
|
||||
test("detect issue with input fallback", () => {
|
||||
const schema = z
|
||||
.string()
|
||||
.transform((val) => val.length)
|
||||
.refine(() => false, { message: "always fails" })
|
||||
.refine(
|
||||
(val) => {
|
||||
if (typeof val !== "number") throw new Error();
|
||||
return (val ^ 2) > 10;
|
||||
} // should be number but it's a string
|
||||
);
|
||||
expect(() => schema.parse("hello")).toThrow(z.ZodError);
|
||||
});
|
||||
|
||||
test("formatting", () => {
|
||||
const invalidItem = {
|
||||
inner: { name: ["aasd", "asdfasdfasfd"] },
|
||||
};
|
||||
const invalidArray = {
|
||||
inner: { name: ["asdfasdf", "asdfasdfasfd"] },
|
||||
};
|
||||
const result1 = schema.safeParse(invalidItem);
|
||||
const result2 = schema.safeParse(invalidArray);
|
||||
|
||||
expect(result1.success).toBe(false);
|
||||
expect(result2.success).toBe(false);
|
||||
const error1 = result1.error!.format();
|
||||
expect(error1._errors).toEqual([]);
|
||||
expect(error1.inner?._errors).toEqual([]);
|
||||
expect(error1.inner?.name?.[1]).toEqual(undefined);
|
||||
|
||||
type FormattedError = z.inferFormattedError<typeof schema>;
|
||||
const error2: FormattedError = result2.error!.format();
|
||||
expect(error2._errors).toEqual([]);
|
||||
expect(error2.inner?._errors).toEqual([]);
|
||||
expect(error2.inner?.name?._errors).toEqual(["Invalid input"]);
|
||||
expect(error2.inner?.name?.[0]).toEqual(undefined);
|
||||
expect(error2.inner?.name?.[1]).toEqual(undefined);
|
||||
expect(error2.inner?.name?.[2]).toEqual(undefined);
|
||||
|
||||
// test custom mapper
|
||||
type FormattedErrorWithNumber = z.inferFormattedError<typeof schema, number>;
|
||||
const errorWithNumber: FormattedErrorWithNumber = result2.error!.format(() => 5);
|
||||
expect(errorWithNumber._errors).toEqual([]);
|
||||
expect(errorWithNumber.inner?._errors).toEqual([]);
|
||||
expect(errorWithNumber.inner?.name?._errors).toEqual([5]);
|
||||
});
|
||||
|
||||
test("formatting with nullable and optional fields", () => {
|
||||
const nameSchema = z.string().refine((val) => val.length > 5);
|
||||
const schema = z.object({
|
||||
nullableObject: z.object({ name: nameSchema }).nullable(),
|
||||
nullableArray: z.array(nameSchema).nullable(),
|
||||
nullableTuple: z.tuple([nameSchema, nameSchema, z.number()]).nullable(),
|
||||
optionalObject: z.object({ name: nameSchema }).optional(),
|
||||
optionalArray: z.array(nameSchema).optional(),
|
||||
optionalTuple: z.tuple([nameSchema, nameSchema, z.number()]).optional(),
|
||||
});
|
||||
const invalidItem = {
|
||||
nullableObject: { name: "abcd" },
|
||||
nullableArray: ["abcd"],
|
||||
nullableTuple: ["abcd", "abcd", 1],
|
||||
optionalObject: { name: "abcd" },
|
||||
optionalArray: ["abcd"],
|
||||
optionalTuple: ["abcd", "abcd", 1],
|
||||
};
|
||||
const result = schema.safeParse(invalidItem);
|
||||
expect(result.success).toBe(false);
|
||||
const error: z.inferFormattedError<typeof schema> = result.error!.format();
|
||||
expect(error._errors).toEqual([]);
|
||||
expect(error.nullableObject?._errors).toEqual([]);
|
||||
expect(error.nullableObject?.name?._errors).toEqual(["Invalid input"]);
|
||||
expect(error.nullableArray?._errors).toEqual([]);
|
||||
expect(error.nullableArray?.[0]?._errors).toEqual(["Invalid input"]);
|
||||
expect(error.nullableTuple?._errors).toEqual([]);
|
||||
expect(error.nullableTuple?.[0]?._errors).toEqual(["Invalid input"]);
|
||||
expect(error.nullableTuple?.[1]?._errors).toEqual(["Invalid input"]);
|
||||
expect(error.optionalObject?._errors).toEqual([]);
|
||||
expect(error.optionalObject?.name?._errors).toEqual(["Invalid input"]);
|
||||
expect(error.optionalArray?._errors).toEqual([]);
|
||||
expect(error.optionalArray?.[0]?._errors).toEqual(["Invalid input"]);
|
||||
expect(error.optionalTuple?._errors).toEqual([]);
|
||||
expect(error.optionalTuple?.[0]?._errors).toEqual(["Invalid input"]);
|
||||
expect(error.optionalTuple?.[1]?._errors).toEqual(["Invalid input"]);
|
||||
|
||||
expect(error).toMatchInlineSnapshot(`
|
||||
{
|
||||
"_errors": [],
|
||||
"nullableArray": {
|
||||
"0": {
|
||||
"_errors": [
|
||||
"Invalid input",
|
||||
],
|
||||
},
|
||||
"_errors": [],
|
||||
},
|
||||
"nullableObject": {
|
||||
"_errors": [],
|
||||
"name": {
|
||||
"_errors": [
|
||||
"Invalid input",
|
||||
],
|
||||
},
|
||||
},
|
||||
"nullableTuple": {
|
||||
"0": {
|
||||
"_errors": [
|
||||
"Invalid input",
|
||||
],
|
||||
},
|
||||
"1": {
|
||||
"_errors": [
|
||||
"Invalid input",
|
||||
],
|
||||
},
|
||||
"_errors": [],
|
||||
},
|
||||
"optionalArray": {
|
||||
"0": {
|
||||
"_errors": [
|
||||
"Invalid input",
|
||||
],
|
||||
},
|
||||
"_errors": [],
|
||||
},
|
||||
"optionalObject": {
|
||||
"_errors": [],
|
||||
"name": {
|
||||
"_errors": [
|
||||
"Invalid input",
|
||||
],
|
||||
},
|
||||
},
|
||||
"optionalTuple": {
|
||||
"0": {
|
||||
"_errors": [
|
||||
"Invalid input",
|
||||
],
|
||||
},
|
||||
"1": {
|
||||
"_errors": [
|
||||
"Invalid input",
|
||||
],
|
||||
},
|
||||
"_errors": [],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("inferFlattenedErrors", () => {
|
||||
const schemaWithTransform = z.object({ foo: z.string() }).transform((o) => ({ bar: o.foo }));
|
||||
|
||||
const result = schemaWithTransform.safeParse({});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
type ValidationErrors = z.inferFlattenedErrors<typeof schemaWithTransform>;
|
||||
const error: ValidationErrors = result.error!.flatten();
|
||||
expect(error).toMatchInlineSnapshot(`
|
||||
{
|
||||
"fieldErrors": {
|
||||
"foo": [
|
||||
"Invalid input: expected string, received undefined",
|
||||
],
|
||||
},
|
||||
"formErrors": [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
const stringWithCustomError = z.string({
|
||||
error: () => "bound",
|
||||
});
|
||||
|
||||
test("schema-bound error map", () => {
|
||||
const result = stringWithCustomError.safeParse(1234);
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error!.issues[0].message).toEqual("bound");
|
||||
});
|
||||
|
||||
test("bound error map overrides contextual", () => {
|
||||
// support contextual override
|
||||
const result = stringWithCustomError.safeParse(undefined, {
|
||||
error: () => ({ message: "override" }),
|
||||
});
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error!.issues[0].message).toEqual("bound");
|
||||
});
|
||||
|
||||
test("z.config customError ", () => {
|
||||
// support overrideErrorMap
|
||||
|
||||
z.config({ customError: () => ({ message: "override" }) });
|
||||
const result = stringWithCustomError.min(10).safeParse("tooshort");
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"origin": "string",
|
||||
"code": "too_small",
|
||||
"minimum": 10,
|
||||
"inclusive": true,
|
||||
"path": [],
|
||||
"message": "override"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
expect(result.error!.issues[0].message).toEqual("override");
|
||||
z.config({ customError: undefined });
|
||||
});
|
||||
|
||||
// test("invalid and required", () => {
|
||||
// const str = z.string({
|
||||
// invalid_type_error: "Invalid name",
|
||||
// required_error: "Name is required",
|
||||
// });
|
||||
// const result1 = str.safeParse(1234);
|
||||
// expect(result1.success).toBe(false);
|
||||
// if (!result1.success) {
|
||||
// expect(result1.error.issues[0].message).toEqual("Invalid name");
|
||||
// }
|
||||
// const result2 = str.safeParse(undefined);
|
||||
// expect(result2.success).toBe(false);
|
||||
// if (!result2.success) {
|
||||
// expect(result2.error.issues[0].message).toEqual("Name is required");
|
||||
// }
|
||||
// });
|
||||
|
||||
// test("Fallback to default required error", () => {
|
||||
// const str = z.string({
|
||||
// invalid_type_error: "Invalid name",
|
||||
// // required_error: "Name is required",
|
||||
// });
|
||||
|
||||
// const result2 = str.safeParse(undefined);
|
||||
// expect(result2.success).toBe(false);
|
||||
// if (!result2.success) {
|
||||
// expect(result2.error.issues[0].message).toEqual("Required");
|
||||
// }
|
||||
// });
|
||||
|
||||
// test("invalid and required and errorMap", () => {
|
||||
// expect(() => {
|
||||
// return z.string({
|
||||
// invalid_type_error: "Invalid name",
|
||||
// required_error: "Name is required",
|
||||
// errorMap: () => ({ message: "override" }),
|
||||
// });
|
||||
// }).toThrow();
|
||||
// });
|
||||
|
||||
// test("strict error message", () => {
|
||||
// const errorMsg = "Invalid object";
|
||||
// const obj = z.object({ x: z.string() }).strict(errorMsg);
|
||||
// const result = obj.safeParse({ x: "a", y: "b" });
|
||||
// expect(result.success).toBe(false);
|
||||
// if (!result.success) {
|
||||
// expect(result.error.issues[0].message).toEqual(errorMsg);
|
||||
// }
|
||||
// });
|
||||
|
||||
test("empty string error message", () => {
|
||||
const schema = z.string().max(1, { message: "" });
|
||||
const result = schema.safeParse("asdf");
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error!.issues[0].message).toEqual("");
|
||||
});
|
||||
|
||||
test("dont short circuit on continuable errors", () => {
|
||||
const user = z
|
||||
.object({
|
||||
password: z.string().min(6),
|
||||
confirm: z.string(),
|
||||
})
|
||||
.refine((data) => data.password === data.confirm, {
|
||||
message: "Passwords don't match",
|
||||
path: ["confirm"],
|
||||
});
|
||||
const result = user.safeParse({ password: "asdf", confirm: "qwer" });
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"origin": "string",
|
||||
"code": "too_small",
|
||||
"minimum": 6,
|
||||
"inclusive": true,
|
||||
"path": [
|
||||
"password"
|
||||
],
|
||||
"message": "Too small: expected string to have >=6 characters"
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"path": [
|
||||
"confirm"
|
||||
],
|
||||
"message": "Passwords don't match"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
// expect(result.error!.issues.length).toEqual(2);
|
||||
});
|
||||
|
||||
test("string error params", () => {
|
||||
const a = z.string("Bad!");
|
||||
expect(a.safeParse(123).error!.issues[0].message).toBe("Bad!");
|
||||
|
||||
const b = z.string().min(5, "Too short!");
|
||||
expect(b.safeParse("abc").error!.issues[0].message).toBe("Too short!");
|
||||
|
||||
const c = z.uuid("Bad UUID!");
|
||||
expect(c.safeParse("not-a-uuid").error!.issues[0].message).toBe("Bad UUID!");
|
||||
|
||||
const d = z.string().datetime({ message: "Bad date!" });
|
||||
expect(d.safeParse("not-a-date").error!.issues[0].message).toBe("Bad date!");
|
||||
|
||||
const e = z.array(z.string(), "Bad array!");
|
||||
expect(e.safeParse("not-an-array").error!.issues[0].message).toBe("Bad array!");
|
||||
|
||||
const f = z.array(z.string()).min(5, "Too few items!");
|
||||
expect(f.safeParse(["a", "b"]).error!.issues[0].message).toBe("Too few items!");
|
||||
|
||||
const g = z.set(z.string(), "Bad set!");
|
||||
expect(g.safeParse("not-a-set").error!.issues[0].message).toBe("Bad set!");
|
||||
|
||||
const h = z.array(z.string(), "Bad array!");
|
||||
expect(h.safeParse(123).error!.issues[0].message).toBe("Bad array!");
|
||||
|
||||
const i = z.set(z.string(), "Bad set!");
|
||||
expect(i.safeParse(123).error!.issues[0].message).toBe("Bad set!");
|
||||
|
||||
const j = z.array(z.string(), "Bad array!");
|
||||
expect(j.safeParse(null).error!.issues[0].message).toBe("Bad array!");
|
||||
});
|
||||
|
||||
test("error inheritance", () => {
|
||||
const e1 = z.string().safeParse(123).error!;
|
||||
expect(e1).toBeInstanceOf(z.core.$ZodError);
|
||||
expect(e1).toBeInstanceOf(z.ZodError);
|
||||
expect(e1).toBeInstanceOf(z.ZodRealError);
|
||||
// expect(e1).not.toBeInstanceOf(Error);
|
||||
|
||||
try {
|
||||
z.string().parse(123);
|
||||
} catch (e2) {
|
||||
expect(e1).toBeInstanceOf(z.core.$ZodError);
|
||||
expect(e2).toBeInstanceOf(z.ZodError);
|
||||
expect(e2).toBeInstanceOf(z.ZodRealError);
|
||||
// expect(e2).toBeInstanceOf(Error);
|
||||
}
|
||||
});
|
||||
|
||||
test("error serialization", () => {
|
||||
try {
|
||||
z.string().parse(123);
|
||||
} catch (e) {
|
||||
expect(e).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [],
|
||||
"message": "Invalid input: expected string, received number"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
expect(inspect(e).split("\n").slice(0, 8).join("\n")).toMatchInlineSnapshot(`
|
||||
"ZodError: [
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [],
|
||||
"message": "Invalid input: expected string, received number"
|
||||
}
|
||||
]"
|
||||
`);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
'use strict';
|
||||
module.exports = function generate__limitProperties(it, $keyword, $ruleType) {
|
||||
var out = ' ';
|
||||
var $lvl = it.level;
|
||||
var $dataLvl = it.dataLevel;
|
||||
var $schema = it.schema[$keyword];
|
||||
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
||||
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
||||
var $breakOnError = !it.opts.allErrors;
|
||||
var $errorKeyword;
|
||||
var $data = 'data' + ($dataLvl || '');
|
||||
var $isData = it.opts.$data && $schema && $schema.$data,
|
||||
$schemaValue;
|
||||
if ($isData) {
|
||||
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
||||
$schemaValue = 'schema' + $lvl;
|
||||
} else {
|
||||
$schemaValue = $schema;
|
||||
}
|
||||
if (!($isData || typeof $schema == 'number')) {
|
||||
throw new Error($keyword + ' must be number');
|
||||
}
|
||||
var $op = $keyword == 'maxProperties' ? '>' : '<';
|
||||
out += 'if ( ';
|
||||
if ($isData) {
|
||||
out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \'number\') || ';
|
||||
}
|
||||
out += ' Object.keys(' + ($data) + ').length ' + ($op) + ' ' + ($schemaValue) + ') { ';
|
||||
var $errorKeyword = $keyword;
|
||||
var $$outStack = $$outStack || [];
|
||||
$$outStack.push(out);
|
||||
out = ''; /* istanbul ignore else */
|
||||
if (it.createErrors !== false) {
|
||||
out += ' { keyword: \'' + ($errorKeyword || '_limitProperties') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } ';
|
||||
if (it.opts.messages !== false) {
|
||||
out += ' , message: \'should NOT have ';
|
||||
if ($keyword == 'maxProperties') {
|
||||
out += 'more';
|
||||
} else {
|
||||
out += 'fewer';
|
||||
}
|
||||
out += ' than ';
|
||||
if ($isData) {
|
||||
out += '\' + ' + ($schemaValue) + ' + \'';
|
||||
} else {
|
||||
out += '' + ($schema);
|
||||
}
|
||||
out += ' properties\' ';
|
||||
}
|
||||
if (it.opts.verbose) {
|
||||
out += ' , schema: ';
|
||||
if ($isData) {
|
||||
out += 'validate.schema' + ($schemaPath);
|
||||
} else {
|
||||
out += '' + ($schema);
|
||||
}
|
||||
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
||||
}
|
||||
out += ' } ';
|
||||
} else {
|
||||
out += ' {} ';
|
||||
}
|
||||
var __err = out;
|
||||
out = $$outStack.pop();
|
||||
if (!it.compositeRule && $breakOnError) {
|
||||
/* istanbul ignore if */
|
||||
if (it.async) {
|
||||
out += ' throw new ValidationError([' + (__err) + ']); ';
|
||||
} else {
|
||||
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
||||
}
|
||||
} else {
|
||||
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
||||
}
|
||||
out += '} ';
|
||||
if ($breakOnError) {
|
||||
out += ' else { ';
|
||||
}
|
||||
return out;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,296 @@
|
||||
/**
|
||||
* Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash.
|
||||
*
|
||||
* There are many poseidon variants with different constants.
|
||||
* We don't provide them: you should construct them manually.
|
||||
* Check out [micro-starknet](https://github.com/paulmillr/micro-starknet) package for a proper example.
|
||||
* @module
|
||||
*/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { _validateObject, bitGet } from "../utils.js";
|
||||
import { FpInvertBatch, FpPow, validateField } from "./modular.js";
|
||||
// Grain LFSR (Linear-Feedback Shift Register): https://eprint.iacr.org/2009/109.pdf
|
||||
function grainLFSR(state) {
|
||||
let pos = 0;
|
||||
if (state.length !== 80)
|
||||
throw new Error('grainLFRS: wrong state length, should be 80 bits');
|
||||
const getBit = () => {
|
||||
const r = (offset) => state[(pos + offset) % 80];
|
||||
const bit = r(62) ^ r(51) ^ r(38) ^ r(23) ^ r(13) ^ r(0);
|
||||
state[pos] = bit;
|
||||
pos = ++pos % 80;
|
||||
return !!bit;
|
||||
};
|
||||
for (let i = 0; i < 160; i++)
|
||||
getBit();
|
||||
return () => {
|
||||
// https://en.wikipedia.org/wiki/Shrinking_generator
|
||||
while (true) {
|
||||
const b1 = getBit();
|
||||
const b2 = getBit();
|
||||
if (!b1)
|
||||
continue;
|
||||
return b2;
|
||||
}
|
||||
};
|
||||
}
|
||||
function assertValidPosOpts(opts) {
|
||||
const { Fp, roundsFull } = opts;
|
||||
validateField(Fp);
|
||||
_validateObject(opts, {
|
||||
t: 'number',
|
||||
roundsFull: 'number',
|
||||
roundsPartial: 'number',
|
||||
}, {
|
||||
isSboxInverse: 'boolean',
|
||||
});
|
||||
for (const i of ['t', 'roundsFull', 'roundsPartial']) {
|
||||
if (!Number.isSafeInteger(opts[i]) || opts[i] < 1)
|
||||
throw new Error('invalid number ' + i);
|
||||
}
|
||||
if (roundsFull & 1)
|
||||
throw new Error('roundsFull is not even' + roundsFull);
|
||||
}
|
||||
function poseidonGrain(opts) {
|
||||
assertValidPosOpts(opts);
|
||||
const { Fp } = opts;
|
||||
const state = Array(80).fill(1);
|
||||
let pos = 0;
|
||||
const writeBits = (value, bitCount) => {
|
||||
for (let i = bitCount - 1; i >= 0; i--)
|
||||
state[pos++] = Number(bitGet(value, i));
|
||||
};
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
writeBits(_1n, 2); // prime field
|
||||
writeBits(opts.isSboxInverse ? _1n : _0n, 4); // b2..b5
|
||||
writeBits(BigInt(Fp.BITS), 12); // b6..b17
|
||||
writeBits(BigInt(opts.t), 12); // b18..b29
|
||||
writeBits(BigInt(opts.roundsFull), 10); // b30..b39
|
||||
writeBits(BigInt(opts.roundsPartial), 10); // b40..b49
|
||||
const getBit = grainLFSR(state);
|
||||
return (count, reject) => {
|
||||
const res = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
while (true) {
|
||||
let num = _0n;
|
||||
for (let i = 0; i < Fp.BITS; i++) {
|
||||
num <<= _1n;
|
||||
if (getBit())
|
||||
num |= _1n;
|
||||
}
|
||||
if (reject && num >= Fp.ORDER)
|
||||
continue; // rejection sampling
|
||||
res.push(Fp.create(num));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
}
|
||||
// NOTE: this is not standard but used often for constant generation for poseidon
|
||||
// (grain LFRS-like structure)
|
||||
export function grainGenConstants(opts, skipMDS = 0) {
|
||||
const { Fp, t, roundsFull, roundsPartial } = opts;
|
||||
const rounds = roundsFull + roundsPartial;
|
||||
const sample = poseidonGrain(opts);
|
||||
const roundConstants = [];
|
||||
for (let r = 0; r < rounds; r++)
|
||||
roundConstants.push(sample(t, true));
|
||||
if (skipMDS > 0)
|
||||
for (let i = 0; i < skipMDS; i++)
|
||||
sample(2 * t, false);
|
||||
const xs = sample(t, false);
|
||||
const ys = sample(t, false);
|
||||
// Construct MDS Matrix M[i][j] = 1 / (xs[i] + ys[j])
|
||||
const mds = [];
|
||||
for (let i = 0; i < t; i++) {
|
||||
const row = [];
|
||||
for (let j = 0; j < t; j++) {
|
||||
const xy = Fp.add(xs[i], ys[j]);
|
||||
if (Fp.is0(xy))
|
||||
throw new Error(`Error generating MDS matrix: xs[${i}] + ys[${j}] resulted in zero.`);
|
||||
row.push(xy);
|
||||
}
|
||||
mds.push(FpInvertBatch(Fp, row));
|
||||
}
|
||||
return { roundConstants, mds };
|
||||
}
|
||||
export function validateOpts(opts) {
|
||||
assertValidPosOpts(opts);
|
||||
const { Fp, mds, reversePartialPowIdx: rev, roundConstants: rc } = opts;
|
||||
const { roundsFull, roundsPartial, sboxPower, t } = opts;
|
||||
// MDS is TxT matrix
|
||||
if (!Array.isArray(mds) || mds.length !== t)
|
||||
throw new Error('Poseidon: invalid MDS matrix');
|
||||
const _mds = mds.map((mdsRow) => {
|
||||
if (!Array.isArray(mdsRow) || mdsRow.length !== t)
|
||||
throw new Error('invalid MDS matrix row: ' + mdsRow);
|
||||
return mdsRow.map((i) => {
|
||||
if (typeof i !== 'bigint')
|
||||
throw new Error('invalid MDS matrix bigint: ' + i);
|
||||
return Fp.create(i);
|
||||
});
|
||||
});
|
||||
if (rev !== undefined && typeof rev !== 'boolean')
|
||||
throw new Error('invalid param reversePartialPowIdx=' + rev);
|
||||
if (roundsFull & 1)
|
||||
throw new Error('roundsFull is not even' + roundsFull);
|
||||
const rounds = roundsFull + roundsPartial;
|
||||
if (!Array.isArray(rc) || rc.length !== rounds)
|
||||
throw new Error('Poseidon: invalid round constants');
|
||||
const roundConstants = rc.map((rc) => {
|
||||
if (!Array.isArray(rc) || rc.length !== t)
|
||||
throw new Error('invalid round constants');
|
||||
return rc.map((i) => {
|
||||
if (typeof i !== 'bigint' || !Fp.isValid(i))
|
||||
throw new Error('invalid round constant');
|
||||
return Fp.create(i);
|
||||
});
|
||||
});
|
||||
if (!sboxPower || ![3, 5, 7, 17].includes(sboxPower))
|
||||
throw new Error('invalid sboxPower');
|
||||
const _sboxPower = BigInt(sboxPower);
|
||||
let sboxFn = (n) => FpPow(Fp, n, _sboxPower);
|
||||
// Unwrapped sbox power for common cases (195->142μs)
|
||||
if (sboxPower === 3)
|
||||
sboxFn = (n) => Fp.mul(Fp.sqrN(n), n);
|
||||
else if (sboxPower === 5)
|
||||
sboxFn = (n) => Fp.mul(Fp.sqrN(Fp.sqrN(n)), n);
|
||||
return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds: _mds });
|
||||
}
|
||||
export function splitConstants(rc, t) {
|
||||
if (typeof t !== 'number')
|
||||
throw new Error('poseidonSplitConstants: invalid t');
|
||||
if (!Array.isArray(rc) || rc.length % t)
|
||||
throw new Error('poseidonSplitConstants: invalid rc');
|
||||
const res = [];
|
||||
let tmp = [];
|
||||
for (let i = 0; i < rc.length; i++) {
|
||||
tmp.push(rc[i]);
|
||||
if (tmp.length === t) {
|
||||
res.push(tmp);
|
||||
tmp = [];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/** Poseidon NTT-friendly hash. */
|
||||
export function poseidon(opts) {
|
||||
const _opts = validateOpts(opts);
|
||||
const { Fp, mds, roundConstants, rounds: totalRounds, roundsPartial, sboxFn, t } = _opts;
|
||||
const halfRoundsFull = _opts.roundsFull / 2;
|
||||
const partialIdx = _opts.reversePartialPowIdx ? t - 1 : 0;
|
||||
const poseidonRound = (values, isFull, idx) => {
|
||||
values = values.map((i, j) => Fp.add(i, roundConstants[idx][j]));
|
||||
if (isFull)
|
||||
values = values.map((i) => sboxFn(i));
|
||||
else
|
||||
values[partialIdx] = sboxFn(values[partialIdx]);
|
||||
// Matrix multiplication
|
||||
values = mds.map((i) => i.reduce((acc, i, j) => Fp.add(acc, Fp.mulN(i, values[j])), Fp.ZERO));
|
||||
return values;
|
||||
};
|
||||
const poseidonHash = function poseidonHash(values) {
|
||||
if (!Array.isArray(values) || values.length !== t)
|
||||
throw new Error('invalid values, expected array of bigints with length ' + t);
|
||||
values = values.map((i) => {
|
||||
if (typeof i !== 'bigint')
|
||||
throw new Error('invalid bigint=' + i);
|
||||
return Fp.create(i);
|
||||
});
|
||||
let lastRound = 0;
|
||||
// Apply r_f/2 full rounds.
|
||||
for (let i = 0; i < halfRoundsFull; i++)
|
||||
values = poseidonRound(values, true, lastRound++);
|
||||
// Apply r_p partial rounds.
|
||||
for (let i = 0; i < roundsPartial; i++)
|
||||
values = poseidonRound(values, false, lastRound++);
|
||||
// Apply r_f/2 full rounds.
|
||||
for (let i = 0; i < halfRoundsFull; i++)
|
||||
values = poseidonRound(values, true, lastRound++);
|
||||
if (lastRound !== totalRounds)
|
||||
throw new Error('invalid number of rounds');
|
||||
return values;
|
||||
};
|
||||
// For verification in tests
|
||||
poseidonHash.roundConstants = roundConstants;
|
||||
return poseidonHash;
|
||||
}
|
||||
export class PoseidonSponge {
|
||||
constructor(Fp, rate, capacity, hash) {
|
||||
this.pos = 0;
|
||||
this.isAbsorbing = true;
|
||||
this.Fp = Fp;
|
||||
this.hash = hash;
|
||||
this.rate = rate;
|
||||
this.capacity = capacity;
|
||||
this.state = new Array(rate + capacity);
|
||||
this.clean();
|
||||
}
|
||||
process() {
|
||||
this.state = this.hash(this.state);
|
||||
}
|
||||
absorb(input) {
|
||||
for (const i of input)
|
||||
if (typeof i !== 'bigint' || !this.Fp.isValid(i))
|
||||
throw new Error('invalid input: ' + i);
|
||||
for (let i = 0; i < input.length;) {
|
||||
if (!this.isAbsorbing || this.pos === this.rate) {
|
||||
this.process();
|
||||
this.pos = 0;
|
||||
this.isAbsorbing = true;
|
||||
}
|
||||
const chunk = Math.min(this.rate - this.pos, input.length - i);
|
||||
for (let j = 0; j < chunk; j++) {
|
||||
const idx = this.capacity + this.pos++;
|
||||
this.state[idx] = this.Fp.add(this.state[idx], input[i++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
squeeze(count) {
|
||||
const res = [];
|
||||
while (res.length < count) {
|
||||
if (this.isAbsorbing || this.pos === this.rate) {
|
||||
this.process();
|
||||
this.pos = 0;
|
||||
this.isAbsorbing = false;
|
||||
}
|
||||
const chunk = Math.min(this.rate - this.pos, count - res.length);
|
||||
for (let i = 0; i < chunk; i++)
|
||||
res.push(this.state[this.capacity + this.pos++]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
clean() {
|
||||
this.state.fill(this.Fp.ZERO);
|
||||
this.isAbsorbing = true;
|
||||
this.pos = 0;
|
||||
}
|
||||
clone() {
|
||||
const c = new PoseidonSponge(this.Fp, this.rate, this.capacity, this.hash);
|
||||
c.pos = this.pos;
|
||||
c.state = [...this.state];
|
||||
return c;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The method is not defined in spec, but nevertheless used often.
|
||||
* Check carefully for compatibility: there are many edge cases, like absorbing an empty array.
|
||||
* We cross-test against:
|
||||
* - https://github.com/ProvableHQ/snarkVM/tree/staging/algorithms
|
||||
* - https://github.com/arkworks-rs/crypto-primitives/tree/main
|
||||
*/
|
||||
export function poseidonSponge(opts) {
|
||||
for (const i of ['rate', 'capacity']) {
|
||||
if (typeof opts[i] !== 'number' || !Number.isSafeInteger(opts[i]))
|
||||
throw new Error('invalid number ' + i);
|
||||
}
|
||||
const { rate, capacity } = opts;
|
||||
const t = opts.rate + opts.capacity;
|
||||
// Re-use hash instance between multiple instances
|
||||
const hash = poseidon({ ...opts, t });
|
||||
const { Fp } = opts;
|
||||
return () => new PoseidonSponge(Fp, rate, capacity, hash);
|
||||
}
|
||||
//# sourceMappingURL=poseidon.js.map
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "../../cjs/_dispose.cjs",
|
||||
"module": "../../esm/_dispose.js"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
"use strict";
|
||||
/**
|
||||
* This is a fork of https://github.com/DefinitelyTyped/DefinitelyTyped/blob/13f63c2eb8d7479caf01ab8d72f9e3683368a8f5/types/json-schema/index.d.ts
|
||||
* We intentionally fork this because:
|
||||
* - ESLint ***ONLY*** supports JSONSchema v4
|
||||
* - We want to provide stricter types
|
||||
*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
@@ -0,0 +1,63 @@
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
interface ArrayBuffer {
|
||||
/**
|
||||
* If this ArrayBuffer is resizable, returns the maximum byte length given during construction; returns the byte length if not.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/maxByteLength)
|
||||
*/
|
||||
get maxByteLength(): number;
|
||||
|
||||
/**
|
||||
* Returns true if this ArrayBuffer can be resized.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/resizable)
|
||||
*/
|
||||
get resizable(): boolean;
|
||||
|
||||
/**
|
||||
* Resizes the ArrayBuffer to the specified size (in bytes).
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/resize)
|
||||
*/
|
||||
resize(newByteLength?: number): void;
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether or not this buffer has been detached (transferred).
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/detached)
|
||||
*/
|
||||
get detached(): boolean;
|
||||
|
||||
/**
|
||||
* Creates a new ArrayBuffer with the same byte content as this buffer, then detaches this buffer.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/transfer)
|
||||
*/
|
||||
transfer(newByteLength?: number): ArrayBuffer;
|
||||
|
||||
/**
|
||||
* Creates a new non-resizable ArrayBuffer with the same byte content as this buffer, then detaches this buffer.
|
||||
*
|
||||
* [MDN](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/transferToFixedLength)
|
||||
*/
|
||||
transferToFixedLength(newByteLength?: number): ArrayBuffer;
|
||||
}
|
||||
|
||||
interface ArrayBufferConstructor {
|
||||
new (byteLength: number, options?: { maxByteLength?: number; }): ArrayBuffer;
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce the use of `u` or `v` flag on regular expressions.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const {
|
||||
CALL,
|
||||
CONSTRUCT,
|
||||
ReferenceTracker,
|
||||
getStringIfConstant,
|
||||
} = require("@eslint-community/eslint-utils");
|
||||
const astUtils = require("./utils/ast-utils.js");
|
||||
const { isValidWithUnicodeFlag } = require("./utils/regular-expressions");
|
||||
|
||||
/**
|
||||
* Checks whether the flag configuration should be treated as a missing flag.
|
||||
* @param {"u"|"v"|undefined} requireFlag A particular flag to require
|
||||
* @param {string} flags The regex flags
|
||||
* @returns {boolean} Whether the flag configuration results in a missing flag.
|
||||
*/
|
||||
function checkFlags(requireFlag, flags) {
|
||||
let missingFlag;
|
||||
|
||||
if (requireFlag === "v") {
|
||||
missingFlag = !flags.includes("v");
|
||||
} else if (requireFlag === "u") {
|
||||
missingFlag = !flags.includes("u");
|
||||
} else {
|
||||
missingFlag = !flags.includes("u") && !flags.includes("v");
|
||||
}
|
||||
|
||||
return missingFlag;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [{}],
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce the use of `u` or `v` flag on regular expressions",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/require-unicode-regexp",
|
||||
},
|
||||
|
||||
hasSuggestions: true,
|
||||
|
||||
messages: {
|
||||
addUFlag: "Add the 'u' flag.",
|
||||
addVFlag: "Add the 'v' flag.",
|
||||
requireUFlag: "Use the 'u' flag.",
|
||||
requireVFlag: "Use the 'v' flag.",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
requireFlag: {
|
||||
enum: ["u", "v"],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
const [{ requireFlag }] = context.options;
|
||||
|
||||
return {
|
||||
"Literal[regex]"(node) {
|
||||
const flags = node.regex.flags || "";
|
||||
|
||||
const missingFlag = checkFlags(requireFlag, flags);
|
||||
|
||||
if (missingFlag) {
|
||||
context.report({
|
||||
messageId:
|
||||
requireFlag === "v"
|
||||
? "requireVFlag"
|
||||
: "requireUFlag",
|
||||
node,
|
||||
suggest: isValidWithUnicodeFlag(
|
||||
context.languageOptions.ecmaVersion,
|
||||
node.regex.pattern,
|
||||
requireFlag,
|
||||
)
|
||||
? [
|
||||
{
|
||||
fix(fixer) {
|
||||
const replaceFlag =
|
||||
requireFlag ?? "u";
|
||||
const regex =
|
||||
sourceCode.getText(node);
|
||||
const slashPos =
|
||||
regex.lastIndexOf("/");
|
||||
|
||||
if (requireFlag) {
|
||||
const flag =
|
||||
requireFlag === "u"
|
||||
? "v"
|
||||
: "u";
|
||||
|
||||
if (
|
||||
regex.includes(
|
||||
flag,
|
||||
slashPos,
|
||||
)
|
||||
) {
|
||||
return fixer.replaceText(
|
||||
node,
|
||||
regex.slice(
|
||||
0,
|
||||
slashPos,
|
||||
) +
|
||||
regex
|
||||
.slice(slashPos)
|
||||
.replace(
|
||||
flag,
|
||||
requireFlag,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return fixer.insertTextAfter(
|
||||
node,
|
||||
replaceFlag,
|
||||
);
|
||||
},
|
||||
messageId:
|
||||
requireFlag === "v"
|
||||
? "addVFlag"
|
||||
: "addUFlag",
|
||||
},
|
||||
]
|
||||
: null,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
Program(node) {
|
||||
const scope = sourceCode.getScope(node);
|
||||
const tracker = new ReferenceTracker(scope);
|
||||
const trackMap = {
|
||||
RegExp: { [CALL]: true, [CONSTRUCT]: true },
|
||||
};
|
||||
|
||||
for (const { node: refNode } of tracker.iterateGlobalReferences(
|
||||
trackMap,
|
||||
)) {
|
||||
const [patternNode, flagsNode] = refNode.arguments;
|
||||
|
||||
if (patternNode && patternNode.type === "SpreadElement") {
|
||||
continue;
|
||||
}
|
||||
const pattern = getStringIfConstant(patternNode, scope);
|
||||
const flags = getStringIfConstant(flagsNode, scope);
|
||||
|
||||
let missingFlag = !flagsNode;
|
||||
|
||||
if (typeof flags === "string") {
|
||||
missingFlag = checkFlags(requireFlag, flags);
|
||||
}
|
||||
|
||||
if (missingFlag) {
|
||||
context.report({
|
||||
messageId:
|
||||
requireFlag === "v"
|
||||
? "requireVFlag"
|
||||
: "requireUFlag",
|
||||
node: refNode,
|
||||
suggest:
|
||||
typeof pattern === "string" &&
|
||||
isValidWithUnicodeFlag(
|
||||
context.languageOptions.ecmaVersion,
|
||||
pattern,
|
||||
requireFlag,
|
||||
)
|
||||
? [
|
||||
{
|
||||
fix(fixer) {
|
||||
const replaceFlag =
|
||||
requireFlag ?? "u";
|
||||
|
||||
if (flagsNode) {
|
||||
if (
|
||||
(flagsNode.type ===
|
||||
"Literal" &&
|
||||
typeof flagsNode.value ===
|
||||
"string") ||
|
||||
flagsNode.type ===
|
||||
"TemplateLiteral"
|
||||
) {
|
||||
const flagsNodeText =
|
||||
sourceCode.getText(
|
||||
flagsNode,
|
||||
);
|
||||
const flag =
|
||||
requireFlag ===
|
||||
"u"
|
||||
? "v"
|
||||
: "u";
|
||||
|
||||
if (
|
||||
flags.includes(
|
||||
flag,
|
||||
)
|
||||
) {
|
||||
// Avoid replacing "u" in escapes like `\uXXXX`
|
||||
if (
|
||||
flagsNode.type ===
|
||||
"Literal" &&
|
||||
flagsNode.raw.includes(
|
||||
"\\",
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Avoid replacing "u" in expressions like "`${regularFlags}g`"
|
||||
if (
|
||||
flagsNode.type ===
|
||||
"TemplateLiteral" &&
|
||||
(flagsNode
|
||||
.expressions
|
||||
.length ||
|
||||
flagsNode.quasis.some(
|
||||
({
|
||||
value: {
|
||||
raw,
|
||||
},
|
||||
}) =>
|
||||
raw.includes(
|
||||
"\\",
|
||||
),
|
||||
))
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fixer.replaceText(
|
||||
flagsNode,
|
||||
flagsNodeText.replace(
|
||||
flag,
|
||||
replaceFlag,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return fixer.replaceText(
|
||||
flagsNode,
|
||||
[
|
||||
flagsNodeText.slice(
|
||||
0,
|
||||
flagsNodeText.length -
|
||||
1,
|
||||
),
|
||||
flagsNodeText.slice(
|
||||
flagsNodeText.length -
|
||||
1,
|
||||
),
|
||||
].join(
|
||||
replaceFlag,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// We intentionally don't suggest concatenating + "u" to non-literals
|
||||
return null;
|
||||
}
|
||||
|
||||
const penultimateToken =
|
||||
sourceCode.getLastToken(
|
||||
refNode,
|
||||
{ skip: 1 },
|
||||
); // skip closing parenthesis
|
||||
|
||||
return fixer.insertTextAfter(
|
||||
penultimateToken,
|
||||
astUtils.isCommaToken(
|
||||
penultimateToken,
|
||||
)
|
||||
? ` "${replaceFlag}",`
|
||||
: `, "${replaceFlag}"`,
|
||||
);
|
||||
},
|
||||
messageId:
|
||||
requireFlag === "v"
|
||||
? "addVFlag"
|
||||
: "addUFlag",
|
||||
},
|
||||
]
|
||||
: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
# Authors
|
||||
|
||||
#### Ordered by first contribution.
|
||||
|
||||
- Romain Beauxis (toots@rastageeks.org)
|
||||
- Tobias Koppers (tobias.koppers@googlemail.com)
|
||||
- Janus (ysangkok@gmail.com)
|
||||
- Rainer Dreyer (rdrey1@gmail.com)
|
||||
- Tõnis Tiigi (tonistiigi@gmail.com)
|
||||
- James Halliday (mail@substack.net)
|
||||
- Michael Williamson (mike@zwobble.org)
|
||||
- elliottcable (github@elliottcable.name)
|
||||
- rafael (rvalle@livelens.net)
|
||||
- Andrew Kelley (superjoe30@gmail.com)
|
||||
- Andreas Madsen (amwebdk@gmail.com)
|
||||
- Mike Brevoort (mike.brevoort@pearson.com)
|
||||
- Brian White (mscdex@mscdex.net)
|
||||
- Feross Aboukhadijeh (feross@feross.org)
|
||||
- Ruben Verborgh (ruben@verborgh.org)
|
||||
- eliang (eliang.cs@gmail.com)
|
||||
- Jesse Tane (jesse.tane@gmail.com)
|
||||
- Alfonso Boza (alfonso@cloud.com)
|
||||
- Mathias Buus (mathiasbuus@gmail.com)
|
||||
- Devon Govett (devongovett@gmail.com)
|
||||
- Daniel Cousens (github@dcousens.com)
|
||||
- Joseph Dykstra (josephdykstra@gmail.com)
|
||||
- Parsha Pourkhomami (parshap+git@gmail.com)
|
||||
- Damjan Košir (damjan.kosir@gmail.com)
|
||||
- daverayment (dave.rayment@gmail.com)
|
||||
- kawanet (u-suke@kawa.net)
|
||||
- Linus Unnebäck (linus@folkdatorn.se)
|
||||
- Nolan Lawson (nolan.lawson@gmail.com)
|
||||
- Calvin Metcalf (calvin.metcalf@gmail.com)
|
||||
- Koki Takahashi (hakatasiloving@gmail.com)
|
||||
- Guy Bedford (guybedford@gmail.com)
|
||||
- Jan Schär (jscissr@gmail.com)
|
||||
- RaulTsc (tomescu.raul@gmail.com)
|
||||
- Matthieu Monsch (monsch@alum.mit.edu)
|
||||
- Dan Ehrenberg (littledan@chromium.org)
|
||||
- Kirill Fomichev (fanatid@ya.ru)
|
||||
- Yusuke Kawasaki (u-suke@kawa.net)
|
||||
- DC (dcposch@dcpos.ch)
|
||||
- John-David Dalton (john.david.dalton@gmail.com)
|
||||
- adventure-yunfei (adventure030@gmail.com)
|
||||
- Emil Bay (github@tixz.dk)
|
||||
- Sam Sudar (sudar.sam@gmail.com)
|
||||
- Volker Mische (volker.mische@gmail.com)
|
||||
- David Walton (support@geekstocks.com)
|
||||
- Сковорода Никита Андреевич (chalkerx@gmail.com)
|
||||
- greenkeeper[bot] (greenkeeper[bot]@users.noreply.github.com)
|
||||
- ukstv (sergey.ukustov@machinomy.com)
|
||||
- Renée Kooi (renee@kooi.me)
|
||||
- ranbochen (ranbochen@qq.com)
|
||||
- Vladimir Borovik (bobahbdb@gmail.com)
|
||||
- greenkeeper[bot] (23040076+greenkeeper[bot]@users.noreply.github.com)
|
||||
- kumavis (aaron@kumavis.me)
|
||||
- Sergey Ukustov (sergey.ukustov@machinomy.com)
|
||||
- Fei Liu (liu.feiwood@gmail.com)
|
||||
- Blaine Bublitz (blaine.bublitz@gmail.com)
|
||||
- clement (clement@seald.io)
|
||||
- Koushik Dutta (koushd@gmail.com)
|
||||
- Jordan Harband (ljharb@gmail.com)
|
||||
- Niklas Mischkulnig (mischnic@users.noreply.github.com)
|
||||
- Nikolai Vavilov (vvnicholas@gmail.com)
|
||||
- Fedor Nezhivoi (gyzerok@users.noreply.github.com)
|
||||
- shuse2 (shus.toda@gmail.com)
|
||||
- Peter Newman (peternewman@users.noreply.github.com)
|
||||
- mathmakgakpak (44949126+mathmakgakpak@users.noreply.github.com)
|
||||
- jkkang (jkkang@smartauth.kr)
|
||||
- Deklan Webster (deklanw@gmail.com)
|
||||
- Martin Heidegger (martin.heidegger@gmail.com)
|
||||
|
||||
#### Generated by bin/update-authors.sh.
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Ensures that a given number falls within a specified range.
|
||||
*
|
||||
* If the number is outside the allowed range, an error is thrown.
|
||||
* This function is primarily used to validate values before encoding them in a codec.
|
||||
*
|
||||
* @param codecDescription - A string describing the codec that is performing the validation.
|
||||
* @param min - The minimum allowed value (inclusive).
|
||||
* @param max - The maximum allowed value (inclusive).
|
||||
* @param value - The number to validate.
|
||||
*
|
||||
* @throws {@link SolanaError} if the value is out of range.
|
||||
*
|
||||
* @example
|
||||
* Validating a number within range.
|
||||
* ```ts
|
||||
* assertNumberIsBetweenForCodec('u8', 0, 255, 42); // Passes
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* Throwing an error for an out-of-range value.
|
||||
* ```ts
|
||||
* assertNumberIsBetweenForCodec('u8', 0, 255, 300); // Throws
|
||||
* ```
|
||||
*/
|
||||
export declare function assertNumberIsBetweenForCodec(codecDescription: string, min: bigint | number, max: bigint | number, value: bigint | number): void;
|
||||
//# sourceMappingURL=assertions.d.ts.map
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "../../cjs/_to_array.cjs",
|
||||
"module": "../../esm/_to_array.js"
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
var fs = require('fs')
|
||||
var path = require('path')
|
||||
var os = require('os')
|
||||
|
||||
// Workaround to fix webpack's build warnings: 'the request of a dependency is an expression'
|
||||
var runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require // eslint-disable-line
|
||||
|
||||
var vars = (process.config && process.config.variables) || {}
|
||||
var prebuildsOnly = !!process.env.PREBUILDS_ONLY
|
||||
var abi = process.versions.modules // TODO: support old node where this is undef
|
||||
var runtime = isElectron() ? 'electron' : (isNwjs() ? 'node-webkit' : 'node')
|
||||
|
||||
var arch = process.env.npm_config_arch || os.arch()
|
||||
var platform = process.env.npm_config_platform || os.platform()
|
||||
var libc = process.env.LIBC || (isAlpine(platform) ? 'musl' : 'glibc')
|
||||
var armv = process.env.ARM_VERSION || (arch === 'arm64' ? '8' : vars.arm_version) || ''
|
||||
var uv = (process.versions.uv || '').split('.')[0]
|
||||
|
||||
module.exports = load
|
||||
|
||||
function load (dir) {
|
||||
return runtimeRequire(load.resolve(dir))
|
||||
}
|
||||
|
||||
load.resolve = load.path = function (dir) {
|
||||
dir = path.resolve(dir || '.')
|
||||
|
||||
try {
|
||||
var name = runtimeRequire(path.join(dir, 'package.json')).name.toUpperCase().replace(/-/g, '_')
|
||||
if (process.env[name + '_PREBUILD']) dir = process.env[name + '_PREBUILD']
|
||||
} catch (err) {}
|
||||
|
||||
if (!prebuildsOnly) {
|
||||
var release = getFirst(path.join(dir, 'build/Release'), matchBuild)
|
||||
if (release) return release
|
||||
|
||||
var debug = getFirst(path.join(dir, 'build/Debug'), matchBuild)
|
||||
if (debug) return debug
|
||||
}
|
||||
|
||||
var prebuild = resolve(dir)
|
||||
if (prebuild) return prebuild
|
||||
|
||||
var nearby = resolve(path.dirname(process.execPath))
|
||||
if (nearby) return nearby
|
||||
|
||||
var target = [
|
||||
'platform=' + platform,
|
||||
'arch=' + arch,
|
||||
'runtime=' + runtime,
|
||||
'abi=' + abi,
|
||||
'uv=' + uv,
|
||||
armv ? 'armv=' + armv : '',
|
||||
'libc=' + libc,
|
||||
'node=' + process.versions.node,
|
||||
process.versions.electron ? 'electron=' + process.versions.electron : '',
|
||||
typeof __webpack_require__ === 'function' ? 'webpack=true' : '' // eslint-disable-line
|
||||
].filter(Boolean).join(' ')
|
||||
|
||||
throw new Error('No native build was found for ' + target + '\n loaded from: ' + dir + '\n')
|
||||
|
||||
function resolve (dir) {
|
||||
// Find matching "prebuilds/<platform>-<arch>" directory
|
||||
var tuples = readdirSync(path.join(dir, 'prebuilds')).map(parseTuple)
|
||||
var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0]
|
||||
if (!tuple) return
|
||||
|
||||
// Find most specific flavor first
|
||||
var prebuilds = path.join(dir, 'prebuilds', tuple.name)
|
||||
var parsed = readdirSync(prebuilds).map(parseTags)
|
||||
var candidates = parsed.filter(matchTags(runtime, abi))
|
||||
var winner = candidates.sort(compareTags(runtime))[0]
|
||||
if (winner) return path.join(prebuilds, winner.file)
|
||||
}
|
||||
}
|
||||
|
||||
function readdirSync (dir) {
|
||||
try {
|
||||
return fs.readdirSync(dir)
|
||||
} catch (err) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
function getFirst (dir, filter) {
|
||||
var files = readdirSync(dir).filter(filter)
|
||||
return files[0] && path.join(dir, files[0])
|
||||
}
|
||||
|
||||
function matchBuild (name) {
|
||||
return /\.node$/.test(name)
|
||||
}
|
||||
|
||||
function parseTuple (name) {
|
||||
// Example: darwin-x64+arm64
|
||||
var arr = name.split('-')
|
||||
if (arr.length !== 2) return
|
||||
|
||||
var platform = arr[0]
|
||||
var architectures = arr[1].split('+')
|
||||
|
||||
if (!platform) return
|
||||
if (!architectures.length) return
|
||||
if (!architectures.every(Boolean)) return
|
||||
|
||||
return { name, platform, architectures }
|
||||
}
|
||||
|
||||
function matchTuple (platform, arch) {
|
||||
return function (tuple) {
|
||||
if (tuple == null) return false
|
||||
if (tuple.platform !== platform) return false
|
||||
return tuple.architectures.includes(arch)
|
||||
}
|
||||
}
|
||||
|
||||
function compareTuples (a, b) {
|
||||
// Prefer single-arch prebuilds over multi-arch
|
||||
return a.architectures.length - b.architectures.length
|
||||
}
|
||||
|
||||
function parseTags (file) {
|
||||
var arr = file.split('.')
|
||||
var extension = arr.pop()
|
||||
var tags = { file: file, specificity: 0 }
|
||||
|
||||
if (extension !== 'node') return
|
||||
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var tag = arr[i]
|
||||
|
||||
if (tag === 'node' || tag === 'electron' || tag === 'node-webkit') {
|
||||
tags.runtime = tag
|
||||
} else if (tag === 'napi') {
|
||||
tags.napi = true
|
||||
} else if (tag.slice(0, 3) === 'abi') {
|
||||
tags.abi = tag.slice(3)
|
||||
} else if (tag.slice(0, 2) === 'uv') {
|
||||
tags.uv = tag.slice(2)
|
||||
} else if (tag.slice(0, 4) === 'armv') {
|
||||
tags.armv = tag.slice(4)
|
||||
} else if (tag === 'glibc' || tag === 'musl') {
|
||||
tags.libc = tag
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
tags.specificity++
|
||||
}
|
||||
|
||||
return tags
|
||||
}
|
||||
|
||||
function matchTags (runtime, abi) {
|
||||
return function (tags) {
|
||||
if (tags == null) return false
|
||||
if (tags.runtime && tags.runtime !== runtime && !runtimeAgnostic(tags)) return false
|
||||
if (tags.abi && tags.abi !== abi && !tags.napi) return false
|
||||
if (tags.uv && tags.uv !== uv) return false
|
||||
if (tags.armv && tags.armv !== armv) return false
|
||||
if (tags.libc && tags.libc !== libc) return false
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
function runtimeAgnostic (tags) {
|
||||
return tags.runtime === 'node' && tags.napi
|
||||
}
|
||||
|
||||
function compareTags (runtime) {
|
||||
// Precedence: non-agnostic runtime, abi over napi, then by specificity.
|
||||
return function (a, b) {
|
||||
if (a.runtime !== b.runtime) {
|
||||
return a.runtime === runtime ? -1 : 1
|
||||
} else if (a.abi !== b.abi) {
|
||||
return a.abi ? -1 : 1
|
||||
} else if (a.specificity !== b.specificity) {
|
||||
return a.specificity > b.specificity ? -1 : 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isNwjs () {
|
||||
return !!(process.versions && process.versions.nw)
|
||||
}
|
||||
|
||||
function isElectron () {
|
||||
if (process.versions && process.versions.electron) return true
|
||||
if (process.env.ELECTRON_RUN_AS_NODE) return true
|
||||
return typeof window !== 'undefined' && window.process && window.process.type === 'renderer'
|
||||
}
|
||||
|
||||
function isAlpine (platform) {
|
||||
return platform === 'linux' && fs.existsSync('/etc/alpine-release')
|
||||
}
|
||||
|
||||
// Exposed for unit tests
|
||||
// TODO: move to lib
|
||||
load.parseTags = parseTags
|
||||
load.matchTags = matchTags
|
||||
load.compareTags = compareTags
|
||||
load.parseTuple = parseTuple
|
||||
load.matchTuple = matchTuple
|
||||
load.compareTuples = compareTuples
|
||||
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ClassFieldInitializerScope = void 0;
|
||||
const ScopeBase_1 = require("./ScopeBase");
|
||||
const ScopeType_1 = require("./ScopeType");
|
||||
class ClassFieldInitializerScope extends ScopeBase_1.ScopeBase {
|
||||
constructor(scopeManager, upperScope, block) {
|
||||
super(scopeManager, ScopeType_1.ScopeType.classFieldInitializer, upperScope, block, false);
|
||||
}
|
||||
}
|
||||
exports.ClassFieldInitializerScope = ClassFieldInitializerScope;
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"elementFlags.js","sourceRoot":"","sources":["../../src/enums/elementFlags.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,MAAM,CAAC,IAAI,YAAiB,CAAC;AAC7B,CAAC,UAAU,YAAY;IACnB,YAAY,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;IAChD,YAAY,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC;IACxD,YAAY,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC;IACxD,YAAY,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;IAChD,YAAY,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC;IACxD,YAAY,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC;IAClD,YAAY,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,UAAU,CAAC;IACzD,YAAY,CAAC,YAAY,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,GAAG,aAAa,CAAC;IAC/D,YAAY,CAAC,YAAY,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC;AAC3D,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC,CAAC"}
|
||||
@@ -0,0 +1,120 @@
|
||||
'use strict'
|
||||
|
||||
/* eslint-disable no-prototype-builtins */
|
||||
|
||||
const { tspl } = require('@matteo.collina/tspl')
|
||||
const http = require('node:http')
|
||||
const { test } = require('node:test')
|
||||
const serializers = require('../lib/res')
|
||||
const { wrapResponseSerializer } = require('../')
|
||||
|
||||
test('res.raw is not enumerable', async (t) => {
|
||||
const p = tspl(t, { plan: 1 })
|
||||
|
||||
const server = http.createServer(handler)
|
||||
server.unref()
|
||||
server.listen(0, () => {
|
||||
http.get(server.address(), () => {})
|
||||
})
|
||||
|
||||
t.after(() => server.close())
|
||||
|
||||
function handler (_req, res) {
|
||||
const serialized = serializers.resSerializer(res)
|
||||
p.strictEqual(serialized.propertyIsEnumerable('raw'), false)
|
||||
res.end()
|
||||
}
|
||||
|
||||
await p.completed
|
||||
})
|
||||
|
||||
test('res.raw is available', async (t) => {
|
||||
const p = tspl(t, { plan: 2 })
|
||||
|
||||
const server = http.createServer(handler)
|
||||
server.unref()
|
||||
server.listen(0, () => {
|
||||
http.get(server.address(), () => {})
|
||||
})
|
||||
|
||||
t.after(() => server.close())
|
||||
|
||||
function handler (_req, res) {
|
||||
res.statusCode = 200
|
||||
const serialized = serializers.resSerializer(res)
|
||||
p.ok(serialized.raw)
|
||||
p.strictEqual(serialized.raw.statusCode, 200)
|
||||
res.end()
|
||||
}
|
||||
|
||||
await p.completed
|
||||
})
|
||||
|
||||
test('can wrap response serializers', async (t) => {
|
||||
const p = tspl(t, { plan: 3 })
|
||||
|
||||
const server = http.createServer(handler)
|
||||
server.unref()
|
||||
server.listen(0, () => {
|
||||
http.get(server.address(), () => {})
|
||||
})
|
||||
|
||||
t.after(() => server.close())
|
||||
|
||||
const serializer = wrapResponseSerializer(function (res) {
|
||||
p.ok(res.statusCode)
|
||||
p.strictEqual(res.statusCode, 200)
|
||||
delete res.statusCode
|
||||
return res
|
||||
})
|
||||
|
||||
function handler (_req, res) {
|
||||
res.end()
|
||||
res.statusCode = 200
|
||||
const serialized = serializer(res)
|
||||
p.ok(!serialized.statusCode)
|
||||
}
|
||||
|
||||
await p.completed
|
||||
})
|
||||
|
||||
test('res.headers is serialized', async (t) => {
|
||||
const p = tspl(t, { plan: 1 })
|
||||
|
||||
const server = http.createServer(handler)
|
||||
server.unref()
|
||||
server.listen(0, () => {
|
||||
http.get(server.address(), () => {})
|
||||
})
|
||||
|
||||
t.after(() => server.close())
|
||||
|
||||
function handler (_req, res) {
|
||||
res.setHeader('x-custom', 'y')
|
||||
const serialized = serializers.resSerializer(res)
|
||||
p.strictEqual(serialized.headers['x-custom'], 'y')
|
||||
res.end()
|
||||
}
|
||||
|
||||
await p.completed
|
||||
})
|
||||
|
||||
test('req.url will be obtained from input request url when input request url is not an object', async (t) => {
|
||||
const p = tspl(t, { plan: 1 })
|
||||
|
||||
const server = http.createServer(handler)
|
||||
server.unref()
|
||||
server.listen(0, () => {
|
||||
http.get(server.address(), () => {})
|
||||
})
|
||||
|
||||
t.after(() => server.close())
|
||||
|
||||
function handler (_req, res) {
|
||||
const serialized = serializers.resSerializer(res)
|
||||
p.strictEqual(serialized.statusCode, null)
|
||||
res.end()
|
||||
}
|
||||
|
||||
await p.completed
|
||||
})
|
||||
@@ -0,0 +1,20 @@
|
||||
# MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,85 @@
|
||||
export declare namespace util {
|
||||
type AssertEqual<T, U> = (<V>() => V extends T ? 1 : 2) extends <V>() => V extends U ? 1 : 2 ? true : false;
|
||||
export type isAny<T> = 0 extends 1 & T ? true : false;
|
||||
export const assertEqual: <A, B>(_: AssertEqual<A, B>) => void;
|
||||
export function assertIs<T>(_arg: T): void;
|
||||
export function assertNever(_x: never): never;
|
||||
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
export type OmitKeys<T, K extends string> = Pick<T, Exclude<keyof T, K>>;
|
||||
export type MakePartial<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
||||
export type Exactly<T, X> = T & Record<Exclude<keyof X, keyof T>, never>;
|
||||
export type InexactPartial<T> = {
|
||||
[k in keyof T]?: T[k] | undefined;
|
||||
};
|
||||
export const arrayToEnum: <T extends string, U extends [T, ...T[]]>(items: U) => { [k in U[number]]: k; };
|
||||
export const getValidEnumValues: (obj: any) => any[];
|
||||
export const objectValues: (obj: any) => any[];
|
||||
export const objectKeys: ObjectConstructor["keys"];
|
||||
export const find: <T>(arr: T[], checker: (arg: T) => any) => T | undefined;
|
||||
export type identity<T> = objectUtil.identity<T>;
|
||||
export type flatten<T> = objectUtil.flatten<T>;
|
||||
export type noUndefined<T> = T extends undefined ? never : T;
|
||||
export const isInteger: NumberConstructor["isInteger"];
|
||||
export function joinValues<T extends any[]>(array: T, separator?: string): string;
|
||||
export const jsonStringifyReplacer: (_: string, value: any) => any;
|
||||
export {};
|
||||
}
|
||||
export declare namespace objectUtil {
|
||||
export type MergeShapes<U, V> = keyof U & keyof V extends never ? U & V : {
|
||||
[k in Exclude<keyof U, keyof V>]: U[k];
|
||||
} & V;
|
||||
type optionalKeys<T extends object> = {
|
||||
[k in keyof T]: undefined extends T[k] ? k : never;
|
||||
}[keyof T];
|
||||
type requiredKeys<T extends object> = {
|
||||
[k in keyof T]: undefined extends T[k] ? never : k;
|
||||
}[keyof T];
|
||||
export type addQuestionMarks<T extends object, _O = any> = {
|
||||
[K in requiredKeys<T>]: T[K];
|
||||
} & {
|
||||
[K in optionalKeys<T>]?: T[K];
|
||||
} & {
|
||||
[k in keyof T]?: unknown;
|
||||
};
|
||||
export type identity<T> = T;
|
||||
export type flatten<T> = identity<{
|
||||
[k in keyof T]: T[k];
|
||||
}>;
|
||||
export type noNeverKeys<T> = {
|
||||
[k in keyof T]: [T[k]] extends [never] ? never : k;
|
||||
}[keyof T];
|
||||
export type noNever<T> = identity<{
|
||||
[k in noNeverKeys<T>]: k extends keyof T ? T[k] : never;
|
||||
}>;
|
||||
export const mergeShapes: <U, T>(first: U, second: T) => T & U;
|
||||
export type extendShape<A extends object, B extends object> = keyof A & keyof B extends never ? A & B : {
|
||||
[K in keyof A as K extends keyof B ? never : K]: A[K];
|
||||
} & {
|
||||
[K in keyof B]: B[K];
|
||||
};
|
||||
export {};
|
||||
}
|
||||
export declare const ZodParsedType: {
|
||||
string: "string";
|
||||
nan: "nan";
|
||||
number: "number";
|
||||
integer: "integer";
|
||||
float: "float";
|
||||
boolean: "boolean";
|
||||
date: "date";
|
||||
bigint: "bigint";
|
||||
symbol: "symbol";
|
||||
function: "function";
|
||||
undefined: "undefined";
|
||||
null: "null";
|
||||
array: "array";
|
||||
object: "object";
|
||||
unknown: "unknown";
|
||||
promise: "promise";
|
||||
void: "void";
|
||||
never: "never";
|
||||
map: "map";
|
||||
set: "set";
|
||||
};
|
||||
export type ZodParsedType = keyof typeof ZodParsedType;
|
||||
export declare const getParsedType: (data: any) => ZodParsedType;
|
||||
@@ -0,0 +1,85 @@
|
||||
"use strict";
|
||||
|
||||
/* global module, require */
|
||||
module.exports = function () {
|
||||
|
||||
"use strict";
|
||||
|
||||
// Get a promise object. This may be native, or it may be polyfilled
|
||||
|
||||
var ES6Promise = require("./promise.js");
|
||||
|
||||
/**
|
||||
* thatLooksLikeAPromiseToMe()
|
||||
*
|
||||
* Duck-types a promise.
|
||||
*
|
||||
* @param {object} o
|
||||
* @return {bool} True if this resembles a promise
|
||||
*/
|
||||
function thatLooksLikeAPromiseToMe(o) {
|
||||
return o && typeof o.then === "function" && typeof o.catch === "function";
|
||||
}
|
||||
|
||||
/**
|
||||
* promisify()
|
||||
*
|
||||
* Transforms callback-based function -- func(arg1, arg2 .. argN, callback) -- into
|
||||
* an ES6-compatible Promise. Promisify provides a default callback of the form (error, result)
|
||||
* and rejects when `error` is truthy. You can also supply settings object as the second argument.
|
||||
*
|
||||
* @param {function} original - The function to promisify
|
||||
* @param {object} settings - Settings object
|
||||
* @param {object} settings.thisArg - A `this` context to use. If not set, assume `settings` _is_ `thisArg`
|
||||
* @param {bool} settings.multiArgs - Should multiple arguments be returned as an array?
|
||||
* @return {function} A promisified version of `original`
|
||||
*/
|
||||
return function promisify(original, settings) {
|
||||
|
||||
return function () {
|
||||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
||||
args[_key] = arguments[_key];
|
||||
}
|
||||
|
||||
var returnMultipleArguments = settings && settings.multiArgs;
|
||||
|
||||
var target = void 0;
|
||||
if (settings && settings.thisArg) {
|
||||
target = settings.thisArg;
|
||||
} else if (settings) {
|
||||
target = settings;
|
||||
}
|
||||
|
||||
// Return the promisified function
|
||||
return new ES6Promise(function (resolve, reject) {
|
||||
|
||||
// Append the callback bound to the context
|
||||
args.push(function callback(err) {
|
||||
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
for (var _len2 = arguments.length, values = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
|
||||
values[_key2 - 1] = arguments[_key2];
|
||||
}
|
||||
|
||||
if (false === !!returnMultipleArguments) {
|
||||
return resolve(values[0]);
|
||||
}
|
||||
|
||||
resolve(values);
|
||||
});
|
||||
|
||||
// Call the function
|
||||
var response = original.apply(target, args);
|
||||
|
||||
// If it looks like original already returns a promise,
|
||||
// then just resolve with that promise. Hopefully, the callback function we added will just be ignored.
|
||||
if (thatLooksLikeAPromiseToMe(response)) {
|
||||
resolve(response);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
}();
|
||||
@@ -0,0 +1,258 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.xhtmlEntities = void 0;
|
||||
exports.xhtmlEntities = {
|
||||
Aacute: '\u00C1',
|
||||
aacute: '\u00E1',
|
||||
Acirc: '\u00C2',
|
||||
acirc: '\u00E2',
|
||||
acute: '\u00B4',
|
||||
AElig: '\u00C6',
|
||||
aelig: '\u00E6',
|
||||
Agrave: '\u00C0',
|
||||
agrave: '\u00E0',
|
||||
alefsym: '\u2135',
|
||||
Alpha: '\u0391',
|
||||
alpha: '\u03B1',
|
||||
amp: '&',
|
||||
and: '\u2227',
|
||||
ang: '\u2220',
|
||||
apos: '\u0027',
|
||||
Aring: '\u00C5',
|
||||
aring: '\u00E5',
|
||||
asymp: '\u2248',
|
||||
Atilde: '\u00C3',
|
||||
atilde: '\u00E3',
|
||||
Auml: '\u00C4',
|
||||
auml: '\u00E4',
|
||||
bdquo: '\u201E',
|
||||
Beta: '\u0392',
|
||||
beta: '\u03B2',
|
||||
brvbar: '\u00A6',
|
||||
bull: '\u2022',
|
||||
cap: '\u2229',
|
||||
Ccedil: '\u00C7',
|
||||
ccedil: '\u00E7',
|
||||
cedil: '\u00B8',
|
||||
cent: '\u00A2',
|
||||
Chi: '\u03A7',
|
||||
chi: '\u03C7',
|
||||
circ: '\u02C6',
|
||||
clubs: '\u2663',
|
||||
cong: '\u2245',
|
||||
copy: '\u00A9',
|
||||
crarr: '\u21B5',
|
||||
cup: '\u222A',
|
||||
curren: '\u00A4',
|
||||
dagger: '\u2020',
|
||||
Dagger: '\u2021',
|
||||
darr: '\u2193',
|
||||
dArr: '\u21D3',
|
||||
deg: '\u00B0',
|
||||
Delta: '\u0394',
|
||||
delta: '\u03B4',
|
||||
diams: '\u2666',
|
||||
divide: '\u00F7',
|
||||
Eacute: '\u00C9',
|
||||
eacute: '\u00E9',
|
||||
Ecirc: '\u00CA',
|
||||
ecirc: '\u00EA',
|
||||
Egrave: '\u00C8',
|
||||
egrave: '\u00E8',
|
||||
empty: '\u2205',
|
||||
emsp: '\u2003',
|
||||
ensp: '\u2002',
|
||||
Epsilon: '\u0395',
|
||||
epsilon: '\u03B5',
|
||||
equiv: '\u2261',
|
||||
Eta: '\u0397',
|
||||
eta: '\u03B7',
|
||||
ETH: '\u00D0',
|
||||
eth: '\u00F0',
|
||||
Euml: '\u00CB',
|
||||
euml: '\u00EB',
|
||||
euro: '\u20AC',
|
||||
exist: '\u2203',
|
||||
fnof: '\u0192',
|
||||
forall: '\u2200',
|
||||
frac12: '\u00BD',
|
||||
frac14: '\u00BC',
|
||||
frac34: '\u00BE',
|
||||
frasl: '\u2044',
|
||||
Gamma: '\u0393',
|
||||
gamma: '\u03B3',
|
||||
ge: '\u2265',
|
||||
gt: '>',
|
||||
harr: '\u2194',
|
||||
hArr: '\u21D4',
|
||||
hearts: '\u2665',
|
||||
hellip: '\u2026',
|
||||
Iacute: '\u00CD',
|
||||
iacute: '\u00ED',
|
||||
Icirc: '\u00CE',
|
||||
icirc: '\u00EE',
|
||||
iexcl: '\u00A1',
|
||||
Igrave: '\u00CC',
|
||||
igrave: '\u00EC',
|
||||
image: '\u2111',
|
||||
infin: '\u221E',
|
||||
int: '\u222B',
|
||||
Iota: '\u0399',
|
||||
iota: '\u03B9',
|
||||
iquest: '\u00BF',
|
||||
isin: '\u2208',
|
||||
Iuml: '\u00CF',
|
||||
iuml: '\u00EF',
|
||||
Kappa: '\u039A',
|
||||
kappa: '\u03BA',
|
||||
Lambda: '\u039B',
|
||||
lambda: '\u03BB',
|
||||
lang: '\u2329',
|
||||
laquo: '\u00AB',
|
||||
larr: '\u2190',
|
||||
lArr: '\u21D0',
|
||||
lceil: '\u2308',
|
||||
ldquo: '\u201C',
|
||||
le: '\u2264',
|
||||
lfloor: '\u230A',
|
||||
lowast: '\u2217',
|
||||
loz: '\u25CA',
|
||||
lrm: '\u200E',
|
||||
lsaquo: '\u2039',
|
||||
lsquo: '\u2018',
|
||||
lt: '<',
|
||||
macr: '\u00AF',
|
||||
mdash: '\u2014',
|
||||
micro: '\u00B5',
|
||||
middot: '\u00B7',
|
||||
minus: '\u2212',
|
||||
Mu: '\u039C',
|
||||
mu: '\u03BC',
|
||||
nabla: '\u2207',
|
||||
nbsp: '\u00A0',
|
||||
ndash: '\u2013',
|
||||
ne: '\u2260',
|
||||
ni: '\u220B',
|
||||
not: '\u00AC',
|
||||
notin: '\u2209',
|
||||
nsub: '\u2284',
|
||||
Ntilde: '\u00D1',
|
||||
ntilde: '\u00F1',
|
||||
Nu: '\u039D',
|
||||
nu: '\u03BD',
|
||||
Oacute: '\u00D3',
|
||||
oacute: '\u00F3',
|
||||
Ocirc: '\u00D4',
|
||||
ocirc: '\u00F4',
|
||||
OElig: '\u0152',
|
||||
oelig: '\u0153',
|
||||
Ograve: '\u00D2',
|
||||
ograve: '\u00F2',
|
||||
oline: '\u203E',
|
||||
Omega: '\u03A9',
|
||||
omega: '\u03C9',
|
||||
Omicron: '\u039F',
|
||||
omicron: '\u03BF',
|
||||
oplus: '\u2295',
|
||||
or: '\u2228',
|
||||
ordf: '\u00AA',
|
||||
ordm: '\u00BA',
|
||||
Oslash: '\u00D8',
|
||||
oslash: '\u00F8',
|
||||
Otilde: '\u00D5',
|
||||
otilde: '\u00F5',
|
||||
otimes: '\u2297',
|
||||
Ouml: '\u00D6',
|
||||
ouml: '\u00F6',
|
||||
para: '\u00B6',
|
||||
part: '\u2202',
|
||||
permil: '\u2030',
|
||||
perp: '\u22A5',
|
||||
Phi: '\u03A6',
|
||||
phi: '\u03C6',
|
||||
Pi: '\u03A0',
|
||||
pi: '\u03C0',
|
||||
piv: '\u03D6',
|
||||
plusmn: '\u00B1',
|
||||
pound: '\u00A3',
|
||||
prime: '\u2032',
|
||||
Prime: '\u2033',
|
||||
prod: '\u220F',
|
||||
prop: '\u221D',
|
||||
Psi: '\u03A8',
|
||||
psi: '\u03C8',
|
||||
quot: '\u0022',
|
||||
radic: '\u221A',
|
||||
rang: '\u232A',
|
||||
raquo: '\u00BB',
|
||||
rarr: '\u2192',
|
||||
rArr: '\u21D2',
|
||||
rceil: '\u2309',
|
||||
rdquo: '\u201D',
|
||||
real: '\u211C',
|
||||
reg: '\u00AE',
|
||||
rfloor: '\u230B',
|
||||
Rho: '\u03A1',
|
||||
rho: '\u03C1',
|
||||
rlm: '\u200F',
|
||||
rsaquo: '\u203A',
|
||||
rsquo: '\u2019',
|
||||
sbquo: '\u201A',
|
||||
Scaron: '\u0160',
|
||||
scaron: '\u0161',
|
||||
sdot: '\u22C5',
|
||||
sect: '\u00A7',
|
||||
shy: '\u00AD',
|
||||
Sigma: '\u03A3',
|
||||
sigma: '\u03C3',
|
||||
sigmaf: '\u03C2',
|
||||
sim: '\u223C',
|
||||
spades: '\u2660',
|
||||
sub: '\u2282',
|
||||
sube: '\u2286',
|
||||
sum: '\u2211',
|
||||
sup: '\u2283',
|
||||
sup1: '\u00B9',
|
||||
sup2: '\u00B2',
|
||||
sup3: '\u00B3',
|
||||
supe: '\u2287',
|
||||
szlig: '\u00DF',
|
||||
Tau: '\u03A4',
|
||||
tau: '\u03C4',
|
||||
there4: '\u2234',
|
||||
Theta: '\u0398',
|
||||
theta: '\u03B8',
|
||||
thetasym: '\u03D1',
|
||||
thinsp: '\u2009',
|
||||
THORN: '\u00DE',
|
||||
thorn: '\u00FE',
|
||||
tilde: '\u02DC',
|
||||
times: '\u00D7',
|
||||
trade: '\u2122',
|
||||
Uacute: '\u00DA',
|
||||
uacute: '\u00FA',
|
||||
uarr: '\u2191',
|
||||
uArr: '\u21D1',
|
||||
Ucirc: '\u00DB',
|
||||
ucirc: '\u00FB',
|
||||
Ugrave: '\u00D9',
|
||||
ugrave: '\u00F9',
|
||||
uml: '\u00A8',
|
||||
upsih: '\u03D2',
|
||||
Upsilon: '\u03A5',
|
||||
upsilon: '\u03C5',
|
||||
Uuml: '\u00DC',
|
||||
uuml: '\u00FC',
|
||||
weierp: '\u2118',
|
||||
Xi: '\u039E',
|
||||
xi: '\u03BE',
|
||||
Yacute: '\u00DD',
|
||||
yacute: '\u00FD',
|
||||
yen: '\u00A5',
|
||||
yuml: '\u00FF',
|
||||
Yuml: '\u0178',
|
||||
Zeta: '\u0396',
|
||||
zeta: '\u03B6',
|
||||
zwj: '\u200D',
|
||||
zwnj: '\u200C',
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isObjectNotArray = isObjectNotArray;
|
||||
exports.deepMerge = deepMerge;
|
||||
/**
|
||||
* Check if the variable contains an object strictly rejecting arrays
|
||||
* @returns `true` if obj is an object
|
||||
*/
|
||||
function isObjectNotArray(obj) {
|
||||
return typeof obj === 'object' && obj != null && !Array.isArray(obj);
|
||||
}
|
||||
/**
|
||||
* Pure function - doesn't mutate either parameter!
|
||||
* Merges two objects together deeply, overwriting the properties in first with the properties in second
|
||||
* @param first The first object
|
||||
* @param second The second object
|
||||
* @returns a new object
|
||||
*/
|
||||
function deepMerge(first = {}, second = {}) {
|
||||
// get the unique set of keys across both objects
|
||||
const keys = new Set([...Object.keys(first), ...Object.keys(second)]);
|
||||
return Object.fromEntries([...keys].map(key => {
|
||||
const firstHasKey = key in first;
|
||||
const secondHasKey = key in second;
|
||||
const firstValue = first[key];
|
||||
const secondValue = second[key];
|
||||
let value;
|
||||
if (firstHasKey && secondHasKey) {
|
||||
if (isObjectNotArray(firstValue) && isObjectNotArray(secondValue)) {
|
||||
// object type
|
||||
value = deepMerge(firstValue, secondValue);
|
||||
}
|
||||
else {
|
||||
// value type
|
||||
value = secondValue;
|
||||
}
|
||||
}
|
||||
else if (firstHasKey) {
|
||||
value = firstValue;
|
||||
}
|
||||
else {
|
||||
value = secondValue;
|
||||
}
|
||||
return [key, value];
|
||||
}));
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"blake2.d.ts","sourceRoot":"","sources":["src/blake2.ts"],"names":[],"mappings":"AASA,OAAO,EAEmB,IAAI,EAC5B,KAAK,MAAM,EAAE,KAAK,KAAK,EACxB,MAAM,YAAY,CAAC;AAEpB,qGAAqG;AACrG,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,KAAK,CAAC;IACZ,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB,CAAC;AA+EF,+CAA+C;AAC/C,8BAAsB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,CAAE,SAAQ,IAAI,CAAC,CAAC,CAAC;IAC/D,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;IACpF,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,MAAM,EAAE;IAClC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;IAC/C,QAAQ,CAAC,OAAO,IAAI,IAAI;IACxB,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC;IAC7B,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC;IAChC,SAAS,CAAC,QAAQ,UAAS;IAC3B,SAAS,CAAC,SAAS,UAAS;IAC5B,SAAS,CAAC,MAAM,EAAE,MAAM,CAAK;IAC7B,SAAS,CAAC,GAAG,EAAE,MAAM,CAAK;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAS/C,MAAM,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI;IAwCzB,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI;IAajC,MAAM,IAAI,UAAU;IAOpB,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC;IAarB,KAAK,IAAI,CAAC;CAGX;AAED,qBAAa,OAAQ,SAAQ,MAAM,CAAC,OAAO,CAAC;IAE1C,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,GAAG,CAAkB;gBAEjB,IAAI,GAAE,UAAe;IAmCjC,SAAS,CAAC,GAAG,IAAI;QACf,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAC9D,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;QAAE,MAAM;KAC/D;IAKD,SAAS,CAAC,GAAG,CACX,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAClD,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAClD,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAClD,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GACjD,IAAI;IAkBP,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;IAkD3E,OAAO,IAAI,IAAI;CAKhB;AAED;;;;GAIG;AACH,eAAO,MAAM,OAAO,EAAE,MAErB,CAAC;AAOF,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAC/C,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAC/C,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IACjD,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;CACpD,CAAC;AAGF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EACtF,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAC9F,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GACnG,KAAK,CAsBP;AAGD,qBAAa,OAAQ,SAAQ,MAAM,CAAC,OAAO,CAAC;IAE1C,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,EAAE,CAAiB;gBAEf,IAAI,GAAE,UAAe;IA+BjC,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAKjF,SAAS,CAAC,GAAG,CACX,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAC7F,IAAI;IAUP,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI;IAkB3E,OAAO,IAAI,IAAI;CAKhB;AAED;;;;GAIG;AACH,eAAO,MAAM,OAAO,EAAE,MAErB,CAAC"}
|
||||
Reference in New Issue
Block a user