77 lines
3.0 KiB
TypeScript
77 lines
3.0 KiB
TypeScript
import { binToHex, hexToBin } from '@bitauth/libauth';
|
|
|
|
/**
|
|
* Matches a bigint encoded in Extended JSON format: `<bigint: 123n>`.
|
|
*/
|
|
const EXTENDED_JSON_BIGINT_PATTERN = /^<bigint: (?<bigint>[+-]?[0-9]+)n>$/u;
|
|
|
|
/**
|
|
* Matches a Uint8Array encoded in Extended JSON format: `<uint8array: abcd>`.
|
|
*/
|
|
const EXTENDED_JSON_UINT8ARRAY_PATTERN = /^<uint8array: (?<hex>[0-9a-f]*)>$/u;
|
|
|
|
/**
|
|
* The JSON replacer that encodes `bigint` and `Uint8Array` values in Extended JSON format,
|
|
* compatible with the format expected by `extendedJsonReviver`.
|
|
*
|
|
* - BigInts are encoded as `<bigint: 123n>`.
|
|
* - Uint8Arrays are encoded as `<uint8array: abcd>`.
|
|
* All other values pass through unchanged and if any incompatible type is encountered, an error is thrown.
|
|
*
|
|
* Note: To use this function, pass it as the second argument to `JSON.stringify` when serializing data.
|
|
*
|
|
* Note to developers: Libauth's `stringify` is the replacer. It also serializes functions and symbols,
|
|
* which we do not support. Passing it would let templates include those values, but revival would then fail.
|
|
* This module provides a dedicated replacer and reviver so serialization and deserialization stay aligned.
|
|
*
|
|
* @param _propertyKey The property key being serialized, required by the `JSON.stringify` replacer but not used here.
|
|
* @param value The value to encode or pass through unchanged.
|
|
* @returns The encoded string
|
|
*/
|
|
export const extendedJsonReplacer = (_propertyKey: string, value: unknown): unknown => {
|
|
if (value instanceof Uint8Array) {
|
|
return `<uint8array: ${binToHex(value)}>`;
|
|
}
|
|
|
|
if (typeof value === 'bigint') {
|
|
return `<bigint: ${value.toString()}n>`;
|
|
}
|
|
|
|
return value;
|
|
};
|
|
|
|
/**
|
|
* The JSON reviver that reconstructs `bigint` and `Uint8Array` values encoded by `extendedJsonReplacer`.
|
|
*
|
|
* Note: To use this function, pass it as the second argument to `JSON.parse` when deserializing data.
|
|
*
|
|
* @param _propertyKey The property key being deserialized, required by the `JSON.parse` reviver but not used here.
|
|
* @param value The value to reconstruct or pass through unchanged.
|
|
* @returns The reconstructed value
|
|
*/
|
|
export const extendedJsonReviver = (_propertyKey: string, value: unknown): unknown => {
|
|
// If the value is not a string, return the original value
|
|
if (typeof value !== 'string') {
|
|
return value;
|
|
}
|
|
|
|
// Match the bigint pattern
|
|
const bigintPatternMatch = value.match(EXTENDED_JSON_BIGINT_PATTERN);
|
|
|
|
// If the value matches the bigint pattern, return the reconstructed bigint
|
|
if (bigintPatternMatch) {
|
|
return BigInt(bigintPatternMatch.groups!.bigint);
|
|
}
|
|
|
|
// Match the Uint8Array pattern
|
|
const uint8arrayPatternMatch = value.match(EXTENDED_JSON_UINT8ARRAY_PATTERN);
|
|
|
|
// If the value matches the Uint8Array pattern, return the reconstructed Uint8Array
|
|
if (uint8arrayPatternMatch) {
|
|
return hexToBin(uint8arrayPatternMatch.groups!.hex);
|
|
}
|
|
|
|
// If the value does not match either pattern, return the original value
|
|
return value;
|
|
};
|