depgraph-core 1.5.1 → 1.8.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/depgraph.js CHANGED
@@ -63,7 +63,9 @@ var require_constants = __commonJS({
63
63
  ".swift",
64
64
  ".kt",
65
65
  ".vue",
66
- ".svelte"
66
+ ".svelte",
67
+ ".dart",
68
+ ".rs"
67
69
  ]);
68
70
  exports2.MAX_FILE_SIZE = 3e5;
69
71
  exports2.MAX_BFS_DEPTH = 10;
@@ -1620,6 +1622,1850 @@ var require_swift = __commonJS({
1620
1622
  }
1621
1623
  });
1622
1624
 
1625
+ // dist/languages/dart.js
1626
+ var require_dart = __commonJS({
1627
+ "dist/languages/dart.js"(exports2) {
1628
+ "use strict";
1629
+ var __importDefault2 = exports2 && exports2.__importDefault || function(mod) {
1630
+ return mod && mod.__esModule ? mod : { "default": mod };
1631
+ };
1632
+ Object.defineProperty(exports2, "__esModule", { value: true });
1633
+ exports2.DartParser = exports2.dartEntityPatterns = void 0;
1634
+ exports2.cleanDartComments = cleanDartComments;
1635
+ exports2._fileStem = _fileStem;
1636
+ exports2._makeId = _makeId;
1637
+ exports2._splitTypes = _splitTypes;
1638
+ exports2._findMatchingBrace = _findMatchingBrace;
1639
+ exports2.estimateComplexity = estimateComplexity;
1640
+ exports2.extractDart = extractDart;
1641
+ var fs_12 = __importDefault2(require("fs"));
1642
+ var path_1 = __importDefault2(require("path"));
1643
+ var registry_1 = require_registry();
1644
+ var constants_1 = require_constants();
1645
+ function escapeRegex(s) {
1646
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1647
+ }
1648
+ function cleanDartComments(src) {
1649
+ const commentStringPattern = /r?"""(?:\\.|[\s\S])*?"""|r?'''(?:\\.|[\s\S])*?'''|r?"(?:\\.|[^"\\])*"|r?'(?:\\.|[^'\\])*'|\/\*[\s\S]*?\*\/|\/\/[^\n]*/g;
1650
+ return src.replace(commentStringPattern, (token) => {
1651
+ if (token.startsWith("/")) {
1652
+ const newlineCount = (token.match(/\n/g) || []).length;
1653
+ return "\n".repeat(newlineCount);
1654
+ }
1655
+ return token;
1656
+ });
1657
+ }
1658
+ function _fileStem(filePath) {
1659
+ const base = path_1.default.basename(filePath);
1660
+ const ext = path_1.default.extname(base);
1661
+ return ext ? base.slice(0, -ext.length) : base;
1662
+ }
1663
+ function _makeId(...parts) {
1664
+ return parts.filter((p) => Boolean(p && p.trim())).map((p) => p.trim().replace(/[^a-zA-Z0-9_.-]/g, "_")).join("__");
1665
+ }
1666
+ function _splitTypes(text) {
1667
+ const parts = [];
1668
+ const current = [];
1669
+ let depth = 0;
1670
+ for (let i = 0; i < text.length; i++) {
1671
+ const char = text[i];
1672
+ if (char === "<") {
1673
+ depth++;
1674
+ current.push(char);
1675
+ } else if (char === ">") {
1676
+ depth--;
1677
+ current.push(char);
1678
+ } else if (char === "," && depth === 0) {
1679
+ const trimmed = current.join("").trim();
1680
+ if (trimmed)
1681
+ parts.push(trimmed);
1682
+ current.length = 0;
1683
+ } else {
1684
+ current.push(char);
1685
+ }
1686
+ }
1687
+ if (current.length > 0) {
1688
+ const trimmed = current.join("").trim();
1689
+ if (trimmed)
1690
+ parts.push(trimmed);
1691
+ }
1692
+ return parts;
1693
+ }
1694
+ function _findMatchingBrace(text, startPos) {
1695
+ let braceCount = 0;
1696
+ let inDoubleQuote = false;
1697
+ let inSingleQuote = false;
1698
+ let escape = false;
1699
+ const firstBrace = text.indexOf("{", startPos);
1700
+ if (firstBrace === -1)
1701
+ return text.length;
1702
+ braceCount = 1;
1703
+ let i = firstBrace + 1;
1704
+ const n = text.length;
1705
+ while (i < n) {
1706
+ const char = text[i];
1707
+ if (escape) {
1708
+ escape = false;
1709
+ i++;
1710
+ continue;
1711
+ }
1712
+ if (char === "\\") {
1713
+ escape = true;
1714
+ i++;
1715
+ continue;
1716
+ }
1717
+ if (text.slice(i, i + 3) === '"""' && !inSingleQuote) {
1718
+ i += 3;
1719
+ const end = text.indexOf('"""', i);
1720
+ i = end !== -1 ? end + 3 : n;
1721
+ continue;
1722
+ }
1723
+ if (text.slice(i, i + 3) === "'''" && !inDoubleQuote) {
1724
+ i += 3;
1725
+ const end = text.indexOf("'''", i);
1726
+ i = end !== -1 ? end + 3 : n;
1727
+ continue;
1728
+ }
1729
+ if (char === '"' && !inSingleQuote) {
1730
+ inDoubleQuote = !inDoubleQuote;
1731
+ } else if (char === "'" && !inDoubleQuote) {
1732
+ inSingleQuote = !inSingleQuote;
1733
+ } else if (!inDoubleQuote && !inSingleQuote) {
1734
+ if (char === "{") {
1735
+ braceCount++;
1736
+ } else if (char === "}") {
1737
+ braceCount--;
1738
+ if (braceCount === 0) {
1739
+ return i + 1;
1740
+ }
1741
+ }
1742
+ }
1743
+ i++;
1744
+ }
1745
+ return text.length;
1746
+ }
1747
+ function estimateComplexity(code, name) {
1748
+ const lines = code.split("\n");
1749
+ const defRegex = new RegExp(`(?:^|\\s)(?:[\\w<>\\[\\],.?]+\\s+)?${escapeRegex(name)}\\s*(?:<[^>]*>)?\\s*\\(`, "m");
1750
+ const defLineIdx = lines.findIndex((l) => defRegex.test(l));
1751
+ if (defLineIdx === -1)
1752
+ return "low";
1753
+ let startLine = defLineIdx;
1754
+ while (startLine < lines.length && !lines[startLine].includes("{") && !lines[startLine].includes("=>")) {
1755
+ startLine++;
1756
+ }
1757
+ if (startLine >= lines.length)
1758
+ return "low";
1759
+ if (lines[startLine].includes("=>") && !lines[startLine].includes("{")) {
1760
+ const arrowStmt = lines.slice(startLine, startLine + 5).join("\n");
1761
+ const branches2 = (arrowStmt.match(/\b(if|else|switch|case|catch|&&|\|\||\?\?)\b|\?[^:]*:/g) || []).length;
1762
+ if (branches2 <= constants_1.COMPLEXITY_THRESHOLDS.low)
1763
+ return "low";
1764
+ if (branches2 <= constants_1.COMPLEXITY_THRESHOLDS.medium)
1765
+ return "medium";
1766
+ return "high";
1767
+ }
1768
+ let braceCount = 0;
1769
+ let started = false;
1770
+ const bodyLines = [];
1771
+ for (let i = startLine; i < lines.length; i++) {
1772
+ const line = lines[i];
1773
+ for (const ch of line) {
1774
+ if (ch === "{") {
1775
+ braceCount++;
1776
+ started = true;
1777
+ } else if (ch === "}") {
1778
+ braceCount--;
1779
+ }
1780
+ }
1781
+ bodyLines.push(line);
1782
+ if (started && braceCount <= 0)
1783
+ break;
1784
+ }
1785
+ const body = bodyLines.join("\n");
1786
+ const branches = (body.match(/\b(if|else\s+if|else|for|while|do|switch|case|catch|&&|\|\||\?\?)\b|\?[^:]*:/g) || []).length;
1787
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
1788
+ return "low";
1789
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
1790
+ return "medium";
1791
+ return "high";
1792
+ }
1793
+ exports2.dartEntityPatterns = [
1794
+ // class, abstract class, sealed class, mixin class, base class, interface class, final class, enum, extension type
1795
+ {
1796
+ regex: /^[ \t]*(?:(?:abstract|sealed|base|interface|final|mixin)\s+)*(?:class|mixin|enum|extension\s+type)\s+([A-Za-z_]\w*)/gm,
1797
+ type: "class"
1798
+ },
1799
+ // extension MyExt on MyClass (named extension)
1800
+ {
1801
+ regex: /^[ \t]{0,4}extension\s+([A-Za-z_]\w+)(?:<[^>]+>)?\s+on\s+[A-Za-z_]\w*/gm,
1802
+ type: "class"
1803
+ },
1804
+ // typedef
1805
+ {
1806
+ regex: /^[ \t]*typedef\s+(?:[\w<>,.?\s]+\s+)?([A-Za-z_]\w*)\s*(?:<[^>]+>)?\s*(?:=|\()/gm,
1807
+ type: "type"
1808
+ },
1809
+ // methods, functions, getters/setters, constructors
1810
+ {
1811
+ regex: /^[ \t]{0,2}(?:(?:factory|static|async|external|abstract)\s+)?(?:\([^)]+\)|[a-zA-Z0-9_<>,.?]+)(?:\s+[a-zA-Z0-9_<>,.?]+){0,3}\s+([A-Za-z_]\w*)\s*\(/gm,
1812
+ type: "function"
1813
+ }
1814
+ ];
1815
+ var DART_KEYWORDS = /* @__PURE__ */ new Set([
1816
+ "if",
1817
+ "for",
1818
+ "while",
1819
+ "switch",
1820
+ "case",
1821
+ "catch",
1822
+ "return",
1823
+ "void",
1824
+ "dynamic",
1825
+ "final",
1826
+ "const",
1827
+ "get",
1828
+ "set",
1829
+ "true",
1830
+ "false",
1831
+ "null",
1832
+ "default",
1833
+ "break",
1834
+ "continue",
1835
+ "throw",
1836
+ "rethrow",
1837
+ "assert",
1838
+ "class",
1839
+ "mixin",
1840
+ "enum",
1841
+ "extension",
1842
+ "typedef",
1843
+ "import",
1844
+ "export",
1845
+ "part",
1846
+ "library",
1847
+ "with",
1848
+ "implements",
1849
+ "extends",
1850
+ "on"
1851
+ ]);
1852
+ var DART_PRIMITIVE_TYPES = /* @__PURE__ */ new Set([
1853
+ "String",
1854
+ "int",
1855
+ "double",
1856
+ "bool",
1857
+ "num",
1858
+ "dynamic",
1859
+ "Object",
1860
+ "void",
1861
+ "List",
1862
+ "Map",
1863
+ "Set",
1864
+ "Future",
1865
+ "Stream",
1866
+ "Function",
1867
+ "Record"
1868
+ ]);
1869
+ function extractEntities(code, filePath) {
1870
+ const cleanCode = cleanDartComments(code);
1871
+ const entities = [];
1872
+ const stem = _fileStem(filePath);
1873
+ function lineAt(offset) {
1874
+ return cleanCode.slice(0, offset).split("\n").length;
1875
+ }
1876
+ const classPattern = /^[ \t]*(?:(?:abstract|sealed|base|interface|final|mixin)\s+)*(?:class|mixin|enum|extension\s+type)\s+(\w+)/gm;
1877
+ let m;
1878
+ while ((m = classPattern.exec(cleanCode)) !== null) {
1879
+ const className = m[1];
1880
+ if (DART_KEYWORDS.has(className))
1881
+ continue;
1882
+ const line = lineAt(m.index);
1883
+ if (!entities.some((e) => e.name === className && e.line === line)) {
1884
+ entities.push({
1885
+ name: className,
1886
+ type: "class",
1887
+ line,
1888
+ complexity: "low"
1889
+ });
1890
+ }
1891
+ }
1892
+ const extPattern = /^[ \t]{0,4}extension\s+(?:(\w+)(?:<[^>]+>)?\s+)?on\s+(\w+)/gm;
1893
+ while ((m = extPattern.exec(cleanCode)) !== null) {
1894
+ const extName = m[1] || `${stem}_anonymous_extension`;
1895
+ const line = lineAt(m.index);
1896
+ if (!entities.some((e) => e.name === extName && e.line === line)) {
1897
+ entities.push({
1898
+ name: extName,
1899
+ type: "class",
1900
+ line,
1901
+ complexity: "low"
1902
+ });
1903
+ }
1904
+ }
1905
+ const typedefPattern = /^[ \t]*typedef\s+(?:[\w<>,.?\s]+\s+)?(\w+)\s*(?:<[^>]+>)?\s*(?:=\s*([^;]+)|\([^;]*\));/gm;
1906
+ while ((m = typedefPattern.exec(cleanCode)) !== null) {
1907
+ const typedefName = m[1];
1908
+ const line = lineAt(m.index);
1909
+ if (!entities.some((e) => e.name === typedefName && e.line === line)) {
1910
+ entities.push({
1911
+ name: typedefName,
1912
+ type: "type",
1913
+ line,
1914
+ complexity: "low"
1915
+ });
1916
+ }
1917
+ }
1918
+ const varPattern = /^[ \t]{0,2}(?:late\s+)?(?:(?:final|const|var)\s+)?(?:\([^)]+\)\s+|([a-zA-Z0-9_<>,.?]+(?:\s+[a-zA-Z0-9_<>,.?]+){0,3})\s+)?(?:(\w+)|(?:\w+\s*)?\(([^)]+)\))\s*(?:=|$|;)/gm;
1919
+ while ((m = varPattern.exec(cleanCode)) !== null) {
1920
+ const varType = m[1];
1921
+ const singleName = m[2];
1922
+ const destructured = m[3];
1923
+ if (!/^[ \t]*(?:late|final|const|var)\b/.test(m[0]) && !varType) {
1924
+ continue;
1925
+ }
1926
+ if (singleName && !DART_KEYWORDS.has(singleName) && !/^[A-Z]/.test(singleName)) {
1927
+ const line = lineAt(m.index);
1928
+ if (!entities.some((e) => e.name === singleName && e.line === line)) {
1929
+ entities.push({
1930
+ name: singleName,
1931
+ type: "variable",
1932
+ line,
1933
+ complexity: "low"
1934
+ });
1935
+ }
1936
+ } else if (destructured) {
1937
+ const line = lineAt(m.index);
1938
+ const names = destructured.split(",").map((n) => n.includes(":") ? n.split(":").pop().trim() : n.trim()).filter((n) => /^[a-zA-Z_]\w*$/.test(n) && !/^[A-Z]/.test(n) && !DART_KEYWORDS.has(n));
1939
+ for (const name of names) {
1940
+ if (!entities.some((e) => e.name === name && e.line === line)) {
1941
+ entities.push({
1942
+ name,
1943
+ type: "variable",
1944
+ line,
1945
+ complexity: "low"
1946
+ });
1947
+ }
1948
+ }
1949
+ }
1950
+ }
1951
+ const methodPattern = /^[ \t]{0,2}(?:factory\s+|static\s+|async\s+|external\s+|abstract\s+)?(?:\([^)]+\)|[a-zA-Z0-9_<>,.?]+)(?:\s+[a-zA-Z0-9_<>,.?]+){0,3}\s+(\w+(?:\.\w+)?)\s*\(/gm;
1952
+ while ((m = methodPattern.exec(cleanCode)) !== null) {
1953
+ const rawName = m[1];
1954
+ const name = rawName.split(".").pop();
1955
+ if (DART_KEYWORDS.has(name) || /^[A-Z]/.test(name))
1956
+ continue;
1957
+ const line = lineAt(m.index);
1958
+ if (!entities.some((e) => e.name === name && e.line === line)) {
1959
+ entities.push({
1960
+ name,
1961
+ type: "function",
1962
+ line,
1963
+ complexity: estimateComplexity(cleanCode, name)
1964
+ });
1965
+ }
1966
+ }
1967
+ const propPattern = /^[ \t]{0,2}(?:(?:static|final|late)\s+)*(?:[\w<>\[\]?]+\s+)?(?:get|set)\s+([A-Za-z_]\w*)/gm;
1968
+ while ((m = propPattern.exec(cleanCode)) !== null) {
1969
+ const name = m[1];
1970
+ if (DART_KEYWORDS.has(name))
1971
+ continue;
1972
+ const line = lineAt(m.index);
1973
+ if (!entities.some((e) => e.name === name && e.line === line)) {
1974
+ entities.push({
1975
+ name,
1976
+ type: "function",
1977
+ line,
1978
+ complexity: estimateComplexity(cleanCode, name)
1979
+ });
1980
+ }
1981
+ }
1982
+ const annotationPattern = /@(\w+)(?:\([^)]*\))?/g;
1983
+ while ((m = annotationPattern.exec(cleanCode)) !== null) {
1984
+ const annotationName = m[1];
1985
+ if (annotationName.toLowerCase() === "riverpod") {
1986
+ const annotationPos = annotationPattern.lastIndex;
1987
+ const intervening = cleanCode.slice(annotationPos, annotationPos + 300);
1988
+ const classM = /^[ \t]*(?:(?:abstract|sealed|base|interface|final|mixin)\s+)*(?:class|mixin|enum|extension\s+type)\s+(\w+)/m.exec(intervening);
1989
+ const funcM = /^[ \t]*(?:factory\s+|static\s+|async\s+|external\s+|abstract\s+)?(?:\([^)]+\)|[a-zA-Z0-9_<>,.?]+)(?:\s+[a-zA-Z0-9_<>,.?]+){0,3}\s+(\w+)\s*\(/m.exec(intervening);
1990
+ let targetName = null;
1991
+ let isClass = false;
1992
+ if (classM && funcM) {
1993
+ if (classM.index < funcM.index) {
1994
+ targetName = classM[1];
1995
+ isClass = true;
1996
+ } else {
1997
+ targetName = funcM[1];
1998
+ }
1999
+ } else if (classM) {
2000
+ targetName = classM[1];
2001
+ isClass = true;
2002
+ } else if (funcM) {
2003
+ targetName = funcM[1];
2004
+ }
2005
+ if (targetName) {
2006
+ const providerName = isClass ? (targetName.length > 1 ? targetName[0].toLowerCase() + targetName.slice(1) : targetName.toLowerCase()) + "Provider" : targetName + "Provider";
2007
+ const line = lineAt(m.index);
2008
+ if (!entities.some((e) => e.name === providerName && e.line === line)) {
2009
+ entities.push({
2010
+ name: providerName,
2011
+ type: "variable",
2012
+ line,
2013
+ complexity: "low"
2014
+ });
2015
+ }
2016
+ }
2017
+ }
2018
+ }
2019
+ return entities;
2020
+ }
2021
+ function extractImports(code) {
2022
+ const cleanCode = cleanDartComments(code);
2023
+ const imports = [];
2024
+ const importPattern = /^[ \t]*import\s+['"]([^'"]+)['"](?:\s+(?:deferred\s+)?as\s+([A-Za-z_]\w*))?((?:\s+(?:show|hide)\s+[A-Za-z0-9_,\s]+)*)\s*;/gm;
2025
+ let m;
2026
+ while ((m = importPattern.exec(cleanCode)) !== null) {
2027
+ const source = m[1];
2028
+ const alias = m[2];
2029
+ const clauses = m[3] || "";
2030
+ const isLocal = !source.startsWith("package:") && !source.startsWith("dart:");
2031
+ const names = [];
2032
+ const showMatch = clauses.match(/\bshow\s+([^;]+)/);
2033
+ if (showMatch) {
2034
+ const shown = showMatch[1].split(",").map((s) => s.trim().split(/\s+/)[0]).filter(Boolean);
2035
+ names.push(...shown);
2036
+ } else if (alias) {
2037
+ names.push(alias);
2038
+ } else {
2039
+ const baseName = path_1.default.basename(source);
2040
+ const cleanStem = baseName.endsWith(".dart") ? baseName.slice(0, -5) : baseName;
2041
+ names.push(cleanStem);
2042
+ }
2043
+ imports.push({
2044
+ source,
2045
+ names: [...new Set(names)],
2046
+ isLocal
2047
+ });
2048
+ }
2049
+ return imports;
2050
+ }
2051
+ function extractExports(code) {
2052
+ const cleanCode = cleanDartComments(code);
2053
+ const exports3 = [];
2054
+ const exportPattern = /^[ \t]*export\s+['"]([^'"]+)['"](?:\s+show\s+([A-Za-z0-9_,\s]+))?\s*;/gm;
2055
+ let m;
2056
+ while ((m = exportPattern.exec(cleanCode)) !== null) {
2057
+ const showClause = m[2];
2058
+ if (showClause) {
2059
+ const names = showClause.split(",").map((s) => s.trim().split(/\s+/)[0]).filter(Boolean);
2060
+ exports3.push(...names);
2061
+ } else {
2062
+ const base = path_1.default.basename(m[1]);
2063
+ const stem = base.endsWith(".dart") ? base.slice(0, -5) : base;
2064
+ exports3.push(stem);
2065
+ }
2066
+ }
2067
+ const typePattern = /^[ \t]*(?:(?:abstract|sealed|base|interface|final|mixin)\s+)*(?:class|mixin|enum|extension\s+type)\s+([A-Za-z_]\w*)/gm;
2068
+ while ((m = typePattern.exec(cleanCode)) !== null) {
2069
+ const name = m[1];
2070
+ if (!name.startsWith("_") && !DART_KEYWORDS.has(name)) {
2071
+ exports3.push(name);
2072
+ }
2073
+ }
2074
+ const extPattern = /^[ \t]{0,4}extension\s+([A-Za-z_]\w+)(?:<[^>]+>)?\s+on\s+[A-Za-z_]\w*/gm;
2075
+ while ((m = extPattern.exec(cleanCode)) !== null) {
2076
+ const name = m[1];
2077
+ if (name && !name.startsWith("_") && !DART_KEYWORDS.has(name)) {
2078
+ exports3.push(name);
2079
+ }
2080
+ }
2081
+ const typedefPattern = /^[ \t]*typedef\s+(?:[\w<>,.?\s]+\s+)?([A-Za-z_]\w*)\s*(?:<[^>]+>)?\s*(?:=|\()/gm;
2082
+ while ((m = typedefPattern.exec(cleanCode)) !== null) {
2083
+ const name = m[1];
2084
+ if (!name.startsWith("_") && !DART_KEYWORDS.has(name)) {
2085
+ exports3.push(name);
2086
+ }
2087
+ }
2088
+ const funcPattern = /^[ \t]{0,2}(?:factory\s+|static\s+|async\s+|external\s+|abstract\s+)?(?:\([^)]+\)|[a-zA-Z0-9_<>,.?]+)(?:\s+[a-zA-Z0-9_<>,.?]+){0,3}\s+([A-Za-z_]\w*)\s*\(/gm;
2089
+ while ((m = funcPattern.exec(cleanCode)) !== null) {
2090
+ const name = m[1];
2091
+ if (!name.startsWith("_") && !/^[A-Z]/.test(name) && !DART_KEYWORDS.has(name)) {
2092
+ exports3.push(name);
2093
+ }
2094
+ }
2095
+ const varPattern = /^[ \t]{0,2}(?:(?:final|const|var)\s+)(?:[a-zA-Z0-9_<>,.?]+\s+)?([A-Za-z_]\w*)\s*=/gm;
2096
+ while ((m = varPattern.exec(cleanCode)) !== null) {
2097
+ const name = m[1];
2098
+ if (!name.startsWith("_") && !DART_KEYWORDS.has(name)) {
2099
+ exports3.push(name);
2100
+ }
2101
+ }
2102
+ return [...new Set(exports3)];
2103
+ }
2104
+ exports2.DartParser = {
2105
+ lang: "dart",
2106
+ extensions: [".dart"],
2107
+ extractEntities,
2108
+ extractImports,
2109
+ extractExports,
2110
+ entityPatterns: exports2.dartEntityPatterns
2111
+ };
2112
+ (0, registry_1.registerParser)(exports2.DartParser);
2113
+ function extractDart(fileInput) {
2114
+ let src;
2115
+ let filePathStr;
2116
+ if (typeof fileInput === "string") {
2117
+ filePathStr = fileInput;
2118
+ const isPath = (fileInput.endsWith(".dart") || fileInput.includes("/") || fileInput.includes("\\")) && !fileInput.includes("\n");
2119
+ if (isPath) {
2120
+ try {
2121
+ src = fs_12.default.readFileSync(fileInput, "utf-8");
2122
+ } catch (err) {
2123
+ return { nodes: [], edges: [], error: `cannot read ${fileInput}` };
2124
+ }
2125
+ } else {
2126
+ src = fileInput;
2127
+ filePathStr = "main.dart";
2128
+ }
2129
+ } else {
2130
+ filePathStr = fileInput.path;
2131
+ try {
2132
+ src = fileInput.readText ? fileInput.readText() : fs_12.default.readFileSync(fileInput.path, "utf-8");
2133
+ } catch (err) {
2134
+ return { nodes: [], edges: [], error: `cannot read ${fileInput.path}` };
2135
+ }
2136
+ }
2137
+ const srcClean = cleanDartComments(src);
2138
+ function lineAt(offset) {
2139
+ return srcClean.slice(0, offset).split("\n").length;
2140
+ }
2141
+ let stem = _fileStem(filePathStr);
2142
+ let fileNid = _makeId(filePathStr);
2143
+ let isPart = false;
2144
+ const partOfMatch = /^\s*part\s+of\s+['"]([^'"]+)['"]/m.exec(srcClean);
2145
+ if (partOfMatch) {
2146
+ const parentRef = partOfMatch[1];
2147
+ if (parentRef.endsWith(".dart")) {
2148
+ try {
2149
+ const parentPath = path_1.default.resolve(path_1.default.dirname(filePathStr), parentRef);
2150
+ if (fs_12.default.existsSync(parentPath)) {
2151
+ stem = _fileStem(parentPath);
2152
+ fileNid = _makeId(parentPath);
2153
+ isPart = true;
2154
+ }
2155
+ } catch {
2156
+ }
2157
+ }
2158
+ }
2159
+ const nodes = [];
2160
+ if (!isPart) {
2161
+ nodes.push({
2162
+ id: fileNid,
2163
+ label: path_1.default.basename(filePathStr),
2164
+ file_type: "code",
2165
+ source_file: filePathStr,
2166
+ source_location: null
2167
+ });
2168
+ }
2169
+ const edges = [];
2170
+ const defined = /* @__PURE__ */ new Set();
2171
+ function addNode(nid, label, ftype = "code", sourceFile = filePathStr, line = null) {
2172
+ if (!defined.has(nid)) {
2173
+ nodes.push({
2174
+ id: nid,
2175
+ label,
2176
+ file_type: ftype,
2177
+ source_file: sourceFile,
2178
+ source_location: line ? `L${line}` : null
2179
+ });
2180
+ defined.add(nid);
2181
+ }
2182
+ }
2183
+ function addEdge(srcId, tgtId, relation, weight = 1, context, line) {
2184
+ const edge = {
2185
+ source: srcId,
2186
+ target: tgtId,
2187
+ relation,
2188
+ confidence: "EXTRACTED",
2189
+ confidence_score: 1,
2190
+ source_file: filePathStr,
2191
+ source_location: line ? `L${line}` : null,
2192
+ weight
2193
+ };
2194
+ if (context)
2195
+ edge.context = context;
2196
+ edges.push(edge);
2197
+ }
2198
+ const classPattern = /^\s*(?:(?:abstract|sealed|base|interface|final|mixin)\s+)*(?:class|mixin|enum|extension\s+type)\s+(\w+)/gm;
2199
+ let m;
2200
+ while ((m = classPattern.exec(srcClean)) !== null) {
2201
+ const className = m[1];
2202
+ const classLine = lineAt(m.index + m[0].indexOf(className));
2203
+ const classNid = _makeId(stem, className);
2204
+ addNode(classNid, className, "code", filePathStr, classLine);
2205
+ addEdge(fileNid, classNid, "defines", 1, void 0, classLine);
2206
+ const startIdx = classPattern.lastIndex;
2207
+ let rest = srcClean.slice(startIdx, startIdx + 500);
2208
+ if (rest.trimStart().startsWith("<")) {
2209
+ const offset = rest.indexOf("<");
2210
+ let depth = 1;
2211
+ let i = offset + 1;
2212
+ while (i < rest.length && depth > 0) {
2213
+ if (rest[i] === "<")
2214
+ depth++;
2215
+ else if (rest[i] === ">")
2216
+ depth--;
2217
+ i++;
2218
+ }
2219
+ rest = rest.slice(i);
2220
+ }
2221
+ if (rest.trimStart().startsWith("(")) {
2222
+ const offset = rest.indexOf("(");
2223
+ let depth = 1;
2224
+ let i = offset + 1;
2225
+ while (i < rest.length && depth > 0) {
2226
+ if (rest[i] === "(")
2227
+ depth++;
2228
+ else if (rest[i] === ")")
2229
+ depth--;
2230
+ i++;
2231
+ }
2232
+ rest = rest.slice(i);
2233
+ }
2234
+ let headerEnd = rest.indexOf("{");
2235
+ if (headerEnd === -1)
2236
+ headerEnd = rest.indexOf(";");
2237
+ if (headerEnd === -1)
2238
+ headerEnd = rest.length;
2239
+ let header = rest.slice(0, headerEnd);
2240
+ let baseClass = null;
2241
+ let generics = null;
2242
+ let mixinsList = [];
2243
+ let interfacesList = [];
2244
+ const extendsM = /^\s*(?:extends|on)\s+([a-zA-Z0-9_.]+)/.exec(header);
2245
+ if (extendsM) {
2246
+ baseClass = extendsM[1];
2247
+ const restHeader = header.slice(extendsM.index + extendsM[0].length);
2248
+ if (restHeader.trimStart().startsWith("<")) {
2249
+ const startBracket = restHeader.indexOf("<");
2250
+ let depth = 1;
2251
+ let i = startBracket + 1;
2252
+ while (i < restHeader.length && depth > 0) {
2253
+ if (restHeader[i] === "<")
2254
+ depth++;
2255
+ else if (restHeader[i] === ">") {
2256
+ depth--;
2257
+ if (depth === 0) {
2258
+ generics = restHeader.slice(startBracket + 1, i);
2259
+ break;
2260
+ }
2261
+ }
2262
+ i++;
2263
+ }
2264
+ header = generics !== null ? restHeader.slice(i + 1) : restHeader;
2265
+ } else {
2266
+ header = restHeader;
2267
+ }
2268
+ }
2269
+ const withM = /^\s*with\s+/.exec(header);
2270
+ if (withM) {
2271
+ const restHeader = header.slice(withM.index + withM[0].length);
2272
+ const implIdx = restHeader.indexOf("implements");
2273
+ let mixinsStr = "";
2274
+ if (implIdx !== -1) {
2275
+ mixinsStr = restHeader.slice(0, implIdx);
2276
+ header = restHeader.slice(implIdx);
2277
+ } else {
2278
+ mixinsStr = restHeader;
2279
+ header = "";
2280
+ }
2281
+ mixinsList = _splitTypes(mixinsStr);
2282
+ }
2283
+ const implM = /^\s*implements\s+/.exec(header);
2284
+ if (implM) {
2285
+ interfacesList = _splitTypes(header.slice(implM.index + implM[0].length));
2286
+ }
2287
+ if (baseClass) {
2288
+ const baseNid = _makeId(baseClass);
2289
+ addNode(baseNid, baseClass, "code", null);
2290
+ addEdge(classNid, baseNid, "inherits", 1, void 0, classLine);
2291
+ if (generics) {
2292
+ for (const gen of _splitTypes(generics)) {
2293
+ const genClean = gen.split("<")[0].trim();
2294
+ if (!DART_PRIMITIVE_TYPES.has(genClean)) {
2295
+ const genNid = _makeId(genClean);
2296
+ addNode(genNid, genClean, "code", null);
2297
+ addEdge(classNid, genNid, "references", 1, void 0, classLine);
2298
+ }
2299
+ }
2300
+ }
2301
+ }
2302
+ for (const mixin of mixinsList) {
2303
+ const mixinClean = mixin.split("<")[0].trim();
2304
+ const mixinNid = _makeId(mixinClean);
2305
+ addNode(mixinNid, mixinClean, "code", null);
2306
+ addEdge(classNid, mixinNid, "mixes_in", 1, void 0, classLine);
2307
+ }
2308
+ for (const iface of interfacesList) {
2309
+ const ifaceClean = iface.split("<")[0].trim();
2310
+ const ifaceNid = _makeId(ifaceClean);
2311
+ addNode(ifaceNid, ifaceClean, "code", null);
2312
+ addEdge(classNid, ifaceNid, "implements", 1, void 0, classLine);
2313
+ }
2314
+ const declStart = m.index;
2315
+ const bracePos = srcClean.indexOf("{", declStart);
2316
+ const semiPos = srcClean.indexOf(";", declStart);
2317
+ let hasBody = bracePos !== -1;
2318
+ if (hasBody && semiPos !== -1 && semiPos < bracePos) {
2319
+ hasBody = false;
2320
+ }
2321
+ if (hasBody) {
2322
+ const endPos = _findMatchingBrace(srcClean, declStart);
2323
+ const classBody = srcClean.slice(bracePos, endPos);
2324
+ const onEventRegex = /\bon<(\w+)>\s*\(/g;
2325
+ let em;
2326
+ while ((em = onEventRegex.exec(classBody)) !== null) {
2327
+ const eventName = em[1];
2328
+ const eventNid = _makeId(eventName);
2329
+ addNode(eventNid, eventName, "code", null);
2330
+ addEdge(classNid, eventNid, "calls", 1, "bloc_event", lineAt(bracePos + em.index));
2331
+ }
2332
+ const emitRegex = /\b(?:emit|yield)\s*\(?\s*(?:const\s+)?([A-Z]\w*)\b/g;
2333
+ let sm;
2334
+ while ((sm = emitRegex.exec(classBody)) !== null) {
2335
+ const stateName = sm[1];
2336
+ if (!DART_PRIMITIVE_TYPES.has(stateName)) {
2337
+ const stateNid = _makeId(stateName);
2338
+ addNode(stateNid, stateName, "code", null);
2339
+ addEdge(classNid, stateNid, "calls", 1, "emit_state", lineAt(bracePos + sm.index));
2340
+ }
2341
+ }
2342
+ const addEventRegex = /\b(?:(?:\w*[Bb]loc\w*|context\.read<\w+>\(\)|widget)\.)?add\(\s*(?:const\s+)?([A-Z]\w*)\b/g;
2343
+ let am;
2344
+ while ((am = addEventRegex.exec(classBody)) !== null) {
2345
+ const eventName = am[1];
2346
+ if (!DART_PRIMITIVE_TYPES.has(eventName)) {
2347
+ const eventNid = _makeId(eventName);
2348
+ addNode(eventNid, eventName, "code", null);
2349
+ addEdge(classNid, eventNid, "calls", 1, "bloc_add_event", lineAt(bracePos + am.index));
2350
+ }
2351
+ }
2352
+ const refRegex = /\bref\.(?:watch|read|listen)\s*\(\s*(\w+)\b/g;
2353
+ let rm;
2354
+ while ((rm = refRegex.exec(classBody)) !== null) {
2355
+ const providerName = rm[1];
2356
+ const providerNid = _makeId(providerName);
2357
+ addNode(providerNid, providerName, "code", null);
2358
+ addEdge(classNid, providerNid, "references", 1, "riverpod_reference", lineAt(bracePos + rm.index));
2359
+ }
2360
+ const widgetBlocRegex = /\bBloc(?:Builder|Listener|Consumer|Provider|Selector)\s*<\s*([a-zA-Z0-9_]+)\b/g;
2361
+ let bm;
2362
+ while ((bm = widgetBlocRegex.exec(classBody)) !== null) {
2363
+ const blocName = bm[1];
2364
+ if (!DART_PRIMITIVE_TYPES.has(blocName)) {
2365
+ const blocNid = _makeId(blocName);
2366
+ addNode(blocNid, blocName, "code", null);
2367
+ addEdge(classNid, blocNid, "references", 1, "bloc_widget_binding", lineAt(bracePos + bm.index));
2368
+ }
2369
+ }
2370
+ const contextLookupRegex = /\b(?:read|watch|select|of)\s*<([a-zA-Z0-9_]+)>/g;
2371
+ let lm;
2372
+ while ((lm = contextLookupRegex.exec(classBody)) !== null) {
2373
+ const blocName = lm[1];
2374
+ if (!DART_PRIMITIVE_TYPES.has(blocName)) {
2375
+ const blocNid = _makeId(blocName);
2376
+ addNode(blocNid, blocName, "code", null);
2377
+ addEdge(classNid, blocNid, "references", 1, "bloc_lookup", lineAt(bracePos + lm.index));
2378
+ }
2379
+ }
2380
+ }
2381
+ }
2382
+ const annotationPattern = /@(\w+)(?:\([^)]*\))?/g;
2383
+ let anMatch;
2384
+ while ((anMatch = annotationPattern.exec(srcClean)) !== null) {
2385
+ const annotationName = anMatch[1];
2386
+ if (["override", "deprecated", "required", "protected", "mustCallSuper"].includes(annotationName)) {
2387
+ continue;
2388
+ }
2389
+ const annotationPos = annotationPattern.lastIndex;
2390
+ const intervening = srcClean.slice(annotationPos, annotationPos + 300);
2391
+ const classM = /^\s*(?:(?:abstract|sealed|base|interface|final|mixin)\s+)*(?:class|mixin|enum|extension\s+type)\s+(\w+)/m.exec(intervening);
2392
+ const funcM = /^\s*(?:factory\s+|static\s+|async\s+|external\s+|abstract\s+)?(?:\([^)]+\)|[a-zA-Z0-9_<>,.?]+)(?:\s+[a-zA-Z0-9_<>,.?]+){0,3}\s+(\w+)\s*\(/m.exec(intervening);
2393
+ let targetNid = null;
2394
+ let targetName = null;
2395
+ let targetType = null;
2396
+ if (classM && funcM) {
2397
+ if (classM.index < funcM.index) {
2398
+ targetName = classM[1];
2399
+ targetType = "class";
2400
+ targetNid = _makeId(stem, targetName);
2401
+ } else {
2402
+ targetName = funcM[1];
2403
+ targetType = "function";
2404
+ targetNid = _makeId(stem, targetName);
2405
+ }
2406
+ } else if (classM) {
2407
+ targetName = classM[1];
2408
+ targetType = "class";
2409
+ targetNid = _makeId(stem, targetName);
2410
+ } else if (funcM) {
2411
+ targetName = funcM[1];
2412
+ targetType = "function";
2413
+ targetNid = _makeId(stem, targetName);
2414
+ }
2415
+ if (targetNid && targetName) {
2416
+ const minOffset = Math.min(classM ? classM.index : 300, funcM ? funcM.index : 300);
2417
+ const actualIntervening = intervening.slice(0, minOffset);
2418
+ if (!actualIntervening.includes(";") && !actualIntervening.includes("}") && !actualIntervening.includes("{")) {
2419
+ const annotationLine = lineAt(anMatch.index);
2420
+ const annotationNid = _makeId("annotation", annotationName.toLowerCase());
2421
+ addNode(annotationNid, `@${annotationName}`, "concept", null);
2422
+ addEdge(targetNid, annotationNid, "configures", 1, void 0, annotationLine);
2423
+ if (annotationName.toLowerCase() === "riverpod") {
2424
+ const providerName = targetType === "class" ? (targetName.length > 1 ? targetName[0].toLowerCase() + targetName.slice(1) : targetName.toLowerCase()) + "Provider" : targetName + "Provider";
2425
+ const providerNid = _makeId(providerName);
2426
+ addNode(providerNid, providerName, "concept", filePathStr, annotationLine);
2427
+ addEdge(targetNid, providerNid, "defines", 1, "riverpod_provider", annotationLine);
2428
+ }
2429
+ }
2430
+ }
2431
+ }
2432
+ const typedefPattern = /^\s*typedef\s+(\w+)\s*(?:<[^>]+>)?\s*=\s*([^;]+);/gm;
2433
+ while ((m = typedefPattern.exec(srcClean)) !== null) {
2434
+ const typedefName = m[1];
2435
+ const typedefLine = lineAt(m.index);
2436
+ const targetType = m[2].split("<")[0].split(".").pop().trim();
2437
+ if (!DART_PRIMITIVE_TYPES.has(targetType)) {
2438
+ const typedefNid = _makeId(stem, typedefName);
2439
+ addNode(typedefNid, typedefName, "code", filePathStr, typedefLine);
2440
+ addEdge(fileNid, typedefNid, "defines", 1, void 0, typedefLine);
2441
+ const targetNid = _makeId(targetType);
2442
+ addNode(targetNid, targetType, "code", null);
2443
+ addEdge(typedefNid, targetNid, "references", 1, "typedef", typedefLine);
2444
+ }
2445
+ }
2446
+ const extPattern = /^\s{0,4}extension\s+(?:(\w+)(?:<[^>]+>)?\s+)?on\s+(\w+)/gm;
2447
+ while ((m = extPattern.exec(srcClean)) !== null) {
2448
+ const extName = m[1] || `${stem}_anonymous_extension`;
2449
+ const targetClass = m[2];
2450
+ const extLine = lineAt(m.index);
2451
+ const extNid = _makeId(stem, extName);
2452
+ const label = m[1] || `Extension on ${targetClass}`;
2453
+ addNode(extNid, label, "code", filePathStr, extLine);
2454
+ addEdge(fileNid, extNid, "defines", 1, void 0, extLine);
2455
+ const targetNid = _makeId(targetClass);
2456
+ addNode(targetNid, targetClass, "code", null);
2457
+ addEdge(extNid, targetNid, "extends", 1, void 0, extLine);
2458
+ }
2459
+ const varPattern = /^\s{0,2}(?:late\s+)?(?:(?:final|const|var)\s+)?(?:\([^)]+\)\s+|([a-zA-Z0-9_<>,.?]+(?:\s+[a-zA-Z0-9_<>,.?]+){0,3})\s+)?(?:(\w+)|(?:\w+\s*)?\(([^)]+)\))\s*(?:=|$|;)/gm;
2460
+ while ((m = varPattern.exec(srcClean)) !== null) {
2461
+ const varType = m[1];
2462
+ const singleName = m[2];
2463
+ const destructuredNames = m[3];
2464
+ if (!/^\s*(?:late|final|const|var)\b/.test(m[0]) && !varType) {
2465
+ continue;
2466
+ }
2467
+ if (singleName && !["if", "for", "while", "switch", "catch", "return"].includes(singleName)) {
2468
+ const varLine = lineAt(m.index);
2469
+ const varNid = _makeId(stem, singleName);
2470
+ addNode(varNid, singleName, "code", filePathStr, varLine);
2471
+ addEdge(fileNid, varNid, "defines", 1, void 0, varLine);
2472
+ if (varType) {
2473
+ const cleanType = varType.split("<")[0].split(".").pop().trim();
2474
+ if (!DART_PRIMITIVE_TYPES.has(cleanType)) {
2475
+ const typeNid = _makeId(cleanType);
2476
+ addNode(typeNid, cleanType, "code", null);
2477
+ addEdge(fileNid, typeNid, "references", 1, "variable_type", varLine);
2478
+ }
2479
+ }
2480
+ } else if (destructuredNames) {
2481
+ const destructureLine = lineAt(m.index);
2482
+ const names = destructuredNames.split(",").map((n) => n.includes(":") ? n.split(":").pop().trim() : n.trim()).filter((n) => /^[a-zA-Z_]\w*$/.test(n) && !/^[A-Z]/.test(n) && !["if", "for", "while", "switch", "catch", "return"].includes(n));
2483
+ for (const name of names) {
2484
+ const varNid = _makeId(stem, name);
2485
+ addNode(varNid, name, "code", filePathStr, destructureLine);
2486
+ addEdge(fileNid, varNid, "defines", 1, void 0, destructureLine);
2487
+ }
2488
+ }
2489
+ }
2490
+ const methodPattern = /^\s{0,2}(?:factory\s+|static\s+|async\s+|external\s+|abstract\s+)?(?:\([^)]+\)|[a-zA-Z0-9_<>,.?]+)(?:\s+[a-zA-Z0-9_<>,.?]+){0,3}\s+(\w+(?:\.\w+)?)\s*\(/gm;
2491
+ while ((m = methodPattern.exec(srcClean)) !== null) {
2492
+ const rawName = m[1];
2493
+ const name = rawName.split(".").pop();
2494
+ if (["if", "for", "while", "switch", "catch", "return", "void", "dynamic", "final", "const", "get", "set"].includes(name)) {
2495
+ continue;
2496
+ }
2497
+ if (/^[A-Z]/.test(name))
2498
+ continue;
2499
+ const methodLine = lineAt(m.index);
2500
+ const nid = _makeId(stem, name);
2501
+ addNode(nid, name, "code", filePathStr, methodLine);
2502
+ addEdge(fileNid, nid, "defines", 1, void 0, methodLine);
2503
+ const startIdx = m.index;
2504
+ const bracePos = srcClean.indexOf("{", startIdx);
2505
+ const semiPos = srcClean.indexOf(";", startIdx);
2506
+ const arrowPos = srcClean.indexOf("=>", startIdx);
2507
+ let hasBody = bracePos !== -1;
2508
+ if (hasBody && semiPos !== -1 && semiPos < bracePos)
2509
+ hasBody = false;
2510
+ if (hasBody && arrowPos !== -1 && arrowPos < bracePos)
2511
+ hasBody = false;
2512
+ if (hasBody) {
2513
+ const endPos = _findMatchingBrace(srcClean, startIdx);
2514
+ const funcBody = srcClean.slice(bracePos, endPos);
2515
+ const refRegex = /\bref\.(?:watch|read|listen)\s*\(\s*(\w+)\b/g;
2516
+ let rm;
2517
+ while ((rm = refRegex.exec(funcBody)) !== null) {
2518
+ const providerName = rm[1];
2519
+ const providerNid = _makeId(providerName);
2520
+ addNode(providerNid, providerName, "code", null);
2521
+ addEdge(nid, providerNid, "references", 1, "riverpod_reference", lineAt(bracePos + rm.index));
2522
+ }
2523
+ const addEventRegex = /\b(?:(?:\w*[Bb]loc\w*|context\.read<\w+>\(\)|widget)\.)?add\(\s*(?:const\s+)?([A-Z]\w*)\b/g;
2524
+ let am;
2525
+ while ((am = addEventRegex.exec(funcBody)) !== null) {
2526
+ const eventName = am[1];
2527
+ if (!DART_PRIMITIVE_TYPES.has(eventName)) {
2528
+ const eventNid = _makeId(eventName);
2529
+ addNode(eventNid, eventName, "code", null);
2530
+ addEdge(nid, eventNid, "calls", 1, "bloc_add_event", lineAt(bracePos + am.index));
2531
+ }
2532
+ }
2533
+ const contextLookupRegex = /\b(?:read|watch|select|of)\s*<([a-zA-Z0-9_]+)>/g;
2534
+ let lm;
2535
+ while ((lm = contextLookupRegex.exec(funcBody)) !== null) {
2536
+ const blocName = lm[1];
2537
+ if (!DART_PRIMITIVE_TYPES.has(blocName)) {
2538
+ const blocNid = _makeId(blocName);
2539
+ addNode(blocNid, blocName, "code", null);
2540
+ addEdge(nid, blocNid, "references", 1, "bloc_lookup", lineAt(bracePos + lm.index));
2541
+ }
2542
+ }
2543
+ const routePathRegex = /\b(?:go|push|goNamed|pushNamed|replace|replaceNamed)\s*\(\s*(?:context\s*,\s*)?['"]([a-zA-Z0-9_/?=&%-]+)['"]/g;
2544
+ let nm;
2545
+ while ((nm = routePathRegex.exec(funcBody)) !== null) {
2546
+ const routePath = nm[1];
2547
+ const routeNid = _makeId("route", routePath.replace(/[/=&#?-]/g, "_"));
2548
+ addNode(routeNid, `Route ${routePath}`, "concept", null);
2549
+ addEdge(nid, routeNid, "navigates", 1, "route_path", lineAt(bracePos + nm.index));
2550
+ }
2551
+ const routeConstRegex = /\b(?:go|push|goNamed|pushNamed|replace|replaceNamed)\s*\(\s*(?:context\s*,\s*)?([A-Z][a-zA-Z0-9_]*\.[a-zA-Z0-9_]+)/g;
2552
+ let cm;
2553
+ while ((cm = routeConstRegex.exec(funcBody)) !== null) {
2554
+ const routeConst = cm[1];
2555
+ const routeNid = _makeId("route", routeConst.replace(/\./g, "_"));
2556
+ addNode(routeNid, routeConst, "concept", null);
2557
+ addEdge(nid, routeNid, "navigates", 1, "route_const", lineAt(bracePos + cm.index));
2558
+ }
2559
+ const routeObjRegex = /\b(?:push|replace)\s*\(\s*(?:context\s*,\s*)?.*?\b([A-Z]\w*(?:Route|Screen|Page))\b/g;
2560
+ let om;
2561
+ while ((om = routeObjRegex.exec(funcBody)) !== null) {
2562
+ const routeClass = om[1];
2563
+ const routeNid = _makeId(routeClass);
2564
+ addNode(routeNid, routeClass, "code", null);
2565
+ addEdge(nid, routeNid, "navigates", 1, "route_object", lineAt(bracePos + om.index));
2566
+ }
2567
+ }
2568
+ }
2569
+ const importPattern = /^\s*import\s+['"]([^'"]+)['"]/gm;
2570
+ while ((m = importPattern.exec(srcClean)) !== null) {
2571
+ const pkg = m[1];
2572
+ const tgtNid = _makeId(pkg);
2573
+ addNode(tgtNid, pkg, "code", null);
2574
+ addEdge(fileNid, tgtNid, "imports", 1, void 0, lineAt(m.index));
2575
+ }
2576
+ const exportPattern = /^\s*export\s+['"]([^'"]+)['"]/gm;
2577
+ while ((m = exportPattern.exec(srcClean)) !== null) {
2578
+ const pkg = m[1];
2579
+ const tgtNid = _makeId(pkg);
2580
+ addNode(tgtNid, pkg, "code", null);
2581
+ addEdge(fileNid, tgtNid, "exports", 1, void 0, lineAt(m.index));
2582
+ }
2583
+ const genericCallPattern = /\b\w+<([a-zA-Z0-9_.]+(?:<[a-zA-Z0-9_.,\s<>]+>)?)\s*>\s*\(/g;
2584
+ while ((m = genericCallPattern.exec(srcClean)) !== null) {
2585
+ const typeName = m[1].split(".").pop().trim();
2586
+ const cleanName = typeName.split("<")[0].trim();
2587
+ if (!DART_PRIMITIVE_TYPES.has(cleanName)) {
2588
+ const targetNid = _makeId(cleanName);
2589
+ addNode(targetNid, cleanName, "code", null);
2590
+ addEdge(fileNid, targetNid, "references", 1, "type_lookup", lineAt(m.index));
2591
+ }
2592
+ }
2593
+ return { nodes, edges };
2594
+ }
2595
+ }
2596
+ });
2597
+
2598
+ // dist/languages/rust.js
2599
+ var require_rust = __commonJS({
2600
+ "dist/languages/rust.js"(exports2) {
2601
+ "use strict";
2602
+ var __importDefault2 = exports2 && exports2.__importDefault || function(mod) {
2603
+ return mod && mod.__esModule ? mod : { "default": mod };
2604
+ };
2605
+ Object.defineProperty(exports2, "__esModule", { value: true });
2606
+ exports2.RustParser = exports2.rustEntityPatterns = exports2.RUST_TRAIT_METHOD_BLOCKLIST = void 0;
2607
+ exports2._fileStem = _fileStem;
2608
+ exports2._makeId = _makeId;
2609
+ exports2.cleanRustComments = cleanRustComments;
2610
+ exports2._splitBalanced = _splitBalanced;
2611
+ exports2._findMatchingBrace = _findMatchingBrace;
2612
+ exports2._rustCollectTypeRefs = _rustCollectTypeRefs;
2613
+ exports2.estimateComplexity = estimateComplexity;
2614
+ exports2.extractRust = extractRust;
2615
+ var fs_12 = __importDefault2(require("fs"));
2616
+ var path_1 = __importDefault2(require("path"));
2617
+ var registry_1 = require_registry();
2618
+ var constants_1 = require_constants();
2619
+ exports2.RUST_TRAIT_METHOD_BLOCKLIST = /* @__PURE__ */ new Set([
2620
+ "new",
2621
+ "default",
2622
+ "parse",
2623
+ "from_str",
2624
+ "now",
2625
+ "clone",
2626
+ "into",
2627
+ "from",
2628
+ "to_string",
2629
+ "to_owned",
2630
+ "len",
2631
+ "is_empty",
2632
+ "iter",
2633
+ "next",
2634
+ "build",
2635
+ "start",
2636
+ "run",
2637
+ "init",
2638
+ "app",
2639
+ "get",
2640
+ "set",
2641
+ "push",
2642
+ "pop",
2643
+ "insert",
2644
+ "remove",
2645
+ "contains",
2646
+ "collect",
2647
+ "map",
2648
+ "filter",
2649
+ "unwrap",
2650
+ "expect",
2651
+ "ok",
2652
+ "err",
2653
+ "some",
2654
+ "none",
2655
+ "send",
2656
+ "recv",
2657
+ "lock",
2658
+ "read",
2659
+ "write"
2660
+ ]);
2661
+ var RUST_PRIMITIVES = /* @__PURE__ */ new Set([
2662
+ "bool",
2663
+ "char",
2664
+ "str",
2665
+ "i8",
2666
+ "i16",
2667
+ "i32",
2668
+ "i64",
2669
+ "i128",
2670
+ "isize",
2671
+ "u8",
2672
+ "u16",
2673
+ "u32",
2674
+ "u64",
2675
+ "u128",
2676
+ "usize",
2677
+ "f32",
2678
+ "f64",
2679
+ "()",
2680
+ "!"
2681
+ ]);
2682
+ var RUST_KEYWORDS = /* @__PURE__ */ new Set([
2683
+ "as",
2684
+ "async",
2685
+ "await",
2686
+ "break",
2687
+ "const",
2688
+ "continue",
2689
+ "crate",
2690
+ "dyn",
2691
+ "else",
2692
+ "enum",
2693
+ "extern",
2694
+ "false",
2695
+ "fn",
2696
+ "for",
2697
+ "if",
2698
+ "impl",
2699
+ "in",
2700
+ "let",
2701
+ "loop",
2702
+ "match",
2703
+ "mod",
2704
+ "move",
2705
+ "mut",
2706
+ "pub",
2707
+ "ref",
2708
+ "return",
2709
+ "self",
2710
+ "Self",
2711
+ "static",
2712
+ "struct",
2713
+ "super",
2714
+ "trait",
2715
+ "true",
2716
+ "type",
2717
+ "unsafe",
2718
+ "use",
2719
+ "where",
2720
+ "while"
2721
+ ]);
2722
+ function escapeRegex(s) {
2723
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2724
+ }
2725
+ function _fileStem(filePath) {
2726
+ const base = path_1.default.basename(filePath);
2727
+ const ext = path_1.default.extname(base);
2728
+ return ext ? base.slice(0, -ext.length) : base;
2729
+ }
2730
+ function _makeId(...parts) {
2731
+ return parts.filter((p) => Boolean(p && p.trim())).map((p) => p.trim().replace(/[^a-zA-Z0-9_.-]/g, "_")).join("__");
2732
+ }
2733
+ function cleanRustComments(src) {
2734
+ const commentStringPattern = /b?r(#*)".*?"\1|b?"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])'|\/\*[\s\S]*?\*\/|\/\/[^\n]*/g;
2735
+ return src.replace(commentStringPattern, (token) => {
2736
+ if (token.startsWith("/")) {
2737
+ const newlineCount = (token.match(/\n/g) || []).length;
2738
+ return "\n".repeat(newlineCount);
2739
+ }
2740
+ return token;
2741
+ });
2742
+ }
2743
+ function _splitBalanced(text, delim = ",") {
2744
+ const parts = [];
2745
+ const current = [];
2746
+ let depthAngle = 0;
2747
+ let depthParen = 0;
2748
+ let depthBracket = 0;
2749
+ for (let i = 0; i < text.length; i++) {
2750
+ const ch = text[i];
2751
+ if (ch === "<")
2752
+ depthAngle++;
2753
+ else if (ch === ">")
2754
+ depthAngle--;
2755
+ else if (ch === "(")
2756
+ depthParen++;
2757
+ else if (ch === ")")
2758
+ depthParen--;
2759
+ else if (ch === "[")
2760
+ depthBracket++;
2761
+ else if (ch === "]")
2762
+ depthBracket--;
2763
+ else if (ch === delim && depthAngle === 0 && depthParen === 0 && depthBracket === 0) {
2764
+ const trimmed = current.join("").trim();
2765
+ if (trimmed)
2766
+ parts.push(trimmed);
2767
+ current.length = 0;
2768
+ continue;
2769
+ }
2770
+ current.push(ch);
2771
+ }
2772
+ if (current.length > 0) {
2773
+ const trimmed = current.join("").trim();
2774
+ if (trimmed)
2775
+ parts.push(trimmed);
2776
+ }
2777
+ return parts;
2778
+ }
2779
+ function _findMatchingBrace(text, startPos) {
2780
+ let braceCount = 0;
2781
+ let inDoubleQuote = false;
2782
+ let escape = false;
2783
+ const firstBrace = text.indexOf("{", startPos);
2784
+ if (firstBrace === -1)
2785
+ return text.length;
2786
+ braceCount = 1;
2787
+ let i = firstBrace + 1;
2788
+ const n = text.length;
2789
+ while (i < n) {
2790
+ const char = text[i];
2791
+ if (escape) {
2792
+ escape = false;
2793
+ i++;
2794
+ continue;
2795
+ }
2796
+ if (char === "\\") {
2797
+ escape = true;
2798
+ i++;
2799
+ continue;
2800
+ }
2801
+ if (char === '"') {
2802
+ inDoubleQuote = !inDoubleQuote;
2803
+ } else if (!inDoubleQuote) {
2804
+ if (char === "{") {
2805
+ braceCount++;
2806
+ } else if (char === "}") {
2807
+ braceCount--;
2808
+ if (braceCount === 0) {
2809
+ return i + 1;
2810
+ }
2811
+ }
2812
+ }
2813
+ i++;
2814
+ }
2815
+ return text.length;
2816
+ }
2817
+ function _rustCollectTypeRefs(typeStr, generic, out) {
2818
+ if (!typeStr)
2819
+ return;
2820
+ const raw = typeStr.trim();
2821
+ if (!raw)
2822
+ return;
2823
+ let clean = raw.replace(/&(?:\s*'[a-zA-Z_]\w*)?\s*(?:mut\s+)?/g, "").trim();
2824
+ clean = clean.replace(/^\*(?:const|mut)\s+/g, "").trim();
2825
+ if (clean.startsWith("[") && clean.endsWith("]")) {
2826
+ const inner = clean.slice(1, -1).split(";")[0].trim();
2827
+ _rustCollectTypeRefs(inner, generic, out);
2828
+ return;
2829
+ }
2830
+ if (clean.startsWith("(") && clean.endsWith(")")) {
2831
+ const inner = clean.slice(1, -1).trim();
2832
+ if (inner) {
2833
+ for (const part of _splitBalanced(inner)) {
2834
+ _rustCollectTypeRefs(part, generic, out);
2835
+ }
2836
+ }
2837
+ return;
2838
+ }
2839
+ if (clean.includes("+") && !clean.includes("<")) {
2840
+ for (const part of clean.split("+")) {
2841
+ _rustCollectTypeRefs(part.trim(), generic, out);
2842
+ }
2843
+ return;
2844
+ }
2845
+ if (clean.startsWith("dyn ")) {
2846
+ clean = clean.slice(4).trim();
2847
+ }
2848
+ const angleIdx = clean.indexOf("<");
2849
+ if (angleIdx !== -1 && clean.endsWith(">")) {
2850
+ const baseType = clean.slice(0, angleIdx).trim();
2851
+ const lastBaseSegment = baseType.split("::").pop().trim();
2852
+ if (!RUST_PRIMITIVES.has(lastBaseSegment) && lastBaseSegment) {
2853
+ out.push([lastBaseSegment, generic ? "generic_arg" : "type"]);
2854
+ }
2855
+ const argsText = clean.slice(angleIdx + 1, -1).trim();
2856
+ const args2 = _splitBalanced(argsText);
2857
+ for (const arg of args2) {
2858
+ _rustCollectTypeRefs(arg, true, out);
2859
+ }
2860
+ return;
2861
+ }
2862
+ const lastSegment = clean.split("::").pop().trim();
2863
+ if (!RUST_PRIMITIVES.has(lastSegment) && /^[a-zA-Z_]\w*$/.test(lastSegment)) {
2864
+ out.push([lastSegment, generic ? "generic_arg" : "type"]);
2865
+ }
2866
+ }
2867
+ function estimateComplexity(code, name) {
2868
+ const lines = code.split("\n");
2869
+ const defRegex = new RegExp(`(?:^|\\s)fn\\s+${escapeRegex(name)}\\s*(?:<[^>]*>)?\\s*\\(`, "m");
2870
+ const defLineIdx = lines.findIndex((l) => defRegex.test(l));
2871
+ if (defLineIdx === -1)
2872
+ return "low";
2873
+ let startLine = defLineIdx;
2874
+ while (startLine < lines.length && !lines[startLine].includes("{")) {
2875
+ startLine++;
2876
+ }
2877
+ if (startLine >= lines.length)
2878
+ return "low";
2879
+ let braceCount = 0;
2880
+ let started = false;
2881
+ const bodyLines = [];
2882
+ for (let i = startLine; i < lines.length; i++) {
2883
+ const line = lines[i];
2884
+ for (const ch of line) {
2885
+ if (ch === "{") {
2886
+ braceCount++;
2887
+ started = true;
2888
+ } else if (ch === "}") {
2889
+ braceCount--;
2890
+ }
2891
+ }
2892
+ bodyLines.push(line);
2893
+ if (started && braceCount <= 0)
2894
+ break;
2895
+ }
2896
+ const body = bodyLines.join("\n");
2897
+ const branches = (body.match(/\b(if|else\s+if|else|for|while|loop|match)\b|\?|(&&|\|\|)/g) || []).length;
2898
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.low)
2899
+ return "low";
2900
+ if (branches <= constants_1.COMPLEXITY_THRESHOLDS.medium)
2901
+ return "medium";
2902
+ return "high";
2903
+ }
2904
+ exports2.rustEntityPatterns = [
2905
+ // Functions: free functions, methods, async fn, const fn, unsafe fn
2906
+ {
2907
+ regex: /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?(?:(?:async|const|unsafe|extern(?:\s+"[^"]*")?)\s+)*fn\s+([A-Za-z_]\w*)/gm,
2908
+ type: "function"
2909
+ },
2910
+ // Structs
2911
+ {
2912
+ regex: /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?struct\s+([A-Za-z_]\w*)/gm,
2913
+ type: "class"
2914
+ },
2915
+ // Enums
2916
+ {
2917
+ regex: /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?enum\s+([A-Za-z_]\w*)/gm,
2918
+ type: "class"
2919
+ },
2920
+ // Traits
2921
+ {
2922
+ regex: /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?(?:unsafe\s+)?trait\s+([A-Za-z_]\w*)/gm,
2923
+ type: "interface"
2924
+ },
2925
+ // Impl blocks: impl Type or impl Trait for Type
2926
+ {
2927
+ regex: /^[ \t]*impl(?:\s*<[^>]*>)?\s+(?:[A-Za-z_]\w*(?:\s*<[^>]*>)?\s+for\s+)?([A-Za-z_]\w*)/gm,
2928
+ type: "class"
2929
+ },
2930
+ // Type aliases
2931
+ {
2932
+ regex: /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?type\s+([A-Za-z_]\w*)/gm,
2933
+ type: "type"
2934
+ }
2935
+ ];
2936
+ function extractEntities(code, _filePath) {
2937
+ const cleanCode = cleanRustComments(code);
2938
+ const entities = [];
2939
+ function lineAt(offset) {
2940
+ return cleanCode.slice(0, offset).split("\n").length;
2941
+ }
2942
+ const itemPattern = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?(?:(struct|enum)|(?:unsafe\s+)?(trait))\s+([A-Za-z_]\w*)/gm;
2943
+ let m;
2944
+ while ((m = itemPattern.exec(cleanCode)) !== null) {
2945
+ const isStructOrEnum = Boolean(m[1]);
2946
+ const name = m[3];
2947
+ if (RUST_KEYWORDS.has(name))
2948
+ continue;
2949
+ const line = lineAt(m.index);
2950
+ if (!entities.some((e) => e.name === name && e.line === line)) {
2951
+ entities.push({
2952
+ name,
2953
+ type: isStructOrEnum ? "class" : "interface",
2954
+ line,
2955
+ complexity: "low"
2956
+ });
2957
+ }
2958
+ }
2959
+ const typeAliasPattern = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?type\s+([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*=/gm;
2960
+ while ((m = typeAliasPattern.exec(cleanCode)) !== null) {
2961
+ const name = m[1];
2962
+ if (RUST_KEYWORDS.has(name))
2963
+ continue;
2964
+ const line = lineAt(m.index);
2965
+ if (!entities.some((e) => e.name === name && e.line === line)) {
2966
+ entities.push({
2967
+ name,
2968
+ type: "type",
2969
+ line,
2970
+ complexity: "low"
2971
+ });
2972
+ }
2973
+ }
2974
+ const fnPattern = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?(?:(?:async|const|unsafe|extern(?:\s+"[^"]*")?)\s+)*fn\s+([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*\(/gm;
2975
+ while ((m = fnPattern.exec(cleanCode)) !== null) {
2976
+ const name = m[1];
2977
+ if (RUST_KEYWORDS.has(name))
2978
+ continue;
2979
+ const line = lineAt(m.index);
2980
+ if (!entities.some((e) => e.name === name && e.line === line)) {
2981
+ entities.push({
2982
+ name,
2983
+ type: "function",
2984
+ line,
2985
+ complexity: estimateComplexity(cleanCode, name)
2986
+ });
2987
+ }
2988
+ }
2989
+ return entities;
2990
+ }
2991
+ function extractImports(code) {
2992
+ const cleanCode = cleanRustComments(code);
2993
+ const imports = [];
2994
+ const usePattern = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?use\s+([^;]+);/gm;
2995
+ let m;
2996
+ while ((m = usePattern.exec(cleanCode)) !== null) {
2997
+ const raw = m[1].trim();
2998
+ const isLocal = raw.startsWith("crate::") || raw.startsWith("super::") || raw.startsWith("self::");
2999
+ if (raw.includes("{")) {
3000
+ const braceStart = raw.indexOf("{");
3001
+ const basePrefix = raw.slice(0, braceStart).replace(/::$/, "").trim();
3002
+ const inner = raw.slice(braceStart + 1, raw.lastIndexOf("}")).trim();
3003
+ const items = inner.split(",").map((s) => s.trim()).filter(Boolean);
3004
+ const names = [];
3005
+ for (const item of items) {
3006
+ if (item === "self") {
3007
+ const baseName = basePrefix.split("::").pop();
3008
+ names.push(baseName);
3009
+ } else if (item.includes(" as ")) {
3010
+ const alias = item.split(" as ")[1].trim();
3011
+ names.push(alias);
3012
+ } else {
3013
+ names.push(item.split("::").pop().trim());
3014
+ }
3015
+ }
3016
+ imports.push({
3017
+ source: basePrefix,
3018
+ names: [...new Set(names)],
3019
+ isLocal
3020
+ });
3021
+ } else {
3022
+ let source = "";
3023
+ let name = "";
3024
+ if (raw.includes(" as ")) {
3025
+ const parts = raw.split(" as ");
3026
+ source = parts[0].trim();
3027
+ name = parts[1].trim();
3028
+ } else {
3029
+ source = raw.trim();
3030
+ const segments = raw.split("::");
3031
+ name = segments[segments.length - 1].trim();
3032
+ }
3033
+ imports.push({
3034
+ source,
3035
+ names: [name],
3036
+ isLocal
3037
+ });
3038
+ }
3039
+ }
3040
+ return imports;
3041
+ }
3042
+ function extractExports(code) {
3043
+ const cleanCode = cleanRustComments(code);
3044
+ const exports3 = [];
3045
+ const itemPattern = /^[ \t]*pub(?:\([^)]*\))?\s+(?:(?:unsafe\s+)?(?:trait)|struct|enum|type)\s+([A-Za-z_]\w*)/gm;
3046
+ let m;
3047
+ while ((m = itemPattern.exec(cleanCode)) !== null) {
3048
+ exports3.push(m[1]);
3049
+ }
3050
+ const fnPattern = /^[ \t]*pub(?:\([^)]*\))?\s+(?:(?:async|const|unsafe|extern(?:\s+"[^"]*")?)\s+)*fn\s+([A-Za-z_]\w*)/gm;
3051
+ while ((m = fnPattern.exec(cleanCode)) !== null) {
3052
+ exports3.push(m[1]);
3053
+ }
3054
+ const constPattern = /^[ \t]*pub(?:\([^)]*\))?\s+(?:const|static)\s+([A-Za-z_]\w*)/gm;
3055
+ while ((m = constPattern.exec(cleanCode)) !== null) {
3056
+ exports3.push(m[1]);
3057
+ }
3058
+ const usePattern = /^[ \t]*pub(?:\([^)]*\))?\s+use\s+([^;]+);/gm;
3059
+ while ((m = usePattern.exec(cleanCode)) !== null) {
3060
+ const raw = m[1].trim();
3061
+ if (raw.includes("{")) {
3062
+ const inner = raw.slice(raw.indexOf("{") + 1, raw.lastIndexOf("}")).trim();
3063
+ const items = inner.split(",").map((s) => s.trim().split(/\s+as\s+/).pop()).filter(Boolean);
3064
+ exports3.push(...items);
3065
+ } else {
3066
+ const last = raw.split(" as ").pop().split("::").pop().trim();
3067
+ if (last && last !== "*")
3068
+ exports3.push(last);
3069
+ }
3070
+ }
3071
+ return [...new Set(exports3)];
3072
+ }
3073
+ exports2.RustParser = {
3074
+ lang: "rust",
3075
+ extensions: [".rs"],
3076
+ extractEntities,
3077
+ extractImports,
3078
+ extractExports,
3079
+ entityPatterns: exports2.rustEntityPatterns
3080
+ };
3081
+ (0, registry_1.registerParser)(exports2.RustParser);
3082
+ function extractRust(fileInput) {
3083
+ let source;
3084
+ let strPath;
3085
+ if (typeof fileInput === "string") {
3086
+ strPath = fileInput;
3087
+ const isPath = (fileInput.endsWith(".rs") || fileInput.includes("/") || fileInput.includes("\\")) && !fileInput.includes("\n");
3088
+ if (isPath) {
3089
+ try {
3090
+ source = fs_12.default.readFileSync(fileInput, "utf-8");
3091
+ } catch (err) {
3092
+ return { nodes: [], edges: [], raw_calls: [], error: `cannot read ${fileInput}` };
3093
+ }
3094
+ } else {
3095
+ source = fileInput;
3096
+ strPath = "main.rs";
3097
+ }
3098
+ } else {
3099
+ strPath = fileInput.path;
3100
+ try {
3101
+ source = fileInput.readText ? fileInput.readText() : fs_12.default.readFileSync(fileInput.path, "utf-8");
3102
+ } catch (err) {
3103
+ return { nodes: [], edges: [], raw_calls: [], error: `cannot read ${fileInput.path}` };
3104
+ }
3105
+ }
3106
+ const cleanSource = cleanRustComments(source);
3107
+ const stem = _fileStem(strPath);
3108
+ function lineAt(offset) {
3109
+ return cleanSource.slice(0, offset).split("\n").length;
3110
+ }
3111
+ const nodes = [];
3112
+ const edges = [];
3113
+ const rawCalls = [];
3114
+ const seenIds = /* @__PURE__ */ new Set();
3115
+ function addNode(nid, label, line) {
3116
+ if (!seenIds.has(nid)) {
3117
+ seenIds.add(nid);
3118
+ nodes.push({
3119
+ id: nid,
3120
+ label,
3121
+ file_type: "code",
3122
+ source_file: strPath,
3123
+ source_location: `L${line}`
3124
+ });
3125
+ }
3126
+ }
3127
+ function addEdge(src, tgt, relation, line, confidence = "EXTRACTED", weight = 1, context) {
3128
+ const edge = {
3129
+ source: src,
3130
+ target: tgt,
3131
+ relation,
3132
+ confidence,
3133
+ source_file: strPath,
3134
+ source_location: `L${line}`,
3135
+ weight
3136
+ };
3137
+ if (context)
3138
+ edge.context = context;
3139
+ edges.push(edge);
3140
+ }
3141
+ const fileNid = _makeId(strPath);
3142
+ addNode(fileNid, path_1.default.basename(strPath), 1);
3143
+ function ensureNamedNode(name, line) {
3144
+ const nidInFile = _makeId(stem, name);
3145
+ if (seenIds.has(nidInFile)) {
3146
+ return nidInFile;
3147
+ }
3148
+ const nidGlobal = _makeId(name);
3149
+ if (!seenIds.has(nidGlobal)) {
3150
+ seenIds.add(nidGlobal);
3151
+ nodes.push({
3152
+ id: nidGlobal,
3153
+ label: name,
3154
+ file_type: "code",
3155
+ source_file: "",
3156
+ source_location: "",
3157
+ origin_file: strPath
3158
+ });
3159
+ }
3160
+ return nidGlobal;
3161
+ }
3162
+ function emitParamReturnRefs(paramsText, returnText, funcNid, line) {
3163
+ if (paramsText) {
3164
+ for (const p of _splitBalanced(paramsText)) {
3165
+ if (p === "&self" || p === "&mut self" || p === "self" || p === "mut self")
3166
+ continue;
3167
+ const colonIdx = p.indexOf(":");
3168
+ if (colonIdx !== -1) {
3169
+ const typePart = p.slice(colonIdx + 1).trim();
3170
+ const refs = [];
3171
+ _rustCollectTypeRefs(typePart, false, refs);
3172
+ for (const [refName, role] of refs) {
3173
+ const ctx = role === "generic_arg" ? "generic_arg" : "parameter_type";
3174
+ const tgt = ensureNamedNode(refName, line);
3175
+ if (tgt !== funcNid) {
3176
+ addEdge(funcNid, tgt, "references", line, "EXTRACTED", 1, ctx);
3177
+ }
3178
+ }
3179
+ }
3180
+ }
3181
+ }
3182
+ if (returnText) {
3183
+ const refs = [];
3184
+ _rustCollectTypeRefs(returnText, false, refs);
3185
+ for (const [refName, role] of refs) {
3186
+ const ctx = role === "generic_arg" ? "generic_arg" : "return_type";
3187
+ const tgt = ensureNamedNode(refName, line);
3188
+ if (tgt !== funcNid) {
3189
+ addEdge(funcNid, tgt, "references", line, "EXTRACTED", 1, ctx);
3190
+ }
3191
+ }
3192
+ }
3193
+ }
3194
+ const functionBodies = [];
3195
+ const itemPattern = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?(?:(struct|enum)|(?:unsafe\s+)?(trait)|(impl))\b/gm;
3196
+ let m;
3197
+ while ((m = itemPattern.exec(cleanSource)) !== null) {
3198
+ const itemStart = m.index;
3199
+ const kind = m[1] || m[2] || m[3];
3200
+ const headerEnd = cleanSource.indexOf("{", itemStart);
3201
+ const semiEnd = cleanSource.indexOf(";", itemStart);
3202
+ if (kind === "struct") {
3203
+ const structM = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?struct\s+([A-Za-z_]\w*)(?:<[^>]*>)?(?:\s*\(([^)]*)\)|\s*\{)?/m.exec(cleanSource.slice(itemStart, itemStart + 300));
3204
+ if (structM) {
3205
+ const structName = structM[1];
3206
+ const line = lineAt(itemStart);
3207
+ const structNid = _makeId(stem, structName);
3208
+ addNode(structNid, structName, line);
3209
+ addEdge(fileNid, structNid, "contains", line);
3210
+ const tupleFields = structM[2];
3211
+ if (tupleFields !== void 0) {
3212
+ for (const field of _splitBalanced(tupleFields)) {
3213
+ const cleanField = field.replace(/^pub(?:\([^)]*\))?\s+/, "").trim();
3214
+ const refs = [];
3215
+ _rustCollectTypeRefs(cleanField, false, refs);
3216
+ for (const [refName, role] of refs) {
3217
+ const ctx = role === "generic_arg" ? "generic_arg" : "field";
3218
+ const tgt = ensureNamedNode(refName, line);
3219
+ if (tgt !== structNid) {
3220
+ addEdge(structNid, tgt, "references", line, "EXTRACTED", 1, ctx);
3221
+ }
3222
+ }
3223
+ }
3224
+ } else if (headerEnd !== -1 && (semiEnd === -1 || headerEnd < semiEnd)) {
3225
+ const bodyEnd = _findMatchingBrace(cleanSource, itemStart);
3226
+ const body = cleanSource.slice(headerEnd + 1, bodyEnd - 1);
3227
+ for (const rawField of _splitBalanced(body, ",")) {
3228
+ const field = rawField.trim();
3229
+ if (!field)
3230
+ continue;
3231
+ const colonIdx = field.indexOf(":");
3232
+ if (colonIdx !== -1) {
3233
+ const fType = field.slice(colonIdx + 1).trim();
3234
+ const fLine = lineAt(headerEnd);
3235
+ const refs = [];
3236
+ _rustCollectTypeRefs(fType, false, refs);
3237
+ for (const [refName, role] of refs) {
3238
+ const ctx = role === "generic_arg" ? "generic_arg" : "field";
3239
+ const tgt = ensureNamedNode(refName, fLine);
3240
+ if (tgt !== structNid) {
3241
+ addEdge(structNid, tgt, "references", fLine, "EXTRACTED", 1, ctx);
3242
+ }
3243
+ }
3244
+ }
3245
+ }
3246
+ }
3247
+ }
3248
+ } else if (kind === "enum") {
3249
+ const enumM = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?enum\s+([A-Za-z_]\w*)/m.exec(cleanSource.slice(itemStart, itemStart + 200));
3250
+ if (enumM && headerEnd !== -1) {
3251
+ const enumName = enumM[1];
3252
+ const line = lineAt(itemStart);
3253
+ const enumNid = _makeId(stem, enumName);
3254
+ addNode(enumNid, enumName, line);
3255
+ addEdge(fileNid, enumNid, "contains", line);
3256
+ const bodyEnd = _findMatchingBrace(cleanSource, itemStart);
3257
+ const body = cleanSource.slice(headerEnd + 1, bodyEnd - 1);
3258
+ const variantPattern = /([A-Za-z_]\w*)(?:\s*\(([^)]*)\)|\s*\{([^}]*)\})?/g;
3259
+ let vm;
3260
+ while ((vm = variantPattern.exec(body)) !== null) {
3261
+ const vLine = lineAt(headerEnd + vm.index);
3262
+ const tupleTypes = vm[2];
3263
+ const structFields = vm[3];
3264
+ if (tupleTypes) {
3265
+ for (const t of _splitBalanced(tupleTypes)) {
3266
+ const refs = [];
3267
+ _rustCollectTypeRefs(t.trim(), false, refs);
3268
+ for (const [refName, role] of refs) {
3269
+ const ctx = role === "generic_arg" ? "generic_arg" : "field";
3270
+ const tgt = ensureNamedNode(refName, vLine);
3271
+ if (tgt !== enumNid) {
3272
+ addEdge(enumNid, tgt, "references", vLine, "EXTRACTED", 1, ctx);
3273
+ }
3274
+ }
3275
+ }
3276
+ } else if (structFields) {
3277
+ for (const rawField of _splitBalanced(structFields, ",")) {
3278
+ const field = rawField.trim();
3279
+ if (!field)
3280
+ continue;
3281
+ const colonIdx = field.indexOf(":");
3282
+ if (colonIdx !== -1) {
3283
+ const fType = field.slice(colonIdx + 1).trim();
3284
+ const refs = [];
3285
+ _rustCollectTypeRefs(fType, false, refs);
3286
+ for (const [refName, role] of refs) {
3287
+ const ctx = role === "generic_arg" ? "generic_arg" : "field";
3288
+ const tgt = ensureNamedNode(refName, vLine);
3289
+ if (tgt !== enumNid) {
3290
+ addEdge(enumNid, tgt, "references", vLine, "EXTRACTED", 1, ctx);
3291
+ }
3292
+ }
3293
+ }
3294
+ }
3295
+ }
3296
+ }
3297
+ }
3298
+ } else if (kind === "trait") {
3299
+ const traitM = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?(?:unsafe\s+)?trait\s+([A-Za-z_]\w*)(?:<[^>]*>)?(?:\s*:\s*([^{]+))?/m.exec(cleanSource.slice(itemStart, itemStart + 300));
3300
+ if (traitM && headerEnd !== -1) {
3301
+ const traitName = traitM[1];
3302
+ const line = lineAt(itemStart);
3303
+ const traitNid = _makeId(stem, traitName);
3304
+ addNode(traitNid, traitName, line);
3305
+ addEdge(fileNid, traitNid, "contains", line);
3306
+ const boundsStr = traitM[2];
3307
+ if (boundsStr) {
3308
+ const bounds = boundsStr.split("+").map((s) => s.trim()).filter(Boolean);
3309
+ for (let idx = 0; idx < bounds.length; idx++) {
3310
+ const b = bounds[idx];
3311
+ const refs = [];
3312
+ _rustCollectTypeRefs(b, false, refs);
3313
+ for (let rIdx = 0; rIdx < refs.length; rIdx++) {
3314
+ const [refName] = refs[rIdx];
3315
+ const tgt = ensureNamedNode(refName, line);
3316
+ if (tgt === traitNid)
3317
+ continue;
3318
+ const rel = idx === 0 && rIdx === 0 ? "inherits" : "references";
3319
+ addEdge(traitNid, tgt, rel, line, "EXTRACTED", 1, rel === "references" ? "generic_arg" : void 0);
3320
+ }
3321
+ }
3322
+ }
3323
+ const bodyEnd = _findMatchingBrace(cleanSource, itemStart);
3324
+ const body = cleanSource.slice(headerEnd + 1, bodyEnd - 1);
3325
+ const traitMethodPattern = /^[ \t]*(?:(?:async|const|unsafe|extern(?:\s+"[^"]*")?)\s+)*fn\s+([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*\(([^)]*)\)(?:\s*->\s*([^{;]+))?\s*([{;])/gm;
3326
+ let tmm;
3327
+ while ((tmm = traitMethodPattern.exec(body)) !== null) {
3328
+ const methodName = tmm[1];
3329
+ const mLine = lineAt(headerEnd + tmm.index);
3330
+ const methodNid = _makeId(traitNid, methodName);
3331
+ addNode(methodNid, `.${methodName}()`, mLine);
3332
+ addEdge(traitNid, methodNid, "method", mLine);
3333
+ emitParamReturnRefs(tmm[2], tmm[3], methodNid, mLine);
3334
+ if (tmm[4] === "{") {
3335
+ const mBodyEnd = _findMatchingBrace(body, tmm.index);
3336
+ const mBody = body.slice(tmm.index + tmm[0].length - 1, mBodyEnd);
3337
+ functionBodies.push([methodNid, mBody, headerEnd + tmm.index + tmm[0].length - 1]);
3338
+ }
3339
+ }
3340
+ }
3341
+ } else if (kind === "impl") {
3342
+ const implHeader = cleanSource.slice(itemStart, headerEnd).trim();
3343
+ const implM = /^[ \t]*impl(?:\s*<[^>]*>)?\s+(?:([A-Za-z_]\w*(?:\s*<[^>]*>)?)\s+for\s+)?([A-Za-z_]\w*(?:\s*<[^>]*>)?)/m.exec(implHeader);
3344
+ if (implM && headerEnd !== -1) {
3345
+ const traitPart = implM[1];
3346
+ const typePart = implM[2];
3347
+ const typeName = typePart.split("<")[0].split("::").pop().trim();
3348
+ const line = lineAt(itemStart);
3349
+ const implNid = _makeId(stem, typeName);
3350
+ addNode(implNid, typeName, line);
3351
+ if (traitPart) {
3352
+ const traitRefs = [];
3353
+ _rustCollectTypeRefs(traitPart, false, traitRefs);
3354
+ for (let idx = 0; idx < traitRefs.length; idx++) {
3355
+ const [refName] = traitRefs[idx];
3356
+ const tgt = ensureNamedNode(refName, line);
3357
+ if (tgt !== implNid) {
3358
+ if (idx === 0) {
3359
+ addEdge(implNid, tgt, "implements", line);
3360
+ } else {
3361
+ addEdge(implNid, tgt, "references", line, "EXTRACTED", 1, "generic_arg");
3362
+ }
3363
+ }
3364
+ }
3365
+ }
3366
+ const bodyEnd = _findMatchingBrace(cleanSource, itemStart);
3367
+ const body = cleanSource.slice(headerEnd + 1, bodyEnd - 1);
3368
+ const implMethodPattern = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?(?:(?:async|const|unsafe|extern(?:\s+"[^"]*")?)\s+)*fn\s+([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*\(([^)]*)\)(?:\s*->\s*([^{]+))?\s*\{/gm;
3369
+ let imm;
3370
+ while ((imm = implMethodPattern.exec(body)) !== null) {
3371
+ const methodName = imm[1];
3372
+ const mLine = lineAt(headerEnd + imm.index);
3373
+ const methodNid = _makeId(implNid, methodName);
3374
+ addNode(methodNid, `.${methodName}()`, mLine);
3375
+ addEdge(implNid, methodNid, "method", mLine);
3376
+ emitParamReturnRefs(imm[2], imm[3], methodNid, mLine);
3377
+ const mBodyEnd = _findMatchingBrace(body, imm.index);
3378
+ const mBody = body.slice(imm.index + imm[0].length - 1, mBodyEnd);
3379
+ functionBodies.push([methodNid, mBody, headerEnd + imm.index + imm[0].length - 1]);
3380
+ }
3381
+ }
3382
+ }
3383
+ }
3384
+ const freeFnPattern = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?(?:(?:async|const|unsafe|extern(?:\s+"[^"]*")?)\s+)*fn\s+([A-Za-z_]\w*)\s*(?:<[^>]*>)?\s*\(([^)]*)\)(?:\s*->\s*([^{]+))?\s*\{/gm;
3385
+ while ((m = freeFnPattern.exec(cleanSource)) !== null) {
3386
+ const funcName = m[1];
3387
+ const funcLine = lineAt(m.index);
3388
+ const funcNid = _makeId(stem, funcName);
3389
+ if (!seenIds.has(funcNid)) {
3390
+ addNode(funcNid, `${funcName}()`, funcLine);
3391
+ addEdge(fileNid, funcNid, "contains", funcLine);
3392
+ emitParamReturnRefs(m[2], m[3], funcNid, funcLine);
3393
+ const mBodyEnd = _findMatchingBrace(cleanSource, m.index);
3394
+ const mBody = cleanSource.slice(m.index + m[0].length - 1, mBodyEnd);
3395
+ functionBodies.push([funcNid, mBody, m.index + m[0].length - 1]);
3396
+ }
3397
+ }
3398
+ const usePattern = /^[ \t]*(?:pub(?:\([^)]*\))?\s+)?use\s+([^;]+);/gm;
3399
+ while ((m = usePattern.exec(cleanSource)) !== null) {
3400
+ const raw = m[1].trim();
3401
+ const line = lineAt(m.index);
3402
+ if (raw.includes("{")) {
3403
+ const basePrefix = raw.slice(0, raw.indexOf("{")).replace(/::$/, "").trim();
3404
+ const moduleName = basePrefix.split("::").pop().trim();
3405
+ if (moduleName) {
3406
+ const tgtNid = _makeId(moduleName);
3407
+ addEdge(fileNid, tgtNid, "imports_from", line, "EXTRACTED", 1, "import");
3408
+ }
3409
+ } else {
3410
+ const clean = raw.split(" as ")[0].trim().replace(/::\*$/, "").replace(/::$/, "");
3411
+ const moduleName = clean.split("::").pop().trim();
3412
+ if (moduleName) {
3413
+ const tgtNid = _makeId(moduleName);
3414
+ addEdge(fileNid, tgtNid, "imports_from", line, "EXTRACTED", 1, "import");
3415
+ }
3416
+ }
3417
+ }
3418
+ const labelToNid = {};
3419
+ for (const n of nodes) {
3420
+ const raw = n.label;
3421
+ const normalised = raw.replace(/\(\)$/, "").replace(/^\./, "");
3422
+ labelToNid[normalised] = n.id;
3423
+ }
3424
+ const seenCallPairs = /* @__PURE__ */ new Set();
3425
+ for (const [callerNid, bodyCode, bodyOffset] of functionBodies) {
3426
+ const callPattern = /([A-Za-z_]\w*)(?:::([A-Za-z_]\w*))?\s*\(|\.([A-Za-z_]\w*)\s*\(/g;
3427
+ let cm;
3428
+ while ((cm = callPattern.exec(bodyCode)) !== null) {
3429
+ const isMemberCall = Boolean(cm[3]);
3430
+ const isScopedCall = Boolean(cm[2]);
3431
+ const calleeName = cm[3] || cm[2] || cm[1];
3432
+ if (!calleeName || RUST_KEYWORDS.has(calleeName))
3433
+ continue;
3434
+ const callLine = lineAt(bodyOffset + cm.index);
3435
+ const tgtNid = labelToNid[calleeName];
3436
+ if (tgtNid && tgtNid !== callerNid) {
3437
+ const pairKey = `${callerNid}->${tgtNid}`;
3438
+ if (!seenCallPairs.has(pairKey)) {
3439
+ seenCallPairs.add(pairKey);
3440
+ edges.push({
3441
+ source: callerNid,
3442
+ target: tgtNid,
3443
+ relation: "calls",
3444
+ confidence: "EXTRACTED",
3445
+ source_file: strPath,
3446
+ source_location: `L${callLine}`,
3447
+ weight: 1,
3448
+ context: "call"
3449
+ });
3450
+ }
3451
+ } else if (!isScopedCall && !exports2.RUST_TRAIT_METHOD_BLOCKLIST.has(calleeName.toLowerCase())) {
3452
+ rawCalls.push({
3453
+ caller_nid: callerNid,
3454
+ callee: calleeName,
3455
+ is_member_call: isMemberCall,
3456
+ source_file: strPath,
3457
+ source_location: `L${callLine}`
3458
+ });
3459
+ }
3460
+ }
3461
+ }
3462
+ const validIds = seenIds;
3463
+ const cleanEdges = edges.filter((e) => validIds.has(e.source) && (validIds.has(e.target) || e.relation === "imports_from" || e.relation === "imports"));
3464
+ return { nodes, edges: cleanEdges, raw_calls: rawCalls };
3465
+ }
3466
+ }
3467
+ });
3468
+
1623
3469
  // dist/stages/collector.js
1624
3470
  var require_collector = __commonJS({
1625
3471
  "dist/stages/collector.js"(exports2) {
@@ -1819,7 +3665,15 @@ var require_graph = __commonJS({
1819
3665
  }
1820
3666
  function resolvePath(fromFile, importSource, allFiles) {
1821
3667
  const fromDir = path_1.default.dirname(fromFile);
1822
- const base = path_1.default.join(fromDir, importSource);
3668
+ let normalizedSource = importSource;
3669
+ if (normalizedSource.startsWith("crate::")) {
3670
+ normalizedSource = normalizedSource.slice(7).replace(/::/g, "/");
3671
+ } else if (normalizedSource.startsWith("super::")) {
3672
+ normalizedSource = "../" + normalizedSource.slice(7).replace(/::/g, "/");
3673
+ } else if (normalizedSource.startsWith("self::")) {
3674
+ normalizedSource = "./" + normalizedSource.slice(6).replace(/::/g, "/");
3675
+ }
3676
+ const base = path_1.default.join(fromDir, normalizedSource);
1823
3677
  const candidates = [
1824
3678
  base,
1825
3679
  `${base}.ts`,
@@ -1827,7 +3681,9 @@ var require_graph = __commonJS({
1827
3681
  `${base}.js`,
1828
3682
  `${base}.jsx`,
1829
3683
  `${base}/index.ts`,
1830
- `${base}/index.js`
3684
+ `${base}/index.js`,
3685
+ `${base}.dart`,
3686
+ `${base}.rs`
1831
3687
  ];
1832
3688
  for (const candidate of candidates) {
1833
3689
  const normalized = candidate.replace(/\\/g, "/");
@@ -1835,6 +3691,23 @@ var require_graph = __commonJS({
1835
3691
  if (found)
1836
3692
  return found.filePath;
1837
3693
  }
3694
+ const parentBase = path_1.default.dirname(base);
3695
+ if (parentBase && parentBase !== base) {
3696
+ const parentCandidates = [
3697
+ `${parentBase}.rs`,
3698
+ `${parentBase}.ts`,
3699
+ `${parentBase}.tsx`,
3700
+ `${parentBase}.js`,
3701
+ `${parentBase}.jsx`,
3702
+ `${parentBase}.dart`
3703
+ ];
3704
+ for (const candidate of parentCandidates) {
3705
+ const normalized = candidate.replace(/\\/g, "/");
3706
+ const found = allFiles.find((f) => f.filePath.replace(/\\/g, "/") === normalized);
3707
+ if (found)
3708
+ return found.filePath;
3709
+ }
3710
+ }
1838
3711
  return null;
1839
3712
  }
1840
3713
  }
@@ -2270,6 +4143,8 @@ require_kotlin();
2270
4143
  require_php();
2271
4144
  require_ruby();
2272
4145
  require_swift();
4146
+ require_dart();
4147
+ require_rust();
2273
4148
  var fs_1 = __importDefault(require("fs"));
2274
4149
  var collector_1 = require_collector();
2275
4150
  var parser_1 = require_parser();
@@ -2298,7 +4173,7 @@ function getFlag(flag) {
2298
4173
  }
2299
4174
  function printHelp() {
2300
4175
  console.log(`
2301
- ${bold("DepGraph")} ${dim("v1.5.1")}
4176
+ ${bold("DepGraph")} ${dim("v1.8.0")}
2302
4177
  ${dim("Dependency mapping \xB7 Impact simulation \xB7 Developer intelligence")}
2303
4178
 
2304
4179
  ${bold("USAGE")}
@@ -2347,7 +4222,7 @@ ${bold("GIT EXAMPLES")}
2347
4222
  function printBanner() {
2348
4223
  console.log(`
2349
4224
  ${bold("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501")}
2350
- ${bold(" DepGraph")} ${dim("v1.0.0")}
4225
+ ${bold(" DepGraph")} ${dim("v1.8.0")}
2351
4226
  ${bold("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501")}
2352
4227
  `);
2353
4228
  }