test: tests for v-bind transform
This commit is contained in:
parent
6ad84614f7
commit
597ada36ed
@ -1 +1,120 @@
|
|||||||
test.todo('v-bind')
|
import {
|
||||||
|
parse,
|
||||||
|
transform,
|
||||||
|
ElementNode,
|
||||||
|
ObjectExpression,
|
||||||
|
CompilerOptions,
|
||||||
|
ErrorCodes
|
||||||
|
} from '../../src'
|
||||||
|
import { transformBind } from '../../src/transforms/vBind'
|
||||||
|
import { transformElement } from '../../src/transforms/transformElement'
|
||||||
|
|
||||||
|
function parseWithVBind(
|
||||||
|
template: string,
|
||||||
|
options: CompilerOptions = {}
|
||||||
|
): ElementNode {
|
||||||
|
const ast = parse(template)
|
||||||
|
transform(ast, {
|
||||||
|
nodeTransforms: [transformElement],
|
||||||
|
directiveTransforms: {
|
||||||
|
bind: transformBind
|
||||||
|
},
|
||||||
|
...options
|
||||||
|
})
|
||||||
|
return ast.children[0] as ElementNode
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('compiler: transform v-bind', () => {
|
||||||
|
test('basic', () => {
|
||||||
|
const node = parseWithVBind(`<div v-bind:id="id"/>`)
|
||||||
|
const props = node.codegenNode!.arguments[1] as ObjectExpression
|
||||||
|
expect(props.properties[0]).toMatchObject({
|
||||||
|
key: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: true,
|
||||||
|
loc: {
|
||||||
|
start: {
|
||||||
|
line: 1,
|
||||||
|
column: 13
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: 1,
|
||||||
|
column: 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: false,
|
||||||
|
loc: {
|
||||||
|
start: {
|
||||||
|
line: 1,
|
||||||
|
column: 16
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: 1,
|
||||||
|
column: 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loc: {
|
||||||
|
start: {
|
||||||
|
line: 1,
|
||||||
|
column: 6
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: 1,
|
||||||
|
column: 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('dynamic arg', () => {
|
||||||
|
const node = parseWithVBind(`<div v-bind:[id]="id"/>`)
|
||||||
|
const props = node.codegenNode!.arguments[1] as ObjectExpression
|
||||||
|
expect(props.properties[0]).toMatchObject({
|
||||||
|
key: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: false
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should error if no expression', () => {
|
||||||
|
const onError = jest.fn()
|
||||||
|
parseWithVBind(`<div v-bind />`, { onError })
|
||||||
|
expect(onError.mock.calls[0][0]).toMatchObject({
|
||||||
|
code: ErrorCodes.X_V_BIND_NO_EXPRESSION,
|
||||||
|
loc: {
|
||||||
|
start: {
|
||||||
|
line: 1,
|
||||||
|
column: 6
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: 1,
|
||||||
|
column: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('.camel modifier', () => {
|
||||||
|
const node = parseWithVBind(`<div v-bind:foo-bar.camel="id"/>`)
|
||||||
|
const props = node.codegenNode!.arguments[1] as ObjectExpression
|
||||||
|
expect(props.properties[0]).toMatchObject({
|
||||||
|
key: {
|
||||||
|
content: `fooBar`,
|
||||||
|
isStatic: true
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
content: `id`,
|
||||||
|
isStatic: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
@ -10,7 +10,6 @@ export const RESOLVE_COMPONENT = `resolveComponent`
|
|||||||
export const RESOLVE_DIRECTIVE = `resolveDirective`
|
export const RESOLVE_DIRECTIVE = `resolveDirective`
|
||||||
export const APPLY_DIRECTIVES = `applyDirectives`
|
export const APPLY_DIRECTIVES = `applyDirectives`
|
||||||
export const RENDER_LIST = `renderList`
|
export const RENDER_LIST = `renderList`
|
||||||
export const CAPITALIZE = `capitalize`
|
|
||||||
export const TO_STRING = `toString`
|
export const TO_STRING = `toString`
|
||||||
export const MERGE_PROPS = `mergeProps`
|
export const MERGE_PROPS = `mergeProps`
|
||||||
export const TO_HANDLERS = `toHandlers`
|
export const TO_HANDLERS = `toHandlers`
|
||||||
|
@ -86,7 +86,7 @@ export function processExpression(
|
|||||||
enter(node: Node & PrefixMeta, parent) {
|
enter(node: Node & PrefixMeta, parent) {
|
||||||
if (node.type === 'Identifier') {
|
if (node.type === 'Identifier') {
|
||||||
if (
|
if (
|
||||||
ids.indexOf(node) === -1 &&
|
!ids.includes(node) &&
|
||||||
!knownIds[node.name] &&
|
!knownIds[node.name] &&
|
||||||
shouldPrefix(node, parent)
|
shouldPrefix(node, parent)
|
||||||
) {
|
) {
|
||||||
@ -177,7 +177,7 @@ function shouldPrefix(identifier: Identifier, parent: Node) {
|
|||||||
// not id of a FunctionDeclaration
|
// not id of a FunctionDeclaration
|
||||||
((parent as any).id === identifier ||
|
((parent as any).id === identifier ||
|
||||||
// not a params of a function
|
// not a params of a function
|
||||||
parent.params.indexOf(identifier) > -1)
|
parent.params.includes(identifier))
|
||||||
) &&
|
) &&
|
||||||
// not a key of Property
|
// not a key of Property
|
||||||
!(
|
!(
|
||||||
|
@ -1,23 +1,28 @@
|
|||||||
import { DirectiveTransform } from '../transform'
|
import { DirectiveTransform } from '../transform'
|
||||||
import { createObjectProperty, createExpression } from '../ast'
|
import { createObjectProperty, createExpression } from '../ast'
|
||||||
import { createCompilerError, ErrorCodes } from '../errors'
|
import { createCompilerError, ErrorCodes } from '../errors'
|
||||||
|
import { camelize } from '@vue/shared'
|
||||||
|
|
||||||
// v-bind without arg is handled directly in ./element.ts due to it affecting
|
// 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
|
// codegen for the entire props object. This transform here is only for v-bind
|
||||||
// *with* args.
|
// *with* args.
|
||||||
export const transformBind: DirectiveTransform = (dir, context) => {
|
export const transformBind: DirectiveTransform = (
|
||||||
if (!dir.exp) {
|
{ exp, arg, modifiers, loc },
|
||||||
context.onError(
|
context
|
||||||
createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, dir.loc)
|
) => {
|
||||||
)
|
if (!exp) {
|
||||||
|
context.onError(createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc))
|
||||||
|
}
|
||||||
|
// .prop is no longer necessary due to new patch behavior
|
||||||
|
// .sync is replced by v-model:arg
|
||||||
|
if (modifiers.includes('camel')) {
|
||||||
|
arg!.content = camelize(arg!.content)
|
||||||
}
|
}
|
||||||
// TODO handle .prop modifier
|
|
||||||
// TODO handle .camel modifier
|
|
||||||
return {
|
return {
|
||||||
props: createObjectProperty(
|
props: createObjectProperty(
|
||||||
dir.arg!,
|
arg!,
|
||||||
dir.exp || createExpression('', true, dir.loc),
|
exp || createExpression('', true, loc),
|
||||||
dir.loc
|
loc
|
||||||
),
|
),
|
||||||
needRuntime: false
|
needRuntime: false
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,21 @@
|
|||||||
import { DirectiveTransform } from '../transform'
|
import { DirectiveTransform } from '../transform'
|
||||||
import { createObjectProperty, createExpression } from '../ast'
|
import { createObjectProperty, createExpression } from '../ast'
|
||||||
import { capitalize } from '@vue/shared'
|
import { capitalize } from '@vue/shared'
|
||||||
import { CAPITALIZE } from '../runtimeConstants'
|
|
||||||
|
|
||||||
// v-on without arg is handled directly in ./element.ts due to it affecting
|
// 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
|
// codegen for the entire props object. This transform here is only for v-on
|
||||||
// *with* args.
|
// *with* args.
|
||||||
export const transformOn: DirectiveTransform = (dir, context) => {
|
export const transformOn: DirectiveTransform = ({ arg, exp, loc }) => {
|
||||||
const arg = dir.arg!
|
const eventName = arg!.isStatic
|
||||||
const eventName = arg.isStatic
|
? createExpression(`on${capitalize(arg!.content)}`, true, arg!.loc)
|
||||||
? createExpression(`on${capitalize(arg.content)}`, true, arg.loc)
|
: createExpression(`'on' + (${arg!.content})`, false, arg!.loc)
|
||||||
: createExpression(`'on' + ${CAPITALIZE}(${arg.content})`, false, arg.loc)
|
|
||||||
// TODO .once modifier handling since it is platform agnostic
|
// TODO .once modifier handling since it is platform agnostic
|
||||||
// other modifiers are handled in compiler-dom
|
// other modifiers are handled in compiler-dom
|
||||||
return {
|
return {
|
||||||
props: createObjectProperty(
|
props: createObjectProperty(
|
||||||
eventName,
|
eventName,
|
||||||
dir.exp || createExpression(`() => {}`, false, dir.loc),
|
exp || createExpression(`() => {}`, false, loc),
|
||||||
dir.loc
|
loc
|
||||||
),
|
),
|
||||||
needRuntime: false
|
needRuntime: false
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,6 @@ export { resolveComponent, resolveDirective } from './helpers/resolveAssets'
|
|||||||
export { renderList } from './helpers/renderList'
|
export { renderList } from './helpers/renderList'
|
||||||
export { toString } from './helpers/toString'
|
export { toString } from './helpers/toString'
|
||||||
export { toHandlers } from './helpers/toHandlers'
|
export { toHandlers } from './helpers/toHandlers'
|
||||||
export { capitalize } from '@vue/shared'
|
|
||||||
|
|
||||||
// Internal, for integration with runtime compiler
|
// Internal, for integration with runtime compiler
|
||||||
export { registerRuntimeCompiler } from './component'
|
export { registerRuntimeCompiler } from './component'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user