Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | 1x 1x 1x 39x 39x 39x 39x 39x 39x 81x 39x 748x 39x 81x 70x 70x 70x 11x 11x 39x 89x 89x 70x 46x 39x 266x 230x 228x 31x 31x 31x 197x 197x 39x 95x 61x 53x 8x 8x 8x 45x 45x 39x 242x 222x 4x 4x 218x 177x 177x 39x 48x 41x 41x 28x 16x 1x 1x 1x 1x 15x 39x 73x 13x 13x 60x 60x 39x 68x 12x 12x 56x 56x 39x 72x 8x 8x 64x 4x 4x 60x 3x 3x 3x 3x 57x 57x 39x 25x 21x 4x 4x 4x 17x 39x 23x 22x 22x 22x 22x 1x 39x 25x 24x 1x 1x 1x 23x 23x 39x 961x 39x | const { Writable } = require("node:stream") const Token = require('./Token.class') module.exports = class HtmlParser extends Writable { constructor() { super() let currentToken = null let currentAttribueName = '' let currentAttribueValue = '' let currentTagName = '' const emit = token => { this.emit('data', token.getLog()) } const isWhiteSpace = char => { return char === ' ' || char === '\t' || char === '\n' } const dataState = char => { // if (char === '&') return dataState if (char === '<') { currentToken = new Token() currentToken.setType('openTag') return tagOpen } emit(new Token('char', char)) return dataState } const tagOpen = char => { currentTagName = '' if (char === ' ') return tagOpen if (char === '/') return tagEnd return tagName(char) // reconsume } const tagName = char => { if (isWhiteSpace(char)) return beforeAttribute if (char === '/') return selfClosingStartTag if (char === '>') { currentToken.setContent(currentTagName) emit(currentToken) return dataState } currentTagName += char return tagName } const beforeAttribute = char => { if (isWhiteSpace(char)) return beforeAttribute if (char === '/') return selfClosingStartTag if (char === '>') { currentToken.setContent(currentTagName) emit(currentToken) return dataState } currentAttribueName = '' return attributeName(char) } const attributeName = char => { if (isWhiteSpace(char)) return attributeName if (char === '/') { currentToken.setAttribute(currentAttribueName, currentAttribueName) return selfClosingStartTag } if (char === '=') return beforeAttributeValue currentAttribueName += char return attributeName } const beforeAttributeValue = char => { if (isWhiteSpace(char)) return beforeAttributeValue currentAttribueValue = '' if (char === '"') return attributeValueDouble if (char === `'`) return attributeValueSingle if (char === '>') { currentToken.setAttribute(currentAttribueName, currentAttribueValue) currentToken.setContent(currentTagName) emit(currentToken) return dataState } return attributeValueUnquoted(char) } const attributeValueDouble = char => { if (char === '"') { currentToken.setAttribute(currentAttribueName, currentAttribueValue) return afterAttributeValueQuoted } // if (char === '&') return attributeValueDouble currentAttribueValue += char return attributeValueDouble } const attributeValueSingle = char => { if (char === `'`) { currentToken.setAttribute(currentAttribueName, currentAttribueValue) return afterAttributeValueQuoted } // if (char === '&') return attributeValueSingle currentAttribueValue += char return attributeValueSingle } const attributeValueUnquoted = char => { if (isWhiteSpace(char)) { currentToken.setAttribute(currentAttribueName, currentAttribueValue) return beforeAttribute } if (char === '/') { currentToken.setAttribute(currentAttribueName, currentAttribueValue) return selfClosingStartTag } // if (char === '&') return attributeValueUnquoted if (char === '>') { currentToken.setAttribute(currentAttribueName, currentAttribueValue) currentToken.setContent(currentTagName) emit(currentToken) return dataState } currentAttribueValue += char return attributeValueUnquoted } const afterAttributeValueQuoted = char => { if (char === '/') return selfClosingStartTag if (char === '>') { currentToken.setContent(currentTagName) emit(currentToken) return dataState } return beforeAttribute(char) } const selfClosingStartTag = char => { if (char === '>') { currentToken.setType('selfClosingTag') currentToken.setContent(currentTagName) emit(currentToken) return dataState } return selfClosingStartTag } const tagEnd = char => { if (isWhiteSpace(char)) return tagEnd if (char === '>') { currentToken = new Token('closeTag') emit(currentToken) return dataState } currentToken.setType('closeTag') return tagName(char) } this.state = dataState } write(char) { this.state = this.state(char) } end() { this.emit('end') } } |