feat(compiler): basic v-bind & v-on transforms

This commit is contained in:
Evan You
2019-09-22 22:19:42 -04:00
parent 3ab016e44f
commit 914087edea
14 changed files with 749 additions and 715 deletions

View File

@@ -366,7 +366,7 @@ function genObjectExpression(node: ObjectExpression, context: CodegenContext) {
const { push, indent, deindent, newline } = context
const { properties } = node
const multilines = properties.length > 1
push(`{`, node)
push(multilines ? `{` : `{ `, node)
multilines && indent()
for (let i = 0; i < properties.length; i++) {
const { key, value } = properties[i]
@@ -385,7 +385,7 @@ function genObjectExpression(node: ObjectExpression, context: CodegenContext) {
}
}
multilines && deindent()
push(`}`)
push(multilines ? `}` : ` }`)
}
function genArrayExpression(node: ArrayExpression, context: CodegenContext) {

View File

@@ -1,8 +1,8 @@
import { Position } from './ast'
import { SourceLocation } from './ast'
export interface CompilerError extends SyntaxError {
code: ErrorCodes
loc: Position
loc: SourceLocation
}
export function defaultOnError(error: CompilerError) {
@@ -11,12 +11,12 @@ export function defaultOnError(error: CompilerError) {
export function createCompilerError(
code: ErrorCodes,
loc: Position
loc: SourceLocation
): CompilerError {
const error = new SyntaxError(
`${__DEV__ || !__BROWSER__ ? errorMessages[code] : code} (${loc.line}:${
loc.column
})`
`${__DEV__ || !__BROWSER__ ? errorMessages[code] : code} (${
loc.start.line
}:${loc.start.column})`
) as CompilerError
error.code = code
error.loc = loc

View File

@@ -6,6 +6,8 @@ import { isString } from '@vue/shared'
import { transformIf } from './transforms/vIf'
import { transformFor } from './transforms/vFor'
import { prepareElementForCodegen } from './transforms/element'
import { transformOn } from './transforms/vOn'
import { transformBind } from './transforms/vBind'
export type CompilerOptions = ParserOptions & TransformOptions & CodegenOptions
@@ -24,7 +26,8 @@ export function compile(
...(options.nodeTransforms || []) // user transforms
],
directiveTransforms: {
// TODO include built-in directive transforms
on: transformOn,
bind: transformBind,
...(options.directiveTransforms || {}) // user transforms
}
})

View File

@@ -842,7 +842,13 @@ function emitError(
loc.offset += offset
loc.column += offset
}
context.options.onError(createCompilerError(code, loc))
context.options.onError(
createCompilerError(code, {
start: loc,
end: loc,
source: ''
})
)
}
function isEnd(

View File

@@ -123,10 +123,7 @@ function buildProps(
mergeArgs.push(prop.exp)
} else {
context.onError(
createCompilerError(
ErrorCodes.X_V_BIND_NO_EXPRESSION,
prop.loc.start
)
createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, prop.loc)
)
}
continue

View File

@@ -1 +1,24 @@
// TODO
import { DirectiveTransform } from '../transform'
import { createObjectProperty, createExpression } from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
// v-bind without arg is handled directly in ./element.ts due to it affecting
// codegen for the entire props object. This transform here is only for v-bind
// *with* args.
export const transformBind: DirectiveTransform = (dir, context) => {
if (!dir.exp) {
context.onError(
createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, dir.loc)
)
}
// TODO handle .prop modifier
// TODO handle .sync modifier
return {
props: createObjectProperty(
dir.arg!,
dir.exp || createExpression('', true, dir.loc),
dir.loc
),
needRuntime: false
}
}

View File

@@ -32,15 +32,12 @@ export const transformFor = createStructuralDirectiveTransform(
})
} else {
context.onError(
createCompilerError(
ErrorCodes.X_FOR_MALFORMED_EXPRESSION,
dir.loc.start
)
createCompilerError(ErrorCodes.X_FOR_MALFORMED_EXPRESSION, dir.loc)
)
}
} else {
context.onError(
createCompilerError(ErrorCodes.X_FOR_NO_EXPRESSION, dir.loc.start)
createCompilerError(ErrorCodes.X_FOR_NO_EXPRESSION, dir.loc)
)
}
}

View File

@@ -49,7 +49,7 @@ export const transformIf = createStructuralDirectiveTransform(
dir.name === 'else'
? ErrorCodes.X_ELSE_NO_ADJACENT_IF
: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
node.loc.start
node.loc
)
)
}

View File

@@ -1 +1,24 @@
// TODO
import { DirectiveTransform } from '../transform'
import { createObjectProperty, createExpression } from '../ast'
import { capitalize } from '@vue/shared'
// v-on without arg is handled directly in ./element.ts due to it affecting
// codegen for the entire props object. This transform here is only for v-on
// *with* args.
export const transformOn: DirectiveTransform = (dir, context) => {
const arg = dir.arg!
const eventName = arg.isStatic
? createExpression(`on${capitalize(arg.content)}`, true, arg.loc)
: // TODO inject capitalize helper
createExpression(`'on' + capitalize(${arg.content})`, false, arg.loc)
// TODO .once modifier handling since it is platform agnostic
// other modifiers are handled in compiler-dom
return {
props: createObjectProperty(
eventName,
dir.exp || createExpression(`() => {}`, false, dir.loc),
dir.loc
),
needRuntime: false
}
}