test('should mark update handler dynamic if it refers slot scope variables', () => {
const root = parseWithVModel(
- '<Comp v-slot="{ foo }"><input v-model="foo"/></Comp>',
+ '<Comp v-slot="{ foo }"><input v-model="foo.bar"/></Comp>',
{
prefixIdentifiers: true
}
})
)
})
+
+ test('used on scope variable', () => {
+ const onError = jest.fn()
+ parseWithVModel('<span v-for="i in list" v-model="i" />', {
+ onError,
+ prefixIdentifiers: true
+ })
+
+ expect(onError).toHaveBeenCalledTimes(1)
+ expect(onError).toHaveBeenCalledWith(
+ expect.objectContaining({
+ code: ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE
+ })
+ )
+ })
})
})
X_V_SLOT_MISPLACED,
X_V_MODEL_NO_EXPRESSION,
X_V_MODEL_MALFORMED_EXPRESSION,
+ X_V_MODEL_ON_SCOPE_VARIABLE,
// generic errors
X_PREFIX_ID_NOT_SUPPORTED,
[ErrorCodes.X_V_SLOT_MISPLACED]: `v-slot can only be used on components or <template> tags.`,
[ErrorCodes.X_V_MODEL_NO_EXPRESSION]: `v-model is missing expression.`,
[ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION]: `v-model value must be a valid JavaScript member expression.`,
+ [ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE]: `v-model cannot be used on v-for or v-slot scope variables because they are not writable.`,
// generic errors
[ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED]: `"prefixIdentifiers" option is not supported in this build of compiler.`,
createInterpolation
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
-import { isMemberExpression } from '../utils'
+import { isMemberExpression, isSimpleIdentifier } from '../utils'
import { isObject } from '@vue/shared'
export const transformModel: DirectiveTransform = (dir, node, context) => {
return createTransformProps()
}
+ if (
+ !__BROWSER__ &&
+ context.prefixIdentifiers &&
+ isSimpleIdentifier(expString) &&
+ context.identifiers[expString]
+ ) {
+ context.onError(
+ createCompilerError(ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE, exp.loc)
+ )
+ return createTransformProps()
+ }
+
const propName = arg ? arg : createSimpleExpression('modelValue', true)
const eventName = arg
? arg.type === NodeTypes.SIMPLE_EXPRESSION && arg.isStatic
} from '../runtimeHelpers'
export const transformModel: DirectiveTransform = (dir, node, context) => {
- const res = baseTransform(dir, node, context)
+ const baseResult = baseTransform(dir, node, context)
+ // base transform has errors
+ if (!baseResult.props.length) {
+ return baseResult
+ }
+
const { tag, tagType } = node
if (tagType === ElementTypes.ELEMENT) {
if (dir.arg) {
// by returning the helper symbol via needRuntime
// the import will replaced a resovleDirective call.
if (!isInvalidType) {
- res.needRuntime = context.helper(directiveToUse)
+ baseResult.needRuntime = context.helper(directiveToUse)
}
} else {
context.onError(
)
}
}
- return res
+ return baseResult
}