Skip to content

Instantly share code, notes, and snippets.

@choegyumin
Last active September 19, 2018 12:58
Show Gist options
  • Save choegyumin/1f3855c56bf1aca5e1ff1a9c21b4f72f to your computer and use it in GitHub Desktop.
Save choegyumin/1f3855c56bf1aca5e1ff1a9c21b4f72f to your computer and use it in GitHub Desktop.
CodeSpitz 3기 3회차 과제
const elementProperties = (input) => {
input = input.trim();
const hasAttrs = input.indexOf(' ') + 1;
if (!hasAttrs) return {name: input, attributes: {}};
const inputAttrs = input.substring(hasAttrs, input.length).trim();
const length = inputAttrs.length;
const attrs = {};
let i = 0;
while (i < length) {
const start = i;
const equalIdx = inputAttrs.indexOf('=', start + 1);
const spaceIdx = inputAttrs.indexOf(' ', start + 1);
const isBoolAttr = equalIdx === -1 || (spaceIdx !== -1 && equalIdx > spaceIdx);
let end, attrName, attrValue;
// @todo HTML Boolean attributes 스펙에 맞게 조건문 개선
if (isBoolAttr) {
end = spaceIdx !== -1 ? spaceIdx : length;
attrName = inputAttrs.substring(start, end).trim();
attrValue = true;
} else {
const firstChar = inputAttrs.charAt(equalIdx + 1);
const isBeginQuote = firstChar === '"' || firstChar === "'";
end = (isBeginQuote ? inputAttrs.indexOf(firstChar, equalIdx + 2) : spaceIdx) + 1;
attrName = inputAttrs.substring(start, equalIdx).trim();
attrValue = inputAttrs.substring(equalIdx + (isBeginQuote ? 2 : 1), end - 1).trim();
}
if (attrName) attrs[attrName] = attrValue;
i = end;
}
return {name: input.substring(0, hasAttrs - 1), attributes: attrs};
};
const elementNode = (input, curr, start, end) => {
const isSingleTag = input[end - 2] === '/';
const tag = {
type: 'node',
...elementProperties(input.substring(start + 1, end - (isSingleTag ? 2 : 1))),
children: [],
};
curr.tag.children.push(tag);
return isSingleTag ? curr : {tag, back: curr};
};
const textNode = (input, curr, start, end) => {
curr.tag.children.push({
type: 'text',
text: input.substring(start, end),
});
return curr;
};
const htmlParser = (input) => {
input = input.trim();
const result = {type: 'node', name: 'ROOT', children: []};
const length = input.length;
let i = 0, curr = {tag: result};
while (i < length) {
const start = i;
const isTag = input[start] === '<';
const end = input.indexOf(isTag ? '>' : '<', start) + (isTag ? 1 : 0);
curr = isTag
? input[start + 1] === '/'
? curr.back
: elementNode(input, curr, start, end)
: textNode(input, curr, start, end);
i = end;
}
return result;
};
const result = htmlParser(`<div>
foo
<p>Lorem Ipsum</p>
<a href="#" style="color: red;">Link</a>
bar
<hr />
<img src="sample.jpg" alt="This is sample image." />
foobar
<button type="button">Click</button>
<div class="block block--modifier">
<input type="text" readonly disabled />
<input type="checkbox" />
<input type="checkbox" checked />
<input disabled type="checkbox" />
</div>
</div>`);
console.log(result);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment