Skip to content

Commit 2bb9ce8

Browse files
committed
refactor(language-core): extract binding collectors
1 parent b930d3a commit 2bb9ce8

File tree

9 files changed

+62
-96
lines changed

9 files changed

+62
-96
lines changed

packages/language-core/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
export * from './lib/codegen/globalTypes';
22
export * from './lib/codegen/template';
3-
export * from './lib/codegen/utils';
43
export * from './lib/languagePlugin';
54
export * from './lib/parsers/scriptSetupRanges';
65
export * from './lib/plugins';
76
export * from './lib/types';
7+
export * from './lib/utils/collectBindings';
88
export * from './lib/utils/parseSfc';
99
export * from './lib/utils/shared';
1010
export * from './lib/utils/ts';

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { isGloballyAllowed, makeMap } from '@vue/shared';
22
import type * as ts from 'typescript';
33
import type { Code, VueCodeInformation } from '../../types';
4+
import { collectBindingNames } from '../../utils/collectBindings';
45
import { getNodeText, getStartEnd } from '../../utils/shared';
56
import type { ScriptCodegenOptions } from '../script';
6-
import { collectBindingNames, createTsAst, identifierRegex } from '../utils';
7+
import { createTsAst, identifierRegex } from '../utils';
78
import type { TemplateCodegenContext } from './context';
89
import type { TemplateCodegenOptions } from './index';
910

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as CompilerDOM from '@vue/compiler-dom';
22
import type { Code } from '../../types';
3-
import { collectBindingNames, createTsAst, endOfLine, newLine } from '../utils';
3+
import { collectBindingNames } from '../../utils/collectBindings';
4+
import { createTsAst, endOfLine, newLine } from '../utils';
45
import type { TemplateCodegenContext } from './context';
56
import { generateElementChildren } from './elementChildren';
67
import type { TemplateCodegenOptions } from './index';

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import * as CompilerDOM from '@vue/compiler-dom';
22
import type * as ts from 'typescript';
33
import type { Code } from '../../types';
4+
import { collectBindingNames } from '../../utils/collectBindings';
45
import { getStartEnd } from '../../utils/shared';
5-
import { collectBindingNames, createTsAst, endOfLine, newLine } from '../utils';
6+
import { createTsAst, endOfLine, newLine } from '../utils';
67
import { wrapWith } from '../utils/wrapWith';
78
import type { TemplateCodegenContext } from './context';
89
import { generateElementChildren } from './elementChildren';

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

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,12 @@
11
import type * as CompilerDOM from '@vue/compiler-dom';
22
import type * as ts from 'typescript';
33
import type { Code, SfcBlock, VueCodeInformation } from '../../types';
4-
import { getNodeText } from '../../utils/shared';
54

65
export const newLine = `\n`;
76
export const endOfLine = `;${newLine}`;
87
export const combineLastMapping: VueCodeInformation = { __combineOffset: 1 };
98
export const identifierRegex = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
109

11-
export function collectBindingNames(
12-
ts: typeof import('typescript'),
13-
node: ts.Node,
14-
ast: ts.SourceFile,
15-
) {
16-
return collectIdentifiers(ts, node).map(({ id }) => getNodeText(ts, id, ast));
17-
}
18-
19-
export function collectIdentifiers(
20-
ts: typeof import('typescript'),
21-
node: ts.Node,
22-
results: {
23-
id: ts.Identifier;
24-
isRest: boolean;
25-
initializer: ts.Expression | undefined;
26-
}[] = [],
27-
isRest = false,
28-
initializer: ts.Expression | undefined = undefined,
29-
) {
30-
if (ts.isIdentifier(node)) {
31-
results.push({ id: node, isRest, initializer });
32-
}
33-
else if (ts.isObjectBindingPattern(node)) {
34-
for (const el of node.elements) {
35-
collectIdentifiers(ts, el.name, results, !!el.dotDotDotToken, el.initializer);
36-
}
37-
}
38-
else if (ts.isArrayBindingPattern(node)) {
39-
for (const el of node.elements) {
40-
if (ts.isBindingElement(el)) {
41-
collectIdentifiers(ts, el.name, results, !!el.dotDotDotToken);
42-
}
43-
}
44-
}
45-
else {
46-
ts.forEachChild(node, node => collectIdentifiers(ts, node, results, false));
47-
}
48-
return results;
49-
}
50-
5110
export function normalizeAttributeValue(node: CompilerDOM.TextNode): [string, number] {
5211
let offset = node.loc.start.offset;
5312
let content = node.loc.source;

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

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type * as ts from 'typescript';
2-
import { collectIdentifiers } from '../codegen/utils';
32
import type { TextRange, VueCompilerOptions } from '../types';
3+
import { collectBindingIdentifiers, collectBindingRanges } from '../utils/collectBindings';
44
import { getNodeText, getStartEnd } from '../utils/shared';
55

66
const tsCheckReg = /^\/\/\s*@ts-(?:no)?check($|\s)/;
@@ -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 = collectBindingIdentifiers(ts, parent.name);
240240
for (const { id, isRest, initializer } of identifiers) {
241241
const name = _getNodeText(id);
242242
if (isRest) {
@@ -374,8 +374,8 @@ export function parseBindingRanges(ts: typeof import('typescript'), ast: ts.Sour
374374
ts.forEachChild(ast, node => {
375375
if (ts.isVariableStatement(node)) {
376376
for (const decl of node.declarationList.declarations) {
377-
const vars = _findBindingVars(decl.name);
378-
bindings.push(...vars.map(range => ({ range })));
377+
const ranges = collectBindingRanges(ts, decl.name, ast);
378+
bindings.push(...ranges.map(range => ({ range })));
379379
}
380380
}
381381
else if (ts.isFunctionDeclaration(node)) {
@@ -445,47 +445,6 @@ export function parseBindingRanges(ts: typeof import('typescript'), ast: ts.Sour
445445
function _getNodeText(node: ts.Node) {
446446
return getNodeText(ts, node, ast);
447447
}
448-
449-
function _findBindingVars(left: ts.BindingName) {
450-
return findBindingVars(ts, left, ast);
451-
}
452-
}
453-
454-
export function findBindingVars(
455-
ts: typeof import('typescript'),
456-
left: ts.BindingName,
457-
ast: ts.SourceFile,
458-
) {
459-
const vars: TextRange[] = [];
460-
worker(left);
461-
return vars;
462-
function worker(node: ts.Node) {
463-
if (ts.isIdentifier(node)) {
464-
vars.push(getStartEnd(ts, node, ast));
465-
}
466-
// { ? } = ...
467-
// [ ? ] = ...
468-
else if (ts.isObjectBindingPattern(node) || ts.isArrayBindingPattern(node)) {
469-
for (const property of node.elements) {
470-
if (ts.isBindingElement(property)) {
471-
worker(property.name);
472-
}
473-
}
474-
}
475-
// { foo: ? } = ...
476-
else if (ts.isPropertyAssignment(node)) {
477-
worker(node.initializer);
478-
}
479-
// { foo } = ...
480-
else if (ts.isShorthandPropertyAssignment(node)) {
481-
vars.push(getStartEnd(ts, node.name, ast));
482-
}
483-
// { ...? } = ...
484-
// [ ...? ] = ...
485-
else if (ts.isSpreadAssignment(node) || ts.isSpreadElement(node)) {
486-
worker(node.expression);
487-
}
488-
}
489448
}
490449

491450
function getStatementRange(
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type * as ts from 'typescript';
2+
import { getNodeText, getStartEnd } from './shared';
3+
4+
export function collectBindingNames(
5+
ts: typeof import('typescript'),
6+
node: ts.Node,
7+
ast: ts.SourceFile,
8+
) {
9+
return collectBindingIdentifiers(ts, node).map(({ id }) => getNodeText(ts, id, ast));
10+
}
11+
12+
export function collectBindingRanges(
13+
ts: typeof import('typescript'),
14+
node: ts.Node,
15+
ast: ts.SourceFile,
16+
) {
17+
return collectBindingIdentifiers(ts, node).map(({ id }) => getStartEnd(ts, id, ast));
18+
}
19+
20+
export function collectBindingIdentifiers(
21+
ts: typeof import('typescript'),
22+
node: ts.Node,
23+
results: {
24+
id: ts.Identifier;
25+
isRest: boolean;
26+
initializer: ts.Expression | undefined;
27+
}[] = [],
28+
isRest = false,
29+
initializer: ts.Expression | undefined = undefined,
30+
) {
31+
if (ts.isIdentifier(node)) {
32+
results.push({ id: node, isRest, initializer });
33+
}
34+
else if (ts.isArrayBindingPattern(node) || ts.isObjectBindingPattern(node)) {
35+
for (const el of node.elements) {
36+
if (ts.isBindingElement(el)) {
37+
collectBindingIdentifiers(ts, el.name, results, !!el.dotDotDotToken, el.initializer);
38+
}
39+
}
40+
}
41+
else {
42+
ts.forEachChild(node, node => collectBindingIdentifiers(ts, node, results, false));
43+
}
44+
return results;
45+
}

packages/language-server/lib/reactivityAnalyze.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { findBindingVars, hyphenateAttr, type TextRange } from '@vue/language-core';
1+
import { collectBindingRanges, hyphenateAttr, type TextRange } from '@vue/language-core';
22
import type * as ts from 'typescript';
33

44
const enum TrackKind {
@@ -164,8 +164,8 @@ export function analyze(
164164
}
165165

166166
function findSubscribers(refName: ts.BindingName, trackKinds: TrackKind[], visited = new Set<number>()) {
167-
return findBindingVars(ts, refName, sourceFile)
168-
.map(binding => findSubscribersWorker(binding, trackKinds, visited))
167+
return collectBindingRanges(ts, refName, sourceFile)
168+
.map(range => findSubscribersWorker(range, trackKinds, visited))
169169
.flat();
170170
}
171171

packages/language-service/lib/plugins/vue-inlayhints.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { InlayHint, InlayHintKind, LanguageServicePlugin } from '@volar/language-service';
2-
import { collectIdentifiers, tsCodegen, VueVirtualCode } from '@vue/language-core';
2+
import { collectBindingIdentifiers, tsCodegen, VueVirtualCode } from '@vue/language-core';
33
import type * as ts from 'typescript';
44
import { URI } from 'vscode-uri';
55

@@ -198,7 +198,7 @@ export function findDestructuredProps(
198198
&& ts.isCallExpression(initializer)
199199
&& initializer.expression.getText(ast) === 'defineProps';
200200

201-
for (const { id } of collectIdentifiers(ts, name)) {
201+
for (const { id } of collectBindingIdentifiers(ts, name)) {
202202
if (isDefineProps) {
203203
excludedIds.add(id);
204204
}
@@ -215,7 +215,7 @@ export function findDestructuredProps(
215215
}
216216

217217
for (const p of parameters) {
218-
for (const { id } of collectIdentifiers(ts, p)) {
218+
for (const { id } of collectBindingIdentifiers(ts, p)) {
219219
registerLocalBinding(id);
220220
}
221221
}

0 commit comments

Comments
 (0)