Last active
September 19, 2018 12:58
-
-
Save choegyumin/1f3855c56bf1aca5e1ff1a9c21b4f72f to your computer and use it in GitHub Desktop.
CodeSpitz 3기 3회차 과제
This file contains 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
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