Last active
January 24, 2018 00:43
-
-
Save DevStarSJ/683b3c1a0b8b7501c784f94930430d33 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const textNode = (text, target) => { | |
if (text.length) { | |
target.push({type: 'TEXT', text}) | |
} | |
return ''; | |
}; | |
const parseAttribute = name => { | |
const attribute = []; | |
if (name.includes(' ')) { | |
const texts = name.split(' '); | |
name = texts[0]; | |
texts.slice(1) | |
.map(text => text.trim()) | |
.forEach(text => { | |
if (text.includes('=')) { // is assign statement | |
const attrTokens = text.split('='); | |
let [key, value] = attrTokens; | |
if (value[0] === value[value.length -1] && value[0] === '"' || value[0] === "'") // is valid quota | |
value = value.substring(1, value.length - 2); | |
const obj = {}; | |
obj[key] = value; | |
attribute.push(obj); | |
} else attribute.push(text); | |
}); | |
} | |
return [ name, attribute ]; | |
}; | |
const tagStart = (input, cursor, stack, stacks) => { | |
let isBreak = false; | |
let [name, attribute] = parseAttribute(input.substring(cursor - 1, cursor = input.indexOf('>', cursor))); | |
const isClose = input[cursor - 1] === '/'; | |
if (isClose) name = name.substr(0, name.length - 1); | |
const tag = {name, type: 'NODE', attribute, children: isClose ? null : []}; | |
cursor++; | |
stack.tag.children.push(tag); | |
if (!isClose) { | |
stacks.push({tag, back: stack}); | |
isBreak = true; | |
} | |
return {cursor, isBreak}; | |
}; | |
const elementNode = (input, cursor, text, stack, stacks) => { | |
const char = input[cursor++]; | |
let isBreak = false; | |
if (char === '<') { | |
text = textNode(text, stack.tag.children); | |
if (input[cursor++] !== '/') { | |
({cursor, isBreak} = tagStart(input, cursor, stack, stacks)); | |
} else if (stack.tag.name == input.substring(cursor, cursor = input.indexOf('>', cursor))) { | |
stack = stack.back; | |
cursor++; | |
} | |
} else text += char; | |
return {cursor, text, stack, isBreak}; | |
} | |
const parser = input => { | |
const result = {tag: {type:'ROOT', children: []}}, stacks = []; | |
let cursor = 0, stack = result; | |
do { | |
let text = ''; | |
while (cursor < input.length) { | |
const v = elementNode(input, cursor, text, stack, stacks); | |
({cursor, text, stack} = v); | |
if (v.isBreak) break; | |
} | |
} while (stack = stacks.pop()); | |
return result; | |
}; | |
const htmls = [ | |
'<div>test</div>', | |
'<div>test<img/></div>', | |
'<div>test<a>aa</a>bb</div>', | |
'<div checked color="#FFFFFF">test<a>aa</a>bb</div>' | |
]; | |
const prettyJSON = (obj) => JSON.stringify(obj, null, 4); | |
const simpleLog = (v,i,a) => console.log(v); | |
htmls.map(parser) | |
.map(prettyJSON) | |
.forEach(simpleLog); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment