Skip to content

Commit 79672ce

Browse files
committed
Dependency formatting
1 parent 8dfefd3 commit 79672ce

3 files changed

Lines changed: 184 additions & 0 deletions

File tree

src/languagePlugins/php/dependencyFormatting/index.test.ts

Whitespace-only changes.
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import type { PHPDependency, PHPDepFile, PHPDepSymbol } from "./types.ts";
2+
import type { ExportedSymbol } from "../exportResolver/types.ts";
3+
import { PHPRegistree } from "../registree/index.ts";
4+
import { PHPIncluseResolver } from "../incluseResolver/index.ts";
5+
import { PHPInvocationResolver } from "../invocationResolver/index.ts";
6+
import type { Invocations } from "../invocationResolver/types.ts";
7+
import type Parser from "tree-sitter";
8+
import type { PHPFile } from "../registree/types.ts";
9+
10+
export class PHPDependencyFormatter {
11+
registree: PHPRegistree;
12+
incluseResolver: PHPIncluseResolver;
13+
invocationResolver: PHPInvocationResolver;
14+
#registry: Map<string, PHPFile>;
15+
16+
constructor(
17+
files: Map<string, { path: string; rootNode: Parser.SyntaxNode }>,
18+
) {
19+
this.registree = new PHPRegistree(files);
20+
this.#registry = this.registree.registry.files;
21+
this.incluseResolver = new PHPIncluseResolver(
22+
this.registree,
23+
);
24+
this.invocationResolver = new PHPInvocationResolver(this.incluseResolver);
25+
}
26+
27+
/**
28+
* Formats the dependencies of a file.
29+
* @param fileDependencies - The dependencies of the file.
30+
* @returns A formatted record of dependencies.
31+
*/
32+
#formatDependencies(
33+
fileDependencies: Invocations,
34+
): Record<string, PHPDependency> {
35+
const dependencies: Record<string, PHPDependency> = {};
36+
const resolved = fileDependencies.resolved;
37+
for (const [symName, symbol] of resolved) {
38+
const filepaths = symbol.map((s) => s.filepath);
39+
const id = symName;
40+
for (const filepath of filepaths) {
41+
if (!dependencies[filepath]) {
42+
dependencies[filepath] = {
43+
id: filepath,
44+
isExternal: false,
45+
symbols: {},
46+
};
47+
}
48+
dependencies[filepath].symbols[id] = id;
49+
}
50+
}
51+
return dependencies;
52+
}
53+
54+
#formatStandardIncludes(
55+
stdincludes: string[],
56+
): Record<string, PHPDependency> {
57+
const dependencies: Record<string, PHPDependency> = {};
58+
for (const id of stdincludes) {
59+
if (!dependencies[id]) {
60+
dependencies[id] = {
61+
id: id,
62+
isExternal: true,
63+
symbols: {},
64+
};
65+
}
66+
}
67+
return dependencies;
68+
}
69+
70+
/**
71+
* Formats the symbols of a file.
72+
* @param fileSymbols - The symbols of the file.
73+
* @returns A formatted record of symbols.
74+
*/
75+
#formatSymbols(
76+
fileSymbols: Map<string, ExportedSymbol[]>,
77+
): Record<string, PHPDepSymbol> {
78+
const symbols: Record<string, PHPDepSymbol> = {};
79+
for (const [symName, symbol] of fileSymbols) {
80+
const id = symName;
81+
const symbolData = symbol[0];
82+
const lineCount = symbol.map((s) =>
83+
s.node.endPosition.row - s.node.startPosition.row
84+
).reduce((sum, current) => sum + current, 0);
85+
const characterCount = symbol.map((s) =>
86+
s.node.endIndex - s.node.startIndex
87+
).reduce((sum, current) => sum + current, 0);
88+
const dependencies = this.invocationResolver.getInvocationsForNode(
89+
symbolData.node,
90+
symbolData.filepath,
91+
symbolData.name,
92+
);
93+
if (!symbols[id]) {
94+
symbols[id] = {
95+
id: id,
96+
type: symbolData.type,
97+
lineCount,
98+
characterCount,
99+
node: symbolData.node, // Wonky
100+
dependents: {},
101+
dependencies: this.#formatDependencies(dependencies),
102+
};
103+
}
104+
}
105+
return symbols;
106+
}
107+
108+
formatFile(filepath: string): PHPDepFile {
109+
const file = this.#registry.get(filepath);
110+
if (!file) {
111+
throw new Error(`File not found: ${filepath}`);
112+
}
113+
const fileSymbols = file.symbols;
114+
const fileDependencies = this.invocationResolver.getInvocationsForFile(
115+
filepath,
116+
);
117+
const includes = this.incluseResolver.resolveImports(file);
118+
if (!includes) {
119+
throw new Error(`File not found: ${filepath}`);
120+
}
121+
const stdincludes = Array.from(includes.unresolved.paths);
122+
const invokedDependencies = this.#formatDependencies(fileDependencies);
123+
const stdDependencies = this.#formatStandardIncludes(stdincludes);
124+
const allDependencies = {
125+
...invokedDependencies,
126+
...stdDependencies,
127+
};
128+
const formattedFile: PHPDepFile = {
129+
id: filepath,
130+
filePath: file.path,
131+
rootNode: file.rootNode,
132+
lineCount: file.rootNode.endPosition.row,
133+
characterCount: file.rootNode.endIndex,
134+
dependencies: allDependencies,
135+
symbols: this.#formatSymbols(fileSymbols),
136+
};
137+
return formattedFile;
138+
}
139+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type Parser from "tree-sitter";
2+
import type { SymbolType } from "../exportResolver/types.ts";
3+
4+
/**
5+
* Represents a dependency in a PHP file
6+
*/
7+
export interface PHPDependency {
8+
id: string;
9+
isExternal: boolean;
10+
symbols: Record<string, string>;
11+
}
12+
13+
/**
14+
* Represents a dependent in a PHP file
15+
*/
16+
export interface PHPDependent {
17+
id: string;
18+
symbols: Record<string, string>;
19+
}
20+
21+
/**
22+
* Represents a symbol in a PHP file
23+
*/
24+
export interface PHPDepSymbol {
25+
id: string;
26+
type: SymbolType;
27+
lineCount: number;
28+
characterCount: number;
29+
node: Parser.SyntaxNode;
30+
dependents: Record<string, PHPDependent>;
31+
dependencies: Record<string, PHPDependency>;
32+
}
33+
34+
/**
35+
* Represents a PHP file with its dependencies and symbols.
36+
*/
37+
export interface PHPDepFile {
38+
id: string;
39+
filePath: string;
40+
rootNode: Parser.SyntaxNode;
41+
lineCount: number;
42+
characterCount: number;
43+
dependencies: Record<string, PHPDependency>;
44+
symbols: Record<string, PHPDepSymbol>;
45+
}

0 commit comments

Comments
 (0)