import * as plugins from './smartjson.plugins.js'; // Define interfaces and types for better type checking and readability interface IBufferLike { type: 'Buffer'; data: string | any[]; // `any[]` for array data representation } interface IEncodedBuffer { type: 'EncodedBuffer', data: string; } type TParseReviver = (this: any, key: string, value: any) => any; type TParseReplacer = (this: any, key: string, value: any) => any; // Utility functions to handle base64 encoding/decoding in a cross-platform way function base64Encode(data: Uint8Array): string { return btoa(String.fromCharCode(...data)); } function base64Decode(str: string): Uint8Array { return new Uint8Array(Array.from(atob(str)).map((char) => char.charCodeAt(0))); } // Main functionality with cross-platform support function stringify(value: any, space?: string | number): string { return JSON.stringify(value, replacer, space); } function parse(text: string): any { return JSON.parse(text, reviver); } const replacer: TParseReplacer = (key, value) => { // Check if value is IBufferLike if (isBufferLike(value)) { let bufferData: Uint8Array; // Handle IBufferLike objects with a .data property if ('data' in value && isArray(value.data)) { if (value.data.length > 0) { bufferData = new Uint8Array(value.data); } else { return ''; // Return empty string for empty data arrays } } // Handle Uint8Array directly else if (value instanceof Uint8Array) { bufferData = value; } else { // If not a recognized format, return value as is return value; } // Encode the bufferData (Uint8Array) to base64 const base64Data = 'base64:' + base64Encode(bufferData); return { type: 'EncodedBuffer', data: base64Data, }; } // Return value unchanged if not buffer-like return value; }; const reviver: TParseReviver = (key, value) => { if (isEncodedBuffer(value)) { if (isString(value.data) && value.data.startsWith('base64:')) { // Correctly slice the 'base64:' prefix before decoding const base64Data = value.data.slice(7); // Skip 'base64:' prefix const buffer = base64Decode(base64Data); // Assuming the rest of your application can work directly with Uint8Array, // otherwise, you might need to convert it to another format return buffer; } } return value; }; function isEncodedBuffer(x: any): x is IEncodedBuffer { return isObject(x) && (x as any).type === 'EncodedBuffer' && isString((x as any).data); } function isBufferLike(x: any): x is IBufferLike | Uint8Array { return ( (isObject(x) && ((x as any).type === 'Buffer' && (isArray((x as any).data) || isString((x as any).data)))) || x instanceof Uint8Array ); } /** * We use this function to check if a value is an array * @param x * @returns */ function isArray(x: any): x is any[] { return Array.isArray(x); } /** * We use this function to check if a value is a string * @param x * @returns */ function isString(x: any): x is string { return typeof x === 'string'; } /** * We use this function to check if a value is an object * @param x */ function isObject(x: any): x is object { return typeof x === 'object' && x !== null; } export { stringify, parse, replacer, reviver };