Skip to content

Commit

Permalink
fix(language-core): correct type and completion support of vue: eve…
Browse files Browse the repository at this point in the history
…nt (#4969)

Co-authored-by: Johnson Chu <[email protected]>
  • Loading branch information
KazariEX and johnsoncodehk authored Dec 20, 2024
1 parent 44f1c28 commit 0a085fe
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 44 deletions.
72 changes: 31 additions & 41 deletions packages/language-core/lib/codegen/template/elementEvents.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as CompilerDOM from '@vue/compiler-dom';
import { camelize, capitalize } from '@vue/shared';
import type * as ts from 'typescript';
import type { Code, VueCodeInformation } from '../../types';
import { hyphenateAttr } from '../../utils/shared';
import type { Code } from '../../types';
import { combineLastMapping, createTsAst, endOfLine, newLine, variableNameRegex, wrapWith } from '../utils';
import { generateCamelized } from '../utils/camelized';
import type { TemplateCodegenContext } from './context';
Expand Down Expand Up @@ -32,9 +31,18 @@ export function* generateElementEvents(
propsVar = ctx.getInternalVariable();
yield `let ${propsVar}!: __VLS_FunctionalComponentProps<typeof ${componentVar}, typeof ${componentInstanceVar}>${endOfLine}`;
}
const originalPropName = camelize('on-' + prop.arg.loc.source);
yield `const ${ctx.getInternalVariable()}: __VLS_NormalizeComponentEvent<typeof ${propsVar}, typeof ${eventsVar}, '${originalPropName}', '${prop.arg.loc.source}', '${camelize(prop.arg.loc.source)}'> = {${newLine}`;
yield* generateEventArg(ctx, prop.arg, true);
let source = prop.arg.loc.source;
let start = prop.arg.loc.start.offset;
let propPrefix = 'on';
let emitPrefix = '';
if (source.startsWith('vue:')) {
source = source.slice('vue:'.length);
start = start + 'vue:'.length;
propPrefix = 'onVnode';
emitPrefix = 'vnode-';
}
yield `const ${ctx.getInternalVariable()}: __VLS_NormalizeComponentEvent<typeof ${propsVar}, typeof ${eventsVar}, '${camelize(propPrefix + '-' + source)}', '${emitPrefix}${source}', '${camelize(emitPrefix + source)}'> = {${newLine}`;
yield* generateEventArg(ctx, source, start, propPrefix);
yield `: `;
yield* generateEventExpression(options, ctx, prop);
yield `}${endOfLine}`;
Expand All @@ -43,54 +51,36 @@ export function* generateElementEvents(
return usedComponentEventsVar;
}

const eventArgFeatures: VueCodeInformation = {
navigation: {
// @click-outside -> onClickOutside
resolveRenameNewName(newName) {
return camelize('on-' + newName);
},
// onClickOutside -> @click-outside
resolveRenameEditText(newName) {
const hName = hyphenateAttr(newName);
if (hyphenateAttr(newName).startsWith('on-')) {
return camelize(hName.slice('on-'.length));
}
return newName;
},
},
};

export function* generateEventArg(
ctx: TemplateCodegenContext,
arg: CompilerDOM.SimpleExpressionNode,
enableHover: boolean
name: string,
start: number,
directive = 'on'
): Generator<Code> {
const features = enableHover
? {
...ctx.codeFeatures.withoutHighlightAndCompletion,
...eventArgFeatures,
}
: eventArgFeatures;
if (variableNameRegex.test(camelize(arg.loc.source))) {
yield ['', 'template', arg.loc.start.offset, features];
yield `on`;
const features = {
...ctx.codeFeatures.withoutHighlightAndCompletion,
...ctx.codeFeatures.navigationWithoutRename,
};
if (variableNameRegex.test(camelize(name))) {
yield ['', 'template', start, features];
yield directive;
yield* generateCamelized(
capitalize(arg.loc.source),
arg.loc.start.offset,
capitalize(name),
start,
combineLastMapping
);
}
else {
yield* wrapWith(
arg.loc.start.offset,
arg.loc.end.offset,
start,
start + name.length,
features,
`'`,
['', 'template', arg.loc.start.offset, combineLastMapping],
'on',
['', 'template', start, combineLastMapping],
directive,
...generateCamelized(
capitalize(arg.loc.source),
arg.loc.start.offset,
capitalize(name),
start,
combineLastMapping
),
`'`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function* generateElementProps(
) {
if (!isComponent) {
yield `...{ `;
yield* generateEventArg(ctx, prop.arg, true);
yield* generateEventArg(ctx, prop.arg.loc.source, prop.arg.loc.start.offset);
yield `: `;
yield* generateEventExpression(options, ctx, prop);
yield `},`;
Expand Down
8 changes: 6 additions & 2 deletions packages/language-service/lib/plugins/vue-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,11 @@ export function create(
}

const { attrs, propsInfo, events } = tagInfo;
const props = propsInfo.map(prop => prop.name);
const props = propsInfo.map(prop =>
hyphenateTag(prop.name).startsWith('on-vnode-')
? 'onVue:' + prop.name.slice('onVnode'.length)
: prop.name
);
const attributes: html.IAttributeData[] = [];
const _tsCodegen = tsCodegen.get(vueCode._sfc);

Expand Down Expand Up @@ -894,7 +898,7 @@ export function create(
}
else if (isEvent) {
item.kind = 23 satisfies typeof vscode.CompletionItemKind.Event;
if (propName.startsWith('vnode-')) {
if (propName.startsWith('vue:')) {
tokens.push('\u0004');
}
}
Expand Down

0 comments on commit 0a085fe

Please sign in to comment.