import { Value } from './values'; export function stringify(x: any): string { if (typeof x?.asPreservesText === 'function') { return x.asPreservesText(); } else { try { return JSON.stringify(x); } catch (_e) { return ('' + x).asPreservesText(); } } } export function preserves(pieces: TemplateStringsArray, ...values: Value[]): string { const result = [pieces[0]]; values.forEach((v, i) => { result.push(stringify(v)); result.push(pieces[i + 1]); }); return result.join(''); } declare global { interface Object { asPreservesText(): string; } } Object.defineProperty(Object.prototype, 'asPreservesText', { enumerable: false, writable: true, value: function(): string { return '#!' + JSON.stringify(this); } }); Boolean.prototype.asPreservesText = function (): string { return this ? '#t' : '#f'; }; Number.prototype.asPreservesText = function (): string { return '' + this; }; String.prototype.asPreservesText = function (): string { return JSON.stringify(this); }; Symbol.prototype.asPreservesText = function (): string { // TODO: escaping return this.description ?? '||'; };