refactor: move compile into compiler-core
This commit is contained in:
@@ -164,7 +164,7 @@ describe('compiler: transform', () => {
|
||||
const ast = parse(`<div/>`)
|
||||
const loc = ast.children[0].loc.start
|
||||
const plugin: Transform = (node, context) => {
|
||||
context.onError(
|
||||
context.emitError(
|
||||
createCompilerError(ErrorCodes.X_INVALID_END_TAG, node.loc.start)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user