refactor: move dom-specific options to compiler-dom

This commit is contained in:
Evan You
2019-09-17 11:07:46 -04:00
parent 5849f42ae1
commit 6c14b409ca
10 changed files with 561 additions and 526 deletions

View File

@@ -1,3 +1,12 @@
// Vue template is a platform-agnostic superset of HTML (syntax only).
// More namespaces like SVG and MathML are declared by platform specific
// compilers.
export type Namespace = number
export const enum Namespaces {
HTML
}
export const enum NodeTypes {
TEXT,
COMMENT,
@@ -15,12 +24,6 @@ export const enum ElementTypes {
TEMPLATE // template, component
}
export const enum Namespaces {
HTML,
SVG, // allows CDATA section and forbids end tag omission.
MATH_ML // allows CDATA section and forbids end tag omission.
}
export interface Node {
type: NodeTypes
loc: SourceLocation
@@ -33,7 +36,7 @@ export interface RootNode extends Node {
export interface ElementNode extends Node {
type: NodeTypes.ELEMENT
ns: Namespaces
ns: Namespace
tag: string
tagType: ElementTypes
isSelfClosing: boolean

View File

@@ -1,3 +1,3 @@
export { parse } from './parser'
export { parse, ParserOptions, TextModes } from './parser'
export * from './ast'
export * from './errorTypes'

View File

@@ -1,13 +1,13 @@
import { ParserErrorTypes } from './errorTypes'
import { ParserErrorTypes, errorMessages } from './errorTypes'
import {
Node,
Namespace,
Namespaces,
AttributeNode,
CommentNode,
DirectiveNode,
ElementNode,
ElementTypes,
ExpressionNode,
Namespaces,
NodeTypes,
Position,
RootNode,
@@ -16,30 +16,46 @@ import {
} from './ast'
export interface ParserOptions {
isVoidTag: (tag: string) => boolean // e.g. img, br, hr
getNamespace: (tag: string, parent: ElementNode | undefined) => Namespaces
getTextMode: (tag: string, ns: Namespaces) => TextModes
delimiters: [string, string] // ['{{', '}}']
transform: (node: Node) => Node // --
ignoreSpaces: boolean
isVoidTag?: (tag: string) => boolean // e.g. img, br, hr
getNamespace?: (tag: string, parent: ElementNode | undefined) => Namespace
getTextMode?: (tag: string, ns: Namespace) => TextModes
delimiters?: [string, string] // ['{{', '}}']
ignoreSpaces?: boolean
// Map to HTML entities. E.g., `{ "amp;": "&" }`
// The full set is https://html.spec.whatwg.org/multipage/named-characters.html#named-character-references
namedCharacterReferences: { [name: string]: string | undefined }
namedCharacterReferences?: { [name: string]: string | undefined }
onError: (type: ParserErrorTypes, loc: Position) => void
onError?: (type: ParserErrorTypes, loc: Position) => void
}
export const defaultParserOptions: Required<ParserOptions> = {
delimiters: [`{{`, `}}`],
ignoreSpaces: true,
getNamespace: () => Namespaces.HTML,
getTextMode: () => TextModes.DATA,
isVoidTag: () => false,
namedCharacterReferences: {},
onError(code: ParserErrorTypes, loc: Position): void {
const error: any = new SyntaxError(
`${errorMessages[code]} (${loc.line}:${loc.column})`
)
error.code = code
error.loc = loc
throw error
}
}
export const enum TextModes {
// | Elements | Entities | End sign | Inside of
DATA, // | ✔ | ✔ | End tags of ancestors |
RCDATA, // | ✘ | ✔ | End tag of the parent | <textarea>
// | Elements | Entities | End sign | Inside of
DATA, // | ✔ | ✔ | End tags of ancestors |
RCDATA, // | ✘ | ✔ | End tag of the parent | <textarea>
RAWTEXT, // | ✘ | ✘ | End tag of the parent | <style>,<script>
CDATA,
ATTRIBUTE_VALUE
}
interface ParserContext extends ParserOptions {
interface ParserContext extends Required<ParserOptions> {
readonly originalSource: string
source: string
offset: number
@@ -48,7 +64,7 @@ interface ParserContext extends ParserOptions {
maxCRNameLength: number
}
export function parse(content: string, options: ParserOptions): RootNode {
export function parse(content: string, options: ParserOptions = {}): RootNode {
const context = createParserContext(content, options)
const start = getCursor(context)
@@ -64,16 +80,17 @@ function createParserContext(
options: ParserOptions
): ParserContext {
return {
...defaultParserOptions,
...options,
column: 1,
line: 1,
offset: 0,
originalSource: content,
source: content,
maxCRNameLength: Object.keys(options.namedCharacterReferences).reduce(
(max, name) => Math.max(max, name.length),
0
)
maxCRNameLength: Object.keys(
options.namedCharacterReferences ||
defaultParserOptions.namedCharacterReferences
).reduce((max, name) => Math.max(max, name.length), 0)
}
}

View File

@@ -1,60 +0,0 @@
import { TextModes, ParserOptions } from './parser'
import { ElementNode, Namespaces, Position, Node } from './ast'
import { ParserErrorTypes, errorMessages } from './errorTypes'
export const parserOptionsMinimal: ParserOptions = {
delimiters: [`{{`, `}}`],
ignoreSpaces: true,
getNamespace(tag: string, parent: ElementNode | undefined): Namespaces {
const ns = parent ? parent.ns : Namespaces.HTML
if (ns === Namespaces.HTML) {
if (tag === 'svg') {
return Namespaces.SVG
}
if (tag === 'math') {
return Namespaces.MATH_ML
}
}
return ns
},
getTextMode(tag: string, ns: Namespaces): TextModes {
if (ns === Namespaces.HTML) {
if (/^textarea$/i.test(tag)) {
return TextModes.RCDATA
}
if (/^(?:style|script)$/i.test(tag)) {
return TextModes.RAWTEXT
}
}
return TextModes.DATA
},
isVoidTag(tag: string): boolean {
return /^(?:area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/i.test(
tag
)
},
namedCharacterReferences: {
'gt;': '>',
'lt;': '<',
'amp;': '&',
'apos;': "'",
'quot;': '"'
},
onError(code: ParserErrorTypes, loc: Position): void {
const error: any = new SyntaxError(
`${errorMessages[code]} (${loc.line}:${loc.column})`
)
error.code = code
error.loc = loc
throw error
},
transform(node: Node): Node {
return node
}
}

File diff suppressed because it is too large Load Diff