diff --git a/packages/compiler-core/src/parser/Tokenizer.ts b/packages/compiler-core/src/parser/Tokenizer.ts index 214817a425b..775ea584262 100644 --- a/packages/compiler-core/src/parser/Tokenizer.ts +++ b/packages/compiler-core/src/parser/Tokenizer.ts @@ -65,8 +65,8 @@ export const enum CharCodes { RightSquare = 93 // "]" } -const defaultDelimitersOpen = [123, 123] // "{{" -const defaultDelimitersClose = [125, 125] // "}}" +const defaultDelimitersOpen = new Uint8Array([123, 123]) // "{{" +const defaultDelimitersClose = new Uint8Array([125, 125]) // "}}" /** All the states the tokenizer can be in. */ const enum State { @@ -115,6 +115,17 @@ const enum State { InEntity } +/** + * HTML only allows ASCII alpha characters (a-z and A-Z) at the beginning of a + * tag name. + */ +function isTagStartChar(c: number): boolean { + return ( + (c >= CharCodes.LowerA && c <= CharCodes.LowerZ) || + (c >= CharCodes.UpperA && c <= CharCodes.UpperZ) + ) +} + export function isWhitespace(c: number): boolean { return ( c === CharCodes.Space || @@ -261,9 +272,9 @@ export default class Tokenizer { } } - public delimiterOpen: number[] = defaultDelimitersOpen - public delimiterClose: number[] = defaultDelimitersClose - private matchDelimiter(c: number, delimiter: number[]): boolean { + public delimiterOpen: Uint8Array = defaultDelimitersOpen + public delimiterClose: Uint8Array = defaultDelimitersClose + private matchDelimiter(c: number, delimiter: Uint8Array): boolean { if (c === delimiter[0]) { const l = delimiter.length for (let i = 1; i < l; i++) { @@ -420,16 +431,6 @@ export default class Tokenizer { } } - /** - * HTML only allows ASCII alpha characters (a-z and A-Z) at the beginning of a tag name. - */ - private isTagStartChar(c: number) { - return ( - (c >= CharCodes.LowerA && c <= CharCodes.LowerZ) || - (c >= CharCodes.UpperA && c <= CharCodes.UpperZ) - ) - } - private startSpecial(sequence: Uint8Array, offset: number) { this.isSpecial = true this.currentSequence = sequence @@ -444,7 +445,7 @@ export default class Tokenizer { } else if (c === CharCodes.Questionmark) { this.state = State.InProcessingInstruction this.sectionStart = this.index + 1 - } else if (this.isTagStartChar(c)) { + } else if (isTagStartChar(c)) { const lower = c | 0x20 this.sectionStart = this.index if (lower === Sequences.TitleEnd[2]) { @@ -476,7 +477,7 @@ export default class Tokenizer { } else if (c === CharCodes.Gt) { this.state = State.Text } else { - this.state = this.isTagStartChar(c) + this.state = isTagStartChar(c) ? State.InClosingTagName : State.InSpecialComment this.sectionStart = this.index diff --git a/packages/compiler-core/src/parser/index.ts b/packages/compiler-core/src/parser/index.ts index 585af7e0d42..f6df84a2654 100644 --- a/packages/compiler-core/src/parser/index.ts +++ b/packages/compiler-core/src/parser/index.ts @@ -19,9 +19,9 @@ import { CompilerCompatOptions } from '../compat/compatConfig' import { NO, extend } from '@vue/shared' import { defaultOnError, defaultOnWarn } from '../errors' import { isCoreComponent } from '../utils' +import { TextModes } from '../parse' type OptionalOptions = - | 'getTextMode' // TODO | 'whitespace' | 'isNativeTag' | 'isBuiltInComponent' @@ -45,7 +45,7 @@ const decodeMap: Record = { export const defaultParserOptions: MergedParserOptions = { delimiters: [`{{`, `}}`], getNamespace: () => Namespaces.HTML, - // getTextMode: () => TextModes.DATA, + getTextMode: () => TextModes.DATA, isVoidTag: NO, isPreTag: NO, isCustomElement: NO, @@ -598,8 +598,12 @@ function reset() { stack.length = 0 } -function toCharCodes(str: string): number[] { - return str.split('').map(c => c.charCodeAt(0)) +function toCharCodes(str: string): Uint8Array { + const ret = new Uint8Array() + for (let i = 0; i < str.length; i++) { + ret[i] = str.charCodeAt(i) + } + return ret } export function baseParse(input: string, options?: ParserOptions): RootNode { diff --git a/packages/compiler-dom/src/parserOptions.ts b/packages/compiler-dom/src/parserOptions.ts index 4d06a776b7a..38e5e8b9d51 100644 --- a/packages/compiler-dom/src/parserOptions.ts +++ b/packages/compiler-dom/src/parserOptions.ts @@ -5,16 +5,11 @@ import { NodeTypes, isBuiltInType } from '@vue/compiler-core' -import { makeMap, isVoidTag, isHTMLTag, isSVGTag } from '@vue/shared' +import { isVoidTag, isHTMLTag, isSVGTag } from '@vue/shared' import { TRANSITION, TRANSITION_GROUP } from './runtimeHelpers' import { decodeHtml } from './decodeHtml' import { decodeHtmlBrowser } from './decodeHtmlBrowser' -const isRawTextContainer = /*#__PURE__*/ makeMap( - 'style,iframe,script,noscript', - true -) - export const enum DOMNamespaces { HTML = 0 /* Namespaces.HTML */, SVG, @@ -38,7 +33,6 @@ export const parserOptions: ParserOptions = { // https://html.spec.whatwg.org/multipage/parsing.html#tree-construction-dispatcher getNamespace(tag: string, parent: ElementNode | undefined): DOMNamespaces { let ns = parent ? parent.ns : DOMNamespaces.HTML - if (parent && ns === DOMNamespaces.MATH_ML) { if (parent.tag === 'annotation-xml') { if (tag === 'svg') { @@ -90,7 +84,7 @@ export const parserOptions: ParserOptions = { if (tag === 'textarea' || tag === 'title') { return TextModes.RCDATA } - if (isRawTextContainer(tag)) { + if (tag === 'style' || tag === 'script') { return TextModes.RAWTEXT } }