const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`;
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
const startTagOpen = new RegExp(`^<${qnameCapture}`);
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`);
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
const startTagClose = /^\s*(\/?)>/;
const defaultTagRE = /\{\{((?:.\r?\n)+?)\}\}/g
function parseHTML(html) {
html = html.trimEnd()
html = html.trimStart()
const ELEMENT_TYPE = 1;
const TEXT_TYPE = 3;
const stack = [];
let currentParent;
let root;
function createAstElement(tag,attrs){
return {
tag:tag,
attrs,
type:ELEMENT_TYPE,
children:[],
parent:null,
}
}
function start(tag,attrs){
let node = createAstElement(tag,attrs)
if (!root) {
root = node
}
if (currentParent) {
node.parent = currentParent
currentParent.children.push(node)
}
stack.push(node)
currentParent = node
}
function chars(text){
text = text.replace(/\s/g,'')
text && currentParent.children.push({
type:TEXT_TYPE,
text,
parent:currentParent
});
}
function end(){
let node = stack.pop();
currentParent = stack[stack.length - 1]
}
function advance(n) {
html = html.substring(n)
}
function parseStartTag() {
const start = html.match(startTagOpen)
if (start) {
const match = {
tagName: start[1],
attrs: []
}
advance(start[0].length);
let attr, end;
while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
advance(attr[0].length)
match.attrs.push({ name: attr[1], value: attr[3] || attr[4] || attr[5] || true })
}
if (end) {
advance(end[0].length)
}
return match
}
return false
}
while (html) {
let textEnd = html.indexOf('<');
if (textEnd == 0) {
let startTagMatch = parseStartTag()
if (startTagMatch) {
start(startTagMatch.tagName,startTagMatch.attrs)
continue
}
let endTagMatch = html.match(endTag)
if (endTagMatch) {
end(startTagMatch.tagName)
advance(endTagMatch[0].length)
continue;
}
}
if (textEnd > 0) {
let text = html.substring(0,textEnd);
if (text) {
chars(text)
advance(text.length)
}
}
}
return root
}
function compilerToFunction(elementTemp) {
let ast = parseHTML(elementTemp)
return ast
};
const temp = `<div class="name"> {{xxx}} <li style="color:red">{{red}}</li> <input type="text" /> <span style="color:red">{{red}}</span> </div> `
compilerToFunction(temp)