import _ = require("lodash"); import cheerio = require("cheerio"); export type nodeTypes = "tag" | "style" | "comment" | "text" | "virtual" ; export type astNode = tagNode | styleNode | commentNode | textNode | virtualNode; interface tagNode { type: "tag"; tagName: string; attribs: any; children: astNode[]; } interface textNode { type: "text"; text: string; } interface styleNode { type: "style"; style: string; } interface commentNode { type: "comment"; comment: string; } interface virtualNode { type: "virtual"; attribs: any; children: astNode[]; } function fromCheerio(rootNode: CheerioStatic): astNode { let rootTags = _.filter(rootNode.root()[0].children, node => true); // put under a file-based root node let astRoot: virtualNode = { type: "virtual", attribs: {}, children: [] }; // collect all first level nodes _.forEach(rootTags, (e)=>astRoot.children.push(visit(e))); return astRoot; } function visit(x: CheerioElement): astNode { let node: astNode; if(x.type === "tag") { node = { type: "tag", tagName: x.name, attribs: x.attribs || {}, children: [] }; _.forEach(x.children, (e)=>(node as tagNode).children.push(visit(e))); } else if(x.type === "style") { node = { type: "style", style: x["data"] }; } else if(x.type === "comment") { node = { type: "comment", comment: x["data"] }; } else if(x.type === "text") { node = { type: "text", text: x["data"] }; } else throw `unknown node type '${x.type}'`; return node; } function renderTsx(node: astNode): string { if(node.type === "tag") return renderTag(node); else if(node.type === "style") return renderStyle(node); else if(node.type === "comment") return renderComment(node); else if(node.type === "text") return renderText(node); else if(node.type === "virtual") return renderVirtual(node); else throw `unknown node type '${(node as astNode).type}'`; } function renderTag(node: tagNode): string { let c = node.children.map(n=>renderTsx(n)).join(""); let a = `<${node.tagName}>${c}`; return a; } function renderStyle(node: styleNode): string { throw "not yet implemented"; } function renderComment(node: commentNode): string { // TODO sanitize comments return `/* ${node.comment} */`; } function renderText(node: textNode): string { return node.text; } function renderVirtual(node: virtualNode): string { let c = node.children.map(n=>renderTsx(n)).join(""); let a = `${c}`; return a; } export function parseHtmlToTsx(rootNode: CheerioStatic): string { let ast = fromCheerio(rootNode); let tsx = renderTsx(ast); return tsx; }