Skip to content

Instantly share code, notes, and snippets.

@DevStarSJ
Last active January 24, 2018 00:43
Show Gist options
  • Save DevStarSJ/683b3c1a0b8b7501c784f94930430d33 to your computer and use it in GitHub Desktop.
Save DevStarSJ/683b3c1a0b8b7501c784f94930430d33 to your computer and use it in GitHub Desktop.
'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