@monoes/graph 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/analyze.d.ts +23 -0
- package/dist/src/analyze.d.ts.map +1 -0
- package/dist/src/analyze.js +105 -0
- package/dist/src/analyze.js.map +1 -0
- package/dist/src/build.d.ts +8 -0
- package/dist/src/build.d.ts.map +1 -0
- package/dist/src/build.js +59 -0
- package/dist/src/build.js.map +1 -0
- package/dist/src/cache.d.ts +10 -0
- package/dist/src/cache.d.ts.map +1 -0
- package/dist/src/cache.js +34 -0
- package/dist/src/cache.js.map +1 -0
- package/dist/src/cluster.d.ts +8 -0
- package/dist/src/cluster.d.ts.map +1 -0
- package/dist/src/cluster.js +50 -0
- package/dist/src/cluster.js.map +1 -0
- package/dist/src/detect.d.ts +8 -0
- package/dist/src/detect.d.ts.map +1 -0
- package/dist/src/detect.js +108 -0
- package/dist/src/detect.js.map +1 -0
- package/dist/src/export.d.ts +21 -0
- package/dist/src/export.d.ts.map +1 -0
- package/dist/src/export.js +68 -0
- package/dist/src/export.js.map +1 -0
- package/dist/src/extract/index.d.ts +20 -0
- package/dist/src/extract/index.d.ts.map +1 -0
- package/dist/src/extract/index.js +158 -0
- package/dist/src/extract/index.js.map +1 -0
- package/dist/src/extract/languages/go.d.ts +3 -0
- package/dist/src/extract/languages/go.d.ts.map +1 -0
- package/dist/src/extract/languages/go.js +181 -0
- package/dist/src/extract/languages/go.js.map +1 -0
- package/dist/src/extract/languages/python.d.ts +3 -0
- package/dist/src/extract/languages/python.d.ts.map +1 -0
- package/dist/src/extract/languages/python.js +230 -0
- package/dist/src/extract/languages/python.js.map +1 -0
- package/dist/src/extract/languages/rust.d.ts +3 -0
- package/dist/src/extract/languages/rust.d.ts.map +1 -0
- package/dist/src/extract/languages/rust.js +195 -0
- package/dist/src/extract/languages/rust.js.map +1 -0
- package/dist/src/extract/languages/typescript.d.ts +3 -0
- package/dist/src/extract/languages/typescript.d.ts.map +1 -0
- package/dist/src/extract/languages/typescript.js +295 -0
- package/dist/src/extract/languages/typescript.js.map +1 -0
- package/dist/src/extract/tree-sitter-runner.d.ts +48 -0
- package/dist/src/extract/tree-sitter-runner.d.ts.map +1 -0
- package/dist/src/extract/tree-sitter-runner.js +128 -0
- package/dist/src/extract/tree-sitter-runner.js.map +1 -0
- package/dist/src/extract/types.d.ts +7 -0
- package/dist/src/extract/types.d.ts.map +1 -0
- package/dist/src/extract/types.js +2 -0
- package/dist/src/extract/types.js.map +1 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/pipeline.d.ts +16 -0
- package/dist/src/pipeline.d.ts.map +1 -0
- package/dist/src/pipeline.js +143 -0
- package/dist/src/pipeline.js.map +1 -0
- package/dist/src/types.d.ts +99 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +44 -0
- package/src/analyze.ts +122 -0
- package/src/build.ts +62 -0
- package/src/cache.ts +38 -0
- package/src/cluster.ts +54 -0
- package/src/detect.ts +123 -0
- package/src/export.ts +78 -0
- package/src/extract/index.ts +190 -0
- package/src/extract/languages/go.ts +206 -0
- package/src/extract/languages/python.ts +270 -0
- package/src/extract/languages/rust.ts +230 -0
- package/src/extract/languages/typescript.ts +344 -0
- package/src/extract/tree-sitter-runner.ts +165 -0
- package/src/extract/types.ts +7 -0
- package/src/index.ts +10 -0
- package/src/pipeline.ts +166 -0
- package/src/types.ts +116 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type Graph from 'graphology';
|
|
2
|
+
import type { GodNode, SurpriseEdge, GraphAnalysis, GraphStats } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Find the most connected nodes (god nodes) — core abstractions of the codebase.
|
|
5
|
+
* Sorted by total degree (in + out), descending.
|
|
6
|
+
*/
|
|
7
|
+
export declare function godNodes(graph: Graph, topN?: number): GodNode[];
|
|
8
|
+
/**
|
|
9
|
+
* Find surprising cross-community connections.
|
|
10
|
+
* An edge is surprising when its endpoints belong to different communities.
|
|
11
|
+
* Scored by the product of their degrees — high degree on both sides = high surprise.
|
|
12
|
+
*/
|
|
13
|
+
export declare function surprisingConnections(graph: Graph, topN?: number): SurpriseEdge[];
|
|
14
|
+
/**
|
|
15
|
+
* Compute high-level graph statistics.
|
|
16
|
+
*/
|
|
17
|
+
export declare function graphStats(graph: Graph, graphPath?: string): GraphStats;
|
|
18
|
+
/**
|
|
19
|
+
* Build a complete GraphAnalysis object from an annotated graph.
|
|
20
|
+
* Assumes community detection has already been run (nodes have `community` attribute).
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildAnalysis(graph: Graph, graphPath?: string): GraphAnalysis;
|
|
23
|
+
//# sourceMappingURL=analyze.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAc,MAAM,YAAY,CAAC;AAE/F;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,SAAK,GAAG,OAAO,EAAE,CAkB3D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,SAAK,GAAG,YAAY,EAAE,CAuB7E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,CAsCvE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAiB7E"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find the most connected nodes (god nodes) — core abstractions of the codebase.
|
|
3
|
+
* Sorted by total degree (in + out), descending.
|
|
4
|
+
*/
|
|
5
|
+
export function godNodes(graph, topN = 15) {
|
|
6
|
+
const nodes = [];
|
|
7
|
+
graph.forEachNode((id, attrs) => {
|
|
8
|
+
nodes.push({
|
|
9
|
+
id,
|
|
10
|
+
label: attrs.label || id,
|
|
11
|
+
degree: graph.degree(id),
|
|
12
|
+
community: attrs.community,
|
|
13
|
+
sourceFile: attrs.sourceFile || '',
|
|
14
|
+
neighbors: graph
|
|
15
|
+
.neighbors(id)
|
|
16
|
+
.slice(0, 8)
|
|
17
|
+
.map((n) => graph.getNodeAttribute(n, 'label') || n),
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
return nodes.sort((a, b) => b.degree - a.degree).slice(0, topN);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Find surprising cross-community connections.
|
|
24
|
+
* An edge is surprising when its endpoints belong to different communities.
|
|
25
|
+
* Scored by the product of their degrees — high degree on both sides = high surprise.
|
|
26
|
+
*/
|
|
27
|
+
export function surprisingConnections(graph, topN = 20) {
|
|
28
|
+
const surprises = [];
|
|
29
|
+
graph.forEachEdge((_, attrs, source, target) => {
|
|
30
|
+
const cu = graph.getNodeAttribute(source, 'community');
|
|
31
|
+
const cv = graph.getNodeAttribute(target, 'community');
|
|
32
|
+
if (cu !== undefined && cv !== undefined && cu !== cv) {
|
|
33
|
+
surprises.push({
|
|
34
|
+
from: graph.getNodeAttribute(source, 'label') || source,
|
|
35
|
+
fromCommunity: cu,
|
|
36
|
+
fromFile: graph.getNodeAttribute(source, 'sourceFile') || '',
|
|
37
|
+
to: graph.getNodeAttribute(target, 'label') || target,
|
|
38
|
+
toCommunity: cv,
|
|
39
|
+
toFile: graph.getNodeAttribute(target, 'sourceFile') || '',
|
|
40
|
+
relation: attrs.relation || '',
|
|
41
|
+
confidence: attrs.confidence ?? 'AMBIGUOUS',
|
|
42
|
+
score: graph.degree(source) * graph.degree(target),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return surprises.sort((a, b) => b.score - a.score).slice(0, topN);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Compute high-level graph statistics.
|
|
50
|
+
*/
|
|
51
|
+
export function graphStats(graph, graphPath) {
|
|
52
|
+
const confidence = {};
|
|
53
|
+
const relations = {};
|
|
54
|
+
const fileTypes = {};
|
|
55
|
+
const commSet = new Set();
|
|
56
|
+
graph.forEachEdge((_, attrs) => {
|
|
57
|
+
const c = attrs.confidence || 'UNKNOWN';
|
|
58
|
+
confidence[c] = (confidence[c] ?? 0) + 1;
|
|
59
|
+
const r = attrs.relation || 'unknown';
|
|
60
|
+
relations[r] = (relations[r] ?? 0) + 1;
|
|
61
|
+
});
|
|
62
|
+
graph.forEachNode((_, attrs) => {
|
|
63
|
+
const ft = attrs.fileType || 'unknown';
|
|
64
|
+
fileTypes[ft] = (fileTypes[ft] ?? 0) + 1;
|
|
65
|
+
const c = attrs.community;
|
|
66
|
+
if (c !== undefined)
|
|
67
|
+
commSet.add(c);
|
|
68
|
+
});
|
|
69
|
+
const topRelations = Object.fromEntries(Object.entries(relations)
|
|
70
|
+
.sort(([, a], [, b]) => b - a)
|
|
71
|
+
.slice(0, 10));
|
|
72
|
+
return {
|
|
73
|
+
nodes: graph.order,
|
|
74
|
+
edges: graph.size,
|
|
75
|
+
communities: commSet.size,
|
|
76
|
+
confidence: confidence,
|
|
77
|
+
fileTypes,
|
|
78
|
+
topRelations,
|
|
79
|
+
isDirected: graph.type === 'directed',
|
|
80
|
+
graphPath,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Build a complete GraphAnalysis object from an annotated graph.
|
|
85
|
+
* Assumes community detection has already been run (nodes have `community` attribute).
|
|
86
|
+
*/
|
|
87
|
+
export function buildAnalysis(graph, graphPath) {
|
|
88
|
+
// Reconstruct communities map from node attributes
|
|
89
|
+
const communities = {};
|
|
90
|
+
graph.forEachNode((id, attrs) => {
|
|
91
|
+
const c = attrs.community;
|
|
92
|
+
if (c !== undefined) {
|
|
93
|
+
if (!communities[c])
|
|
94
|
+
communities[c] = [];
|
|
95
|
+
communities[c].push(id);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
godNodes: godNodes(graph),
|
|
100
|
+
surprises: surprisingConnections(graph),
|
|
101
|
+
communities,
|
|
102
|
+
stats: graphStats(graph, graphPath),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/analyze.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import Graph from 'graphology';
|
|
2
|
+
import type { ExtractionResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Build a graphology Graph from extracted nodes and edges.
|
|
5
|
+
* Deduplicates nodes by id, merges parallel edges with higher weight.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildGraph(extraction: ExtractionResult): Graph;
|
|
8
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,gBAAgB,GAAG,KAAK,CAsD9D"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Graph from 'graphology';
|
|
2
|
+
/**
|
|
3
|
+
* Build a graphology Graph from extracted nodes and edges.
|
|
4
|
+
* Deduplicates nodes by id, merges parallel edges with higher weight.
|
|
5
|
+
*/
|
|
6
|
+
export function buildGraph(extraction) {
|
|
7
|
+
const graph = new Graph({ type: 'directed', multi: false });
|
|
8
|
+
// Add all nodes — merge attributes if already present (dedup by id)
|
|
9
|
+
for (const node of extraction.nodes) {
|
|
10
|
+
if (!graph.hasNode(node.id)) {
|
|
11
|
+
graph.addNode(node.id, { ...node });
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
graph.mergeNodeAttributes(node.id, { ...node });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// Add edges — skip self-loops, auto-stub missing endpoints
|
|
18
|
+
for (const edge of extraction.edges) {
|
|
19
|
+
if (edge.source === edge.target)
|
|
20
|
+
continue;
|
|
21
|
+
// Create stub nodes for referenced endpoints not in the extraction
|
|
22
|
+
if (!graph.hasNode(edge.source)) {
|
|
23
|
+
graph.addNode(edge.source, {
|
|
24
|
+
id: edge.source,
|
|
25
|
+
label: edge.source,
|
|
26
|
+
fileType: 'unknown',
|
|
27
|
+
sourceFile: '',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (!graph.hasNode(edge.target)) {
|
|
31
|
+
graph.addNode(edge.target, {
|
|
32
|
+
id: edge.target,
|
|
33
|
+
label: edge.target,
|
|
34
|
+
fileType: 'unknown',
|
|
35
|
+
sourceFile: '',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
graph.addEdge(edge.source, edge.target, {
|
|
40
|
+
relation: edge.relation,
|
|
41
|
+
confidence: edge.confidence,
|
|
42
|
+
confidenceScore: edge.confidenceScore,
|
|
43
|
+
weight: edge.weight ?? 1,
|
|
44
|
+
sourceFile: edge.sourceFile,
|
|
45
|
+
sourceLocation: edge.sourceLocation,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Edge already exists — bump its weight
|
|
50
|
+
const existing = graph.edge(edge.source, edge.target);
|
|
51
|
+
if (existing) {
|
|
52
|
+
const prev = graph.getEdgeAttribute(existing, 'weight') ?? 1;
|
|
53
|
+
graph.setEdgeAttribute(existing, 'weight', prev + 1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return graph;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAG/B;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,UAA4B;IACrD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAE5D,oEAAoE;IACpE,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5B,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;YAAE,SAAS;QAE1C,mEAAmE;QACnE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE;gBACzB,EAAE,EAAE,IAAI,CAAC,MAAM;gBACf,KAAK,EAAE,IAAI,CAAC,MAAM;gBAClB,QAAQ,EAAE,SAAS;gBACnB,UAAU,EAAE,EAAE;aACf,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE;gBACzB,EAAE,EAAE,IAAI,CAAC,MAAM;gBACf,KAAK,EAAE,IAAI,CAAC,MAAM;gBAClB,QAAQ,EAAE,SAAS;gBACnB,UAAU,EAAE,EAAE;aACf,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC;YACH,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;gBACtC,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,eAAe,EAAE,IAAI,CAAC,eAAe;gBACrC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC;gBACxB,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,cAAc,EAAE,IAAI,CAAC,cAAc;aACpC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;YACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACtD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,GAAI,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAY,IAAI,CAAC,CAAC;gBACzE,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ExtractionResult } from './types.js';
|
|
2
|
+
export declare class FileCache {
|
|
3
|
+
private cacheDir;
|
|
4
|
+
constructor(outputDir: string);
|
|
5
|
+
key(filePath: string, content: string): string;
|
|
6
|
+
get(key: string): ExtractionResult | null;
|
|
7
|
+
set(key: string, result: ExtractionResult): void;
|
|
8
|
+
has(key: string): boolean;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;gBAEb,SAAS,EAAE,MAAM;IAK7B,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAM9C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAUzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAKhD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG1B"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
export class FileCache {
|
|
5
|
+
cacheDir;
|
|
6
|
+
constructor(outputDir) {
|
|
7
|
+
this.cacheDir = join(outputDir, 'cache');
|
|
8
|
+
mkdirSync(this.cacheDir, { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
key(filePath, content) {
|
|
11
|
+
return createHash('sha256')
|
|
12
|
+
.update(filePath + content)
|
|
13
|
+
.digest('hex');
|
|
14
|
+
}
|
|
15
|
+
get(key) {
|
|
16
|
+
const p = join(this.cacheDir, `${key}.json`);
|
|
17
|
+
if (!existsSync(p))
|
|
18
|
+
return null;
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(readFileSync(p, 'utf-8'));
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
set(key, result) {
|
|
27
|
+
const p = join(this.cacheDir, `${key}.json`);
|
|
28
|
+
writeFileSync(p, JSON.stringify(result), 'utf-8');
|
|
29
|
+
}
|
|
30
|
+
has(key) {
|
|
31
|
+
return existsSync(join(this.cacheDir, `${key}.json`));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,MAAM,OAAO,SAAS;IACZ,QAAQ,CAAS;IAEzB,YAAY,SAAiB;QAC3B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACzC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,GAAG,CAAC,QAAgB,EAAE,OAAe;QACnC,OAAO,UAAU,CAAC,QAAQ,CAAC;aACxB,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC;aAC1B,MAAM,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAChC,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAqB,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,MAAwB;QACvC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;QAC7C,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAED,GAAG,CAAC,GAAW;QACb,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type Graph from 'graphology';
|
|
2
|
+
/**
|
|
3
|
+
* Run Louvain community detection on the graph.
|
|
4
|
+
* Assigns the `community` attribute to each node in-place.
|
|
5
|
+
* Returns a map from communityId → list of nodeIds.
|
|
6
|
+
*/
|
|
7
|
+
export declare function detectCommunities(graph: Graph): Promise<Record<number, string[]>>;
|
|
8
|
+
//# sourceMappingURL=cluster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../../src/cluster.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AAEpC;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAqBvF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run Louvain community detection on the graph.
|
|
3
|
+
* Assigns the `community` attribute to each node in-place.
|
|
4
|
+
* Returns a map from communityId → list of nodeIds.
|
|
5
|
+
*/
|
|
6
|
+
export async function detectCommunities(graph) {
|
|
7
|
+
try {
|
|
8
|
+
const { default: louvain } = await import('graphology-communities-louvain');
|
|
9
|
+
const assignment = louvain(graph);
|
|
10
|
+
// Write community id back onto each node
|
|
11
|
+
for (const [nodeId, communityId] of Object.entries(assignment)) {
|
|
12
|
+
graph.setNodeAttribute(nodeId, 'community', communityId);
|
|
13
|
+
}
|
|
14
|
+
// Build communityId → members map
|
|
15
|
+
const communities = {};
|
|
16
|
+
for (const [nodeId, communityId] of Object.entries(assignment)) {
|
|
17
|
+
if (!communities[communityId])
|
|
18
|
+
communities[communityId] = [];
|
|
19
|
+
communities[communityId].push(nodeId);
|
|
20
|
+
}
|
|
21
|
+
return communities;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Louvain unavailable — fall back to directory-based clustering
|
|
25
|
+
return fallbackCluster(graph);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Fallback: group nodes by the directory portion of their sourceFile attribute.
|
|
30
|
+
* Deterministic and zero-dependency.
|
|
31
|
+
*/
|
|
32
|
+
function fallbackCluster(graph) {
|
|
33
|
+
const dirMap = new Map();
|
|
34
|
+
let nextId = 0;
|
|
35
|
+
const communities = {};
|
|
36
|
+
graph.forEachNode((id, attrs) => {
|
|
37
|
+
const file = attrs.sourceFile || '';
|
|
38
|
+
const parts = file.split('/');
|
|
39
|
+
const dir = parts.length > 1 ? parts.slice(0, -1).join('/') : 'root';
|
|
40
|
+
if (!dirMap.has(dir))
|
|
41
|
+
dirMap.set(dir, nextId++);
|
|
42
|
+
const cid = dirMap.get(dir);
|
|
43
|
+
graph.setNodeAttribute(id, 'community', cid);
|
|
44
|
+
if (!communities[cid])
|
|
45
|
+
communities[cid] = [];
|
|
46
|
+
communities[cid].push(id);
|
|
47
|
+
});
|
|
48
|
+
return communities;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=cluster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster.js","sourceRoot":"","sources":["../../src/cluster.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAAY;IAClD,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAC;QAC5E,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAA2B,CAAC;QAE5D,yCAAyC;QACzC,KAAK,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/D,KAAK,CAAC,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;QAC3D,CAAC;QAED,kCAAkC;QAClC,MAAM,WAAW,GAA6B,EAAE,CAAC;QACjD,KAAK,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/D,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC;gBAAE,WAAW,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;YAC7D,WAAW,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;QAChE,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,KAAY;IACnC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,WAAW,GAA6B,EAAE,CAAC;IAEjD,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE;QAC9B,MAAM,IAAI,GAAI,KAAK,CAAC,UAAqB,IAAI,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAErE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC;QAE7B,KAAK,CAAC,gBAAgB,CAAC,EAAE,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;QAC7C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;YAAE,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAC7C,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BuildOptions, ClassifiedFile } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Recursively collects and classifies all files under rootPath, applying
|
|
4
|
+
* exclusion rules for directories, file size limits, and optional language
|
|
5
|
+
* filtering from BuildOptions.
|
|
6
|
+
*/
|
|
7
|
+
export declare function collectFiles(rootPath: string, options?: BuildOptions): ClassifiedFile[];
|
|
8
|
+
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/detect.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAY,MAAM,YAAY,CAAC;AAwCzE;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,YAAiB,GACzB,cAAc,EAAE,CAwElB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { readdirSync, statSync } from 'fs';
|
|
2
|
+
import { join, extname, relative } from 'path';
|
|
3
|
+
const DEFAULT_MAX_FILE_SIZE = 500 * 1024; // 500KB
|
|
4
|
+
const EXCLUDED_DIRS = new Set([
|
|
5
|
+
'node_modules',
|
|
6
|
+
'.git',
|
|
7
|
+
'dist',
|
|
8
|
+
'build',
|
|
9
|
+
'.monobrain',
|
|
10
|
+
'__pycache__',
|
|
11
|
+
'.pytest_cache',
|
|
12
|
+
'target',
|
|
13
|
+
'.cache',
|
|
14
|
+
]);
|
|
15
|
+
// Maps file extension to [fileType, language]
|
|
16
|
+
const EXTENSION_MAP = {
|
|
17
|
+
'.ts': ['code', 'typescript'],
|
|
18
|
+
'.tsx': ['code', 'typescript'],
|
|
19
|
+
'.js': ['code', 'javascript'],
|
|
20
|
+
'.jsx': ['code', 'javascript'],
|
|
21
|
+
'.py': ['code', 'python'],
|
|
22
|
+
'.go': ['code', 'go'],
|
|
23
|
+
'.rs': ['code', 'rust'],
|
|
24
|
+
'.java': ['code', 'java'],
|
|
25
|
+
'.c': ['code', 'c'],
|
|
26
|
+
'.cpp': ['code', 'cpp'],
|
|
27
|
+
'.h': ['code', 'c'],
|
|
28
|
+
'.cs': ['code', 'csharp'],
|
|
29
|
+
'.rb': ['code', 'ruby'],
|
|
30
|
+
'.php': ['code', 'php'],
|
|
31
|
+
'.swift': ['code', 'swift'],
|
|
32
|
+
'.kt': ['code', 'kotlin'],
|
|
33
|
+
'.scala': ['code', 'scala'],
|
|
34
|
+
'.md': ['document', 'markdown'],
|
|
35
|
+
'.txt': ['document', 'text'],
|
|
36
|
+
'.rst': ['document', 'rst'],
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Recursively collects and classifies all files under rootPath, applying
|
|
40
|
+
* exclusion rules for directories, file size limits, and optional language
|
|
41
|
+
* filtering from BuildOptions.
|
|
42
|
+
*/
|
|
43
|
+
export function collectFiles(rootPath, options = {}) {
|
|
44
|
+
const maxFileSizeBytes = options.maxFileSizeBytes ?? DEFAULT_MAX_FILE_SIZE;
|
|
45
|
+
const codeOnly = options.codeOnly ?? false;
|
|
46
|
+
const languageFilter = options.languages ? new Set(options.languages) : null;
|
|
47
|
+
const excludePatterns = options.excludePatterns ?? [];
|
|
48
|
+
const results = [];
|
|
49
|
+
function walkDir(dirPath) {
|
|
50
|
+
let entries;
|
|
51
|
+
try {
|
|
52
|
+
entries = readdirSync(dirPath);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Skip unreadable directories
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
for (const entry of entries) {
|
|
59
|
+
const fullPath = join(dirPath, entry);
|
|
60
|
+
// Check against custom exclude patterns (matched against relative path)
|
|
61
|
+
const relPath = relative(rootPath, fullPath);
|
|
62
|
+
if (excludePatterns.some((pat) => relPath.includes(pat))) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
let stat;
|
|
66
|
+
try {
|
|
67
|
+
stat = statSync(fullPath);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (stat.isDirectory()) {
|
|
73
|
+
// Skip excluded directory names
|
|
74
|
+
if (EXCLUDED_DIRS.has(entry))
|
|
75
|
+
continue;
|
|
76
|
+
walkDir(fullPath);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (!stat.isFile())
|
|
80
|
+
continue;
|
|
81
|
+
// Enforce file size limit
|
|
82
|
+
if (stat.size > maxFileSizeBytes)
|
|
83
|
+
continue;
|
|
84
|
+
const ext = extname(entry).toLowerCase();
|
|
85
|
+
const mapping = EXTENSION_MAP[ext];
|
|
86
|
+
if (!mapping) {
|
|
87
|
+
// Unknown extension — skip rather than emit 'unknown' noise
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const [fileType, language] = mapping;
|
|
91
|
+
// Apply codeOnly filter
|
|
92
|
+
if (codeOnly && fileType !== 'code')
|
|
93
|
+
continue;
|
|
94
|
+
// Apply language filter
|
|
95
|
+
if (languageFilter && !languageFilter.has(language))
|
|
96
|
+
continue;
|
|
97
|
+
results.push({
|
|
98
|
+
path: fullPath,
|
|
99
|
+
fileType,
|
|
100
|
+
language,
|
|
101
|
+
sizeBytes: stat.size,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
walkDir(rootPath);
|
|
106
|
+
return results;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/detect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Graph from 'graphology';
|
|
2
|
+
/**
|
|
3
|
+
* Serialize a graphology graph to disk as a JSON file.
|
|
4
|
+
* Creates the output directory if it does not exist.
|
|
5
|
+
* Returns the absolute path to the written file.
|
|
6
|
+
*/
|
|
7
|
+
export declare function saveGraph(graph: Graph, outputDir: string, projectPath: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Deserialize a graph from a previously saved JSON file.
|
|
10
|
+
* Silently skips edges whose endpoints are missing from the node list.
|
|
11
|
+
*/
|
|
12
|
+
export declare function loadGraph(graphPath: string): Graph;
|
|
13
|
+
/**
|
|
14
|
+
* Return true when a graph.json already exists in the given output directory.
|
|
15
|
+
*/
|
|
16
|
+
export declare function graphExists(outputDir: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Return the canonical path to graph.json inside an output directory.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getGraphPath(outputDir: string): string;
|
|
21
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/export.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,YAAY,CAAC;AAG/B;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAsBtF;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAyBlD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import Graph from 'graphology';
|
|
4
|
+
/**
|
|
5
|
+
* Serialize a graphology graph to disk as a JSON file.
|
|
6
|
+
* Creates the output directory if it does not exist.
|
|
7
|
+
* Returns the absolute path to the written file.
|
|
8
|
+
*/
|
|
9
|
+
export function saveGraph(graph, outputDir, projectPath) {
|
|
10
|
+
mkdirSync(outputDir, { recursive: true });
|
|
11
|
+
const graphPath = join(outputDir, 'graph.json');
|
|
12
|
+
const nodes = [];
|
|
13
|
+
graph.forEachNode((id, attrs) => nodes.push({ id, ...attrs }));
|
|
14
|
+
const links = [];
|
|
15
|
+
graph.forEachEdge((_, attrs, source, target) => links.push({ source, target, ...attrs }));
|
|
16
|
+
const serialized = {
|
|
17
|
+
version: '1.0.0',
|
|
18
|
+
builtAt: new Date().toISOString(),
|
|
19
|
+
projectPath,
|
|
20
|
+
nodes,
|
|
21
|
+
links,
|
|
22
|
+
directed: graph.type === 'directed',
|
|
23
|
+
multigraph: graph.multi,
|
|
24
|
+
};
|
|
25
|
+
writeFileSync(graphPath, JSON.stringify(serialized, null, 2), 'utf-8');
|
|
26
|
+
return graphPath;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Deserialize a graph from a previously saved JSON file.
|
|
30
|
+
* Silently skips edges whose endpoints are missing from the node list.
|
|
31
|
+
*/
|
|
32
|
+
export function loadGraph(graphPath) {
|
|
33
|
+
const raw = readFileSync(graphPath, 'utf-8');
|
|
34
|
+
const data = JSON.parse(raw);
|
|
35
|
+
const graph = new Graph({
|
|
36
|
+
type: data.directed ? 'directed' : 'undirected',
|
|
37
|
+
multi: false,
|
|
38
|
+
});
|
|
39
|
+
for (const node of data.nodes) {
|
|
40
|
+
const { id, ...attrs } = node;
|
|
41
|
+
graph.addNode(id, attrs);
|
|
42
|
+
}
|
|
43
|
+
for (const link of data.links) {
|
|
44
|
+
const { source, target, ...attrs } = link;
|
|
45
|
+
if (!graph.hasNode(source) || !graph.hasNode(target))
|
|
46
|
+
continue;
|
|
47
|
+
try {
|
|
48
|
+
graph.addEdge(source, target, attrs);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Duplicate edge — ignore
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return graph;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Return true when a graph.json already exists in the given output directory.
|
|
58
|
+
*/
|
|
59
|
+
export function graphExists(outputDir) {
|
|
60
|
+
return existsSync(join(outputDir, 'graph.json'));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Return the canonical path to graph.json inside an output directory.
|
|
64
|
+
*/
|
|
65
|
+
export function getGraphPath(outputDir) {
|
|
66
|
+
return join(outputDir, 'graph.json');
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ClassifiedFile, ExtractionResult, BuildOptions } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extract graph nodes and edges from all classified files.
|
|
4
|
+
*
|
|
5
|
+
* Reads each file, checks the on-disk cache keyed by SHA-256 content hash,
|
|
6
|
+
* dispatches to the appropriate language extractor, and merges all results
|
|
7
|
+
* into a single ExtractionResult (nodes deduplicated by id, edges by source+target+relation).
|
|
8
|
+
*
|
|
9
|
+
* @param files - Classified files to process (from the classify layer)
|
|
10
|
+
* @param outputDir - Directory used for cache storage (.monobrain/graph by default)
|
|
11
|
+
* @param options - Build options (languages filter, maxFileSizeBytes, etc.)
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractAll(files: ClassifiedFile[], outputDir: string, options?: BuildOptions): Promise<ExtractionResult>;
|
|
14
|
+
export type { LanguageExtractor } from './types.js';
|
|
15
|
+
export { typescriptExtractor } from './languages/typescript.js';
|
|
16
|
+
export { pythonExtractor } from './languages/python.js';
|
|
17
|
+
export { goExtractor } from './languages/go.js';
|
|
18
|
+
export { rustExtractor } from './languages/rust.js';
|
|
19
|
+
export { isTreeSitterAvailable, tryLoadParser, walk, parseFile, parseFileFromDisk } from './tree-sitter-runner.js';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extract/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAwB,MAAM,aAAa,CAAC;AA+ExG;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,cAAc,EAAE,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,gBAAgB,CAAC,CAqF3B;AAGD,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC"}
|