@fairfox/polly 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -741,15 +741,37 @@ class RelationshipExtractor {
|
|
|
741
741
|
const expr = descendant.getExpression();
|
|
742
742
|
if (Node.isIdentifier(expr)) {
|
|
743
743
|
const functionName = expr.getText();
|
|
744
|
-
|
|
744
|
+
let functionDecl = sourceFile.getFunction(functionName);
|
|
745
|
+
let targetSourceFile = sourceFile;
|
|
746
|
+
if (!functionDecl) {
|
|
747
|
+
const resolved = this.resolveImportedFunction(functionName, sourceFile);
|
|
748
|
+
if (resolved) {
|
|
749
|
+
functionDecl = resolved.functionDecl;
|
|
750
|
+
targetSourceFile = resolved.sourceFile;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
745
753
|
if (functionDecl && !visited.has(functionName)) {
|
|
746
754
|
visited.add(functionName);
|
|
747
755
|
const body = functionDecl.getBody();
|
|
748
756
|
if (body) {
|
|
749
|
-
this.extractFromNode(body,
|
|
757
|
+
this.extractFromNode(body, targetSourceFile, handlerName, relationships, visited);
|
|
750
758
|
}
|
|
751
759
|
return;
|
|
752
760
|
}
|
|
761
|
+
if (!functionDecl) {
|
|
762
|
+
const componentFromName = this.inferComponentFromFunctionName(functionName);
|
|
763
|
+
if (componentFromName) {
|
|
764
|
+
relationships.push({
|
|
765
|
+
from: this.toComponentId(handlerName),
|
|
766
|
+
to: componentFromName,
|
|
767
|
+
description: `Calls ${functionName}()`,
|
|
768
|
+
technology: "Function Call",
|
|
769
|
+
confidence: "medium",
|
|
770
|
+
evidence: [`Function call: ${functionName}`]
|
|
771
|
+
});
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
753
775
|
}
|
|
754
776
|
if (Node.isPropertyAccessExpression(expr)) {
|
|
755
777
|
const rel2 = this.extractFromPropertyAccess(expr, handlerName);
|
|
@@ -829,9 +851,12 @@ class RelationshipExtractor {
|
|
|
829
851
|
return null;
|
|
830
852
|
}
|
|
831
853
|
const fullChain = propAccess.getText();
|
|
832
|
-
const objectExpr = propAccess.getExpression();
|
|
833
|
-
const objectName = objectExpr.getText();
|
|
834
854
|
const methodName = propAccess.getName();
|
|
855
|
+
let rootObject = propAccess.getExpression();
|
|
856
|
+
while (Node.isPropertyAccessExpression(rootObject)) {
|
|
857
|
+
rootObject = rootObject.getExpression();
|
|
858
|
+
}
|
|
859
|
+
const objectName = rootObject.getText();
|
|
835
860
|
const targetComponent = this.inferComponentFromCall(objectName, methodName);
|
|
836
861
|
if (!targetComponent) {
|
|
837
862
|
return null;
|
|
@@ -894,6 +919,7 @@ class RelationshipExtractor {
|
|
|
894
919
|
database: "database",
|
|
895
920
|
repos: "repositories",
|
|
896
921
|
repository: "repositories",
|
|
922
|
+
repositories: "repositories",
|
|
897
923
|
cache: "cache",
|
|
898
924
|
storage: "storage",
|
|
899
925
|
ai: "ai_service",
|
|
@@ -907,6 +933,49 @@ class RelationshipExtractor {
|
|
|
907
933
|
const normalized = objectName.toLowerCase();
|
|
908
934
|
return mappings[normalized] || null;
|
|
909
935
|
}
|
|
936
|
+
inferComponentFromFunctionName(functionName) {
|
|
937
|
+
const normalized = functionName.toLowerCase();
|
|
938
|
+
if (normalized.startsWith("get") || normalized.startsWith("create")) {
|
|
939
|
+
const suffix = functionName.substring(normalized.startsWith("get") ? 3 : 6);
|
|
940
|
+
const suffixLower = suffix.toLowerCase();
|
|
941
|
+
if (suffixLower.includes("database") || suffixLower === "db" || suffixLower.includes("dbconnection") || suffixLower.includes("connection")) {
|
|
942
|
+
return "db_client";
|
|
943
|
+
}
|
|
944
|
+
if (suffixLower.includes("repositories") || suffixLower.includes("repos") || suffixLower.includes("repository")) {
|
|
945
|
+
return "repositories";
|
|
946
|
+
}
|
|
947
|
+
if (suffixLower.includes("service")) {
|
|
948
|
+
const serviceMatch = suffix.match(/^(.+?)Service/i);
|
|
949
|
+
if (serviceMatch) {
|
|
950
|
+
return this.toComponentId(`${serviceMatch[1]}_service`);
|
|
951
|
+
}
|
|
952
|
+
return "service";
|
|
953
|
+
}
|
|
954
|
+
if (suffixLower.includes("cache")) {
|
|
955
|
+
return "cache";
|
|
956
|
+
}
|
|
957
|
+
if (suffixLower.includes("storage")) {
|
|
958
|
+
return "storage";
|
|
959
|
+
}
|
|
960
|
+
if (suffixLower.includes("ai") || suffixLower.includes("llm")) {
|
|
961
|
+
return "ai_service";
|
|
962
|
+
}
|
|
963
|
+
if (suffixLower.includes("logger")) {
|
|
964
|
+
return "logger";
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
if (normalized.startsWith("init") || normalized.startsWith("setup")) {
|
|
968
|
+
const suffix = functionName.substring(normalized.startsWith("init") ? 4 : 5);
|
|
969
|
+
const suffixLower = suffix.toLowerCase();
|
|
970
|
+
if (suffixLower.includes("database") || suffixLower === "db") {
|
|
971
|
+
return "db_client";
|
|
972
|
+
}
|
|
973
|
+
if (suffixLower.includes("cache")) {
|
|
974
|
+
return "cache";
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
return null;
|
|
978
|
+
}
|
|
910
979
|
resolveComponentFromImport(functionName, sourceFile) {
|
|
911
980
|
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
912
981
|
const namedImports = importDecl.getNamedImports();
|
|
@@ -930,6 +999,40 @@ class RelationshipExtractor {
|
|
|
930
999
|
}
|
|
931
1000
|
return null;
|
|
932
1001
|
}
|
|
1002
|
+
resolveImportedFunction(functionName, sourceFile) {
|
|
1003
|
+
try {
|
|
1004
|
+
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
1005
|
+
const namedImports = importDecl.getNamedImports();
|
|
1006
|
+
for (const namedImport of namedImports) {
|
|
1007
|
+
if (namedImport.getName() === functionName) {
|
|
1008
|
+
const moduleSpecifier = importDecl.getModuleSpecifierSourceFile();
|
|
1009
|
+
if (!moduleSpecifier)
|
|
1010
|
+
continue;
|
|
1011
|
+
const functionDecl = moduleSpecifier.getFunction(functionName);
|
|
1012
|
+
if (functionDecl) {
|
|
1013
|
+
return {
|
|
1014
|
+
functionDecl,
|
|
1015
|
+
sourceFile: moduleSpecifier
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
const variableDecl = moduleSpecifier.getVariableDeclaration(functionName);
|
|
1019
|
+
if (variableDecl) {
|
|
1020
|
+
const initializer = variableDecl.getInitializer();
|
|
1021
|
+
if (initializer && (Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer))) {
|
|
1022
|
+
return {
|
|
1023
|
+
functionDecl: initializer,
|
|
1024
|
+
sourceFile: moduleSpecifier
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
} catch (error) {
|
|
1032
|
+
return null;
|
|
1033
|
+
}
|
|
1034
|
+
return null;
|
|
1035
|
+
}
|
|
933
1036
|
inferDatabaseOperation(callExpr) {
|
|
934
1037
|
if (callExpr.includes("query") || callExpr.includes("select")) {
|
|
935
1038
|
return "Reads from database";
|
|
@@ -2640,4 +2743,4 @@ Stack trace:`, COLORS.gray));
|
|
|
2640
2743
|
process.exit(1);
|
|
2641
2744
|
});
|
|
2642
2745
|
|
|
2643
|
-
//# debugId=
|
|
2746
|
+
//# debugId=C40ED4F55177D0FC64756E2164756E21
|