Skip to content

Commit 15f6feb

Browse files
authored
fix(language-core): generate slot parameters in the same way as interpolation (#5618)
1 parent 3bcdd35 commit 15f6feb

File tree

3 files changed

+71
-32
lines changed

3 files changed

+71
-32
lines changed

packages/language-core/lib/codegen/template/interpolation.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -214,14 +214,17 @@ function walkIdentifiers(
214214
}
215215
else if (ts.isVariableDeclaration(node)) {
216216
const bindingNames = collectBindingNames(ts, node.name, ast);
217-
218217
for (const name of bindingNames) {
219218
ctx.addLocalVariable(name);
220219
blockVars.push(name);
221220
}
222-
223-
if (node.initializer) {
224-
walkIdentifiers(ts, node.initializer, ast, cb, ctx, blockVars);
221+
walkIdentifiersInBinding(ts, node, ast, cb, ctx, blockVars);
222+
}
223+
else if (ts.isArrayBindingPattern(node) || ts.isObjectBindingPattern(node)) {
224+
for (const element of node.elements) {
225+
if (ts.isBindingElement(element)) {
226+
walkIdentifiersInBinding(ts, element, ast, cb, ctx, blockVars);
227+
}
225228
}
226229
}
227230
else if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
@@ -276,6 +279,25 @@ function walkIdentifiers(
276279
}
277280
}
278281

282+
function walkIdentifiersInBinding(
283+
ts: typeof import('typescript'),
284+
node: ts.BindingElement | ts.ParameterDeclaration | ts.VariableDeclaration,
285+
ast: ts.SourceFile,
286+
cb: (varNode: ts.Identifier, isShorthand: boolean) => void,
287+
ctx: TemplateCodegenContext,
288+
blockVars: string[],
289+
) {
290+
if ('type' in node && node.type) {
291+
walkIdentifiersInTypeNode(ts, node.type, cb);
292+
}
293+
if (!ts.isIdentifier(node.name)) {
294+
walkIdentifiers(ts, node.name, ast, cb, ctx, blockVars);
295+
}
296+
if (node.initializer) {
297+
walkIdentifiers(ts, node.initializer, ast, cb, ctx, blockVars);
298+
}
299+
}
300+
279301
function walkIdentifiersInFunction(
280302
ts: typeof import('typescript'),
281303
node: ts.ArrowFunction | ts.FunctionExpression | ts.AccessorDeclaration | ts.MethodDeclaration,
@@ -286,9 +308,7 @@ function walkIdentifiersInFunction(
286308
const functionArgs: string[] = [];
287309
for (const param of node.parameters) {
288310
functionArgs.push(...collectBindingNames(ts, param.name, ast));
289-
if (param.type) {
290-
walkIdentifiersInTypeNode(ts, param.type, cb);
291-
}
311+
walkIdentifiersInBinding(ts, param, ast, cb, ctx, functionArgs);
292312
}
293313
for (const varName of functionArgs) {
294314
ctx.addLocalVariable(varName);

packages/language-core/lib/codegen/template/vSlot.ts

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import * as CompilerDOM from '@vue/compiler-dom';
2+
import { replaceSourceRange } from 'muggle-string';
23
import type * as ts from 'typescript';
34
import type { Code } from '../../types';
45
import { collectBindingNames } from '../../utils/collectBindings';
5-
import { getStartEnd } from '../../utils/shared';
66
import { codeFeatures } from '../codeFeatures';
77
import { createTsAst, endOfLine, newLine } from '../utils';
88
import { wrapWith } from '../utils/wrapWith';
99
import type { TemplateCodegenContext } from './context';
1010
import { generateElementChildren } from './elementChildren';
1111
import type { TemplateCodegenOptions } from './index';
12+
import { generateInterpolation } from './interpolation';
1213
import { generateObjectProperty } from './objectProperty';
1314

1415
export function* generateVSlot(
@@ -67,7 +68,7 @@ export function* generateVSlot(
6768
if (slotDir?.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
6869
const slotAst = createTsAst(options.ts, ctx.inlineTsAsts, `(${slotDir.exp.content}) => {}`);
6970
slotBlockVars.push(...collectBindingNames(options.ts, slotAst, slotAst));
70-
yield* generateSlotParameters(options, slotAst, slotDir.exp, slotVar);
71+
yield* generateSlotParameters(options, ctx, slotAst, slotDir.exp, slotVar);
7172
}
7273

7374
for (const varName of slotBlockVars) {
@@ -107,6 +108,7 @@ export function* generateVSlot(
107108

108109
function* generateSlotParameters(
109110
options: TemplateCodegenOptions,
111+
ctx: TemplateCodegenContext,
110112
ast: ts.SourceFile,
111113
exp: CompilerDOM.SimpleExpressionNode,
112114
slotVar: string,
@@ -120,31 +122,42 @@ function* generateSlotParameters(
120122

121123
const { expression } = statement;
122124
const startOffset = exp.loc.start.offset - 1;
123-
const modifies: [Code[], number, number][] = [];
124125
const types: (Code | null)[] = [];
125126

127+
const interpolation = [...generateInterpolation(
128+
options,
129+
ctx,
130+
'template',
131+
codeFeatures.all,
132+
ast.text,
133+
startOffset,
134+
)];
135+
136+
replaceSourceRange(interpolation, 'template', startOffset, startOffset + `(`.length);
137+
replaceSourceRange(
138+
interpolation,
139+
'template',
140+
startOffset + ast.text.length - `) => {}`.length,
141+
startOffset + ast.text.length,
142+
);
143+
126144
for (const { name, type } of expression.parameters) {
127145
if (type) {
128-
modifies.push([
129-
[``],
130-
name.end,
131-
type.end,
146+
types.push([
147+
ast.text.slice(name.end, type.end),
148+
'template',
149+
startOffset + name.end,
150+
codeFeatures.all,
132151
]);
133-
types.push(chunk(getStartEnd(ts, type, ast).start, type.end));
152+
replaceSourceRange(interpolation, 'template', startOffset + name.end, startOffset + type.end);
134153
}
135154
else {
136155
types.push(null);
137156
}
138157
}
139158

140159
yield `const [`;
141-
let nextStart = 1;
142-
for (const [codes, start, end] of modifies) {
143-
yield chunk(nextStart, start);
144-
yield* codes;
145-
nextStart = end;
146-
}
147-
yield chunk(nextStart, expression.equalsGreaterThanToken.pos - 1);
160+
yield* interpolation;
148161
yield `] = __VLS_getSlotParameters(${slotVar}!`;
149162

150163
if (types.some(t => t)) {
@@ -154,18 +167,9 @@ function* generateSlotParameters(
154167
exp.loc.end.offset,
155168
codeFeatures.verification,
156169
`(`,
157-
...types.flatMap(type => type ? [`_: `, type, `, `] : `_, `),
170+
...types.flatMap(type => type ? [`_`, type, `, `] : `_, `),
158171
`) => [] as any`,
159172
);
160173
}
161174
yield `)${endOfLine}`;
162-
163-
function chunk(start: number, end: number): Code {
164-
return [
165-
ast.text.slice(start, end),
166-
'template',
167-
startOffset + start,
168-
codeFeatures.all,
169-
];
170-
}
171175
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue';
3+
4+
declare const Comp: (props: {}, ctx: { slots: {
5+
default: (props: { foo: number }) => void;
6+
} }) => {};
7+
8+
const bar = ref(0);
9+
</script>
10+
11+
<template>
12+
<Comp v-slot="{ foo = bar + 1 }">
13+
{{ foo }}
14+
</Comp>
15+
</template>

0 commit comments

Comments
 (0)