@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
- const functionDecl = sourceFile.getFunction(functionName);
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, sourceFile, handlerName, relationships, visited);
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=F2D5F1DF2FB1D52164756E2164756E21
2746
+ //# debugId=C40ED4F55177D0FC64756E2164756E21