import { htmlDecodeTree, xmlDecodeTree, BinTrieFlags, determineBranch, replaceCodePoint, } from "entities/lib/decode.js"; var CharCodes; (function (CharCodes) { CharCodes[CharCodes["Tab"] = 9] = "Tab"; CharCodes[CharCodes["NewLine"] = 10] = "NewLine"; CharCodes[CharCodes["FormFeed"] = 12] = "FormFeed"; CharCodes[CharCodes["CarriageReturn"] = 13] = "CarriageReturn"; CharCodes[CharCodes["Space"] = 32] = "Space"; CharCodes[CharCodes["ExclamationMark"] = 33] = "ExclamationMark"; CharCodes[CharCodes["Num"] = 35] = "Num"; CharCodes[CharCodes["Amp"] = 38] = "Amp"; CharCodes[CharCodes["SingleQuote"] = 39] = "SingleQuote"; CharCodes[CharCodes["DoubleQuote"] = 34] = "DoubleQuote"; CharCodes[CharCodes["Dash"] = 45] = "Dash"; CharCodes[CharCodes["Slash"] = 47] = "Slash"; CharCodes[CharCodes["Zero"] = 48] = "Zero"; CharCodes[CharCodes["Nine"] = 57] = "Nine"; CharCodes[CharCodes["Semi"] = 59] = "Semi"; CharCodes[CharCodes["Lt"] = 60] = "Lt"; CharCodes[CharCodes["Eq"] = 61] = "Eq"; CharCodes[CharCodes["Gt"] = 62] = "Gt"; CharCodes[CharCodes["Questionmark"] = 63] = "Questionmark"; CharCodes[CharCodes["UpperA"] = 65] = "UpperA"; CharCodes[CharCodes["LowerA"] = 97] = "LowerA"; CharCodes[CharCodes["UpperF"] = 70] = "UpperF"; CharCodes[CharCodes["LowerF"] = 102] = "LowerF"; CharCodes[CharCodes["UpperZ"] = 90] = "UpperZ"; CharCodes[CharCodes["LowerZ"] = 122] = "LowerZ"; CharCodes[CharCodes["LowerX"] = 120] = "LowerX"; CharCodes[CharCodes["OpeningSquareBracket"] = 91] = "OpeningSquareBracket"; })(CharCodes || (CharCodes = {})); /** All the states the tokenizer can be in. */ var State; (function (State) { State[State["Text"] = 1] = "Text"; State[State["BeforeTagName"] = 2] = "BeforeTagName"; State[State["InTagName"] = 3] = "InTagName"; State[State["InSelfClosingTag"] = 4] = "InSelfClosingTag"; State[State["BeforeClosingTagName"] = 5] = "BeforeClosingTagName"; State[State["InClosingTagName"] = 6] = "InClosingTagName"; State[State["AfterClosingTagName"] = 7] = "AfterClosingTagName"; // Attributes State[State["BeforeAttributeName"] = 8] = "BeforeAttributeName"; State[State["InAttributeName"] = 9] = "InAttributeName"; State[State["AfterAttributeName"] = 10] = "AfterAttributeName"; State[State["BeforeAttributeValue"] = 11] = "BeforeAttributeValue"; State[State["InAttributeValueDq"] = 12] = "InAttributeValueDq"; State[State["InAttributeValueSq"] = 13] = "InAttributeValueSq"; State[State["InAttributeValueNq"] = 14] = "InAttributeValueNq"; // Declarations State[State["BeforeDeclaration"] = 15] = "BeforeDeclaration"; State[State["InDeclaration"] = 16] = "InDeclaration"; // Processing instructions State[State["InProcessingInstruction"] = 17] = "InProcessingInstruction"; // Comments & CDATA State[State["BeforeComment"] = 18] = "BeforeComment"; State[State["CDATASequence"] = 19] = "CDATASequence"; State[State["InSpecialComment"] = 20] = "InSpecialComment"; State[State["InCommentLike"] = 21] = "InCommentLike"; // Special tags State[State["BeforeSpecialS"] = 22] = "BeforeSpecialS"; State[State["SpecialStartSequence"] = 23] = "SpecialStartSequence"; State[State["InSpecialTag"] = 24] = "InSpecialTag"; State[State["BeforeEntity"] = 25] = "BeforeEntity"; State[State["BeforeNumericEntity"] = 26] = "BeforeNumericEntity"; State[State["InNamedEntity"] = 27] = "InNamedEntity"; State[State["InNumericEntity"] = 28] = "InNumericEntity"; State[State["InHexEntity"] = 29] = "InHexEntity"; })(State || (State = {})); function isWhitespace(c) { return (c === CharCodes.Space || c === CharCodes.NewLine || c === CharCodes.Tab || c === CharCodes.FormFeed || c === CharCodes.CarriageReturn); } function isEndOfTagSection(c) { return c === CharCodes.Slash || c === CharCodes.Gt || isWhitespace(c); } function isNumber(c) { return c >= CharCodes.Zero && c <= CharCodes.Nine; } function isASCIIAlpha(c) { return ((c >= CharCodes.LowerA && c <= CharCodes.LowerZ) || (c >= CharCodes.UpperA && c <= CharCodes.UpperZ)); } function isHexDigit(c) { return ((c >= CharCodes.UpperA && c <= CharCodes.UpperF) || (c >= CharCodes.LowerA && c <= CharCodes.LowerF)); } export var QuoteType; (function (QuoteType) { QuoteType[QuoteType["NoValue"] = 0] = "NoValue"; QuoteType[QuoteType["Unquoted"] = 1] = "Unquoted"; QuoteType[QuoteType["Single"] = 2] = "Single"; QuoteType[QuoteType["Double"] = 3] = "Double"; })(QuoteType || (QuoteType = {})); /** * Sequences used to match longer strings. * * We don't have `Script`, `Style`, or `Title` here. Instead, we re-use the *End * sequences with an increased offset. */ const Sequences = { Cdata: new Uint8Array([0x43, 0x44, 0x41, 0x54, 0x41, 0x5b]), CdataEnd: new Uint8Array([0x5d, 0x5d, 0x3e]), CommentEnd: new Uint8Array([0x2d, 0x2d, 0x3e]), ScriptEnd: new Uint8Array([0x3c, 0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74]), StyleEnd: new Uint8Array([0x3c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65]), TitleEnd: new Uint8Array([0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65]), // ` this.sectionStart) { this.cbs.ontext(this.sectionStart, this.index); } this.state = State.BeforeTagName; this.sectionStart = this.index; } else if (this.decodeEntities && c === CharCodes.Amp) { this.state = State.BeforeEntity; } } stateSpecialStartSequence(c) { const isEnd = this.sequenceIndex === this.currentSequence.length; const isMatch = isEnd ? // If we are at the end of the sequence, make sure the tag name has ended isEndOfTagSection(c) : // Otherwise, do a case-insensitive comparison (c | 0x20) === this.currentSequence[this.sequenceIndex]; if (!isMatch) { this.isSpecial = false; } else if (!isEnd) { this.sequenceIndex++; return; } this.sequenceIndex = 0; this.state = State.InTagName; this.stateInTagName(c); } /** Look for an end tag. For tags, also decode entities. */ stateInSpecialTag(c) { if (this.sequenceIndex === this.currentSequence.length) { if (c === CharCodes.Gt || isWhitespace(c)) { const endOfText = this.index - this.currentSequence.length; if (this.sectionStart < endOfText) { // Spoof the index so that reported locations match up. const actualIndex = this.index; this.index = endOfText; this.cbs.ontext(this.sectionStart, endOfText); this.index = actualIndex; } this.isSpecial = false; this.sectionStart = endOfText + 2; // Skip over the `</` this.stateInClosingTagName(c); return; // We are done; skip the rest of the function. } this.sequenceIndex = 0; } if ((c | 0x20) === this.currentSequence[this.sequenceIndex]) { this.sequenceIndex += 1; } else if (this.sequenceIndex === 0) { if (this.currentSequence === Sequences.TitleEnd) { // We have to parse entities in <title> tags. if (this.decodeEntities && c === CharCodes.Amp) { this.state = State.BeforeEntity; } } else if (this.fastForwardTo(CharCodes.Lt)) { // Outside of <title> tags, we can fast-forward. this.sequenceIndex = 1; } } else { // If we see a `<`, set the sequence index to 1; useful for eg. `<</script>`. this.sequenceIndex = Number(c === CharCodes.Lt); } } stateCDATASequence(c) { if (c === Sequences.Cdata[this.sequenceIndex]) { if (++this.sequenceIndex === Sequences.Cdata.length) { this.state = State.InCommentLike; this.currentSequence = Sequences.CdataEnd; this.sequenceIndex = 0; this.sectionStart = this.index + 1; } } else { this.sequenceIndex = 0; this.state = State.InDeclaration; this.stateInDeclaration(c); // Reconsume the character } } /** * When we wait for one specific character, we can speed things up * by skipping through the buffer until we find it. * * @returns Whether the character was found. */ fastForwardTo(c) { while (++this.index < this.buffer.length + this.offset) { if (this.buffer.charCodeAt(this.index - this.offset) === c) { return true; } } /* * We increment the index at the end of the `parse` loop, * so set it to `buffer.length - 1` here. * * TODO: Refactor `parse` to increment index before calling states. */ this.index = this.buffer.length + this.offset - 1; return false; } /** * Comments and CDATA end with `-->` and `]]>`. * * Their common qualities are: * - Their end sequences have a distinct character they start with. * - That character is then repeated, so we have to check multiple repeats. * - All characters but the start character of the sequence can be skipped. */ stateInCommentLike(c) { if (c === this.currentSequence[this.sequenceIndex]) { if (++this.sequenceIndex === this.currentSequence.length) { if (this.currentSequence === Sequences.CdataEnd) { this.cbs.oncdata(this.sectionStart, this.index, 2); } else { this.cbs.oncomment(this.sectionStart, this.index, 2); } this.sequenceIndex = 0; this.sectionStart = this.index + 1; this.state = State.Text; } } else if (this.sequenceIndex === 0) { // Fast-forward to the first character of the sequence if (this.fastForwardTo(this.currentSequence[0])) { this.sequenceIndex = 1; } } else if (c !== this.currentSequence[this.sequenceIndex - 1]) { // Allow long sequences, eg. --->, ]]]> this.sequenceIndex = 0; } } /** * HTML only allows ASCII alpha characters (a-z and A-Z) at the beginning of a tag name. * * XML allows a lot more characters here (@see https://www.w3.org/TR/REC-xml/#NT-NameStartChar). * We allow anything that wouldn't end the tag. */ isTagStartChar(c) { return this.xmlMode ? !isEndOfTagSection(c) : isASCIIAlpha(c); } startSpecial(sequence, offset) { this.isSpecial = true; this.currentSequence = sequence; this.sequenceIndex = offset; this.state = State.SpecialStartSequence; } stateBeforeTagName(c) { if (c === CharCodes.ExclamationMark) { this.state = State.BeforeDeclaration; this.sectionStart = this.index + 1; } else if (c === CharCodes.Questionmark) { this.state = State.InProcessingInstruction; this.sectionStart = this.index + 1; } else if (this.isTagStartChar(c)) { const lower = c | 0x20; this.sectionStart = this.index; if (!this.xmlMode && lower === Sequences.TitleEnd[2]) { this.startSpecial(Sequences.TitleEnd, 3); } else { this.state = !this.xmlMode && lower === Sequences.ScriptEnd[2] ? State.BeforeSpecialS : State.InTagName; } } else if (c === CharCodes.Slash) { this.state = State.BeforeClosingTagName; } else { this.state = State.Text; this.stateText(c); } } stateInTagName(c) { if (isEndOfTagSection(c)) { this.cbs.onopentagname(this.sectionStart, this.index); this.sectionStart = -1; this.state = State.BeforeAttributeName; this.stateBeforeAttributeName(c); } } stateBeforeClosingTagName(c) { if (isWhitespace(c)) { // Ignore } else if (c === CharCodes.Gt) { this.state = State.Text; } else { this.state = this.isTagStartChar(c) ? State.InClosingTagName : State.InSpecialComment; this.sectionStart = this.index; } } stateInClosingTagName(c) { if (c === CharCodes.Gt || isWhitespace(c)) { this.cbs.onclosetag(this.sectionStart, this.index); this.sectionStart = -1; this.state = State.AfterClosingTagName; this.stateAfterClosingTagName(c); } } stateAfterClosingTagName(c) { // Skip everything until ">" if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) { this.state = State.Text; this.sectionStart = this.index + 1; } } stateBeforeAttributeName(c) { if (c === CharCodes.Gt) { this.cbs.onopentagend(this.index); if (this.isSpecial) { this.state = State.InSpecialTag; this.sequenceIndex = 0; } else { this.state = State.Text; } this.baseState = this.state; this.sectionStart = this.index + 1; } else if (c === CharCodes.Slash) { this.state = State.InSelfClosingTag; } else if (!isWhitespace(c)) { this.state = State.InAttributeName; this.sectionStart = this.index; } } stateInSelfClosingTag(c) { if (c === CharCodes.Gt) { this.cbs.onselfclosingtag(this.index); this.state = State.Text; this.baseState = State.Text; this.sectionStart = this.index + 1; this.isSpecial = false; // Reset special state, in case of self-closing special tags } else if (!isWhitespace(c)) { this.state = State.BeforeAttributeName; this.stateBeforeAttributeName(c); } } stateInAttributeName(c) { if (c === CharCodes.Eq || isEndOfTagSection(c)) { this.cbs.onattribname(this.sectionStart, this.index); this.sectionStart = -1; this.state = State.AfterAttributeName; this.stateAfterAttributeName(c); } } stateAfterAttributeName(c) { if (c === CharCodes.Eq) { this.state = State.BeforeAttributeValue; } else if (c === CharCodes.Slash || c === CharCodes.Gt) { this.cbs.onattribend(QuoteType.NoValue, this.index); this.state = State.BeforeAttributeName; this.stateBeforeAttributeName(c); } else if (!isWhitespace(c)) { this.cbs.onattribend(QuoteType.NoValue, this.index); this.state = State.InAttributeName; this.sectionStart = this.index; } } stateBeforeAttributeValue(c) { if (c === CharCodes.DoubleQuote) { this.state = State.InAttributeValueDq; this.sectionStart = this.index + 1; } else if (c === CharCodes.SingleQuote) { this.state = State.InAttributeValueSq; this.sectionStart = this.index + 1; } else if (!isWhitespace(c)) { this.sectionStart = this.index; this.state = State.InAttributeValueNq; this.stateInAttributeValueNoQuotes(c); // Reconsume token } } handleInAttributeValue(c, quote) { if (c === quote || (!this.decodeEntities && this.fastForwardTo(quote))) { this.cbs.onattribdata(this.sectionStart, this.index); this.sectionStart = -1; this.cbs.onattribend(quote === CharCodes.DoubleQuote ? QuoteType.Double : QuoteType.Single, this.index); this.state = State.BeforeAttributeName; } else if (this.decodeEntities && c === CharCodes.Amp) { this.baseState = this.state; this.state = State.BeforeEntity; } } stateInAttributeValueDoubleQuotes(c) { this.handleInAttributeValue(c, CharCodes.DoubleQuote); } stateInAttributeValueSingleQuotes(c) { this.handleInAttributeValue(c, CharCodes.SingleQuote); } stateInAttributeValueNoQuotes(c) { if (isWhitespace(c) || c === CharCodes.Gt) { this.cbs.onattribdata(this.sectionStart, this.index); this.sectionStart = -1; this.cbs.onattribend(QuoteType.Unquoted, this.index); this.state = State.BeforeAttributeName; this.stateBeforeAttributeName(c); } else if (this.decodeEntities && c === CharCodes.Amp) { this.baseState = this.state; this.state = State.BeforeEntity; } } stateBeforeDeclaration(c) { if (c === CharCodes.OpeningSquareBracket) { this.state = State.CDATASequence; this.sequenceIndex = 0; } else { this.state = c === CharCodes.Dash ? State.BeforeComment : State.InDeclaration; } } stateInDeclaration(c) { if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) { this.cbs.ondeclaration(this.sectionStart, this.index); this.state = State.Text; this.sectionStart = this.index + 1; } } stateInProcessingInstruction(c) { if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) { this.cbs.onprocessinginstruction(this.sectionStart, this.index); this.state = State.Text; this.sectionStart = this.index + 1; } } stateBeforeComment(c) { if (c === CharCodes.Dash) { this.state = State.InCommentLike; this.currentSequence = Sequences.CommentEnd; // Allow short comments (eg. <!-->) this.sequenceIndex = 2; this.sectionStart = this.index + 1; } else { this.state = State.InDeclaration; } } stateInSpecialComment(c) { if (c === CharCodes.Gt || this.fastForwardTo(CharCodes.Gt)) { this.cbs.oncomment(this.sectionStart, this.index, 0); this.state = State.Text; this.sectionStart = this.index + 1; } } stateBeforeSpecialS(c) { const lower = c | 0x20; if (lower === Sequences.ScriptEnd[3]) { this.startSpecial(Sequences.ScriptEnd, 4); } else if (lower === Sequences.StyleEnd[3]) { this.startSpecial(Sequences.StyleEnd, 4); } else { this.state = State.InTagName; this.stateInTagName(c); // Consume the token again } } stateBeforeEntity(c) { // Start excess with 1 to include the '&' this.entityExcess = 1; this.entityResult = 0; if (c === CharCodes.Num) { this.state = State.BeforeNumericEntity; } else if (c === CharCodes.Amp) { // We have two `&` characters in a row. Stay in the current state. } else { this.trieIndex = 0; this.trieCurrent = this.entityTrie[0]; this.state = State.InNamedEntity; this.stateInNamedEntity(c); } } stateInNamedEntity(c) { this.entityExcess += 1; this.trieIndex = determineBranch(this.entityTrie, this.trieCurrent, this.trieIndex + 1, c); if (this.trieIndex < 0) { this.emitNamedEntity(); this.index--; return; } this.trieCurrent = this.entityTrie[this.trieIndex]; const masked = this.trieCurrent & BinTrieFlags.VALUE_LENGTH; // If the branch is a value, store it and continue if (masked) { // The mask is the number of bytes of the value, including the current byte. const valueLength = (masked >> 14) - 1; // If we have a legacy entity while parsing strictly, just skip the number of bytes if (!this.allowLegacyEntity() && c !== CharCodes.Semi) { this.trieIndex += valueLength; } else { // Add 1 as we have already incremented the excess const entityStart = this.index - this.entityExcess + 1; if (entityStart > this.sectionStart) { this.emitPartial(this.sectionStart, entityStart); } // If this is a surrogate pair, consume the next two bytes this.entityResult = this.trieIndex; this.trieIndex += valueLength; this.entityExcess = 0; this.sectionStart = this.index + 1; if (valueLength === 0) { this.emitNamedEntity(); } } } } emitNamedEntity() { this.state = this.baseState; if (this.entityResult === 0) { return; } const valueLength = (this.entityTrie[this.entityResult] & BinTrieFlags.VALUE_LENGTH) >> 14; switch (valueLength) { case 1: this.emitCodePoint(this.entityTrie[this.entityResult] & ~BinTrieFlags.VALUE_LENGTH); break; case 2: this.emitCodePoint(this.entityTrie[this.entityResult + 1]); break; case 3: { this.emitCodePoint(this.entityTrie[this.entityResult + 1]); this.emitCodePoint(this.entityTrie[this.entityResult + 2]); } } } stateBeforeNumericEntity(c) { if ((c | 0x20) === CharCodes.LowerX) { this.entityExcess++; this.state = State.InHexEntity; } else { this.state = State.InNumericEntity; this.stateInNumericEntity(c); } } emitNumericEntity(strict) { const entityStart = this.index - this.entityExcess - 1; const numberStart = entityStart + 2 + Number(this.state === State.InHexEntity); if (numberStart !== this.index) { // Emit leading data if any if (entityStart > this.sectionStart) { this.emitPartial(this.sectionStart, entityStart); } this.sectionStart = this.index + Number(strict); this.emitCodePoint(replaceCodePoint(this.entityResult)); } this.state = this.baseState; } stateInNumericEntity(c) { if (c === CharCodes.Semi) { this.emitNumericEntity(true); } else if (isNumber(c)) { this.entityResult = this.entityResult * 10 + (c - CharCodes.Zero); this.entityExcess++; } else { if (this.allowLegacyEntity()) { this.emitNumericEntity(false); } else { this.state = this.baseState; } this.index--; } } stateInHexEntity(c) { if (c === CharCodes.Semi) { this.emitNumericEntity(true); } else if (isNumber(c)) { this.entityResult = this.entityResult * 16 + (c - CharCodes.Zero); this.entityExcess++; } else if (isHexDigit(c)) { this.entityResult = this.entityResult * 16 + ((c | 0x20) - CharCodes.LowerA + 10); this.entityExcess++; } else { if (this.allowLegacyEntity()) { this.emitNumericEntity(false); } else { this.state = this.baseState; } this.index--; } } allowLegacyEntity() { return (!this.xmlMode && (this.baseState === State.Text || this.baseState === State.InSpecialTag)); } /** * Remove data that has already been consumed from the buffer. */ cleanup() { // If we are inside of text or attributes, emit what we already have. if (this.running && this.sectionStart !== this.index) { if (this.state === State.Text || (this.state === State.InSpecialTag && this.sequenceIndex === 0)) { this.cbs.ontext(this.sectionStart, this.index); this.sectionStart = this.index; } else if (this.state === State.InAttributeValueDq || this.state === State.InAttributeValueSq || this.state === State.InAttributeValueNq) { this.cbs.onattribdata(this.sectionStart, this.index); this.sectionStart = this.index; } } } shouldContinue() { return this.index < this.buffer.length + this.offset && this.running; } /** * Iterates through the buffer, calling the function corresponding to the current state. * * States that are more likely to be hit are higher up, as a performance improvement. */ parse() { while (this.shouldContinue()) { const c = this.buffer.charCodeAt(this.index - this.offset); if (this.state === State.Text) { this.stateText(c); } else if (this.state === State.SpecialStartSequence) { this.stateSpecialStartSequence(c); } else if (this.state === State.InSpecialTag) { this.stateInSpecialTag(c); } else if (this.state === State.CDATASequence) { this.stateCDATASequence(c); } else if (this.state === State.InAttributeValueDq) { this.stateInAttributeValueDoubleQuotes(c); } else if (this.state === State.InAttributeName) { this.stateInAttributeName(c); } else if (this.state === State.InCommentLike) { this.stateInCommentLike(c); } else if (this.state === State.InSpecialComment) { this.stateInSpecialComment(c); } else if (this.state === State.BeforeAttributeName) { this.stateBeforeAttributeName(c); } else if (this.state === State.InTagName) { this.stateInTagName(c); } else if (this.state === State.InClosingTagName) { this.stateInClosingTagName(c); } else if (this.state === State.BeforeTagName) { this.stateBeforeTagName(c); } else if (this.state === State.AfterAttributeName) { this.stateAfterAttributeName(c); } else if (this.state === State.InAttributeValueSq) { this.stateInAttributeValueSingleQuotes(c); } else if (this.state === State.BeforeAttributeValue) { this.stateBeforeAttributeValue(c); } else if (this.state === State.BeforeClosingTagName) { this.stateBeforeClosingTagName(c); } else if (this.state === State.AfterClosingTagName) { this.stateAfterClosingTagName(c); } else if (this.state === State.BeforeSpecialS) { this.stateBeforeSpecialS(c); } else if (this.state === State.InAttributeValueNq) { this.stateInAttributeValueNoQuotes(c); } else if (this.state === State.InSelfClosingTag) { this.stateInSelfClosingTag(c); } else if (this.state === State.InDeclaration) { this.stateInDeclaration(c); } else if (this.state === State.BeforeDeclaration) { this.stateBeforeDeclaration(c); } else if (this.state === State.BeforeComment) { this.stateBeforeComment(c); } else if (this.state === State.InProcessingInstruction) { this.stateInProcessingInstruction(c); } else if (this.state === State.InNamedEntity) { this.stateInNamedEntity(c); } else if (this.state === State.BeforeEntity) { this.stateBeforeEntity(c); } else if (this.state === State.InHexEntity) { this.stateInHexEntity(c); } else if (this.state === State.InNumericEntity) { this.stateInNumericEntity(c); } else { // `this._state === State.BeforeNumericEntity` this.stateBeforeNumericEntity(c); } this.index++; } this.cleanup(); } finish() { if (this.state === State.InNamedEntity) { this.emitNamedEntity(); } // If there is remaining data, emit it in a reasonable way if (this.sectionStart < this.index) { this.handleTrailingData(); } this.cbs.onend(); } /** Handle any trailing data. */ handleTrailingData() { const endIndex = this.buffer.length + this.offset; if (this.state === State.InCommentLike) { if (this.currentSequence === Sequences.CdataEnd) { this.cbs.oncdata(this.sectionStart, endIndex, 0); } else { this.cbs.oncomment(this.sectionStart, endIndex, 0); } } else if (this.state === State.InNumericEntity && this.allowLegacyEntity()) { this.emitNumericEntity(false); // All trailing data will have been consumed } else if (this.state === State.InHexEntity && this.allowLegacyEntity()) { this.emitNumericEntity(false); // All trailing data will have been consumed } else if (this.state === State.InTagName || this.state === State.BeforeAttributeName || this.state === State.BeforeAttributeValue || this.state === State.AfterAttributeName || this.state === State.InAttributeName || this.state === State.InAttributeValueSq || this.state === State.InAttributeValueDq || this.state === State.InAttributeValueNq || this.state === State.InClosingTagName) { /* * If we are currently in an opening or closing tag, us not calling the * respective callback signals that the tag should be ignored. */ } else { this.cbs.ontext(this.sectionStart, endIndex); } } emitPartial(start, endIndex) { if (this.baseState !== State.Text && this.baseState !== State.InSpecialTag) { this.cbs.onattribdata(start, endIndex); } else { this.cbs.ontext(start, endIndex); } } emitCodePoint(cp) { if (this.baseState !== State.Text && this.baseState !== State.InSpecialTag) { this.cbs.onattribentity(cp); } else { this.cbs.ontextentity(cp); } } } //# sourceMappingURL=Tokenizer.js.map