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/dist/cli.js CHANGED
@@ -2,18 +2,18 @@
2
2
 
3
3
  import {
4
4
  FlowStorage
5
- } from "./chunk-LXZ73T7X.js";
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 readFileSync4, writeFileSync } from "fs";
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 = readFileSync(filePath, "utf-8");
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 = readFileSync(filePath, "utf-8");
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 readFileSync2 } from "fs";
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 = readFileSync2(filePath, "utf-8");
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 = readFileSync2(filePath, "utf-8");
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 readFileSync3, existsSync as existsSync2 } from "fs";
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 = readFileSync3(dockerfilePath, "utf-8");
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 = readFileSync3(file, "utf-8");
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(readFileSync4(claudeConfigPath, "utf-8"));
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.2.0");
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-4XSR5P4N.js");
3863
+ await import("./flow-server-FMPWJSLK.js");
3240
3864
  });
3241
3865
  program.parse();
3242
3866
  //# sourceMappingURL=cli.js.map