diff --git a/packages/language-core/lib/codegen/template/interpolation.ts b/packages/language-core/lib/codegen/template/interpolation.ts
index c097deeb4e..85f27813f3 100644
--- a/packages/language-core/lib/codegen/template/interpolation.ts
+++ b/packages/language-core/lib/codegen/template/interpolation.ts
@@ -214,14 +214,17 @@ function walkIdentifiers(
}
else if (ts.isVariableDeclaration(node)) {
const bindingNames = collectBindingNames(ts, node.name, ast);
-
for (const name of bindingNames) {
ctx.addLocalVariable(name);
blockVars.push(name);
}
-
- if (node.initializer) {
- walkIdentifiers(ts, node.initializer, ast, cb, ctx, blockVars);
+ walkIdentifiersInBinding(ts, node, ast, cb, ctx, blockVars);
+ }
+ else if (ts.isArrayBindingPattern(node) || ts.isObjectBindingPattern(node)) {
+ for (const element of node.elements) {
+ if (ts.isBindingElement(element)) {
+ walkIdentifiersInBinding(ts, element, ast, cb, ctx, blockVars);
+ }
}
}
else if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
@@ -276,6 +279,25 @@ function walkIdentifiers(
}
}
+function walkIdentifiersInBinding(
+ ts: typeof import('typescript'),
+ node: ts.BindingElement | ts.ParameterDeclaration | ts.VariableDeclaration,
+ ast: ts.SourceFile,
+ cb: (varNode: ts.Identifier, isShorthand: boolean) => void,
+ ctx: TemplateCodegenContext,
+ blockVars: string[],
+) {
+ if ('type' in node && node.type) {
+ walkIdentifiersInTypeNode(ts, node.type, cb);
+ }
+ if (!ts.isIdentifier(node.name)) {
+ walkIdentifiers(ts, node.name, ast, cb, ctx, blockVars);
+ }
+ if (node.initializer) {
+ walkIdentifiers(ts, node.initializer, ast, cb, ctx, blockVars);
+ }
+}
+
function walkIdentifiersInFunction(
ts: typeof import('typescript'),
node: ts.ArrowFunction | ts.FunctionExpression | ts.AccessorDeclaration | ts.MethodDeclaration,
@@ -286,9 +308,7 @@ function walkIdentifiersInFunction(
const functionArgs: string[] = [];
for (const param of node.parameters) {
functionArgs.push(...collectBindingNames(ts, param.name, ast));
- if (param.type) {
- walkIdentifiersInTypeNode(ts, param.type, cb);
- }
+ walkIdentifiersInBinding(ts, param, ast, cb, ctx, functionArgs);
}
for (const varName of functionArgs) {
ctx.addLocalVariable(varName);
diff --git a/packages/language-core/lib/codegen/template/vSlot.ts b/packages/language-core/lib/codegen/template/vSlot.ts
index 670ea9229c..f42ce04de7 100644
--- a/packages/language-core/lib/codegen/template/vSlot.ts
+++ b/packages/language-core/lib/codegen/template/vSlot.ts
@@ -1,14 +1,15 @@
import * as CompilerDOM from '@vue/compiler-dom';
+import { replaceSourceRange } from 'muggle-string';
import type * as ts from 'typescript';
import type { Code } from '../../types';
import { collectBindingNames } from '../../utils/collectBindings';
-import { getStartEnd } from '../../utils/shared';
import { codeFeatures } from '../codeFeatures';
import { createTsAst, endOfLine, newLine } from '../utils';
import { wrapWith } from '../utils/wrapWith';
import type { TemplateCodegenContext } from './context';
import { generateElementChildren } from './elementChildren';
import type { TemplateCodegenOptions } from './index';
+import { generateInterpolation } from './interpolation';
import { generateObjectProperty } from './objectProperty';
export function* generateVSlot(
@@ -67,7 +68,7 @@ export function* generateVSlot(
if (slotDir?.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
const slotAst = createTsAst(options.ts, ctx.inlineTsAsts, `(${slotDir.exp.content}) => {}`);
slotBlockVars.push(...collectBindingNames(options.ts, slotAst, slotAst));
- yield* generateSlotParameters(options, slotAst, slotDir.exp, slotVar);
+ yield* generateSlotParameters(options, ctx, slotAst, slotDir.exp, slotVar);
}
for (const varName of slotBlockVars) {
@@ -107,6 +108,7 @@ export function* generateVSlot(
function* generateSlotParameters(
options: TemplateCodegenOptions,
+ ctx: TemplateCodegenContext,
ast: ts.SourceFile,
exp: CompilerDOM.SimpleExpressionNode,
slotVar: string,
@@ -120,17 +122,34 @@ function* generateSlotParameters(
const { expression } = statement;
const startOffset = exp.loc.start.offset - 1;
- const modifies: [Code[], number, number][] = [];
const types: (Code | null)[] = [];
+ const interpolation = [...generateInterpolation(
+ options,
+ ctx,
+ 'template',
+ codeFeatures.all,
+ ast.text,
+ startOffset,
+ )];
+
+ replaceSourceRange(interpolation, 'template', startOffset, startOffset + `(`.length);
+ replaceSourceRange(
+ interpolation,
+ 'template',
+ startOffset + ast.text.length - `) => {}`.length,
+ startOffset + ast.text.length,
+ );
+
for (const { name, type } of expression.parameters) {
if (type) {
- modifies.push([
- [``],
- name.end,
- type.end,
+ types.push([
+ ast.text.slice(name.end, type.end),
+ 'template',
+ startOffset + name.end,
+ codeFeatures.all,
]);
- types.push(chunk(getStartEnd(ts, type, ast).start, type.end));
+ replaceSourceRange(interpolation, 'template', startOffset + name.end, startOffset + type.end);
}
else {
types.push(null);
@@ -138,13 +157,7 @@ function* generateSlotParameters(
}
yield `const [`;
- let nextStart = 1;
- for (const [codes, start, end] of modifies) {
- yield chunk(nextStart, start);
- yield* codes;
- nextStart = end;
- }
- yield chunk(nextStart, expression.equalsGreaterThanToken.pos - 1);
+ yield* interpolation;
yield `] = __VLS_getSlotParameters(${slotVar}!`;
if (types.some(t => t)) {
@@ -154,18 +167,9 @@ function* generateSlotParameters(
exp.loc.end.offset,
codeFeatures.verification,
`(`,
- ...types.flatMap(type => type ? [`_: `, type, `, `] : `_, `),
+ ...types.flatMap(type => type ? [`_`, type, `, `] : `_, `),
`) => [] as any`,
);
}
yield `)${endOfLine}`;
-
- function chunk(start: number, end: number): Code {
- return [
- ast.text.slice(start, end),
- 'template',
- startOffset + start,
- codeFeatures.all,
- ];
- }
}
diff --git a/test-workspace/tsc/passedFixtures/vue3/#5617/main.vue b/test-workspace/tsc/passedFixtures/vue3/#5617/main.vue
new file mode 100644
index 0000000000..1c62995a57
--- /dev/null
+++ b/test-workspace/tsc/passedFixtures/vue3/#5617/main.vue
@@ -0,0 +1,15 @@
+
+
+
+
+ {{ foo }}
+
+