Skip to content

Commit 583a843

Browse files
committed
Optimize
1 parent af0b037 commit 583a843

3 files changed

Lines changed: 69 additions & 53 deletions

File tree

src/analyzer.ts

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,16 @@ interface NamedRange {
3939
range: DecorationSegment
4040
}
4141

42+
interface LocalComponent {
43+
kind: Exclude<ComponentKind, 'unknown'>
44+
range: DecorationSegment
45+
}
46+
4247
interface FileAnalysis {
4348
exportReferences: NamedRange[]
44-
importReferences: NamedRange[]
45-
imports: Map<string, string>
49+
imports: Map<string, { range: DecorationSegment; source: string }>
4650
jsxTags: JsxTagReference[]
47-
localComponentDeclarations: NamedRange[]
48-
localComponentKinds: Map<string, Exclude<ComponentKind, 'unknown'>>
51+
localComponents: Map<string, LocalComponent>
4952
ownComponentKind: Exclude<ComponentKind, 'unknown'>
5053
typeIdentifiers: TypeIdentifier[]
5154
}
@@ -106,15 +109,18 @@ export class ComponentLensAnalyzer {
106109
if (scope.element || scope.import) {
107110
const uniqueFilePaths = new Set<string>()
108111

109-
for (const [lookupName, source] of analysis.imports) {
112+
for (const [lookupName, entry] of analysis.imports) {
110113
if (
111-
analysis.localComponentKinds.has(lookupName) ||
114+
analysis.localComponents.has(lookupName) ||
112115
resolvedPaths.has(lookupName)
113116
) {
114117
continue
115118
}
116119

117-
const resolvedFilePath = this.resolver.resolveImport(filePath, source)
120+
const resolvedFilePath = this.resolver.resolveImport(
121+
filePath,
122+
entry.source,
123+
)
118124
if (resolvedFilePath) {
119125
resolvedPaths.set(lookupName, resolvedFilePath)
120126
uniqueFilePaths.add(resolvedFilePath)
@@ -132,11 +138,10 @@ export class ComponentLensAnalyzer {
132138

133139
if (scope.element) {
134140
for (const jsxTag of analysis.jsxTags) {
135-
if (analysis.localComponentKinds.has(jsxTag.lookupName)) {
141+
const localComponent = analysis.localComponents.get(jsxTag.lookupName)
142+
if (localComponent) {
136143
usages.push({
137-
kind:
138-
analysis.localComponentKinds.get(jsxTag.lookupName) ??
139-
analysis.ownComponentKind,
144+
kind: localComponent.kind,
140145
ranges: jsxTag.ranges,
141146
sourceFilePath: filePath,
142147
tagName: jsxTag.tagName,
@@ -164,8 +169,8 @@ export class ComponentLensAnalyzer {
164169
}
165170

166171
if (scope.import) {
167-
for (const ref of analysis.importReferences) {
168-
const resolvedFilePath = resolvedPaths.get(ref.name)
172+
for (const [name, entry] of analysis.imports) {
173+
const resolvedFilePath = resolvedPaths.get(name)
169174
if (!resolvedFilePath) {
170175
continue
171176
}
@@ -177,22 +182,20 @@ export class ComponentLensAnalyzer {
177182

178183
usages.push({
179184
kind: componentKind,
180-
ranges: [ref.range],
185+
ranges: [entry.range],
181186
sourceFilePath: resolvedFilePath,
182-
tagName: ref.name,
187+
tagName: name,
183188
})
184189
}
185190
}
186191

187192
if (scope.declaration) {
188-
for (const declaration of analysis.localComponentDeclarations) {
193+
for (const [name, component] of analysis.localComponents) {
189194
usages.push({
190-
kind:
191-
analysis.localComponentKinds.get(declaration.name) ??
192-
analysis.ownComponentKind,
193-
ranges: [declaration.range],
195+
kind: component.kind,
196+
ranges: [component.range],
194197
sourceFilePath: filePath,
195-
tagName: declaration.name,
198+
tagName: name,
196199
})
197200
}
198201
}
@@ -207,7 +210,7 @@ export class ComponentLensAnalyzer {
207210
for (const typeId of analysis.typeIdentifiers) {
208211
if (typeId.enclosingComponent) {
209212
const kind =
210-
analysis.localComponentKinds.get(typeId.enclosingComponent) ??
213+
analysis.localComponents.get(typeId.enclosingComponent)?.kind ??
211214
analysis.ownComponentKind
212215
if (!typeUsageKinds.has(typeId.name) || kind === 'client') {
213216
typeUsageKinds.set(typeId.name, kind)
@@ -307,13 +310,11 @@ function parseFileAnalysis(filePath: string, sourceText: string): FileAnalysis {
307310
const asyncComponents = new Set<string>()
308311
const componentRanges: { end: number; name: string; start: number }[] = []
309312
const exportReferences: NamedRange[] = []
310-
const importReferences: NamedRange[] = []
311-
const imports = new Map<string, string>()
312-
const localComponentDeclarations: NamedRange[] = []
313-
const localComponentKinds = new Map<
313+
const imports = new Map<
314314
string,
315-
Exclude<ComponentKind, 'unknown'>
315+
{ range: DecorationSegment; source: string }
316316
>()
317+
const localComponents = new Map<string, LocalComponent>()
317318
const typeIdentifiers: TypeIdentifier[] = []
318319
let ownComponentKind: Exclude<ComponentKind, 'unknown'> = 'server'
319320
let statementIndex = 0
@@ -328,8 +329,10 @@ function parseFileAnalysis(filePath: string, sourceText: string): FileAnalysis {
328329
nameNode: ts.Node,
329330
scopeNode: ts.Node,
330331
): void => {
331-
localComponentDeclarations.push({ name, range: nodeRange(nameNode) })
332-
localComponentKinds.set(name, ownComponentKind)
332+
localComponents.set(name, {
333+
kind: ownComponentKind,
334+
range: nodeRange(nameNode),
335+
})
333336
componentRanges.push({
334337
end: scopeNode.getEnd(),
335338
name,
@@ -339,8 +342,7 @@ function parseFileAnalysis(filePath: string, sourceText: string): FileAnalysis {
339342

340343
const hasAsyncModifier = (
341344
modifiers: ts.NodeArray<ts.ModifierLike> | undefined,
342-
): boolean =>
343-
modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) ?? false
345+
): boolean => modifiers?.some((m) => m.kind === ASYNC_KEYWORD) ?? false
344346

345347
for (; statementIndex < sourceFile.statements.length; statementIndex++) {
346348
const statement = sourceFile.statements[statementIndex]!
@@ -366,11 +368,10 @@ function parseFileAnalysis(filePath: string, sourceText: string): FileAnalysis {
366368
) {
367369
const source = statement.moduleSpecifier.text
368370
const addImport = (identifier: ts.Identifier): void => {
369-
imports.set(identifier.text, source)
370371
if (isComponentIdentifier(identifier.text)) {
371-
importReferences.push({
372-
name: identifier.text,
372+
imports.set(identifier.text, {
373373
range: nodeRange(identifier),
374+
source,
374375
})
375376
}
376377
}
@@ -493,23 +494,23 @@ function parseFileAnalysis(filePath: string, sourceText: string): FileAnalysis {
493494
sourceFile,
494495
componentRanges,
495496
typeIdentifiers,
496-
localComponentKinds,
497+
localComponents,
497498
asyncComponents,
498499
ownComponentKind === 'server',
499500
)
500501

501502
return {
502503
exportReferences,
503-
importReferences,
504504
imports,
505505
jsxTags,
506-
localComponentDeclarations,
507-
localComponentKinds,
506+
localComponents,
508507
ownComponentKind,
509508
typeIdentifiers,
510509
}
511510
}
512511

512+
const ASYNC_KEYWORD = ts.SyntaxKind.AsyncKeyword
513+
513514
const COMPONENT_WRAPPER_NAMES = new Set([
514515
'forwardRef',
515516
'memo',
@@ -584,7 +585,7 @@ function collectSourceElements(
584585
sourceFile: ts.SourceFile,
585586
componentRanges: { end: number; name: string; start: number }[],
586587
typeIdentifiers: TypeIdentifier[],
587-
localComponentKinds: Map<string, Exclude<ComponentKind, 'unknown'>>,
588+
localComponents: Map<string, LocalComponent>,
588589
asyncComponents: Set<string>,
589590
inferClientKind: boolean,
590591
): JsxTagReference[] {
@@ -595,11 +596,14 @@ function collectSourceElements(
595596
componentByStart.set(range.start, range)
596597
}
597598

598-
const perComponentFuncs = new Map<string, Map<string, boolean>>()
599-
const perComponentRefs = new Map<string, string[]>()
600-
const componentsWithInlineFn = new Set<string>()
599+
let perComponentFuncs: Map<string, Map<string, boolean>> | undefined
600+
let perComponentRefs: Map<string, string[]> | undefined
601+
let componentsWithInlineFn: Set<string> | undefined
601602

602603
if (inferClientKind) {
604+
perComponentFuncs = new Map()
605+
perComponentRefs = new Map()
606+
componentsWithInlineFn = new Set()
603607
for (const range of componentRanges) {
604608
if (!asyncComponents.has(range.name)) {
605609
perComponentFuncs.set(range.name, new Map())
@@ -647,8 +651,8 @@ function collectSourceElements(
647651

648652
if (
649653
currentComponent &&
650-
perComponentFuncs.has(currentComponent) &&
651-
!componentsWithInlineFn.has(currentComponent)
654+
perComponentFuncs?.has(currentComponent) &&
655+
!componentsWithInlineFn!.has(currentComponent)
652656
) {
653657
if (ts.isFunctionDeclaration(node) && node.name) {
654658
perComponentFuncs
@@ -676,9 +680,9 @@ function collectSourceElements(
676680
(ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) &&
677681
!hasUseServerDirective(expr)
678682
) {
679-
componentsWithInlineFn.add(currentComponent)
683+
componentsWithInlineFn!.add(currentComponent)
680684
} else if (ts.isIdentifier(expr)) {
681-
perComponentRefs.get(currentComponent)!.push(expr.text)
685+
perComponentRefs!.get(currentComponent)!.push(expr.text)
682686
}
683687
}
684688
}
@@ -691,14 +695,18 @@ function collectSourceElements(
691695
}
692696
ts.forEachChild(sourceFile, visit)
693697

698+
if (!perComponentFuncs) {
699+
return jsxTags
700+
}
701+
694702
for (const [name, funcs] of perComponentFuncs) {
695-
if (componentsWithInlineFn.has(name)) {
696-
localComponentKinds.set(name, 'client')
703+
if (componentsWithInlineFn!.has(name)) {
704+
localComponents.get(name)!.kind = 'client'
697705
continue
698706
}
699-
const refs = perComponentRefs.get(name)!
707+
const refs = perComponentRefs!.get(name)!
700708
if (refs.some((ref) => funcs.has(ref) && !funcs.get(ref))) {
701-
localComponentKinds.set(name, 'client')
709+
localComponents.get(name)!.kind = 'client'
702710
}
703711
}
704712

src/decorations.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,15 @@ export class LensDecorations implements vscode.Disposable {
3232
const hoverCache = new Map<string, vscode.MarkdownString>()
3333

3434
for (const usage of usages) {
35-
let hoverMessage = hoverCache.get(usage.sourceFilePath)
35+
const cacheKey = `${usage.kind}:${usage.sourceFilePath}`
36+
let hoverMessage = hoverCache.get(cacheKey)
3637
if (!hoverMessage) {
3738
const displayPath = toDisplayPath(editorDir, usage.sourceFilePath)
3839
const label = usage.kind === 'client' ? 'Client' : 'Server'
3940
hoverMessage = new vscode.MarkdownString(
4041
`${label} component from \`${displayPath}\``,
4142
)
42-
hoverCache.set(usage.sourceFilePath, hoverMessage)
43+
hoverCache.set(cacheKey, hoverMessage)
4344
}
4445

4546
const target =

src/extension.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,8 @@ class WorkspaceSourceHost implements SourceHost {
279279
}
280280

281281
private documentCache: Map<string, vscode.TextDocument> | undefined
282+
private lastFilePath = ''
283+
private lastNormalizedPath = ''
282284

283285
private getOpenDocument(filePath: string): vscode.TextDocument | undefined {
284286
if (!this.documentCache) {
@@ -287,7 +289,12 @@ class WorkspaceSourceHost implements SourceHost {
287289
this.documentCache.set(path.normalize(document.fileName), document)
288290
}
289291
}
290-
return this.documentCache.get(path.normalize(filePath))
292+
293+
if (filePath !== this.lastFilePath) {
294+
this.lastFilePath = filePath
295+
this.lastNormalizedPath = path.normalize(filePath)
296+
}
297+
return this.documentCache.get(this.lastNormalizedPath)
291298
}
292299
}
293300

0 commit comments

Comments
 (0)