@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
|
-
|
|
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,
|
|
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=
|
|
4006
|
+
//# debugId=5BFF854178F00CEB64756E2164756E21
|