// A hack to make a list of strings on type level. // If you add another type to be parsable i.e. implement a parser for it, also add its name here const primitives = ["string", "MathMLElement", "HTMLElement", "SVGElement"] as const type Primitive = string | MathMLElement | HTMLElement | SVGElement type Parsable_Primitive = { parseAs: typeof primitives[number], content: string }; function is_primitive(a: any): a is Parsable_Primitive { return "parseAs" in a && primitives.includes(a.parseAs) && "content" in a && typeof a.content === "string" } // type Typed_JSONObject = { [data: string]: Primitive | Backend_Object } // declare var Generic_BackendObject: { // label: MathMLElement // uri: string // type: string // [data: string]: any // prototype: Backend_Object; // }; type Parsable_BO = { [key: string]: Parsable_Primitive | Parsable_BO | [Parsable_BO] }; const parser = new DOMParser; // A shorthand we will need several times function parse (s: string): Primitive { const doc = parser.parseFromString(s, "text/html") const errorNode = doc.querySelector("parsererror"); if (errorNode) { console.error(errorNode) throw{} } else { return doc.body.firstChild as Primitive } } /** * * @param json_object * @returns * @throws TypeError if {@link json_object} doesn't adhere to the JSON schema */ function backendObject_fromJSON(json_object: Parsable_BO): Backend_Object { // the Backend_Object to be let bo: {[data:string]: any} = {} // If the input is sensible this works, otherwise we have to throw a TypeError anyway for (let i in json_object) { const member = json_object[i] //console.log(member) if (is_primitive(member)) { switch (member.parseAs) { case "string": bo[i] = member.content break; // all other cases are identical () case "MathMLElement": case "HTMLElement": case "SVGElement": //console.log(i, parse(member.content), bo) bo[i] = parse(member.content) break; } } else { if (Array.isArray(member)) { bo[i] = [] member.forEach((value, index) => { bo[i][index] = backendObject_fromJSON(value) }) } else { bo[i] = backendObject_fromJSON(member) } } } if (!("label" in bo)) { console.error(`Attribute 'label' is missing. Cannot finish parsing`, json_object, bo) throw new TypeError } if (!("uri" in bo && typeof bo.uri === "string")) { console.error(`Attribute 'uri': ${bo.uri} is missing or not a string. Cannot finish parsing`, json_object, bo) throw new TypeError } if (!("type" in bo && typeof bo.type === "string")) { console.error(`Attribute 'type': ${bo.type} is missing or not a string. Cannot finish parsing`, json_object, bo) throw new TypeError } // for some reason ts does not believe the conditions above return bo as unknown as Backend_Object }