Skip to content

Commit 08269b1

Browse files
authored
fix(language-core): avoid redundant increment of block variable depth (#5511)
1 parent 7be6d37 commit 08269b1

File tree

5 files changed

+29
-33
lines changed

5 files changed

+29
-33
lines changed

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

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type * as ts from 'typescript';
33
import type { Code, VueCodeInformation } from '../../types';
44
import { getNodeText, getStartEnd } from '../../utils/shared';
55
import type { ScriptCodegenOptions } from '../script';
6-
import { collectVars, createTsAst, identifierRegex } from '../utils';
6+
import { collectBindingNames, createTsAst, identifierRegex } from '../utils';
77
import type { TemplateCodegenContext } from './context';
88
import type { TemplateCodegenOptions } from './index';
99

@@ -126,7 +126,7 @@ function* forEachInterpolationSegment(
126126
});
127127
}
128128
};
129-
ts.forEachChild(ast, node => walkIdentifiers(ts, node, ast, varCb, ctx));
129+
ts.forEachChild(ast, node => walkIdentifiers(ts, node, ast, varCb, ctx, [], true));
130130
}
131131

132132
ctxVars = ctxVars.sort((a, b) => a.offset - b.offset);
@@ -198,8 +198,8 @@ function walkIdentifiers(
198198
ast: ts.SourceFile,
199199
cb: (varNode: ts.Identifier, isShorthand: boolean) => void,
200200
ctx: TemplateCodegenContext,
201-
blockVars: string[] = [],
202-
isRoot: boolean = true,
201+
blockVars: string[],
202+
isRoot: boolean = false,
203203
) {
204204
if (ts.isIdentifier(node)) {
205205
cb(node, false);
@@ -208,56 +208,57 @@ function walkIdentifiers(
208208
cb(node.name, true);
209209
}
210210
else if (ts.isPropertyAccessExpression(node)) {
211-
walkIdentifiers(ts, node.expression, ast, cb, ctx, blockVars, false);
211+
walkIdentifiers(ts, node.expression, ast, cb, ctx, blockVars);
212212
}
213213
else if (ts.isVariableDeclaration(node)) {
214-
collectVars(ts, node.name, ast, blockVars);
214+
const bindingNames = collectBindingNames(ts, node.name, ast);
215215

216-
for (const varName of blockVars) {
217-
ctx.addLocalVariable(varName);
216+
for (const name of bindingNames) {
217+
ctx.addLocalVariable(name);
218+
blockVars.push(name);
218219
}
219220

220221
if (node.initializer) {
221-
walkIdentifiers(ts, node.initializer, ast, cb, ctx, blockVars, false);
222+
walkIdentifiers(ts, node.initializer, ast, cb, ctx, blockVars);
222223
}
223224
}
224225
else if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
225-
processFunction(ts, node, ast, cb, ctx);
226+
walkIdentifiersInFunction(ts, node, ast, cb, ctx);
226227
}
227228
else if (ts.isObjectLiteralExpression(node)) {
228229
for (const prop of node.properties) {
229230
if (ts.isPropertyAssignment(prop)) {
230231
// fix https://github.com/vuejs/language-tools/issues/1176
231232
if (ts.isComputedPropertyName(prop.name)) {
232-
walkIdentifiers(ts, prop.name.expression, ast, cb, ctx, blockVars, false);
233+
walkIdentifiers(ts, prop.name.expression, ast, cb, ctx, blockVars);
233234
}
234-
walkIdentifiers(ts, prop.initializer, ast, cb, ctx, blockVars, false);
235+
walkIdentifiers(ts, prop.initializer, ast, cb, ctx, blockVars);
235236
}
236237
// fix https://github.com/vuejs/language-tools/issues/1156
237238
else if (ts.isShorthandPropertyAssignment(prop)) {
238-
walkIdentifiers(ts, prop, ast, cb, ctx, blockVars, false);
239+
walkIdentifiers(ts, prop, ast, cb, ctx, blockVars);
239240
}
240241
// fix https://github.com/vuejs/language-tools/issues/1148#issuecomment-1094378126
241242
else if (ts.isSpreadAssignment(prop)) {
242243
// TODO: cannot report "Spread types may only be created from object types.ts(2698)"
243-
walkIdentifiers(ts, prop.expression, ast, cb, ctx, blockVars, false);
244+
walkIdentifiers(ts, prop.expression, ast, cb, ctx, blockVars);
244245
}
245246
// fix https://github.com/vuejs/language-tools/issues/4604
246247
else if (ts.isFunctionLike(prop) && prop.body) {
247-
processFunction(ts, prop, ast, cb, ctx);
248+
walkIdentifiersInFunction(ts, prop, ast, cb, ctx);
248249
}
249250
}
250251
}
252+
// fix https://github.com/vuejs/language-tools/issues/1422
251253
else if (ts.isTypeNode(node)) {
252-
// fix https://github.com/vuejs/language-tools/issues/1422
253254
walkIdentifiersInTypeNode(ts, node, cb);
254255
}
255256
else {
256257
const _blockVars = blockVars;
257258
if (ts.isBlock(node)) {
258259
blockVars = [];
259260
}
260-
ts.forEachChild(node, node => walkIdentifiers(ts, node, ast, cb, ctx, blockVars, false));
261+
ts.forEachChild(node, node => walkIdentifiers(ts, node, ast, cb, ctx, blockVars));
261262
if (ts.isBlock(node)) {
262263
for (const varName of blockVars) {
263264
ctx.removeLocalVariable(varName);
@@ -273,7 +274,7 @@ function walkIdentifiers(
273274
}
274275
}
275276

276-
function processFunction(
277+
function walkIdentifiersInFunction(
277278
ts: typeof import('typescript'),
278279
node: ts.ArrowFunction | ts.FunctionExpression | ts.AccessorDeclaration | ts.MethodDeclaration,
279280
ast: ts.SourceFile,
@@ -282,16 +283,16 @@ function processFunction(
282283
) {
283284
const functionArgs: string[] = [];
284285
for (const param of node.parameters) {
285-
collectVars(ts, param.name, ast, functionArgs);
286+
functionArgs.push(...collectBindingNames(ts, param.name, ast));
286287
if (param.type) {
287-
walkIdentifiers(ts, param.type, ast, cb, ctx);
288+
walkIdentifiersInTypeNode(ts, param.type, cb);
288289
}
289290
}
290291
for (const varName of functionArgs) {
291292
ctx.addLocalVariable(varName);
292293
}
293294
if (node.body) {
294-
walkIdentifiers(ts, node.body, ast, cb, ctx);
295+
walkIdentifiers(ts, node.body, ast, cb, ctx, [], true);
295296
}
296297
for (const varName of functionArgs) {
297298
ctx.removeLocalVariable(varName);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as CompilerDOM from '@vue/compiler-dom';
22
import type { Code } from '../../types';
3-
import { collectVars, createTsAst, endOfLine, newLine } from '../utils';
3+
import { collectBindingNames, createTsAst, endOfLine, newLine } from '../utils';
44
import type { TemplateCodegenContext } from './context';
55
import { generateElementChildren } from './elementChildren';
66
import type { TemplateCodegenOptions } from './index';
@@ -18,7 +18,7 @@ export function* generateVFor(
1818
yield `for (const [`;
1919
if (leftExpressionRange && leftExpressionText) {
2020
const collectAst = createTsAst(options.ts, ctx.inlineTsAsts, `const [${leftExpressionText}]`);
21-
collectVars(options.ts, collectAst, collectAst, forBlockVars);
21+
forBlockVars.push(...collectBindingNames(options.ts, collectAst, collectAst));
2222
yield [
2323
leftExpressionText,
2424
'template',

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as CompilerDOM from '@vue/compiler-dom';
22
import type * as ts from 'typescript';
33
import type { Code } from '../../types';
44
import { getStartEnd } from '../../utils/shared';
5-
import { collectVars, createTsAst, endOfLine, newLine } from '../utils';
5+
import { collectBindingNames, createTsAst, endOfLine, newLine } from '../utils';
66
import { wrapWith } from '../utils/wrapWith';
77
import type { TemplateCodegenContext } from './context';
88
import { generateElementChildren } from './elementChildren';
@@ -64,7 +64,7 @@ export function* generateVSlot(
6464

6565
if (slotDir?.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
6666
const slotAst = createTsAst(options.ts, ctx.inlineTsAsts, `(${slotDir.exp.content}) => {}`);
67-
collectVars(options.ts, slotAst, slotAst, slotBlockVars);
67+
slotBlockVars.push(...collectBindingNames(options.ts, slotAst, slotAst));
6868
yield* generateSlotParameters(options, ctx, slotAst, slotDir.exp, slotVar);
6969
}
7070

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,12 @@ export const endOfLine = `;${newLine}`;
88
export const combineLastMapping: VueCodeInformation = { __combineOffset: 1 };
99
export const identifierRegex = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
1010

11-
export function collectVars(
11+
export function collectBindingNames(
1212
ts: typeof import('typescript'),
1313
node: ts.Node,
1414
ast: ts.SourceFile,
15-
results: string[] = [],
1615
) {
17-
const identifiers = collectIdentifiers(ts, node, []);
18-
for (const { id } of identifiers) {
19-
results.push(getNodeText(ts, id, ast));
20-
}
21-
return results;
16+
return collectIdentifiers(ts, node).map(({ id }) => getNodeText(ts, id, ast));
2217
}
2318

2419
export function collectIdentifiers(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ export function parseScriptSetupRanges(
236236
};
237237
if (ts.isVariableDeclaration(parent) && ts.isObjectBindingPattern(parent.name)) {
238238
defineProps.destructured = new Map();
239-
const identifiers = collectIdentifiers(ts, parent.name, []);
239+
const identifiers = collectIdentifiers(ts, parent.name);
240240
for (const { id, isRest, initializer } of identifiers) {
241241
const name = _getNodeText(id);
242242
if (isRest) {

0 commit comments

Comments
 (0)