/src/canopy/companion/crx/fable-core/umd/Serialize.js
JavaScript | 338 lines | 338 code | 0 blank | 0 comment | 123 complexity | 065598c3fb154e756295ba4bcbc61fef MD5 | raw file
Possible License(s): MIT, Apache-2.0
- import FableSymbol from "./Symbol";
- import { getType } from "./Symbol";
- import List from "./List";
- import { ofArray as listOfArray } from "./List";
- import FableSet from "./Set";
- import FableMap from "./Map";
- import { create as mapCreate } from "./Map";
- import { create as setCreate } from "./Set";
- import { hasInterface } from "./Util";
- import { getDefinition } from "./Util";
- import { NonDeclaredType } from "./Util";
- import { fold } from "./Seq";
- import { resolveGeneric, getTypeFullName } from "./Reflection";
- import { parse as dateParse } from "./Date";
- import { fsFormat } from "./String";
- export function toJson(o) {
- return JSON.stringify(o, function (k, v) {
- if (ArrayBuffer.isView(v)) {
- return Array.from(v);
- }
- else if (v != null && typeof v === "object") {
- var properties = typeof v[FableSymbol.reflection] === "function" ? v[FableSymbol.reflection]().properties : null;
- if (v instanceof List || v instanceof FableSet || v instanceof Set) {
- return Array.from(v);
- }
- else if (v instanceof FableMap || v instanceof Map) {
- var stringKeys_1 = null;
- return fold(function (o, kv) {
- if (stringKeys_1 === null) {
- stringKeys_1 = typeof kv[0] === "string";
- }
- o[stringKeys_1 ? kv[0] : toJson(kv[0])] = kv[1];
- return o;
- }, {}, v);
- }
- else if (!hasInterface(v, "FSharpRecord") && properties) {
- return fold(function (o, prop) {
- return o[prop] = v[prop], o;
- }, {}, Object.getOwnPropertyNames(properties));
- }
- else if (hasInterface(v, "FSharpUnion")) {
- if (!v.Fields || !v.Fields.length) {
- return v.Case;
- }
- else if (v.Fields.length === 1) {
- var fieldValue = typeof v.Fields[0] === 'undefined' ? null : v.Fields[0];
- return _a = {}, _a[v.Case] = fieldValue, _a;
- }
- else {
- return _b = {}, _b[v.Case] = v.Fields, _b;
- }
- }
- }
- return v;
- var _a, _b;
- });
- }
- function combine(path1, path2) {
- return typeof path2 === "number"
- ? path1 + "[" + path2 + "]"
- : (path1 ? path1 + "." : "") + path2;
- }
- function isNullable(typ) {
- if (typeof typ === "string") {
- return typ !== "boolean" && typ !== "number";
- }
- else if (typ instanceof NonDeclaredType) {
- return typ.kind !== "Array" && typ.kind !== "Tuple";
- }
- else {
- var info = typeof typ.prototype[FableSymbol.reflection] === "function"
- ? typ.prototype[FableSymbol.reflection]() : null;
- return info ? info.nullable : true;
- }
- }
- function invalidate(val, typ, path) {
- throw new Error(fsFormat("%A", val) + " " + (path ? "(" + path + ")" : "") + " is not of type " + getTypeFullName(typ));
- }
- function needsInflate(enclosing) {
- var typ = enclosing.head;
- if (typeof typ === "string") {
- return false;
- }
- if (typ instanceof NonDeclaredType) {
- switch (typ.kind) {
- case "Option":
- case "Array":
- return typ.definition != null || needsInflate(new List(typ.generics, enclosing));
- case "Tuple":
- return typ.generics.some(function (x) {
- return needsInflate(new List(x, enclosing));
- });
- case "GenericParam":
- return needsInflate(resolveGeneric(typ.definition, enclosing.tail));
- case "GenericType":
- return true;
- default:
- return false;
- }
- }
- return true;
- }
- function inflateArray(arr, enclosing, path) {
- if (!Array.isArray) {
- invalidate(arr, "array", path);
- }
- return needsInflate(enclosing)
- ? arr.map(function (x, i) { return inflate(x, enclosing, combine(path, i)); })
- : arr;
- }
- function inflateMap(obj, keyEnclosing, valEnclosing, path) {
- var inflateKey = keyEnclosing.head !== "string";
- var inflateVal = needsInflate(valEnclosing);
- return Object
- .getOwnPropertyNames(obj)
- .map(function (k) {
- var key = inflateKey ? inflate(JSON.parse(k), keyEnclosing, combine(path, k)) : k;
- var val = inflateVal ? inflate(obj[k], valEnclosing, combine(path, k)) : obj[k];
- return [key, val];
- });
- }
- function inflateList(val, enclosing, path) {
- var ar = [], li = new List(), cur = val, inf = needsInflate(enclosing);
- while (cur.tail != null) {
- ar.push(inf ? inflate(cur.head, enclosing, path) : cur.head);
- cur = cur.tail;
- }
- ar.reverse();
- for (var i = 0; i < ar.length; i++) {
- li = new List(ar[i], li);
- }
- return li;
- }
- function inflate(val, typ, path) {
- var enclosing = null;
- if (typ instanceof List) {
- enclosing = typ;
- typ = typ.head;
- }
- else {
- enclosing = new List(typ, new List());
- }
- if (val == null) {
- if (!isNullable(typ)) {
- invalidate(val, typ, path);
- }
- return val;
- }
- else if (typeof typ === "string") {
- if ((typ === "boolean" || typ === "number" || typ === "string") && (typeof val !== typ)) {
- invalidate(val, typ, path);
- }
- return val;
- }
- else if (typ instanceof NonDeclaredType) {
- switch (typ.kind) {
- case "Unit":
- return null;
- case "Option":
- return inflate(val, new List(typ.generics, enclosing), path);
- case "Array":
- if (typ.definition != null) {
- return new typ.definition(val);
- }
- else {
- return inflateArray(val, new List(typ.generics, enclosing), path);
- }
- case "Tuple":
- return typ.generics.map(function (x, i) {
- return inflate(val[i], new List(x, enclosing), combine(path, i));
- });
- case "GenericParam":
- return inflate(val, resolveGeneric(typ.definition, enclosing.tail), path);
- case "GenericType":
- var def = typ.definition;
- if (def === List) {
- return Array.isArray(val)
- ? listOfArray(inflateArray(val, resolveGeneric(0, enclosing), path))
- : inflateList(val, resolveGeneric(0, enclosing), path);
- }
- if (def === FableSet) {
- return setCreate(inflateArray(val, resolveGeneric(0, enclosing), path));
- }
- if (def === Set) {
- return new Set(inflateArray(val, resolveGeneric(0, enclosing), path));
- }
- if (def === FableMap) {
- return mapCreate(inflateMap(val, resolveGeneric(0, enclosing), resolveGeneric(1, enclosing), path));
- }
- if (def === Map) {
- return new Map(inflateMap(val, resolveGeneric(0, enclosing), resolveGeneric(1, enclosing), path));
- }
- return inflate(val, new List(typ.definition, enclosing), path);
- default:
- return val;
- }
- }
- else if (typeof typ === "function") {
- if (typ === Date) {
- return dateParse(val);
- }
- var info = typeof typ.prototype[FableSymbol.reflection] === "function" ? typ.prototype[FableSymbol.reflection]() : {};
- if (info.cases) {
- var uCase = void 0, uFields = [];
- if (typeof val === "string") {
- uCase = val;
- }
- else if (typeof val.Case === "string" && Array.isArray(val.Fields)) {
- uCase = val.Case;
- uFields = val.Fields;
- }
- else {
- var caseName = Object.getOwnPropertyNames(val)[0];
- var fieldTypes = info.cases[caseName];
- if (Array.isArray(fieldTypes)) {
- var fields = fieldTypes.length > 1 ? val[caseName] : [val[caseName]];
- uCase = caseName;
- path = combine(path, caseName);
- for (var i = 0; i < fieldTypes.length; i++) {
- uFields.push(inflate(fields[i], new List(fieldTypes[i], enclosing), combine(path, i)));
- }
- }
- }
- if (uCase in info.cases === false) {
- invalidate(val, typ, path);
- }
- return new typ(uCase, uFields);
- }
- if (info.properties) {
- var newObj = new typ();
- var properties = info.properties;
- var ks = Object.getOwnPropertyNames(properties);
- for (var i = 0; i < ks.length; i++) {
- var k = ks[i];
- newObj[k] = inflate(val[k], new List(properties[k], enclosing), combine(path, k));
- }
- return newObj;
- }
- return val;
- }
- throw new Error("Unexpected type when deserializing JSON: " + typ);
- }
- function inflatePublic(val, genArgs) {
- return inflate(val, genArgs ? genArgs.T : null, "");
- }
- export { inflatePublic as inflate };
- export function ofJson(json, genArgs) {
- return inflate(JSON.parse(json), genArgs ? genArgs.T : null, "");
- }
- export function toJsonWithTypeInfo(o) {
- return JSON.stringify(o, function (k, v) {
- if (ArrayBuffer.isView(v)) {
- return Array.from(v);
- }
- else if (v != null && typeof v === "object") {
- var typeName = typeof v[FableSymbol.reflection] === "function" ? v[FableSymbol.reflection]().type : null;
- if (v instanceof List || v instanceof FableSet || v instanceof Set) {
- return {
- $type: typeName || "System.Collections.Generic.HashSet",
- $values: Array.from(v)
- };
- }
- else if (v instanceof FableMap || v instanceof Map) {
- return fold(function (o, kv) { o[kv[0]] = kv[1]; return o; }, { $type: typeName || "System.Collections.Generic.Dictionary" }, v);
- }
- else if (typeName) {
- if (hasInterface(v, "FSharpUnion") || hasInterface(v, "FSharpRecord")) {
- return Object.assign({ $type: typeName }, v);
- }
- else {
- var proto = Object.getPrototypeOf(v), props = Object.getOwnPropertyNames(proto), o_1 = { $type: typeName };
- for (var i = 0; i < props.length; i++) {
- var prop = Object.getOwnPropertyDescriptor(proto, props[i]);
- if (prop.get)
- o_1[props[i]] = prop.get.apply(v);
- }
- return o_1;
- }
- }
- }
- return v;
- });
- }
- export function ofJsonWithTypeInfo(json, genArgs) {
- var parsed = JSON.parse(json, function (k, v) {
- if (v == null)
- return v;
- else if (typeof v === "object" && typeof v.$type === "string") {
- var type = v.$type.replace('+', '.'), i = type.indexOf('`');
- if (i > -1) {
- type = type.substr(0, i);
- }
- else {
- i = type.indexOf(',');
- type = i > -1 ? type.substr(0, i) : type;
- }
- if (type === "System.Collections.Generic.List" || (type.indexOf("[]") === type.length - 2)) {
- return v.$values;
- }
- if (type === "Microsoft.FSharp.Collections.FSharpList") {
- return listOfArray(v.$values);
- }
- else if (type == "Microsoft.FSharp.Collections.FSharpSet") {
- return setCreate(v.$values);
- }
- else if (type == "System.Collections.Generic.HashSet") {
- return new Set(v.$values);
- }
- else if (type == "Microsoft.FSharp.Collections.FSharpMap") {
- delete v.$type;
- return mapCreate(Object.getOwnPropertyNames(v)
- .map(function (k) { return [k, v[k]]; }));
- }
- else if (type == "System.Collections.Generic.Dictionary") {
- delete v.$type;
- return new Map(Object.getOwnPropertyNames(v)
- .map(function (k) { return [k, v[k]]; }));
- }
- else {
- var T = getType(type);
- if (T) {
- delete v.$type;
- return Object.assign(new T(), v);
- }
- }
- }
- else if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:\d{2}|Z)$/.test(v))
- return dateParse(v);
- else
- return v;
- });
- var expected = genArgs ? genArgs.T : null;
- if (parsed != null && typeof expected === "function"
- && !(parsed instanceof getDefinition(expected))) {
- throw new Error("JSON is not of type " + expected.name + ": " + json);
- }
- return parsed;
- }