@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.
@@ -1332,15 +1332,37 @@ class RelationshipExtractor {
1332
1332
  const expr = descendant.getExpression();
1333
1333
  if (Node4.isIdentifier(expr)) {
1334
1334
  const functionName = expr.getText();
1335
- const functionDecl = sourceFile.getFunction(functionName);
1335
+ let functionDecl = sourceFile.getFunction(functionName);
1336
+ let targetSourceFile = sourceFile;
1337
+ if (!functionDecl) {
1338
+ const resolved = this.resolveImportedFunction(functionName, sourceFile);
1339
+ if (resolved) {
1340
+ functionDecl = resolved.functionDecl;
1341
+ targetSourceFile = resolved.sourceFile;
1342
+ }
1343
+ }
1336
1344
  if (functionDecl && !visited.has(functionName)) {
1337
1345
  visited.add(functionName);
1338
1346
  const body = functionDecl.getBody();
1339
1347
  if (body) {
1340
- this.extractFromNode(body, sourceFile, handlerName, relationships, visited);
1348
+ this.extractFromNode(body, targetSourceFile, handlerName, relationships, visited);
1341
1349
  }
1342
1350
  return;
1343
1351
  }
1352
+ if (!functionDecl) {
1353
+ const componentFromName = this.inferComponentFromFunctionName(functionName);
1354
+ if (componentFromName) {
1355
+ relationships.push({
1356
+ from: this.toComponentId(handlerName),
1357
+ to: componentFromName,
1358
+ description: `Calls ${functionName}()`,
1359
+ technology: "Function Call",
1360
+ confidence: "medium",
1361
+ evidence: [`Function call: ${functionName}`]
1362
+ });
1363
+ return;
1364
+ }
1365
+ }
1344
1366
  }
1345
1367
  if (Node4.isPropertyAccessExpression(expr)) {
1346
1368
  const rel2 = this.extractFromPropertyAccess(expr, handlerName);
@@ -1420,9 +1442,12 @@ class RelationshipExtractor {
1420
1442
  return null;
1421
1443
  }
1422
1444
  const fullChain = propAccess.getText();
1423
- const objectExpr = propAccess.getExpression();
1424
- const objectName = objectExpr.getText();
1425
1445
  const methodName = propAccess.getName();
1446
+ let rootObject = propAccess.getExpression();
1447
+ while (Node4.isPropertyAccessExpression(rootObject)) {
1448
+ rootObject = rootObject.getExpression();
1449
+ }
1450
+ const objectName = rootObject.getText();
1426
1451
  const targetComponent = this.inferComponentFromCall(objectName, methodName);
1427
1452
  if (!targetComponent) {
1428
1453
  return null;
@@ -1485,6 +1510,7 @@ class RelationshipExtractor {
1485
1510
  database: "database",
1486
1511
  repos: "repositories",
1487
1512
  repository: "repositories",
1513
+ repositories: "repositories",
1488
1514
  cache: "cache",
1489
1515
  storage: "storage",
1490
1516
  ai: "ai_service",
@@ -1498,6 +1524,49 @@ class RelationshipExtractor {
1498
1524
  const normalized = objectName.toLowerCase();
1499
1525
  return mappings[normalized] || null;
1500
1526
  }
1527
+ inferComponentFromFunctionName(functionName) {
1528
+ const normalized = functionName.toLowerCase();
1529
+ if (normalized.startsWith("get") || normalized.startsWith("create")) {
1530
+ const suffix = functionName.substring(normalized.startsWith("get") ? 3 : 6);
1531
+ const suffixLower = suffix.toLowerCase();
1532
+ if (suffixLower.includes("database") || suffixLower === "db" || suffixLower.includes("dbconnection") || suffixLower.includes("connection")) {
1533
+ return "db_client";
1534
+ }
1535
+ if (suffixLower.includes("repositories") || suffixLower.includes("repos") || suffixLower.includes("repository")) {
1536
+ return "repositories";
1537
+ }
1538
+ if (suffixLower.includes("service")) {
1539
+ const serviceMatch = suffix.match(/^(.+?)Service/i);
1540
+ if (serviceMatch) {
1541
+ return this.toComponentId(`${serviceMatch[1]}_service`);
1542
+ }
1543
+ return "service";
1544
+ }
1545
+ if (suffixLower.includes("cache")) {
1546
+ return "cache";
1547
+ }
1548
+ if (suffixLower.includes("storage")) {
1549
+ return "storage";
1550
+ }
1551
+ if (suffixLower.includes("ai") || suffixLower.includes("llm")) {
1552
+ return "ai_service";
1553
+ }
1554
+ if (suffixLower.includes("logger")) {
1555
+ return "logger";
1556
+ }
1557
+ }
1558
+ if (normalized.startsWith("init") || normalized.startsWith("setup")) {
1559
+ const suffix = functionName.substring(normalized.startsWith("init") ? 4 : 5);
1560
+ const suffixLower = suffix.toLowerCase();
1561
+ if (suffixLower.includes("database") || suffixLower === "db") {
1562
+ return "db_client";
1563
+ }
1564
+ if (suffixLower.includes("cache")) {
1565
+ return "cache";
1566
+ }
1567
+ }
1568
+ return null;
1569
+ }
1501
1570
  resolveComponentFromImport(functionName, sourceFile) {
1502
1571
  for (const importDecl of sourceFile.getImportDeclarations()) {
1503
1572
  const namedImports = importDecl.getNamedImports();
@@ -1521,6 +1590,40 @@ class RelationshipExtractor {
1521
1590
  }
1522
1591
  return null;
1523
1592
  }
1593
+ resolveImportedFunction(functionName, sourceFile) {
1594
+ try {
1595
+ for (const importDecl of sourceFile.getImportDeclarations()) {
1596
+ const namedImports = importDecl.getNamedImports();
1597
+ for (const namedImport of namedImports) {
1598
+ if (namedImport.getName() === functionName) {
1599
+ const moduleSpecifier = importDecl.getModuleSpecifierSourceFile();
1600
+ if (!moduleSpecifier)
1601
+ continue;
1602
+ const functionDecl = moduleSpecifier.getFunction(functionName);
1603
+ if (functionDecl) {
1604
+ return {
1605
+ functionDecl,
1606
+ sourceFile: moduleSpecifier
1607
+ };
1608
+ }
1609
+ const variableDecl = moduleSpecifier.getVariableDeclaration(functionName);
1610
+ if (variableDecl) {
1611
+ const initializer = variableDecl.getInitializer();
1612
+ if (initializer && (Node4.isArrowFunction(initializer) || Node4.isFunctionExpression(initializer))) {
1613
+ return {
1614
+ functionDecl: initializer,
1615
+ sourceFile: moduleSpecifier
1616
+ };
1617
+ }
1618
+ }
1619
+ }
1620
+ }
1621
+ }
1622
+ } catch (error) {
1623
+ return null;
1624
+ }
1625
+ return null;
1626
+ }
1524
1627
  inferDatabaseOperation(callExpr) {
1525
1628
  if (callExpr.includes("query") || callExpr.includes("select")) {
1526
1629
  return "Reads from database";
@@ -3900,4 +4003,4 @@ Stack trace:`, COLORS.gray));
3900
4003
  process.exit(1);
3901
4004
  });
3902
4005
 
3903
- //# debugId=59C09397E2AB6BFF64756E2164756E21
4006
+ //# debugId=5BFF854178F00CEB64756E2164756E21