refactor: move compile into compiler-core

This commit is contained in:
Evan You
2019-09-20 12:16:19 -04:00
parent 3e1973f065
commit 8a923f6a52
12 changed files with 106 additions and 77 deletions

View File

@@ -66,12 +66,11 @@ export function generate(
function createCodegenContext(
ast: RootNode,
options: CodegenOptions
{ module = false, filename = `template.vue.html` }: CodegenOptions
): CodegenContext {
const context: CodegenContext = {
module: false,
filename: `template.vue.html`,
...options,
module,
filename,
source: ast.loc.source,
code: ``,
column: 1,

View File

@@ -27,7 +27,7 @@ export const transformFor = createDirectiveTransform(
children: [node]
})
} else {
context.onError(
context.emitError(
createCompilerError(
ErrorCodes.X_FOR_MALFORMED_EXPRESSION,
dir.loc.start
@@ -35,7 +35,7 @@ export const transformFor = createDirectiveTransform(
)
}
} else {
context.onError(
context.emitError(
createCompilerError(ErrorCodes.X_FOR_NO_EXPRESSION, dir.loc.start)
)
}

View File

@@ -38,7 +38,7 @@ export const transformIf = createDirectiveTransform(
}
sibling.branches.push(branch)
} else {
context.onError(
context.emitError(
createCompilerError(
dir.name === 'else'
? ErrorCodes.X_ELSE_NO_ADJACENT_IF

View File

@@ -5,6 +5,10 @@ export interface CompilerError extends SyntaxError {
loc: Position
}
export function defaultOnError(error: CompilerError) {
throw error
}
export function createCompilerError(
code: ErrorCodes,
loc: Position

View File

@@ -1,11 +1,35 @@
import { parse, ParserOptions } from './parse'
import { transform, TransformOptions } from './transform'
import { generate, CodegenOptions, CodegenResult } from './codegen'
export type CompilerOptions = ParserOptions & TransformOptions & CodegenOptions
export function compile(
template: string,
options: CompilerOptions = {}
): CodegenResult {
const ast = parse(template, options)
transform(ast, {
...options,
transforms: [
// TODO include built-in core transforms
...(options.transforms || []) // user transforms
]
})
return generate(ast, options)
}
// Also expose lower level APIs & types
export { parse, ParserOptions, TextModes } from './parse'
export {
transform,
createDirectiveTransform,
TransformOptions,
Transform
Transform,
DirectiveTransform
} from './transform'
export { generate, CodegenOptions, CodegenResult } from './codegen'
export { ErrorCodes, CompilerError, createCompilerError } from './errors'
export * from './ast'

View File

@@ -1,4 +1,9 @@
import { ErrorCodes, CompilerError, createCompilerError } from './errors'
import {
ErrorCodes,
CompilerError,
createCompilerError,
defaultOnError
} from './errors'
import {
assert,
advancePositionWithMutation,
@@ -48,9 +53,7 @@ export const defaultParserOptions: Required<ParserOptions> = {
'apos;': "'",
'quot;': '"'
},
onError(error: CompilerError): void {
throw error
}
onError: defaultOnError
}
export const enum TextModes {
@@ -62,7 +65,8 @@ export const enum TextModes {
ATTRIBUTE_VALUE
}
interface ParserContext extends Required<ParserOptions> {
interface ParserContext {
options: Required<ParserOptions>
readonly originalSource: string
source: string
offset: number
@@ -87,8 +91,10 @@ function createParserContext(
options: ParserOptions
): ParserContext {
return {
...defaultParserOptions,
...options,
options: {
...defaultParserOptions,
...options
},
column: 1,
line: 1,
offset: 0,
@@ -115,7 +121,7 @@ function parseChildren(
const s = context.source
let node: any = null
if (startsWith(s, context.delimiters[0])) {
if (startsWith(s, context.options.delimiters[0])) {
// '{{'
node = parseInterpolation(context, mode)
} else if (mode === TextModes.DATA && s[0] === '<') {
@@ -194,7 +200,11 @@ function pushNode(
if (!__DEV__ && node.type === NodeTypes.COMMENT) {
return
}
if (context.ignoreSpaces && node.type === NodeTypes.TEXT && node.isEmpty) {
if (
context.options.ignoreSpaces &&
node.type === NodeTypes.TEXT &&
node.isEmpty
) {
return
}
@@ -311,13 +321,13 @@ function parseElement(
const parent = last(ancestors)
const element = parseTag(context, TagType.Start, parent)
if (element.isSelfClosing || context.isVoidTag(element.tag)) {
if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {
return element
}
// Children.
ancestors.push(element)
const mode = (context.getTextMode(
const mode = (context.options.getTextMode(
element.tag,
element.ns
) as unknown) as TextModes
@@ -368,7 +378,7 @@ function parseTag(
const tag = match[1]
const attrs = []
const directives = []
const ns = context.getNamespace(tag, parent)
const ns = context.options.getNamespace(tag, parent)
advanceBy(context, match[0].length)
advanceSpaces(context)
@@ -601,7 +611,7 @@ function parseInterpolation(
context: ParserContext,
mode: TextModes
): ExpressionNode | undefined {
const [open, close] = context.delimiters
const [open, close] = context.options.delimiters
__DEV__ && assert(startsWith(context.source, open))
const closeIndex = context.source.indexOf(close, open.length)
@@ -626,7 +636,7 @@ function parseInterpolation(
function parseText(context: ParserContext, mode: TextModes): TextNode {
__DEV__ && assert(context.source.length > 0)
const [open] = context.delimiters
const [open] = context.options.delimiters
const endIndex = Math.min(
...[
context.source.indexOf('<', 1),
@@ -691,7 +701,7 @@ function parseTextData(
--length
) {
name = context.source.substr(1, length)
value = context.namedCharacterReferences[name]
value = context.options.namedCharacterReferences[name]
}
if (value) {
const semi = name.endsWith(';')
@@ -837,7 +847,7 @@ function emitError(
loc.offset += offset
loc.column += offset
}
context.onError(createCompilerError(code, loc))
context.options.onError(createCompilerError(code, loc))
}
function isEnd(

View File

@@ -7,7 +7,7 @@ import {
DirectiveNode
} from './ast'
import { isString } from '@vue/shared'
import { CompilerError } from './errors'
import { CompilerError, defaultOnError } from './errors'
export type Transform = (node: ChildNode, context: TransformContext) => void
@@ -18,11 +18,13 @@ export type DirectiveTransform = (
) => false | void
export interface TransformOptions {
transforms: Transform[]
transforms?: Transform[]
onError?: (error: CompilerError) => void
}
interface TransformContext extends Required<TransformOptions> {
interface TransformContext {
transforms: Transform[]
emitError: (error: CompilerError) => void
parent: ParentNode
ancestors: ParentNode[]
childIndex: number
@@ -42,10 +44,8 @@ function createTransformContext(
options: TransformOptions
): TransformContext {
const context: TransformContext = {
onError(error: CompilerError) {
throw error
},
...options,
transforms: options.transforms || [],
emitError: options.onError || defaultOnError,
parent: root,
ancestors: [],
childIndex: 0,
@@ -109,7 +109,7 @@ function traverseNode(
ancestors: ParentNode[]
) {
// apply transform plugins
const transforms = context.transforms
const { transforms } = context
for (let i = 0; i < transforms.length; i++) {
const plugin = transforms[i]
plugin(node, context)