UNPKG

@sinclair/typebox

Version:

Json Schema Type Builder with Static Type Resolution for TypeScript

153 lines (151 loc) 5.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValueHashError = void 0; exports.Hash = Hash; const index_1 = require("../guard/index"); const index_2 = require("../../type/error/index"); // ------------------------------------------------------------------ // Errors // ------------------------------------------------------------------ class ValueHashError extends index_2.TypeBoxError { constructor(value) { super(`Unable to hash value`); this.value = value; } } exports.ValueHashError = ValueHashError; // ------------------------------------------------------------------ // ByteMarker // ------------------------------------------------------------------ var ByteMarker; (function (ByteMarker) { ByteMarker[ByteMarker["Undefined"] = 0] = "Undefined"; ByteMarker[ByteMarker["Null"] = 1] = "Null"; ByteMarker[ByteMarker["Boolean"] = 2] = "Boolean"; ByteMarker[ByteMarker["Number"] = 3] = "Number"; ByteMarker[ByteMarker["String"] = 4] = "String"; ByteMarker[ByteMarker["Object"] = 5] = "Object"; ByteMarker[ByteMarker["Array"] = 6] = "Array"; ByteMarker[ByteMarker["Date"] = 7] = "Date"; ByteMarker[ByteMarker["Uint8Array"] = 8] = "Uint8Array"; ByteMarker[ByteMarker["Symbol"] = 9] = "Symbol"; ByteMarker[ByteMarker["BigInt"] = 10] = "BigInt"; })(ByteMarker || (ByteMarker = {})); // ------------------------------------------------------------------ // State // ------------------------------------------------------------------ let Accumulator = BigInt('14695981039346656037'); const [Prime, Size] = [BigInt('1099511628211'), BigInt('2') ** BigInt('64')]; const Bytes = Array.from({ length: 256 }).map((_, i) => BigInt(i)); const F64 = new Float64Array(1); const F64In = new DataView(F64.buffer); const F64Out = new Uint8Array(F64.buffer); // ------------------------------------------------------------------ // NumberToBytes // ------------------------------------------------------------------ function* NumberToBytes(value) { const byteCount = value === 0 ? 1 : Math.ceil(Math.floor(Math.log2(value) + 1) / 8); for (let i = 0; i < byteCount; i++) { yield (value >> (8 * (byteCount - 1 - i))) & 0xff; } } // ------------------------------------------------------------------ // Hashing Functions // ------------------------------------------------------------------ function ArrayType(value) { FNV1A64(ByteMarker.Array); for (const item of value) { Visit(item); } } function BooleanType(value) { FNV1A64(ByteMarker.Boolean); FNV1A64(value ? 1 : 0); } function BigIntType(value) { FNV1A64(ByteMarker.BigInt); F64In.setBigInt64(0, value); for (const byte of F64Out) { FNV1A64(byte); } } function DateType(value) { FNV1A64(ByteMarker.Date); Visit(value.getTime()); } function NullType(value) { FNV1A64(ByteMarker.Null); } function NumberType(value) { FNV1A64(ByteMarker.Number); F64In.setFloat64(0, value); for (const byte of F64Out) { FNV1A64(byte); } } function ObjectType(value) { FNV1A64(ByteMarker.Object); for (const key of globalThis.Object.getOwnPropertyNames(value).sort()) { Visit(key); Visit(value[key]); } } function StringType(value) { FNV1A64(ByteMarker.String); for (let i = 0; i < value.length; i++) { for (const byte of NumberToBytes(value.charCodeAt(i))) { FNV1A64(byte); } } } function SymbolType(value) { FNV1A64(ByteMarker.Symbol); Visit(value.description); } function Uint8ArrayType(value) { FNV1A64(ByteMarker.Uint8Array); for (let i = 0; i < value.length; i++) { FNV1A64(value[i]); } } function UndefinedType(value) { return FNV1A64(ByteMarker.Undefined); } function Visit(value) { if ((0, index_1.IsArray)(value)) return ArrayType(value); if ((0, index_1.IsBoolean)(value)) return BooleanType(value); if ((0, index_1.IsBigInt)(value)) return BigIntType(value); if ((0, index_1.IsDate)(value)) return DateType(value); if ((0, index_1.IsNull)(value)) return NullType(value); if ((0, index_1.IsNumber)(value)) return NumberType(value); if ((0, index_1.IsObject)(value)) return ObjectType(value); if ((0, index_1.IsString)(value)) return StringType(value); if ((0, index_1.IsSymbol)(value)) return SymbolType(value); if ((0, index_1.IsUint8Array)(value)) return Uint8ArrayType(value); if ((0, index_1.IsUndefined)(value)) return UndefinedType(value); throw new ValueHashError(value); } function FNV1A64(byte) { Accumulator = Accumulator ^ Bytes[byte]; Accumulator = (Accumulator * Prime) % Size; } // ------------------------------------------------------------------ // Hash // ------------------------------------------------------------------ /** Creates a FNV1A-64 non cryptographic hash of the given value */ function Hash(value) { Accumulator = BigInt('14695981039346656037'); Visit(value); return Accumulator; }