diff --git a/packages/language-core/lib/codegen/template/elementEvents.ts b/packages/language-core/lib/codegen/template/elementEvents.ts index 7e2455bbb7..2a7348045c 100644 --- a/packages/language-core/lib/codegen/template/elementEvents.ts +++ b/packages/language-core/lib/codegen/template/elementEvents.ts @@ -20,13 +20,17 @@ export function* generateElementEvents( let emitVar: string | undefined; let eventsVar: string | undefined; let propsVar: string | undefined; + for (const prop of node.props) { if ( prop.type === CompilerDOM.NodeTypes.DIRECTIVE - && prop.name === 'on' - && prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION - && !prop.arg.loc.source.startsWith('[') - && !prop.arg.loc.source.endsWith(']') + && ( + prop.name === 'model' + || prop.name === 'on' + && prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION + && !prop.arg.loc.source.startsWith('[') + && !prop.arg.loc.source.endsWith(']') + ) ) { ctx.currentComponent!.used = true; if (!emitVar) { @@ -37,21 +41,33 @@ export function* generateElementEvents( yield `let ${eventsVar}!: __VLS_NormalizeEmits${endOfLine}`; yield `let ${propsVar}!: __VLS_FunctionalComponentProps${endOfLine}`; } - let source = prop.arg.loc.source; - let start = prop.arg.loc.start.offset; - let propPrefix = 'on'; + + let source = prop.arg?.loc.source ?? 'model-value'; + let start = prop.arg?.loc.start.offset; + let propPrefix = 'on-'; let emitPrefix = ''; - if (source.startsWith('vue:')) { + if (prop.name === 'model') { + propPrefix = 'onUpdate:'; + emitPrefix = 'update:'; + } + else if (source.startsWith('vue:')) { source = source.slice('vue:'.length); - start = start + 'vue:'.length; - propPrefix = 'onVnode'; + start = start! + 'vue:'.length; + propPrefix = 'onVnode-'; emitPrefix = 'vnode-'; } - yield `const ${ctx.getInternalVariable()}: __VLS_NormalizeComponentEvent = {${newLine}`; - yield* generateEventArg(ctx, source, start, propPrefix); - yield `: `; - yield* generateEventExpression(options, ctx, prop); - yield `}${endOfLine}`; + + yield `(): __VLS_NormalizeComponentEvent => ({${newLine}`; + if (prop.name === 'on') { + yield* generateEventArg(ctx, source, start!, propPrefix.slice(0, -1)); + yield `: `; + yield* generateEventExpression(options, ctx, prop); + } + else { + yield `'${camelize(propPrefix + source)}': `; + yield* generateModelEventExpression(options, ctx, prop); + } + yield `})${endOfLine}`; } } } @@ -159,6 +175,29 @@ export function* generateEventExpression( } } +export function* generateModelEventExpression( + options: TemplateCodegenOptions, + ctx: TemplateCodegenContext, + prop: CompilerDOM.DirectiveNode +): Generator { + if (prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) { + yield `(...[$event]) => (`; + yield* generateInterpolation( + options, + ctx, + 'template', + ctx.codeFeatures.verification, + prop.exp.content, + prop.exp.loc.start.offset, + prop.exp.loc + ) + yield ` = $event)`; + } + else { + yield `() => {}`; + } +} + export function isCompoundExpression(ts: typeof import('typescript'), ast: ts.SourceFile) { let result = true; if (ast.statements.length === 0) { diff --git a/test-workspace/tsc/passedFixtures/vue3/#4646/child.vue b/test-workspace/tsc/passedFixtures/vue3/#4646/child.vue index c5d5b5c1b4..3383be25ec 100644 --- a/test-workspace/tsc/passedFixtures/vue3/#4646/child.vue +++ b/test-workspace/tsc/passedFixtures/vue3/#4646/child.vue @@ -1,13 +1,15 @@ - - + + diff --git a/test-workspace/tsc/passedFixtures/vue3/#4646/child2.vue b/test-workspace/tsc/passedFixtures/vue3/#4646/child2.vue index 3c9de244f0..481e6ca147 100644 --- a/test-workspace/tsc/passedFixtures/vue3/#4646/child2.vue +++ b/test-workspace/tsc/passedFixtures/vue3/#4646/child2.vue @@ -1,5 +1,7 @@ - - + + diff --git a/test-workspace/tsc/passedFixtures/vue3/#4646/parent.vue b/test-workspace/tsc/passedFixtures/vue3/#4646/parent.vue index 162862da20..38b59cfc7d 100644 --- a/test-workspace/tsc/passedFixtures/vue3/#4646/parent.vue +++ b/test-workspace/tsc/passedFixtures/vue3/#4646/parent.vue @@ -1,15 +1,16 @@ - + + diff --git a/test-workspace/tsc/passedFixtures/vue3/#4822/main.vue b/test-workspace/tsc/passedFixtures/vue3/#4822/main.vue index c6f1e69582..2b77561b60 100644 --- a/test-workspace/tsc/passedFixtures/vue3/#4822/main.vue +++ b/test-workspace/tsc/passedFixtures/vue3/#4822/main.vue @@ -11,7 +11,7 @@ export default defineComponent({