fix(compiler-core): generate TS-cast safe assignment code for v-model

fix #4655
This commit is contained in:
Evan You 2021-09-22 16:54:59 -04:00
parent 1873f0f48c
commit 686d0149b6
6 changed files with 51 additions and 52 deletions

View File

@ -6,7 +6,7 @@ exports[`compiler: transform v-model compound expression (with prefixIdentifiers
export function render(_ctx, _cache) { export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"input\\", { return (_openBlock(), _createElementBlock(\\"input\\", {
modelValue: _ctx.model[_ctx.index], modelValue: _ctx.model[_ctx.index],
\\"onUpdate:modelValue\\": $event => (_ctx.model[_ctx.index] = $event) \\"onUpdate:modelValue\\": $event => ((_ctx.model[_ctx.index]) = $event)
}, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"])) }, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"]))
}" }"
`; `;
@ -20,7 +20,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"input\\", { return (_openBlock(), _createElementBlock(\\"input\\", {
modelValue: model[index], modelValue: model[index],
\\"onUpdate:modelValue\\": $event => (model[index] = $event) \\"onUpdate:modelValue\\": $event => ((model[index]) = $event)
}, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"])) }, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"]))
} }
}" }"
@ -39,11 +39,11 @@ return function render(_ctx, _cache) {
. .
foo foo
, ,
\\"onUpdate:modelValue\\": $event => ( \\"onUpdate:modelValue\\": $event => ((
model model
. .
foo foo
= $event) ) = $event)
}, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"])) }, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"]))
} }
}" }"
@ -55,7 +55,7 @@ exports[`compiler: transform v-model simple expression (with prefixIdentifiers)
export function render(_ctx, _cache) { export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"input\\", { return (_openBlock(), _createElementBlock(\\"input\\", {
modelValue: _ctx.model, modelValue: _ctx.model,
\\"onUpdate:modelValue\\": $event => (_ctx.model = $event) \\"onUpdate:modelValue\\": $event => ((_ctx.model) = $event)
}, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"])) }, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"]))
}" }"
`; `;
@ -69,7 +69,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"input\\", { return (_openBlock(), _createElementBlock(\\"input\\", {
modelValue: model, modelValue: model,
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"])) }, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"]))
} }
}" }"
@ -84,7 +84,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"input\\", { return (_openBlock(), _createElementBlock(\\"input\\", {
value: model, value: model,
\\"onUpdate:value\\": $event => (model = $event) \\"onUpdate:value\\": $event => ((model) = $event)
}, null, 40 /* PROPS, HYDRATE_EVENTS */, [\\"value\\", \\"onUpdate:value\\"])) }, null, 40 /* PROPS, HYDRATE_EVENTS */, [\\"value\\", \\"onUpdate:value\\"]))
} }
}" }"
@ -96,7 +96,7 @@ exports[`compiler: transform v-model with dynamic argument (with prefixIdentifie
export function render(_ctx, _cache) { export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"input\\", _normalizeProps({ return (_openBlock(), _createElementBlock(\\"input\\", _normalizeProps({
[_ctx.value]: _ctx.model, [_ctx.value]: _ctx.model,
[\\"onUpdate:\\" + _ctx.value]: $event => (_ctx.model = $event) [\\"onUpdate:\\" + _ctx.value]: $event => ((_ctx.model) = $event)
}), null, 16 /* FULL_PROPS */)) }), null, 16 /* FULL_PROPS */))
}" }"
`; `;
@ -110,7 +110,7 @@ return function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"input\\", _normalizeProps({ return (_openBlock(), _createElementBlock(\\"input\\", _normalizeProps({
[value]: model, [value]: model,
[\\"onUpdate:\\" + value]: $event => (model = $event) [\\"onUpdate:\\" + value]: $event => ((model) = $event)
}), null, 16 /* FULL_PROPS */)) }), null, 16 /* FULL_PROPS */))
} }
}" }"

View File

@ -65,12 +65,12 @@ describe('compiler: transform v-model', () => {
}, },
value: { value: {
children: [ children: [
'$event => (', '$event => ((',
{ {
content: 'model', content: 'model',
isStatic: false isStatic: false
}, },
' = $event)' ') = $event)'
] ]
} }
}) })
@ -104,12 +104,12 @@ describe('compiler: transform v-model', () => {
}, },
value: { value: {
children: [ children: [
'$event => (', '$event => ((',
{ {
content: '_ctx.model', content: '_ctx.model',
isStatic: false isStatic: false
}, },
' = $event)' ') = $event)'
] ]
} }
}) })
@ -142,12 +142,12 @@ describe('compiler: transform v-model', () => {
}, },
value: { value: {
children: [ children: [
'$event => (', '$event => ((',
{ {
content: '\n model\n.\nfoo \n', content: '\n model\n.\nfoo \n',
isStatic: false isStatic: false
}, },
' = $event)' ') = $event)'
] ]
} }
}) })
@ -179,12 +179,12 @@ describe('compiler: transform v-model', () => {
}, },
value: { value: {
children: [ children: [
'$event => (', '$event => ((',
{ {
content: 'model[index]', content: 'model[index]',
isStatic: false isStatic: false
}, },
' = $event)' ') = $event)'
] ]
} }
}) })
@ -228,7 +228,7 @@ describe('compiler: transform v-model', () => {
}, },
value: { value: {
children: [ children: [
'$event => (', '$event => ((',
{ {
children: [ children: [
{ {
@ -243,7 +243,7 @@ describe('compiler: transform v-model', () => {
']' ']'
] ]
}, },
' = $event)' ') = $event)'
] ]
} }
}) })
@ -274,12 +274,12 @@ describe('compiler: transform v-model', () => {
}, },
value: { value: {
children: [ children: [
'$event => (', '$event => ((',
{ {
content: 'model', content: 'model',
isStatic: false isStatic: false
}, },
' = $event)' ') = $event)'
] ]
} }
}) })
@ -322,12 +322,12 @@ describe('compiler: transform v-model', () => {
}, },
value: { value: {
children: [ children: [
'$event => (', '$event => ((',
{ {
content: 'model', content: 'model',
isStatic: false isStatic: false
}, },
' = $event)' ') = $event)'
] ]
} }
} }
@ -376,12 +376,12 @@ describe('compiler: transform v-model', () => {
}, },
value: { value: {
children: [ children: [
'$event => (', '$event => ((',
{ {
content: '_ctx.model', content: '_ctx.model',
isStatic: false isStatic: false
}, },
' = $event)' ') = $event)'
] ]
} }
} }

View File

@ -76,9 +76,9 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
if (bindingType === BindingTypes.SETUP_REF) { if (bindingType === BindingTypes.SETUP_REF) {
// v-model used on known ref. // v-model used on known ref.
assignmentExp = createCompoundExpression([ assignmentExp = createCompoundExpression([
`${eventArg} => (`, `${eventArg} => ((`,
createSimpleExpression(rawExp, false, exp.loc), createSimpleExpression(rawExp, false, exp.loc),
`.value = $event)` `).value = $event)`
]) ])
} else { } else {
// v-model used on a potentially ref binding in <script setup> inline mode. // v-model used on a potentially ref binding in <script setup> inline mode.
@ -86,16 +86,16 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
const altAssignment = const altAssignment =
bindingType === BindingTypes.SETUP_LET ? `${rawExp} = $event` : `null` bindingType === BindingTypes.SETUP_LET ? `${rawExp} = $event` : `null`
assignmentExp = createCompoundExpression([ assignmentExp = createCompoundExpression([
`${eventArg} => (${context.helperString(IS_REF)}(${rawExp}) ? `, `${eventArg} => (${context.helperString(IS_REF)}(${rawExp}) ? (`,
createSimpleExpression(rawExp, false, exp.loc), createSimpleExpression(rawExp, false, exp.loc),
`.value = $event : ${altAssignment})` `).value = $event : ${altAssignment})`
]) ])
} }
} else { } else {
assignmentExp = createCompoundExpression([ assignmentExp = createCompoundExpression([
`${eventArg} => (`, `${eventArg} => ((`,
exp, exp,
` = $event)` `) = $event)`
]) ])
} }

View File

@ -8,7 +8,7 @@ return function render(_ctx, _cache) {
const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return _withDirectives((_openBlock(), _createElementBlock(\\"my-input\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"my-input\\", {
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[_vModelText, model] [_vModelText, model]
]) ])
@ -24,7 +24,7 @@ return function render(_ctx, _cache) {
const { vModelDynamic: _vModelDynamic, mergeProps: _mergeProps, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { vModelDynamic: _vModelDynamic, mergeProps: _mergeProps, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", _mergeProps(obj, { return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", _mergeProps(obj, {
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}), null, 16 /* FULL_PROPS */, [\\"onUpdate:modelValue\\"])), [ }), null, 16 /* FULL_PROPS */, [\\"onUpdate:modelValue\\"])), [
[_vModelDynamic, model] [_vModelDynamic, model]
]) ])
@ -42,7 +42,7 @@ return function render(_ctx, _cache) {
const _directive_bind = _resolveDirective(\\"bind\\") const _directive_bind = _resolveDirective(\\"bind\\")
return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", {
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[_directive_bind, val, key], [_directive_bind, val, key],
[_vModelDynamic, model] [_vModelDynamic, model]
@ -59,7 +59,7 @@ return function render(_ctx, _cache) {
const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", {
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[ [
_vModelText, _vModelText,
@ -80,7 +80,7 @@ return function render(_ctx, _cache) {
const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", {
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[ [
_vModelText, _vModelText,
@ -101,7 +101,7 @@ return function render(_ctx, _cache) {
const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", {
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[ [
_vModelText, _vModelText,
@ -122,7 +122,7 @@ return function render(_ctx, _cache) {
const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", {
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[_vModelText, model] [_vModelText, model]
]) ])
@ -139,7 +139,7 @@ return function render(_ctx, _cache) {
return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", {
type: \\"checkbox\\", type: \\"checkbox\\",
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[_vModelCheckbox, model] [_vModelCheckbox, model]
]) ])
@ -157,7 +157,7 @@ return function render(_ctx, _cache) {
const _directive_bind = _resolveDirective(\\"bind\\") const _directive_bind = _resolveDirective(\\"bind\\")
return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", {
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[_directive_bind, foo, \\"type\\"], [_directive_bind, foo, \\"type\\"],
[_vModelDynamic, model] [_vModelDynamic, model]
@ -175,7 +175,7 @@ return function render(_ctx, _cache) {
return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", {
type: \\"radio\\", type: \\"radio\\",
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[_vModelRadio, model] [_vModelRadio, model]
]) ])
@ -192,7 +192,7 @@ return function render(_ctx, _cache) {
return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"input\\", {
type: \\"text\\", type: \\"text\\",
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[_vModelText, model] [_vModelText, model]
]) ])
@ -208,7 +208,7 @@ return function render(_ctx, _cache) {
const { vModelSelect: _vModelSelect, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { vModelSelect: _vModelSelect, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return _withDirectives((_openBlock(), _createElementBlock(\\"select\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"select\\", {
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[_vModelSelect, model] [_vModelSelect, model]
]) ])
@ -224,7 +224,7 @@ return function render(_ctx, _cache) {
const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const { vModelText: _vModelText, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return _withDirectives((_openBlock(), _createElementBlock(\\"textarea\\", { return _withDirectives((_openBlock(), _createElementBlock(\\"textarea\\", {
\\"onUpdate:modelValue\\": $event => (model = $event) \\"onUpdate:modelValue\\": $event => ((model) = $event)
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [ }, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
[_vModelText, model] [_vModelText, model]
]) ])

View File

@ -924,17 +924,17 @@ export default {
return (_ctx, _cache) => { return (_ctx, _cache) => {
return (_openBlock(), _createElementBlock(_Fragment, null, [ return (_openBlock(), _createElementBlock(_Fragment, null, [
_withDirectives(_createElementVNode(\\"input\\", { _withDirectives(_createElementVNode(\\"input\\", {
\\"onUpdate:modelValue\\": _cache[0] || (_cache[0] = $event => (count.value = $event)) \\"onUpdate:modelValue\\": _cache[0] || (_cache[0] = $event => ((count).value = $event))
}, null, 512 /* NEED_PATCH */), [ }, null, 512 /* NEED_PATCH */), [
[_vModelText, count.value] [_vModelText, count.value]
]), ]),
_withDirectives(_createElementVNode(\\"input\\", { _withDirectives(_createElementVNode(\\"input\\", {
\\"onUpdate:modelValue\\": _cache[1] || (_cache[1] = $event => (_isRef(maybe) ? maybe.value = $event : null)) \\"onUpdate:modelValue\\": _cache[1] || (_cache[1] = $event => (_isRef(maybe) ? (maybe).value = $event : null))
}, null, 512 /* NEED_PATCH */), [ }, null, 512 /* NEED_PATCH */), [
[_vModelText, _unref(maybe)] [_vModelText, _unref(maybe)]
]), ]),
_withDirectives(_createElementVNode(\\"input\\", { _withDirectives(_createElementVNode(\\"input\\", {
\\"onUpdate:modelValue\\": _cache[2] || (_cache[2] = $event => (_isRef(lett) ? lett.value = $event : lett = $event)) \\"onUpdate:modelValue\\": _cache[2] || (_cache[2] = $event => (_isRef(lett) ? (lett).value = $event : lett = $event))
}, null, 512 /* NEED_PATCH */), [ }, null, 512 /* NEED_PATCH */), [
[_vModelText, _unref(lett)] [_vModelText, _unref(lett)]
]) ])

View File

@ -523,13 +523,12 @@ defineExpose({ foo: 123 })
{ inlineTemplate: true } { inlineTemplate: true }
) )
// known const ref: set value // known const ref: set value
expect(content).toMatch(`count.value = $event`) expect(content).toMatch(`(count).value = $event`)
// const but maybe ref: also assign .value directly since non-ref // const but maybe ref: assign if ref, otherwise do nothing
// won't work expect(content).toMatch(`_isRef(maybe) ? (maybe).value = $event : null`)
expect(content).toMatch(`maybe.value = $event`)
// let: handle both cases // let: handle both cases
expect(content).toMatch( expect(content).toMatch(
`_isRef(lett) ? lett.value = $event : lett = $event` `_isRef(lett) ? (lett).value = $event : lett = $event`
) )
assertCode(content) assertCode(content)
}) })