Skip to content

Commit adfa3f8

Browse files
authored
fix(language-core): use return values of useSlots and useAttrs directly in the template (#5185)
1 parent 938a11a commit adfa3f8

File tree

3 files changed

+93
-55
lines changed

3 files changed

+93
-55
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export interface TemplateCodegenOptions {
2121
hasDefineSlots?: boolean;
2222
slotsAssignName?: string;
2323
propsAssignName?: string;
24+
slotsReferenceNames: Set<string>;
25+
attrsReferenceNames: Set<string>;
2426
inheritAttrs: boolean;
2527
selfComponentName?: string;
2628
}
@@ -34,6 +36,12 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator<Co
3436
if (options.propsAssignName) {
3537
ctx.addLocalVariable(options.propsAssignName);
3638
}
39+
for (const name of options.slotsReferenceNames) {
40+
ctx.addLocalVariable(name);
41+
}
42+
for (const name of options.attrsReferenceNames) {
43+
ctx.addLocalVariable(name);
44+
}
3745
const slotsPropertyName = getSlotsPropertyName(options.vueCompilerOptions.target);
3846
ctx.specialVars.add(slotsPropertyName);
3947
ctx.specialVars.add('$attrs');

packages/language-core/lib/parsers/scriptSetupRanges.ts

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,15 @@ type DefineOptions = {
5454
inheritAttrs?: string;
5555
};
5656

57-
type UseAttrs = CallExpressionRange;
57+
type UseAttrs = CallExpressionRange & {
58+
name?: string;
59+
};
5860

5961
type UseCssModule = CallExpressionRange;
6062

61-
type UseSlots = CallExpressionRange;
63+
type UseSlots = CallExpressionRange & {
64+
name?: string;
65+
};
6266

6367
type UseTemplateRef = CallExpressionRange & {
6468
name?: string;
@@ -284,26 +288,21 @@ export function parseScriptSetupRanges(
284288
}
285289
else if (vueCompilerOptions.macros.defineProps.includes(callText)) {
286290
defineProps = {
287-
...parseCallExpression(node),
291+
...parseCallExpressionAssignment(node, parent),
288292
statement: getStatementRange(ts, parents, node, ast),
289293
argNode: node.arguments[0]
290294
};
291-
if (ts.isVariableDeclaration(parent)) {
292-
if (ts.isObjectBindingPattern(parent.name)) {
293-
defineProps.destructured = new Map();
294-
const identifiers = collectIdentifiers(ts, parent.name, []);
295-
for (const { id, isRest, initializer } of identifiers) {
296-
const name = _getNodeText(id);
297-
if (isRest) {
298-
defineProps.destructuredRest = name;
299-
}
300-
else {
301-
defineProps.destructured.set(name, initializer);
302-
}
295+
if (ts.isVariableDeclaration(parent) && ts.isObjectBindingPattern(parent.name)) {
296+
defineProps.destructured = new Map();
297+
const identifiers = collectIdentifiers(ts, parent.name, []);
298+
for (const { id, isRest, initializer } of identifiers) {
299+
const name = _getNodeText(id);
300+
if (isRest) {
301+
defineProps.destructuredRest = name;
302+
}
303+
else {
304+
defineProps.destructured.set(name, initializer);
303305
}
304-
}
305-
else {
306-
defineProps.name = _getNodeText(parent.name);
307306
}
308307
}
309308
else if (
@@ -327,12 +326,9 @@ export function parseScriptSetupRanges(
327326
}
328327
else if (vueCompilerOptions.macros.defineEmits.includes(callText)) {
329328
defineEmits = {
330-
...parseCallExpression(node),
329+
...parseCallExpressionAssignment(node, parent),
331330
statement: getStatementRange(ts, parents, node, ast)
332331
};
333-
if (ts.isVariableDeclaration(parent)) {
334-
defineEmits.name = _getNodeText(parent.name);
335-
}
336332
if (node.typeArguments?.length && ts.isTypeLiteralNode(node.typeArguments[0])) {
337333
for (const member of node.typeArguments[0].members) {
338334
if (ts.isCallSignatureDeclaration(member)) {
@@ -347,12 +343,9 @@ export function parseScriptSetupRanges(
347343
}
348344
else if (vueCompilerOptions.macros.defineSlots.includes(callText)) {
349345
defineSlots = {
350-
...parseCallExpression(node),
346+
...parseCallExpressionAssignment(node, parent),
351347
statement: getStatementRange(ts, parents, node, ast)
352348
};
353-
if (ts.isVariableDeclaration(parent)) {
354-
defineSlots.name = _getNodeText(parent.name);
355-
}
356349
}
357350
else if (vueCompilerOptions.macros.defineExpose.includes(callText)) {
358351
defineExpose = parseCallExpression(node);
@@ -377,22 +370,19 @@ export function parseScriptSetupRanges(
377370
}
378371
}
379372
else if (vueCompilerOptions.composables.useAttrs.includes(callText)) {
380-
useAttrs.push(parseCallExpression(node));
373+
useAttrs.push(parseCallExpressionAssignment(node, parent));
381374
}
382375
else if (vueCompilerOptions.composables.useCssModule.includes(callText)) {
383376
useCssModule.push(parseCallExpression(node));
384377
}
385378
else if (vueCompilerOptions.composables.useSlots.includes(callText)) {
386-
useSlots.push(parseCallExpression(node));
379+
useSlots.push(parseCallExpressionAssignment(node, parent));
387380
}
388381
else if (
389382
vueCompilerOptions.composables.useTemplateRef.includes(callText)
390383
&& !node.typeArguments?.length
391384
) {
392-
useTemplateRef.push({
393-
name: ts.isVariableDeclaration(parent) ? _getNodeText(parent.name) : undefined,
394-
...parseCallExpression(node)
395-
});
385+
useTemplateRef.push(parseCallExpressionAssignment(node, parent));
396386
}
397387
}
398388

@@ -415,6 +405,13 @@ export function parseScriptSetupRanges(
415405
};
416406
}
417407

408+
function parseCallExpressionAssignment(node: ts.CallExpression, parent: ts.Node) {
409+
return {
410+
name: ts.isVariableDeclaration(parent) ? _getNodeText(parent.name) : undefined,
411+
...parseCallExpression(node),
412+
};
413+
}
414+
418415
function _getStartEnd(node: ts.Node) {
419416
return getStartEnd(ts, node, ast);
420417
}

packages/language-core/lib/plugins/vue-tsx.ts

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,67 +69,74 @@ export default plugin;
6969

7070
function createTsx(
7171
fileName: string,
72-
_sfc: Sfc,
72+
sfc: Sfc,
7373
ctx: Parameters<VueLanguagePlugin>[0],
7474
appendGlobalTypes: boolean
7575
) {
7676
const ts = ctx.modules.typescript;
77+
7778
const getLang = computed(() => {
78-
return !_sfc.script && !_sfc.scriptSetup ? 'ts'
79-
: _sfc.scriptSetup && _sfc.scriptSetup.lang !== 'js' ? _sfc.scriptSetup.lang
80-
: _sfc.script && _sfc.script.lang !== 'js' ? _sfc.script.lang
79+
return !sfc.script && !sfc.scriptSetup ? 'ts'
80+
: sfc.scriptSetup && sfc.scriptSetup.lang !== 'js' ? sfc.scriptSetup.lang
81+
: sfc.script && sfc.script.lang !== 'js' ? sfc.script.lang
8182
: 'js';
8283
});
84+
8385
const getResolvedOptions = computed(() => {
84-
const options = parseVueCompilerOptions(_sfc.comments);
86+
const options = parseVueCompilerOptions(sfc.comments);
8587
if (options) {
8688
const resolver = new CompilerOptionsResolver();
8789
resolver.addConfig(options, path.dirname(fileName));
8890
return resolver.build(ctx.vueCompilerOptions);
8991
}
9092
return ctx.vueCompilerOptions;
9193
});
94+
9295
const getScriptRanges = computed(() =>
93-
_sfc.script
94-
? parseScriptRanges(ts, _sfc.script.ast, !!_sfc.scriptSetup, false)
96+
sfc.script
97+
? parseScriptRanges(ts, sfc.script.ast, !!sfc.scriptSetup, false)
9598
: undefined
9699
);
100+
97101
const getScriptSetupRanges = computed(() =>
98-
_sfc.scriptSetup
99-
? parseScriptSetupRanges(ts, _sfc.scriptSetup.ast, getResolvedOptions())
102+
sfc.scriptSetup
103+
? parseScriptSetupRanges(ts, sfc.scriptSetup.ast, getResolvedOptions())
100104
: undefined
101105
);
106+
102107
const getSetupBindingNames = computedSet(
103108
computed(() => {
104109
const newNames = new Set<string>();
105110
const bindings = getScriptSetupRanges()?.bindings;
106-
if (_sfc.scriptSetup && bindings) {
111+
if (sfc.scriptSetup && bindings) {
107112
for (const { range } of bindings) {
108-
newNames.add(_sfc.scriptSetup.content.slice(range.start, range.end));
113+
newNames.add(sfc.scriptSetup.content.slice(range.start, range.end));
109114
}
110115
}
111116
return newNames;
112117
})
113118
);
119+
114120
const getSetupImportComponentNames = computedSet(
115121
computed(() => {
116122
const newNames = new Set<string>();
117123
const bindings = getScriptSetupRanges()?.bindings;
118-
if (_sfc.scriptSetup && bindings) {
124+
if (sfc.scriptSetup && bindings) {
119125
for (const { range, moduleName, isDefaultImport, isNamespace } of bindings) {
120126
if (
121127
moduleName
122128
&& isDefaultImport
123129
&& !isNamespace
124130
&& ctx.vueCompilerOptions.extensions.some(ext => moduleName.endsWith(ext))
125131
) {
126-
newNames.add(_sfc.scriptSetup.content.slice(range.start, range.end));
132+
newNames.add(sfc.scriptSetup.content.slice(range.start, range.end));
127133
}
128134
}
129135
}
130136
return newNames;
131137
})
132138
);
139+
133140
const getSetupDestructuredPropNames = computedSet(
134141
computed(() => {
135142
const newNames = new Set(getScriptSetupRanges()?.defineProps?.destructured?.keys());
@@ -140,6 +147,7 @@ function createTsx(
140147
return newNames;
141148
})
142149
);
150+
143151
const getSetupTemplateRefNames = computedSet(
144152
computed(() => {
145153
const newNames = new Set(
@@ -150,29 +158,52 @@ function createTsx(
150158
return newNames;
151159
})
152160
);
161+
153162
const setupHasDefineSlots = computed(() => !!getScriptSetupRanges()?.defineSlots);
163+
154164
const getSetupSlotsAssignName = computed(() => getScriptSetupRanges()?.defineSlots?.name);
165+
155166
const getSetupPropsAssignName = computed(() => getScriptSetupRanges()?.defineProps?.name);
167+
156168
const getSetupInheritAttrs = computed(() => {
157169
const value = getScriptSetupRanges()?.defineOptions?.inheritAttrs ?? getScriptRanges()?.exportDefault?.inheritAttrsOption;
158170
return value !== 'false';
159171
});
172+
173+
const getSetupSlotsReferenceName = computedSet(
174+
computed(() => {
175+
const newNames = new Set(
176+
getScriptSetupRanges()?.useSlots.map(({ name }) => name).filter(name => name !== undefined)
177+
);
178+
return newNames;
179+
})
180+
);
181+
182+
const getSetupAttrsReferenceName = computedSet(
183+
computed(() => {
184+
const newNames = new Set(
185+
getScriptSetupRanges()?.useAttrs.map(({ name }) => name).filter(name => name !== undefined)
186+
);
187+
return newNames;
188+
})
189+
);
190+
160191
const getComponentSelfName = computed(() => {
161192
const { exportDefault } = getScriptRanges() ?? {};
162-
if (_sfc.script && exportDefault?.nameOption) {
193+
if (sfc.script && exportDefault?.nameOption) {
163194
const { nameOption } = exportDefault;
164-
return _sfc.script.content.slice(nameOption.start + 1, nameOption.end - 1);
195+
return sfc.script.content.slice(nameOption.start + 1, nameOption.end - 1);
165196
}
166197
const { defineOptions } = getScriptSetupRanges() ?? {};
167-
if (_sfc.scriptSetup && defineOptions?.name) {
198+
if (sfc.scriptSetup && defineOptions?.name) {
168199
return defineOptions.name;
169200
}
170201
const baseName = path.basename(fileName);
171202
return capitalize(camelize(baseName.slice(0, baseName.lastIndexOf('.'))));
172203
});
173-
const getGeneratedTemplate = computed(() => {
174204

175-
if (getResolvedOptions().skipTemplateCodegen || !_sfc.template) {
205+
const getGeneratedTemplate = computed(() => {
206+
if (getResolvedOptions().skipTemplateCodegen || !sfc.template) {
176207
return;
177208
}
178209

@@ -181,7 +212,7 @@ function createTsx(
181212
ts,
182213
compilerOptions: ctx.compilerOptions,
183214
vueCompilerOptions: getResolvedOptions(),
184-
template: _sfc.template,
215+
template: sfc.template,
185216
edited: getResolvedOptions().__test || (fileEditTimes.get(fileName) ?? 0) >= 2,
186217
scriptSetupBindingNames: getSetupBindingNames(),
187218
scriptSetupImportComponentNames: getSetupImportComponentNames(),
@@ -190,12 +221,13 @@ function createTsx(
190221
hasDefineSlots: setupHasDefineSlots(),
191222
slotsAssignName: getSetupSlotsAssignName(),
192223
propsAssignName: getSetupPropsAssignName(),
224+
slotsReferenceNames: getSetupSlotsReferenceName(),
225+
attrsReferenceNames: getSetupAttrsReferenceName(),
193226
inheritAttrs: getSetupInheritAttrs(),
194227
selfComponentName: getComponentSelfName(),
195228
});
196229

197230
let current = codegen.next();
198-
199231
while (!current.done) {
200232
const code = current.value;
201233
codes.push(code);
@@ -207,15 +239,17 @@ function createTsx(
207239
codes,
208240
};
209241
});
242+
210243
const getGeneratedScript = computed(() => {
211-
const codes: Code[] = [];
212244
const linkedCodeMappings: Mapping[] = [];
213245
let generatedLength = 0;
246+
247+
const codes: Code[] = [];
214248
const codegen = generateScript({
215249
ts,
216250
compilerOptions: ctx.compilerOptions,
217251
vueCompilerOptions: getResolvedOptions(),
218-
sfc: _sfc,
252+
sfc: sfc,
219253
edited: getResolvedOptions().__test || (fileEditTimes.get(fileName) ?? 0) >= 2,
220254
fileName,
221255
lang: getLang(),
@@ -231,7 +265,6 @@ function createTsx(
231265
fileEditTimes.set(fileName, (fileEditTimes.get(fileName) ?? 0) + 1);
232266

233267
let current = codegen.next();
234-
235268
while (!current.done) {
236269
const code = current.value;
237270
codes.push(code);

0 commit comments

Comments
 (0)