fix(compiler-core): allow multiline expression on v-model and v-on (#1234)
This commit is contained in:
parent
c97d1bae56
commit
958b6c80cf
@ -26,6 +26,25 @@ return function render(_ctx, _cache) {
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: transform v-model simple expression (with multilines) 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
with (_ctx) {
|
||||||
|
const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = _Vue
|
||||||
|
|
||||||
|
return (_openBlock(), _createBlock(\\"input\\", {
|
||||||
|
modelValue:
|
||||||
|
model
|
||||||
|
,
|
||||||
|
\\"onUpdate:modelValue\\": $event => (
|
||||||
|
model
|
||||||
|
= $event)
|
||||||
|
}, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"]))
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compiler: transform v-model simple expression (with prefixIdentifiers) 1`] = `
|
exports[`compiler: transform v-model simple expression (with prefixIdentifiers) 1`] = `
|
||||||
"import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
|
"import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
|
||||||
|
|
||||||
|
@ -115,6 +115,43 @@ describe('compiler: transform v-model', () => {
|
|||||||
expect(generate(root, { mode: 'module' }).code).toMatchSnapshot()
|
expect(generate(root, { mode: 'module' }).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('simple expression (with multilines)', () => {
|
||||||
|
const root = parseWithVModel('<input v-model="\n model \n" />')
|
||||||
|
const node = root.children[0] as ElementNode
|
||||||
|
const props = ((node.codegenNode as VNodeCall).props as ObjectExpression)
|
||||||
|
.properties
|
||||||
|
|
||||||
|
expect(props[0]).toMatchObject({
|
||||||
|
key: {
|
||||||
|
content: 'modelValue',
|
||||||
|
isStatic: true
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
content: '\n model \n',
|
||||||
|
isStatic: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(props[1]).toMatchObject({
|
||||||
|
key: {
|
||||||
|
content: 'onUpdate:modelValue',
|
||||||
|
isStatic: true
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
children: [
|
||||||
|
'$event => (',
|
||||||
|
{
|
||||||
|
content: '\n model \n',
|
||||||
|
isStatic: false
|
||||||
|
},
|
||||||
|
' = $event)'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
test('compound expression', () => {
|
test('compound expression', () => {
|
||||||
const root = parseWithVModel('<input v-model="model[index]" />')
|
const root = parseWithVModel('<input v-model="model[index]" />')
|
||||||
const node = root.children[0] as ElementNode
|
const node = root.children[0] as ElementNode
|
||||||
|
@ -167,6 +167,24 @@ describe('compiler: transform v-on', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should handle multiple line statement', () => {
|
||||||
|
const { node } = parseWithVOn(`<div @click="\nfoo();\nbar()\n"/>`)
|
||||||
|
expect((node.codegenNode as VNodeCall).props).toMatchObject({
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
key: { content: `onClick` },
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.COMPOUND_EXPRESSION,
|
||||||
|
// should wrap with `{` for multiple statements
|
||||||
|
// in this case the return value is discarded and the behavior is
|
||||||
|
// consistent with 2.x
|
||||||
|
children: [`$event => {`, { content: `\nfoo();\nbar()\n` }, `}`]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('inline statement w/ prefixIdentifiers: true', () => {
|
test('inline statement w/ prefixIdentifiers: true', () => {
|
||||||
const { node } = parseWithVOn(`<div @click="foo($event)"/>`, {
|
const { node } = parseWithVOn(`<div @click="foo($event)"/>`, {
|
||||||
prefixIdentifiers: true
|
prefixIdentifiers: true
|
||||||
|
@ -21,6 +21,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
|||||||
|
|
||||||
const expString =
|
const expString =
|
||||||
exp.type === NodeTypes.SIMPLE_EXPRESSION ? exp.content : exp.loc.source
|
exp.type === NodeTypes.SIMPLE_EXPRESSION ? exp.content : exp.loc.source
|
||||||
|
|
||||||
if (!isMemberExpression(expString)) {
|
if (!isMemberExpression(expString)) {
|
||||||
context.onError(
|
context.onError(
|
||||||
createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION, exp.loc)
|
createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION, exp.loc)
|
||||||
|
@ -84,8 +84,10 @@ export const isSimpleIdentifier = (name: string): boolean =>
|
|||||||
!nonIdentifierRE.test(name)
|
!nonIdentifierRE.test(name)
|
||||||
|
|
||||||
const memberExpRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\[[^\]]+\])*$/
|
const memberExpRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\[[^\]]+\])*$/
|
||||||
export const isMemberExpression = (path: string): boolean =>
|
export const isMemberExpression = (path: string): boolean => {
|
||||||
memberExpRE.test(path)
|
if (!path) return false
|
||||||
|
return memberExpRE.test(path.trim())
|
||||||
|
}
|
||||||
|
|
||||||
export function getInnerRange(
|
export function getInnerRange(
|
||||||
loc: SourceLocation,
|
loc: SourceLocation,
|
||||||
|
Loading…
Reference in New Issue
Block a user