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/.vscode/depgraph-output.json +7197 -2405
- package/README.md +50 -6
- package/depgraph-mcp.js +24282 -0
- package/depgraph-output.json +7138 -2482
- package/depgraph.js +1880 -5
- package/package.json +10 -3
- package/docs/README.md +0 -56
- package/docs/architecture.md +0 -89
- package/docs/data-types.md +0 -218
- package/docs/language-registry.md +0 -205
- package/docs/stage-collector.md +0 -109
- package/docs/stage-graph.md +0 -157
- package/docs/stage-impact.md +0 -154
- package/docs/stage-metrics.md +0 -113
- package/docs/stage-output.md +0 -144
- package/docs/stage-parser.md +0 -144
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
|
-
|
|
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.
|
|
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.
|
|
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
|
}
|