Skip to content

Commit a8b0a66

Browse files
author
Noam Kfir
committed
Extract js package functions to PackageReader and add js-specific module path to uri converter
1 parent c171546 commit a8b0a66

File tree

4 files changed

+129
-17
lines changed

4 files changed

+129
-17
lines changed

src/services/languages/javascript/languageExtractor.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ import { IMethodExtractor, ISpanExtractor } from '../extractors';
44
import { LanguageExtractor } from '../languageExtractor';
55
import { IMethodPositionSelector } from '../methodPositionSelector';
66
import { JSMethodPositionSelector } from './methodPositionSelector';
7-
import { IModulePathToUriConverter, LogicalModulePathToUriConverter, PhysicalModulePathToUriConverter } from '../modulePathToUriConverters';
7+
import { IModulePathToUriConverter } from '../modulePathToUriConverters';
88
import { JSMethodExtractor } from './methodExtractor';
99
import { JSSpanExtractor } from './spanExtractor';
10+
import { JSPackageReader } from './packageReader';
11+
import { JSPackageToUriConverter } from './modulePathToUriConverters';
1012

1113
export class JSLanguageExtractor extends LanguageExtractor
1214
{
15+
16+
private packageReader: JSPackageReader = new JSPackageReader();
1317
public requiredExtensionLoaded: boolean = false;
1418

1519
public get requiredExtensionId(): string {
@@ -22,7 +26,7 @@ export class JSLanguageExtractor extends LanguageExtractor
2226

2327
public get methodExtractors(): IMethodExtractor[] {
2428
return [
25-
new JSMethodExtractor()
29+
new JSMethodExtractor(this.packageReader),
2630
];
2731
}
2832

@@ -37,9 +41,9 @@ export class JSLanguageExtractor extends LanguageExtractor
3741
}
3842

3943
public async getModulePathToUriConverters(): Promise<IModulePathToUriConverter[]> {
44+
const packagesMap = await this.packageReader.loadPackagesMap();
4045
return [
41-
new LogicalModulePathToUriConverter(),
42-
new PhysicalModulePathToUriConverter(),
46+
new JSPackageToUriConverter(packagesMap),
4347
];
4448
}
4549
}

src/services/languages/javascript/methodExtractor.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import * as vscode from 'vscode';
22
import * as path from 'path';
33
import { DocumentSymbol } from 'vscode-languageclient';
44
import { IMethodExtractor, SymbolInfo } from '../extractors';
5-
import { Logger } from '../../logger';
65
import { Token, TokenType } from '../tokens';
76
import {
87
MethodSymbolInfoExtractor,
@@ -11,20 +10,23 @@ import {
1110
AnonymousExpressRequestHandlerSymbolInfoExtractor,
1211
VariableFunctionSymbolInfoExtractor,
1312
} from './symbolInfoExtractors';
13+
import { JSPackageReader } from './packageReader';
1414

1515
export class JSMethodExtractor implements IMethodExtractor {
1616

17+
constructor(
18+
private packageReader: JSPackageReader,
19+
) {
20+
}
21+
1722
public async extractMethods(document: vscode.TextDocument, docSymbols: DocumentSymbol[], tokens: Token[]): Promise<SymbolInfo[]> {
18-
const packages = await vscode.workspace.findFiles('**/package.json');
19-
const packageFile = packages.find(f => document.uri.fsPath.startsWith(path.dirname(f.fsPath)));
23+
const packageFile = await this.packageReader.findPackage(document.uri);
2024
if (!packageFile) {
21-
Logger.warn(`Could not resolve package file for '${document.uri.path}'`);
2225
return [];
2326
}
2427

25-
let packageName = await this.getPackageName(packageFile);
26-
if (packageName === undefined || packageName === "") {
27-
Logger.warn(`Could not find package name in '${packageFile.path}'`);
28+
let packageName = await this.packageReader.getPackageName(packageFile);
29+
if (packageName === undefined) {
2830
return [];
2931
}
3032

@@ -46,12 +48,6 @@ export class JSMethodExtractor implements IMethodExtractor {
4648
return this.extractFunctions(document, codeObjectPath, '', docSymbols, tokens);
4749
}
4850

49-
private async getPackageName(packageFile: vscode.Uri): Promise<string | undefined> {
50-
const modDocument = await vscode.workspace.openTextDocument(packageFile);
51-
const pkgjson = JSON.parse(modDocument.getText());
52-
return pkgjson.name;
53-
}
54-
5551
private extractFunctions(document: vscode.TextDocument, codeObjectPath: string, parentSymbolPath: string, symbols: DocumentSymbol[], tokens: Token[]): SymbolInfo[] {
5652
const symbolInfos: SymbolInfo[] = [];
5753

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { dirname, join } from 'path';
2+
import * as vscode from 'vscode';
3+
import { IModulePathToUriConverter, ModulePathInfo } from '../modulePathToUriConverters';
4+
5+
export class JSPackageToUriConverter implements IModulePathToUriConverter {
6+
7+
private codeObjectIdParser = new JSCodeObjectIdParser();
8+
9+
constructor(
10+
private packagesMap: Map<string, vscode.Uri>,
11+
) {
12+
}
13+
14+
async convert(pathInfo: ModulePathInfo): Promise<vscode.Uri | undefined> {
15+
const { codeObjectId, modulePhysicalPath } = pathInfo;
16+
if(codeObjectId && modulePhysicalPath) {
17+
const info = this.codeObjectIdParser.parse(codeObjectId);
18+
const { packageName } = info;
19+
const packageUri = this.packagesMap.get(packageName);
20+
if(packageUri) {
21+
const basePath = dirname(packageUri.fsPath);
22+
const path = join(basePath, modulePhysicalPath);
23+
const uri = vscode.Uri.file(path);
24+
return uri;
25+
}
26+
}
27+
}
28+
}
29+
30+
interface JSCodeObjectInfo {
31+
packageName: string
32+
modulePath: string
33+
symbol: string
34+
}
35+
36+
class JSCodeObjectIdParser {
37+
parse(codeObjectId: string): JSCodeObjectInfo {
38+
const pattern = /([\w\@/-]+):(?:.)+\$_\$(?:.)*/;
39+
const matches = codeObjectId.match(pattern);
40+
if(matches) {
41+
const [ , packageName, modulePath, symbol ] = matches;
42+
return {
43+
packageName,
44+
modulePath,
45+
symbol,
46+
};
47+
}
48+
49+
return {
50+
packageName: '',
51+
modulePath: '',
52+
symbol: '',
53+
};
54+
}
55+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import * as vscode from 'vscode';
2+
import { dirname } from 'path';
3+
import { Logger } from '../../logger';
4+
5+
type PackagesMap = Map<string, vscode.Uri>;
6+
7+
export class JSPackageReader {
8+
private packagesMap: PackagesMap = new Map<string, vscode.Uri>();
9+
10+
public async findAllPackagesInWorkspace() {
11+
const packages = await vscode.workspace.findFiles('**/package.json');
12+
return packages;
13+
}
14+
15+
public async findPackage(uri: vscode.Uri): Promise<vscode.Uri | undefined> {
16+
const packages = await this.findAllPackagesInWorkspace();
17+
const packageFile = packages.find(f => uri.fsPath.startsWith(dirname(f.fsPath)));
18+
if (!packageFile) {
19+
Logger.warn(`Could not resolve package file for '${uri.path}'`);
20+
return undefined;
21+
}
22+
return packageFile;
23+
}
24+
25+
public async getPackageName(packageFile: vscode.Uri): Promise<string | undefined> {
26+
const modDocument = await vscode.workspace.openTextDocument(packageFile);
27+
const pkgjson = JSON.parse(modDocument.getText());
28+
const packageName = pkgjson.name;
29+
if (packageName === undefined || packageName === '') {
30+
Logger.warn(`Could not find package name in '${packageFile.path}'`);
31+
return undefined;
32+
}
33+
return packageName;
34+
}
35+
36+
public async loadPackagesMap(force: boolean = false): Promise<PackagesMap> {
37+
if(force) {
38+
this.packagesMap.clear();
39+
}
40+
if(this.packagesMap.size === 0) {
41+
const packages = await this.findAllPackagesInWorkspace();
42+
for await (const packageFile of packages) {
43+
try {
44+
const packageName = await this.getPackageName(packageFile);
45+
if(packageName) {
46+
this.packagesMap.set(packageName, packageFile);
47+
}
48+
console.log(packageName, packageFile.fsPath);
49+
}
50+
catch(err) {
51+
console.error('failed to parse package name for', packageFile);
52+
}
53+
}
54+
}
55+
return this.packagesMap;
56+
}
57+
}

0 commit comments

Comments
 (0)