import { embed, GenericEmbedded } from "./embedded"; import { Bytes } from "./bytes"; import { Record, Tuple } from "./record"; import { Value } from "./values"; import { Dictionary, Set } from "./dictionary"; export function fromJS(x: any): Value { switch (typeof x) { case 'number': if (!Number.isInteger(x)) { // We require that clients be explicit about integer vs. non-integer types. throw new TypeError("Refusing to autoconvert non-integer number to Single or Double"); } // FALL THROUGH case 'bigint': case 'string': case 'symbol': case 'boolean': return x; case 'undefined': case 'function': break; case 'object': if (x === null) { break; } if (typeof x.__as_preserve__ === 'function') { return x.__as_preserve__(); } if (Record.isRecord, Tuple>, T>(x)) { return x; } if (Array.isArray(x)) { return x.map>(fromJS); } if (ArrayBuffer.isView(x) || x instanceof ArrayBuffer) { return Bytes.from(x); } if (Map.isMap(x)) { const d = new Dictionary(); x.forEach((v, k) => d.set(fromJS(k), fromJS(v))); return d; } if (Set.isSet(x)) { const s = new Set(); x.forEach(v => s.add(fromJS(v))); return s; } // Just... assume it's a T. return embed(x as T); default: break; } throw new TypeError("Cannot represent JavaScript value as Preserves: " + x); } declare module "./dictionary" { namespace Dictionary { export function fromJS(x: object): Dictionary>; } } Dictionary.fromJS = function (x: object): Dictionary> { if (Dictionary.isDictionary>(x)) return x; const d = new Dictionary>(); Object.entries(x).forEach(([key, value]) => d.set(key, fromJS(value))); return d; };