codemap-ai 3.4.0 → 3.5.0
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.
- package/README.md +28 -1
- package/dist/{chunk-VB74K47A.js → chunk-BRVRY5KT.js} +62 -1
- package/dist/chunk-BRVRY5KT.js.map +1 -0
- package/dist/{chunk-LXZ73T7X.js → chunk-EEMILSZ4.js} +58 -3
- package/dist/chunk-EEMILSZ4.js.map +1 -0
- package/dist/cli.js +638 -14
- package/dist/cli.js.map +1 -1
- package/dist/{flow-server-4XSR5P4N.js → flow-server-FMPWJSLK.js} +3 -3
- package/dist/{flow-server-4XSR5P4N.js.map → flow-server-FMPWJSLK.js.map} +1 -1
- package/dist/index.js +628 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +2 -2
- package/dist/mcp-server.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-LXZ73T7X.js.map +0 -1
- package/dist/chunk-VB74K47A.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
FlowStorage
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BRVRY5KT.js";
|
|
6
6
|
|
|
7
7
|
// src/cli-flow.ts
|
|
8
8
|
import { Command } from "commander";
|
|
9
9
|
import { resolve as resolve3, join as join4 } from "path";
|
|
10
|
-
import { existsSync as existsSync3, mkdirSync, readFileSync as
|
|
10
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync5, writeFileSync } from "fs";
|
|
11
11
|
import { homedir } from "os";
|
|
12
12
|
import chalk from "chalk";
|
|
13
13
|
import ora from "ora";
|
|
14
14
|
|
|
15
15
|
// src/flow/builder.ts
|
|
16
|
-
import { readFileSync, statSync } from "fs";
|
|
16
|
+
import { readFileSync as readFileSync2, statSync } from "fs";
|
|
17
17
|
import { createHash } from "crypto";
|
|
18
18
|
import { glob } from "glob";
|
|
19
19
|
import { resolve, relative, extname } from "path";
|
|
@@ -483,10 +483,13 @@ var TypeScriptParser = class extends BaseParser {
|
|
|
483
483
|
language = "typescript";
|
|
484
484
|
extensions = [".ts", ".tsx"];
|
|
485
485
|
parser;
|
|
486
|
+
treeSitterParser;
|
|
487
|
+
// Expose for Phase 3
|
|
486
488
|
constructor() {
|
|
487
489
|
super();
|
|
488
490
|
this.parser = new Parser();
|
|
489
491
|
this.parser.setLanguage(TypeScript.typescript);
|
|
492
|
+
this.treeSitterParser = this.parser;
|
|
490
493
|
}
|
|
491
494
|
parse(filePath, content) {
|
|
492
495
|
const analysis = this.createEmptyAnalysis(filePath);
|
|
@@ -774,6 +777,7 @@ var JavaScriptParser = class extends TypeScriptParser {
|
|
|
774
777
|
super();
|
|
775
778
|
this.parser = new Parser();
|
|
776
779
|
this.parser.setLanguage(JavaScript);
|
|
780
|
+
this.treeSitterParser = this.parser;
|
|
777
781
|
}
|
|
778
782
|
parse(filePath, content) {
|
|
779
783
|
const sourceCode = typeof content === "string" ? content : String(content);
|
|
@@ -798,10 +802,13 @@ var PythonParser = class extends BaseParser {
|
|
|
798
802
|
language = "python";
|
|
799
803
|
extensions = [".py"];
|
|
800
804
|
parser;
|
|
805
|
+
treeSitterParser;
|
|
806
|
+
// Expose for Phase 3
|
|
801
807
|
constructor() {
|
|
802
808
|
super();
|
|
803
809
|
this.parser = new Parser2();
|
|
804
810
|
this.parser.setLanguage(Python);
|
|
811
|
+
this.treeSitterParser = this.parser;
|
|
805
812
|
}
|
|
806
813
|
parse(filePath, content) {
|
|
807
814
|
const analysis = this.createEmptyAnalysis(filePath);
|
|
@@ -1362,6 +1369,614 @@ function registerAllParsers() {
|
|
|
1362
1369
|
}
|
|
1363
1370
|
registerAllParsers();
|
|
1364
1371
|
|
|
1372
|
+
// src/flow/phase3-analyzer.ts
|
|
1373
|
+
import { readFileSync } from "fs";
|
|
1374
|
+
|
|
1375
|
+
// src/analysis/property-tracker.ts
|
|
1376
|
+
function extractPropertyAccesses(functionNode, scopeId, scopeName, filePath) {
|
|
1377
|
+
const accesses = [];
|
|
1378
|
+
const isJS = /\.(js|ts|jsx|tsx)$/.test(filePath);
|
|
1379
|
+
const isPython = /\.py$/.test(filePath);
|
|
1380
|
+
if (isJS) {
|
|
1381
|
+
extractJavaScriptPropertyAccesses(functionNode, scopeId, scopeName, accesses);
|
|
1382
|
+
} else if (isPython) {
|
|
1383
|
+
extractPythonPropertyAccesses(functionNode, scopeId, scopeName, accesses);
|
|
1384
|
+
}
|
|
1385
|
+
return accesses;
|
|
1386
|
+
}
|
|
1387
|
+
function extractJavaScriptPropertyAccesses(node, scopeId, scopeName, accesses) {
|
|
1388
|
+
traverseNode(node, (current) => {
|
|
1389
|
+
if (current.type === "member_expression") {
|
|
1390
|
+
const access = parseJavaScriptMemberExpression(current, scopeId);
|
|
1391
|
+
if (access) {
|
|
1392
|
+
accesses.push(access);
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
if (current.type === "optional_chain") {
|
|
1396
|
+
const memberExpr = current.children.find((c) => c.type === "member_expression");
|
|
1397
|
+
if (memberExpr) {
|
|
1398
|
+
const access = parseJavaScriptMemberExpression(memberExpr, scopeId);
|
|
1399
|
+
if (access) {
|
|
1400
|
+
access.accessType = "optional";
|
|
1401
|
+
accesses.push(access);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
if (current.type === "subscript_expression") {
|
|
1406
|
+
const access = parseJavaScriptSubscript(current, scopeId);
|
|
1407
|
+
if (access) {
|
|
1408
|
+
accesses.push(access);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
function parseJavaScriptMemberExpression(node, scopeId) {
|
|
1414
|
+
const propertyPath = [];
|
|
1415
|
+
let objectName = "";
|
|
1416
|
+
let currentNode = node;
|
|
1417
|
+
while (currentNode && currentNode.type === "member_expression") {
|
|
1418
|
+
const propertyNode = currentNode.childForFieldName("property");
|
|
1419
|
+
if (propertyNode) {
|
|
1420
|
+
propertyPath.unshift(propertyNode.text);
|
|
1421
|
+
}
|
|
1422
|
+
const objectNode = currentNode.childForFieldName("object");
|
|
1423
|
+
if (!objectNode) break;
|
|
1424
|
+
if (objectNode.type === "identifier") {
|
|
1425
|
+
objectName = objectNode.text;
|
|
1426
|
+
break;
|
|
1427
|
+
} else if (objectNode.type === "member_expression") {
|
|
1428
|
+
currentNode = objectNode;
|
|
1429
|
+
} else {
|
|
1430
|
+
return null;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
if (!objectName || isCommonJavaScriptObject(objectName)) {
|
|
1434
|
+
return null;
|
|
1435
|
+
}
|
|
1436
|
+
if (propertyPath.length === 0) {
|
|
1437
|
+
return null;
|
|
1438
|
+
}
|
|
1439
|
+
return {
|
|
1440
|
+
objectName,
|
|
1441
|
+
propertyPath,
|
|
1442
|
+
fullPath: `${objectName}.${propertyPath.join(".")}`,
|
|
1443
|
+
line: node.startPosition.row + 1,
|
|
1444
|
+
scopeId,
|
|
1445
|
+
accessType: "dot"
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
function parseJavaScriptSubscript(node, scopeId) {
|
|
1449
|
+
const objectNode = node.childForFieldName("object");
|
|
1450
|
+
const indexNode = node.childForFieldName("index");
|
|
1451
|
+
if (!objectNode || !indexNode) return null;
|
|
1452
|
+
if (indexNode.type !== "string") return null;
|
|
1453
|
+
const objectName = objectNode.text;
|
|
1454
|
+
const propertyName = indexNode.text.replace(/['"]/g, "");
|
|
1455
|
+
if (isCommonJavaScriptObject(objectName)) {
|
|
1456
|
+
return null;
|
|
1457
|
+
}
|
|
1458
|
+
return {
|
|
1459
|
+
objectName,
|
|
1460
|
+
propertyPath: [propertyName],
|
|
1461
|
+
fullPath: `${objectName}.${propertyName}`,
|
|
1462
|
+
line: node.startPosition.row + 1,
|
|
1463
|
+
scopeId,
|
|
1464
|
+
accessType: "bracket"
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
function extractPythonPropertyAccesses(node, scopeId, scopeName, accesses) {
|
|
1468
|
+
traverseNode(node, (current) => {
|
|
1469
|
+
if (current.type === "attribute") {
|
|
1470
|
+
const access = parsePythonAttribute(current, scopeId);
|
|
1471
|
+
if (access) {
|
|
1472
|
+
accesses.push(access);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
if (current.type === "subscript") {
|
|
1476
|
+
const access = parsePythonSubscript(current, scopeId);
|
|
1477
|
+
if (access) {
|
|
1478
|
+
accesses.push(access);
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
function parsePythonAttribute(node, scopeId) {
|
|
1484
|
+
const propertyPath = [];
|
|
1485
|
+
let objectName = "";
|
|
1486
|
+
let currentNode = node;
|
|
1487
|
+
while (currentNode && currentNode.type === "attribute") {
|
|
1488
|
+
const attrNode = currentNode.childForFieldName("attribute");
|
|
1489
|
+
if (attrNode) {
|
|
1490
|
+
propertyPath.unshift(attrNode.text);
|
|
1491
|
+
}
|
|
1492
|
+
const objectNode = currentNode.childForFieldName("object");
|
|
1493
|
+
if (!objectNode) break;
|
|
1494
|
+
if (objectNode.type === "identifier") {
|
|
1495
|
+
objectName = objectNode.text;
|
|
1496
|
+
break;
|
|
1497
|
+
} else if (objectNode.type === "attribute") {
|
|
1498
|
+
currentNode = objectNode;
|
|
1499
|
+
} else {
|
|
1500
|
+
return null;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
if (!objectName || isCommonPythonObject(objectName)) {
|
|
1504
|
+
return null;
|
|
1505
|
+
}
|
|
1506
|
+
if (propertyPath.length === 0) {
|
|
1507
|
+
return null;
|
|
1508
|
+
}
|
|
1509
|
+
return {
|
|
1510
|
+
objectName,
|
|
1511
|
+
propertyPath,
|
|
1512
|
+
fullPath: `${objectName}.${propertyPath.join(".")}`,
|
|
1513
|
+
line: node.startPosition.row + 1,
|
|
1514
|
+
scopeId,
|
|
1515
|
+
accessType: "dot"
|
|
1516
|
+
};
|
|
1517
|
+
}
|
|
1518
|
+
function parsePythonSubscript(node, scopeId) {
|
|
1519
|
+
const valueNode = node.childForFieldName("value");
|
|
1520
|
+
const subscriptChildren = node.children.filter(
|
|
1521
|
+
(c) => c.type === "string" || c.type === "identifier"
|
|
1522
|
+
);
|
|
1523
|
+
if (!valueNode || subscriptChildren.length === 0) return null;
|
|
1524
|
+
const keyNode = subscriptChildren.find((c) => c.type === "string");
|
|
1525
|
+
if (!keyNode) return null;
|
|
1526
|
+
const objectName = valueNode.text;
|
|
1527
|
+
const stringContent = keyNode.children.find((c) => c.type === "string_content");
|
|
1528
|
+
const propertyName = stringContent ? stringContent.text : keyNode.text.replace(/['"]/g, "");
|
|
1529
|
+
if (isCommonPythonObject(objectName)) {
|
|
1530
|
+
return null;
|
|
1531
|
+
}
|
|
1532
|
+
return {
|
|
1533
|
+
objectName,
|
|
1534
|
+
propertyPath: [propertyName],
|
|
1535
|
+
fullPath: `${objectName}.${propertyName}`,
|
|
1536
|
+
line: node.startPosition.row + 1,
|
|
1537
|
+
scopeId,
|
|
1538
|
+
accessType: "bracket"
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1541
|
+
function traverseNode(node, visitor) {
|
|
1542
|
+
visitor(node);
|
|
1543
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
1544
|
+
const child = node.child(i);
|
|
1545
|
+
if (child) {
|
|
1546
|
+
traverseNode(child, visitor);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
function isCommonJavaScriptObject(name) {
|
|
1551
|
+
const commonObjects = /* @__PURE__ */ new Set([
|
|
1552
|
+
// Global objects
|
|
1553
|
+
"console",
|
|
1554
|
+
"window",
|
|
1555
|
+
"document",
|
|
1556
|
+
"process",
|
|
1557
|
+
"global",
|
|
1558
|
+
// Common libraries
|
|
1559
|
+
"Math",
|
|
1560
|
+
"JSON",
|
|
1561
|
+
"Date",
|
|
1562
|
+
"Array",
|
|
1563
|
+
"Object",
|
|
1564
|
+
"String",
|
|
1565
|
+
"Number",
|
|
1566
|
+
// Keywords
|
|
1567
|
+
"this",
|
|
1568
|
+
"super",
|
|
1569
|
+
// Common module patterns
|
|
1570
|
+
"exports",
|
|
1571
|
+
"module",
|
|
1572
|
+
"require"
|
|
1573
|
+
]);
|
|
1574
|
+
return commonObjects.has(name);
|
|
1575
|
+
}
|
|
1576
|
+
function isCommonPythonObject(name) {
|
|
1577
|
+
const commonObjects = /* @__PURE__ */ new Set([
|
|
1578
|
+
// Keywords
|
|
1579
|
+
"self",
|
|
1580
|
+
"cls",
|
|
1581
|
+
// Built-in types
|
|
1582
|
+
"str",
|
|
1583
|
+
"int",
|
|
1584
|
+
"float",
|
|
1585
|
+
"dict",
|
|
1586
|
+
"list",
|
|
1587
|
+
"tuple",
|
|
1588
|
+
"set",
|
|
1589
|
+
// Common modules
|
|
1590
|
+
"os",
|
|
1591
|
+
"sys",
|
|
1592
|
+
"json",
|
|
1593
|
+
"math",
|
|
1594
|
+
"datetime"
|
|
1595
|
+
]);
|
|
1596
|
+
return commonObjects.has(name);
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
// src/analysis/return-analyzer.ts
|
|
1600
|
+
function analyzeReturnStatements(functionNode, functionId, functionName, filePath) {
|
|
1601
|
+
const returns = [];
|
|
1602
|
+
const isJS = /\.(js|ts|jsx|tsx)$/.test(filePath);
|
|
1603
|
+
const isPython = /\.py$/.test(filePath);
|
|
1604
|
+
if (isJS) {
|
|
1605
|
+
extractJavaScriptReturns(functionNode, functionId, functionName, returns);
|
|
1606
|
+
} else if (isPython) {
|
|
1607
|
+
extractPythonReturns(functionNode, functionId, functionName, returns);
|
|
1608
|
+
}
|
|
1609
|
+
return returns;
|
|
1610
|
+
}
|
|
1611
|
+
function extractJavaScriptReturns(node, functionId, functionName, returns) {
|
|
1612
|
+
traverseNode2(node, (current) => {
|
|
1613
|
+
if (current.type === "return_statement") {
|
|
1614
|
+
const returnNode = current.children.find(
|
|
1615
|
+
(c) => c.type !== "return" && c.type !== ";"
|
|
1616
|
+
);
|
|
1617
|
+
if (returnNode) {
|
|
1618
|
+
const returnInfo = parseJavaScriptReturnValue(
|
|
1619
|
+
returnNode,
|
|
1620
|
+
functionId,
|
|
1621
|
+
functionName
|
|
1622
|
+
);
|
|
1623
|
+
if (returnInfo) {
|
|
1624
|
+
returns.push(returnInfo);
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
});
|
|
1629
|
+
}
|
|
1630
|
+
function parseJavaScriptReturnValue(returnNode, functionId, functionName) {
|
|
1631
|
+
const line = returnNode.startPosition.row + 1;
|
|
1632
|
+
const returnExpression = returnNode.text;
|
|
1633
|
+
let returnType = null;
|
|
1634
|
+
let objectShape = null;
|
|
1635
|
+
if (returnNode.type === "object") {
|
|
1636
|
+
objectShape = extractJavaScriptObjectShape(returnNode);
|
|
1637
|
+
returnType = "object";
|
|
1638
|
+
} else if (returnNode.type === "array") {
|
|
1639
|
+
returnType = "array";
|
|
1640
|
+
objectShape = {
|
|
1641
|
+
properties: [],
|
|
1642
|
+
propertyTypes: /* @__PURE__ */ new Map(),
|
|
1643
|
+
nestedShapes: /* @__PURE__ */ new Map(),
|
|
1644
|
+
isArray: true,
|
|
1645
|
+
isDictionary: false,
|
|
1646
|
+
isOptional: false
|
|
1647
|
+
};
|
|
1648
|
+
} else if (returnNode.type === "new_expression") {
|
|
1649
|
+
const constructorNode = returnNode.childForFieldName("constructor");
|
|
1650
|
+
if (constructorNode) {
|
|
1651
|
+
returnType = constructorNode.text;
|
|
1652
|
+
}
|
|
1653
|
+
} else if (returnNode.type === "identifier") {
|
|
1654
|
+
returnType = `@var:${returnNode.text}`;
|
|
1655
|
+
} else if (returnNode.type === "call_expression") {
|
|
1656
|
+
const funcNode = returnNode.childForFieldName("function");
|
|
1657
|
+
if (funcNode) {
|
|
1658
|
+
returnType = `@call:${funcNode.text}`;
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
return {
|
|
1662
|
+
functionId,
|
|
1663
|
+
functionName,
|
|
1664
|
+
returnType,
|
|
1665
|
+
objectShape,
|
|
1666
|
+
line,
|
|
1667
|
+
returnExpression
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
function extractJavaScriptObjectShape(objectNode) {
|
|
1671
|
+
const properties = [];
|
|
1672
|
+
const propertyTypes = /* @__PURE__ */ new Map();
|
|
1673
|
+
const nestedShapes = /* @__PURE__ */ new Map();
|
|
1674
|
+
for (const child of objectNode.children) {
|
|
1675
|
+
if (child.type === "pair") {
|
|
1676
|
+
const keyNode = child.childForFieldName("key");
|
|
1677
|
+
const valueNode = child.childForFieldName("value");
|
|
1678
|
+
if (keyNode) {
|
|
1679
|
+
const propertyName = keyNode.text.replace(/['"]/g, "");
|
|
1680
|
+
properties.push(propertyName);
|
|
1681
|
+
if (valueNode) {
|
|
1682
|
+
const propertyType = inferJavaScriptType(valueNode);
|
|
1683
|
+
propertyTypes.set(propertyName, propertyType);
|
|
1684
|
+
if (valueNode.type === "object") {
|
|
1685
|
+
const nestedShape = extractJavaScriptObjectShape(valueNode);
|
|
1686
|
+
nestedShapes.set(propertyName, nestedShape);
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
return {
|
|
1693
|
+
properties,
|
|
1694
|
+
propertyTypes,
|
|
1695
|
+
nestedShapes,
|
|
1696
|
+
isArray: false,
|
|
1697
|
+
isDictionary: false,
|
|
1698
|
+
isOptional: false
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
function inferJavaScriptType(valueNode) {
|
|
1702
|
+
switch (valueNode.type) {
|
|
1703
|
+
case "number":
|
|
1704
|
+
return "number";
|
|
1705
|
+
case "string":
|
|
1706
|
+
case "template_string":
|
|
1707
|
+
return "string";
|
|
1708
|
+
case "true":
|
|
1709
|
+
case "false":
|
|
1710
|
+
return "boolean";
|
|
1711
|
+
case "null":
|
|
1712
|
+
return "null";
|
|
1713
|
+
case "undefined":
|
|
1714
|
+
return "undefined";
|
|
1715
|
+
case "array":
|
|
1716
|
+
return "array";
|
|
1717
|
+
case "object":
|
|
1718
|
+
return "object";
|
|
1719
|
+
case "arrow_function":
|
|
1720
|
+
case "function_expression":
|
|
1721
|
+
return "function";
|
|
1722
|
+
case "identifier":
|
|
1723
|
+
return `@var:${valueNode.text}`;
|
|
1724
|
+
case "call_expression":
|
|
1725
|
+
return "@call";
|
|
1726
|
+
default:
|
|
1727
|
+
return "unknown";
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
function extractPythonReturns(node, functionId, functionName, returns) {
|
|
1731
|
+
traverseNode2(node, (current) => {
|
|
1732
|
+
if (current.type === "return_statement") {
|
|
1733
|
+
const returnNode = current.children.find((c) => c.type !== "return");
|
|
1734
|
+
if (returnNode) {
|
|
1735
|
+
const returnInfo = parsePythonReturnValue(
|
|
1736
|
+
returnNode,
|
|
1737
|
+
functionId,
|
|
1738
|
+
functionName
|
|
1739
|
+
);
|
|
1740
|
+
if (returnInfo) {
|
|
1741
|
+
returns.push(returnInfo);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
function parsePythonReturnValue(returnNode, functionId, functionName) {
|
|
1748
|
+
const line = returnNode.startPosition.row + 1;
|
|
1749
|
+
const returnExpression = returnNode.text;
|
|
1750
|
+
let returnType = null;
|
|
1751
|
+
let objectShape = null;
|
|
1752
|
+
if (returnNode.type === "dictionary") {
|
|
1753
|
+
objectShape = extractPythonDictionaryShape(returnNode);
|
|
1754
|
+
returnType = "dict";
|
|
1755
|
+
} else if (returnNode.type === "list") {
|
|
1756
|
+
returnType = "list";
|
|
1757
|
+
objectShape = {
|
|
1758
|
+
properties: [],
|
|
1759
|
+
propertyTypes: /* @__PURE__ */ new Map(),
|
|
1760
|
+
nestedShapes: /* @__PURE__ */ new Map(),
|
|
1761
|
+
isArray: true,
|
|
1762
|
+
isDictionary: false,
|
|
1763
|
+
isOptional: false
|
|
1764
|
+
};
|
|
1765
|
+
} else if (returnNode.type === "call") {
|
|
1766
|
+
const funcNode = returnNode.childForFieldName("function");
|
|
1767
|
+
if (funcNode) {
|
|
1768
|
+
const funcName = funcNode.text;
|
|
1769
|
+
if (funcName[0] === funcName[0].toUpperCase()) {
|
|
1770
|
+
returnType = funcName;
|
|
1771
|
+
} else {
|
|
1772
|
+
returnType = `@call:${funcName}`;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
} else if (returnNode.type === "identifier") {
|
|
1776
|
+
returnType = `@var:${returnNode.text}`;
|
|
1777
|
+
} else if (returnNode.type === "list_comprehension") {
|
|
1778
|
+
returnType = "list";
|
|
1779
|
+
objectShape = {
|
|
1780
|
+
properties: [],
|
|
1781
|
+
propertyTypes: /* @__PURE__ */ new Map(),
|
|
1782
|
+
nestedShapes: /* @__PURE__ */ new Map(),
|
|
1783
|
+
isArray: true,
|
|
1784
|
+
isDictionary: false,
|
|
1785
|
+
isOptional: false
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
return {
|
|
1789
|
+
functionId,
|
|
1790
|
+
functionName,
|
|
1791
|
+
returnType,
|
|
1792
|
+
objectShape,
|
|
1793
|
+
line,
|
|
1794
|
+
returnExpression
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
function extractPythonDictionaryShape(dictNode) {
|
|
1798
|
+
const properties = [];
|
|
1799
|
+
const propertyTypes = /* @__PURE__ */ new Map();
|
|
1800
|
+
const nestedShapes = /* @__PURE__ */ new Map();
|
|
1801
|
+
for (const child of dictNode.children) {
|
|
1802
|
+
if (child.type === "pair") {
|
|
1803
|
+
const keyNode = child.children.find((c) => c.type === "string");
|
|
1804
|
+
const valueNode = child.children.find(
|
|
1805
|
+
(c) => c.type !== "string" && c.type !== ":"
|
|
1806
|
+
);
|
|
1807
|
+
if (keyNode) {
|
|
1808
|
+
const stringContent = keyNode.children.find(
|
|
1809
|
+
(c) => c.type === "string_content"
|
|
1810
|
+
);
|
|
1811
|
+
const propertyName = stringContent ? stringContent.text : keyNode.text.replace(/['"]/g, "");
|
|
1812
|
+
properties.push(propertyName);
|
|
1813
|
+
if (valueNode) {
|
|
1814
|
+
const propertyType = inferPythonType(valueNode);
|
|
1815
|
+
propertyTypes.set(propertyName, propertyType);
|
|
1816
|
+
if (valueNode.type === "dictionary") {
|
|
1817
|
+
const nestedShape = extractPythonDictionaryShape(valueNode);
|
|
1818
|
+
nestedShapes.set(propertyName, nestedShape);
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
return {
|
|
1825
|
+
properties,
|
|
1826
|
+
propertyTypes,
|
|
1827
|
+
nestedShapes,
|
|
1828
|
+
isArray: false,
|
|
1829
|
+
isDictionary: true,
|
|
1830
|
+
isOptional: false
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1833
|
+
function inferPythonType(valueNode) {
|
|
1834
|
+
switch (valueNode.type) {
|
|
1835
|
+
case "integer":
|
|
1836
|
+
case "float":
|
|
1837
|
+
return "number";
|
|
1838
|
+
case "string":
|
|
1839
|
+
return "string";
|
|
1840
|
+
case "true":
|
|
1841
|
+
case "false":
|
|
1842
|
+
return "boolean";
|
|
1843
|
+
case "none":
|
|
1844
|
+
return "None";
|
|
1845
|
+
case "list":
|
|
1846
|
+
return "list";
|
|
1847
|
+
case "dictionary":
|
|
1848
|
+
return "dict";
|
|
1849
|
+
case "lambda":
|
|
1850
|
+
return "function";
|
|
1851
|
+
case "identifier":
|
|
1852
|
+
return `@var:${valueNode.text}`;
|
|
1853
|
+
case "call":
|
|
1854
|
+
return "@call";
|
|
1855
|
+
default:
|
|
1856
|
+
return "unknown";
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
function traverseNode2(node, visitor) {
|
|
1860
|
+
visitor(node);
|
|
1861
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
1862
|
+
const child = node.child(i);
|
|
1863
|
+
if (child) {
|
|
1864
|
+
traverseNode2(child, visitor);
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// src/flow/storage-queries-phase3.ts
|
|
1870
|
+
import { randomUUID } from "crypto";
|
|
1871
|
+
function storePropertyAccesses(db, accesses) {
|
|
1872
|
+
const stmt = db.prepare(`
|
|
1873
|
+
INSERT OR REPLACE INTO property_accesses
|
|
1874
|
+
(id, scope_node_id, object_name, property_path, full_path, access_type, file_path, line)
|
|
1875
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
1876
|
+
`);
|
|
1877
|
+
const insert = db.transaction((accesses2) => {
|
|
1878
|
+
for (const access of accesses2) {
|
|
1879
|
+
stmt.run(
|
|
1880
|
+
randomUUID(),
|
|
1881
|
+
access.scopeId,
|
|
1882
|
+
access.objectName,
|
|
1883
|
+
JSON.stringify(access.propertyPath),
|
|
1884
|
+
access.fullPath,
|
|
1885
|
+
access.accessType,
|
|
1886
|
+
access.filePath || "",
|
|
1887
|
+
access.line
|
|
1888
|
+
);
|
|
1889
|
+
}
|
|
1890
|
+
});
|
|
1891
|
+
insert(accesses);
|
|
1892
|
+
}
|
|
1893
|
+
function storeReturnInfo(db, returns) {
|
|
1894
|
+
const stmt = db.prepare(`
|
|
1895
|
+
INSERT OR REPLACE INTO return_shapes
|
|
1896
|
+
(id, function_id, return_type, object_shape, line, return_expression)
|
|
1897
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
1898
|
+
`);
|
|
1899
|
+
const insert = db.transaction((returns2) => {
|
|
1900
|
+
for (const ret of returns2) {
|
|
1901
|
+
stmt.run(
|
|
1902
|
+
randomUUID(),
|
|
1903
|
+
ret.functionId,
|
|
1904
|
+
ret.returnType,
|
|
1905
|
+
ret.objectShape ? JSON.stringify(serializeObjectShape(ret.objectShape)) : null,
|
|
1906
|
+
ret.line,
|
|
1907
|
+
ret.returnExpression
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
});
|
|
1911
|
+
insert(returns);
|
|
1912
|
+
}
|
|
1913
|
+
function serializeObjectShape(shape) {
|
|
1914
|
+
return {
|
|
1915
|
+
properties: shape.properties,
|
|
1916
|
+
propertyTypes: Array.from(shape.propertyTypes.entries()),
|
|
1917
|
+
nestedShapes: Array.from(shape.nestedShapes.entries()).map(([key, nested]) => [
|
|
1918
|
+
key,
|
|
1919
|
+
serializeObjectShape(nested)
|
|
1920
|
+
]),
|
|
1921
|
+
isArray: shape.isArray,
|
|
1922
|
+
isDictionary: shape.isDictionary,
|
|
1923
|
+
isOptional: shape.isOptional
|
|
1924
|
+
};
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
// src/flow/phase3-analyzer.ts
|
|
1928
|
+
function analyzeFileForPhase3(filePath, functionNodes, db) {
|
|
1929
|
+
try {
|
|
1930
|
+
const language = getLanguageFromPath(filePath);
|
|
1931
|
+
if (!language) return;
|
|
1932
|
+
const parserInstance = parserRegistry.getByLanguage(language);
|
|
1933
|
+
if (!parserInstance || !parserInstance.treeSitterParser) return;
|
|
1934
|
+
const content = readFileSync(filePath, "utf-8");
|
|
1935
|
+
const tree = parserInstance.treeSitterParser.parse(content);
|
|
1936
|
+
const rootNode = tree.rootNode;
|
|
1937
|
+
for (const func of functionNodes) {
|
|
1938
|
+
const funcNode = findNodeAtLine(rootNode, func.startLine, func.endLine);
|
|
1939
|
+
if (!funcNode) continue;
|
|
1940
|
+
const accesses = extractPropertyAccesses(funcNode, func.id, func.name, filePath);
|
|
1941
|
+
if (accesses.length > 0) {
|
|
1942
|
+
const accessesWithFile = accesses.map((a) => ({ ...a, filePath }));
|
|
1943
|
+
storePropertyAccesses(db, accessesWithFile);
|
|
1944
|
+
}
|
|
1945
|
+
const returns = analyzeReturnStatements(funcNode, func.id, func.name, filePath);
|
|
1946
|
+
if (returns.length > 0) {
|
|
1947
|
+
storeReturnInfo(db, returns);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
} catch (error) {
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
function getLanguageFromPath(filePath) {
|
|
1954
|
+
if (filePath.endsWith(".py")) return "python";
|
|
1955
|
+
if (filePath.endsWith(".js") || filePath.endsWith(".jsx")) return "javascript";
|
|
1956
|
+
if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) return "typescript";
|
|
1957
|
+
return null;
|
|
1958
|
+
}
|
|
1959
|
+
function findNodeAtLine(node, startLine, endLine) {
|
|
1960
|
+
const nodeStart = node.startPosition.row + 1;
|
|
1961
|
+
const nodeEnd = node.endPosition.row + 1;
|
|
1962
|
+
if (nodeStart === startLine && nodeEnd === endLine) {
|
|
1963
|
+
return node;
|
|
1964
|
+
}
|
|
1965
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
1966
|
+
const child = node.child(i);
|
|
1967
|
+
if (child) {
|
|
1968
|
+
const result = findNodeAtLine(child, startLine, endLine);
|
|
1969
|
+
if (result) return result;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
if (nodeStart <= startLine && nodeEnd >= endLine) {
|
|
1973
|
+
if (node.type === "function_definition" || node.type === "function_declaration" || node.type === "method_definition" || node.type === "arrow_function" || node.type === "function_expression") {
|
|
1974
|
+
return node;
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
return null;
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1365
1980
|
// src/flow/builder.ts
|
|
1366
1981
|
var FlowBuilder = class {
|
|
1367
1982
|
storage;
|
|
@@ -1389,7 +2004,7 @@ var FlowBuilder = class {
|
|
|
1389
2004
|
const filesToIndex = [];
|
|
1390
2005
|
let skipped = 0;
|
|
1391
2006
|
for (const filePath of allFiles) {
|
|
1392
|
-
const content =
|
|
2007
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
1393
2008
|
const hash = this.hashContent(content);
|
|
1394
2009
|
if (!this.config.forceReindex) {
|
|
1395
2010
|
const existingHash = this.storage.getFileHash(filePath);
|
|
@@ -1473,7 +2088,7 @@ var FlowBuilder = class {
|
|
|
1473
2088
|
}
|
|
1474
2089
|
async parseAndStore(filePath, hash, rootPath) {
|
|
1475
2090
|
const language = this.getLanguage(filePath);
|
|
1476
|
-
const content =
|
|
2091
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
1477
2092
|
const parser = parserRegistry.getByLanguage(language);
|
|
1478
2093
|
if (!parser) {
|
|
1479
2094
|
throw new Error(`No parser found for language: ${language}`);
|
|
@@ -1510,6 +2125,15 @@ var FlowBuilder = class {
|
|
|
1510
2125
|
);
|
|
1511
2126
|
}
|
|
1512
2127
|
}
|
|
2128
|
+
const functionNodes = analysis.nodes.filter((n) => n.type === "function" || n.type === "method").map((n) => ({
|
|
2129
|
+
id: n.id,
|
|
2130
|
+
name: n.name,
|
|
2131
|
+
startLine: n.startLine,
|
|
2132
|
+
endLine: n.endLine
|
|
2133
|
+
}));
|
|
2134
|
+
if (functionNodes.length > 0) {
|
|
2135
|
+
analyzeFileForPhase3(filePath, functionNodes, this.storage.db);
|
|
2136
|
+
}
|
|
1513
2137
|
if (analysis.databaseOperations) {
|
|
1514
2138
|
for (const dbOp of analysis.databaseOperations) {
|
|
1515
2139
|
this.storage.insertDatabaseOperation({
|
|
@@ -1789,7 +2413,7 @@ function getGitStatus(rootPath) {
|
|
|
1789
2413
|
}
|
|
1790
2414
|
|
|
1791
2415
|
// src/analysis/imports.ts
|
|
1792
|
-
import { readFileSync as
|
|
2416
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
1793
2417
|
function isJavaScriptBuiltin(identifier) {
|
|
1794
2418
|
const builtins = /* @__PURE__ */ new Set([
|
|
1795
2419
|
"Object",
|
|
@@ -1872,7 +2496,7 @@ function isPythonBuiltin(identifier) {
|
|
|
1872
2496
|
return builtins.has(identifier);
|
|
1873
2497
|
}
|
|
1874
2498
|
function analyzeJavaScriptImports(filePath) {
|
|
1875
|
-
const content =
|
|
2499
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
1876
2500
|
const lines = content.split("\n");
|
|
1877
2501
|
const imports = /* @__PURE__ */ new Map();
|
|
1878
2502
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -1967,7 +2591,7 @@ function analyzeJavaScriptImports(filePath) {
|
|
|
1967
2591
|
return { missing, unused };
|
|
1968
2592
|
}
|
|
1969
2593
|
function analyzePythonImports(filePath) {
|
|
1970
|
-
const content =
|
|
2594
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
1971
2595
|
const lines = content.split("\n");
|
|
1972
2596
|
const imports = /* @__PURE__ */ new Map();
|
|
1973
2597
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -2066,14 +2690,14 @@ function analyzeImports(filePath) {
|
|
|
2066
2690
|
}
|
|
2067
2691
|
|
|
2068
2692
|
// src/analysis/docker.ts
|
|
2069
|
-
import { readFileSync as
|
|
2693
|
+
import { readFileSync as readFileSync4, existsSync as existsSync2 } from "fs";
|
|
2070
2694
|
import { load as parseYaml } from "js-yaml";
|
|
2071
2695
|
import { join as join2 } from "path";
|
|
2072
2696
|
function parseDockerfile(dockerfilePath) {
|
|
2073
2697
|
if (!existsSync2(dockerfilePath)) {
|
|
2074
2698
|
return null;
|
|
2075
2699
|
}
|
|
2076
|
-
const content =
|
|
2700
|
+
const content = readFileSync4(dockerfilePath, "utf-8");
|
|
2077
2701
|
const lines = content.split("\n");
|
|
2078
2702
|
let inHealthCheck = false;
|
|
2079
2703
|
for (const line of lines) {
|
|
@@ -2151,7 +2775,7 @@ function parseDockerCompose(projectRoot) {
|
|
|
2151
2775
|
let composeData = null;
|
|
2152
2776
|
for (const file of composeFiles) {
|
|
2153
2777
|
if (existsSync2(file)) {
|
|
2154
|
-
const content =
|
|
2778
|
+
const content = readFileSync4(file, "utf-8");
|
|
2155
2779
|
composeData = parseYaml(content);
|
|
2156
2780
|
break;
|
|
2157
2781
|
}
|
|
@@ -2923,7 +3547,7 @@ function configureMCPServer(projectPath) {
|
|
|
2923
3547
|
if (!existsSync3(claudeConfigPath)) {
|
|
2924
3548
|
return false;
|
|
2925
3549
|
}
|
|
2926
|
-
const config = JSON.parse(
|
|
3550
|
+
const config = JSON.parse(readFileSync5(claudeConfigPath, "utf-8"));
|
|
2927
3551
|
if (!config.mcpServers) {
|
|
2928
3552
|
config.mcpServers = {};
|
|
2929
3553
|
}
|
|
@@ -2937,7 +3561,7 @@ function configureMCPServer(projectPath) {
|
|
|
2937
3561
|
return false;
|
|
2938
3562
|
}
|
|
2939
3563
|
}
|
|
2940
|
-
program.name("codemap").description("CodeMap Flow - Call graph analyzer for understanding code impact").version("3.
|
|
3564
|
+
program.name("codemap").description("CodeMap Flow - Call graph analyzer for understanding code impact").version("3.5.0");
|
|
2941
3565
|
program.command("index").description("Build call graph for your codebase").argument("[path]", "Path to the project root", ".").option("-f, --force", "Force reindex all files (ignore cache)").option("--include <patterns...>", "Glob patterns to include").option("--exclude <patterns...>", "Glob patterns to exclude").action(async (path, options) => {
|
|
2942
3566
|
const rootPath = resolve3(path);
|
|
2943
3567
|
const outputDir = join4(rootPath, ".codemap");
|
|
@@ -3236,7 +3860,7 @@ program.command("reindex").description("Force full re-index of codebase").argume
|
|
|
3236
3860
|
program.command("mcp-server").description("Start MCP server for Claude Code integration").option("-p, --path <path>", "Project root path", ".").action(async (options) => {
|
|
3237
3861
|
process.env.CODEMAP_PROJECT_ROOT = resolve3(options.path);
|
|
3238
3862
|
process.env.CODEMAP_DB_PATH = join4(resolve3(options.path), ".codemap", "graph.db");
|
|
3239
|
-
await import("./flow-server-
|
|
3863
|
+
await import("./flow-server-FMPWJSLK.js");
|
|
3240
3864
|
});
|
|
3241
3865
|
program.parse();
|
|
3242
3866
|
//# sourceMappingURL=cli.js.map
|