Something went wrong. Try again.
Mirrored from GitHub github.com/roostorg/coop
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127import stringify from 'safe-stable-stringify';import { type Opaque } from 'type-fest';
import { type JSON } from './json-schema-types.js';
/** * This function accepts any JS string and encodes it in base64, using a UTF8 * representation of the string to derive the underlying binary data. */export function b64Encode<T extends string>(it: T) { return Buffer.from(it, 'utf-8').toString('base64') as B64Of<T>;}
/** * This function accepts any b64 encoded string, as generated by * {@link b64Encode}, and returns the original JS string that was encoded. */export function b64Decode<T extends B64Of<string>>(it: T) { return Buffer.from(it, 'base64').toString('utf-8') as T[typeof meta];}
export function b64UrlEncode<T extends string>(it: T) { return b64Encode(it).replace('+', '-').replace('/', '_') as B64UrlOf<T>;}
export function b64UrlDecode<T extends B64UrlOf<string>>(it: T) { const b64String = it.replace('-', '+').replace('_', '/') as B64Of< (typeof it)[typeof meta] >;
return b64Decode(b64String);}
export function b64EncodeArrayBuffer<T extends ArrayBuffer>(it: T) { return Buffer.from(it).toString('base64') as B64Of<T>;}
/** * Converts a value to JSON, while preserving its type for future inspection. * * Sometimes, we need to stringify a value (e.g., to use the string as a key), * but we'd still like to Typescript to track the original type that we * stringified, so that we can have type checking on the data we'll get back * if/when we JSON.parse the string later. That's what this `jsonStringify` * helper function does. See {@link jsonParse}. * * NB: technically, this should return a JsonOf<Jsonify<T>>, but we don't do * that for now because using Jsonify almost always runs up against TS stack * limits. * * @param it The value to stringify. */export function jsonStringify<T>(it: T) { return stringify(it) as JsonOf<T>;}
/** * Identical to {@link jsonStringify}, except that it does not normalize the * order of object keys in the final, returned string. Therefore, e.g., * `{ a: 0, b: 0 }` and `{ b: 0, a: 0 }` will produce different strings. This is * usually not what you want -- it prevents the resulting string from being used * reliably as a cache key, e.g. -- but may give slightly better performance. */export function jsonStringifyUnstable<T>(it: T) { // eslint-disable-next-line no-restricted-syntax return JSON.stringify(it) as JsonOf<T>;}
/** * Parses the JSON, and returns its original type, for JSON generated by * {@link jsonStringify}. */export function jsonParse<T extends JsonOf<unknown>>(it: T) { // eslint-disable-next-line no-restricted-syntax return JSON.parse(it) as (typeof it)[typeof meta];}
/** * Returns the parsed value if JSON parsing succeeds; else undefined. */export function tryJsonParse(it: string): JSON | undefined { try { // eslint-disable-next-line no-restricted-syntax return JSON.parse(it); } catch (e) { return undefined; }}
/** * Constructs an array whose elements are tuples of the characters * and the number of times they appear in order of the string. * IE: teeest = [['t', 1], ['e', 3], ['s', 1], ['t', 1]] */export function runEncode(text: string): [string, number][] { const ret: [string, number][] = []; let lastChar = null; let charCount = 0; for (const c of text) { if (c === lastChar) { charCount++; } else { if (lastChar !== null) { ret.push([lastChar, charCount]); } lastChar = c; charCount = 1; } } if (lastChar) { ret.push([lastChar, charCount]); } return ret;}
/** * Escape any characters that have a special meaning in regex syntax. */export function regexEscape(text: string) { return text.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');}
declare const meta: unique symbol;export type JsonOf<T> = Opaque<string, 'JSON'> & { readonly [meta]: T };export type B64Of<T> = Opaque<string, 'B64'> & { readonly [meta]: T };export type B64UrlOf<T> = Opaque<string, 'B64Url'> & { readonly [meta]: T };