61 lines
1.9 KiB
TypeScript
61 lines
1.9 KiB
TypeScript
import { embed, DefaultPointer } from "./pointer";
|
|
import { Bytes } from "./bytes";
|
|
import { Record, Tuple } from "./record";
|
|
import { AsPreserve } from "./symbols";
|
|
import { Value } from "./values";
|
|
import { Dictionary, Set } from "./dictionary";
|
|
|
|
export function fromJS<T = DefaultPointer>(x: any): Value<T> {
|
|
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 'string':
|
|
case 'symbol':
|
|
case 'boolean':
|
|
return x;
|
|
|
|
case 'undefined':
|
|
case 'function':
|
|
case 'bigint':
|
|
break;
|
|
|
|
case 'object':
|
|
if (x === null) {
|
|
break;
|
|
}
|
|
if (typeof x[AsPreserve] === 'function') {
|
|
return x[AsPreserve]();
|
|
}
|
|
if (Record.isRecord<Value<T>, Tuple<Value<T>>, T>(x)) {
|
|
return x;
|
|
}
|
|
if (Array.isArray(x)) {
|
|
return x.map<Value<T>>(fromJS);
|
|
}
|
|
if (ArrayBuffer.isView(x) || x instanceof ArrayBuffer) {
|
|
return Bytes.from(x);
|
|
}
|
|
if (Map.isMap(x)) {
|
|
const d = new Dictionary<T>();
|
|
x.forEach((v, k) => d.set(fromJS(k), fromJS(v)));
|
|
return d;
|
|
}
|
|
if (Set.isSet(x)) {
|
|
const s = new Set<T>();
|
|
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);
|
|
}
|