rho-graph 0.1.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.
Files changed (118) hide show
  1. package/README.md +277 -0
  2. package/bin/rho-graph.js +2 -0
  3. package/dist/cli/commands/index-cmd.d.ts +2 -0
  4. package/dist/cli/commands/index-cmd.js +45 -0
  5. package/dist/cli/commands/index-cmd.js.map +1 -0
  6. package/dist/cli/commands/init.d.ts +3 -0
  7. package/dist/cli/commands/init.js +55 -0
  8. package/dist/cli/commands/init.js.map +1 -0
  9. package/dist/cli/commands/install-hook.d.ts +3 -0
  10. package/dist/cli/commands/install-hook.js +37 -0
  11. package/dist/cli/commands/install-hook.js.map +1 -0
  12. package/dist/cli/commands/install-mcp.d.ts +3 -0
  13. package/dist/cli/commands/install-mcp.js +32 -0
  14. package/dist/cli/commands/install-mcp.js.map +1 -0
  15. package/dist/cli/commands/query.d.ts +2 -0
  16. package/dist/cli/commands/query.js +92 -0
  17. package/dist/cli/commands/query.js.map +1 -0
  18. package/dist/cli/commands/setup.d.ts +2 -0
  19. package/dist/cli/commands/setup.js +15 -0
  20. package/dist/cli/commands/setup.js.map +1 -0
  21. package/dist/cli/commands/status.d.ts +2 -0
  22. package/dist/cli/commands/status.js +40 -0
  23. package/dist/cli/commands/status.js.map +1 -0
  24. package/dist/cli/commands/visualize.d.ts +2 -0
  25. package/dist/cli/commands/visualize.js +45 -0
  26. package/dist/cli/commands/visualize.js.map +1 -0
  27. package/dist/cli/index.d.ts +1 -0
  28. package/dist/cli/index.js +32 -0
  29. package/dist/cli/index.js.map +1 -0
  30. package/dist/config.d.ts +22 -0
  31. package/dist/config.js +95 -0
  32. package/dist/config.js.map +1 -0
  33. package/dist/db/connection.d.ts +13 -0
  34. package/dist/db/connection.js +25 -0
  35. package/dist/db/connection.js.map +1 -0
  36. package/dist/db/queries.d.ts +106 -0
  37. package/dist/db/queries.js +247 -0
  38. package/dist/db/queries.js.map +1 -0
  39. package/dist/db/schema.d.ts +2 -0
  40. package/dist/db/schema.js +22 -0
  41. package/dist/db/schema.js.map +1 -0
  42. package/dist/docker/neo4j.d.ts +5 -0
  43. package/dist/docker/neo4j.js +85 -0
  44. package/dist/docker/neo4j.js.map +1 -0
  45. package/dist/indexer/batch-writer.d.ts +35 -0
  46. package/dist/indexer/batch-writer.js +202 -0
  47. package/dist/indexer/batch-writer.js.map +1 -0
  48. package/dist/indexer/extractor.d.ts +35 -0
  49. package/dist/indexer/extractor.js +141 -0
  50. package/dist/indexer/extractor.js.map +1 -0
  51. package/dist/indexer/graph-writer.d.ts +12 -0
  52. package/dist/indexer/graph-writer.js +75 -0
  53. package/dist/indexer/graph-writer.js.map +1 -0
  54. package/dist/indexer/import-resolver.d.ts +8 -0
  55. package/dist/indexer/import-resolver.js +80 -0
  56. package/dist/indexer/import-resolver.js.map +1 -0
  57. package/dist/indexer/index.d.ts +21 -0
  58. package/dist/indexer/index.js +262 -0
  59. package/dist/indexer/index.js.map +1 -0
  60. package/dist/indexer/language-map.json +101 -0
  61. package/dist/indexer/parallel-pipeline.d.ts +41 -0
  62. package/dist/indexer/parallel-pipeline.js +82 -0
  63. package/dist/indexer/parallel-pipeline.js.map +1 -0
  64. package/dist/indexer/parser.d.ts +9 -0
  65. package/dist/indexer/parser.js +85 -0
  66. package/dist/indexer/parser.js.map +1 -0
  67. package/dist/indexer/staleness.d.ts +12 -0
  68. package/dist/indexer/staleness.js +60 -0
  69. package/dist/indexer/staleness.js.map +1 -0
  70. package/dist/mcp/index.d.ts +1 -0
  71. package/dist/mcp/index.js +38 -0
  72. package/dist/mcp/index.js.map +1 -0
  73. package/dist/mcp/staleness-check.d.ts +7 -0
  74. package/dist/mcp/staleness-check.js +31 -0
  75. package/dist/mcp/staleness-check.js.map +1 -0
  76. package/dist/mcp/tools/get-callees.d.ts +3 -0
  77. package/dist/mcp/tools/get-callees.js +34 -0
  78. package/dist/mcp/tools/get-callees.js.map +1 -0
  79. package/dist/mcp/tools/get-callers.d.ts +3 -0
  80. package/dist/mcp/tools/get-callers.js +34 -0
  81. package/dist/mcp/tools/get-callers.js.map +1 -0
  82. package/dist/mcp/tools/get-class.d.ts +3 -0
  83. package/dist/mcp/tools/get-class.js +42 -0
  84. package/dist/mcp/tools/get-class.js.map +1 -0
  85. package/dist/mcp/tools/get-dependencies.d.ts +3 -0
  86. package/dist/mcp/tools/get-dependencies.js +26 -0
  87. package/dist/mcp/tools/get-dependencies.js.map +1 -0
  88. package/dist/mcp/tools/get-dependents.d.ts +3 -0
  89. package/dist/mcp/tools/get-dependents.js +26 -0
  90. package/dist/mcp/tools/get-dependents.js.map +1 -0
  91. package/dist/mcp/tools/get-file-structure.d.ts +3 -0
  92. package/dist/mcp/tools/get-file-structure.js +33 -0
  93. package/dist/mcp/tools/get-file-structure.js.map +1 -0
  94. package/dist/mcp/tools/get-function.d.ts +3 -0
  95. package/dist/mcp/tools/get-function.js +34 -0
  96. package/dist/mcp/tools/get-function.js.map +1 -0
  97. package/dist/mcp/tools/get-repo-structure.d.ts +3 -0
  98. package/dist/mcp/tools/get-repo-structure.js +39 -0
  99. package/dist/mcp/tools/get-repo-structure.js.map +1 -0
  100. package/dist/mcp/tools/reindex.d.ts +4 -0
  101. package/dist/mcp/tools/reindex.js +27 -0
  102. package/dist/mcp/tools/reindex.js.map +1 -0
  103. package/dist/mcp/tools/search-code.d.ts +3 -0
  104. package/dist/mcp/tools/search-code.js +43 -0
  105. package/dist/mcp/tools/search-code.js.map +1 -0
  106. package/dist/visualize/public/graph.js +445 -0
  107. package/dist/visualize/public/index.html +88 -0
  108. package/dist/visualize/queries.d.ts +14 -0
  109. package/dist/visualize/queries.js +84 -0
  110. package/dist/visualize/queries.js.map +1 -0
  111. package/dist/visualize/server.d.ts +19 -0
  112. package/dist/visualize/server.js +293 -0
  113. package/dist/visualize/server.js.map +1 -0
  114. package/docker-compose.yml +16 -0
  115. package/package.json +69 -0
  116. package/src/indexer/language-map.json +128 -0
  117. package/src/visualize/public/graph.js +445 -0
  118. package/src/visualize/public/index.html +88 -0
@@ -0,0 +1,22 @@
1
+ export async function setupSchema(db) {
2
+ const session = db.session();
3
+ try {
4
+ // Uniqueness constraints
5
+ await session.run("CREATE CONSTRAINT repo_path IF NOT EXISTS FOR (r:Repository) REQUIRE r.path IS UNIQUE");
6
+ await session.run("CREATE CONSTRAINT file_path IF NOT EXISTS FOR (f:File) REQUIRE f.path IS UNIQUE");
7
+ // Indexes for fast lookup
8
+ await session.run("CREATE INDEX function_name IF NOT EXISTS FOR (f:Function) ON (f.name)");
9
+ await session.run("CREATE INDEX class_name IF NOT EXISTS FOR (c:Class) ON (c.name)");
10
+ await session.run("CREATE INDEX file_language IF NOT EXISTS FOR (f:File) ON (f.language)");
11
+ // Full-text index for search_code
12
+ await session.run(`
13
+ CREATE FULLTEXT INDEX code_search IF NOT EXISTS
14
+ FOR (n:Function|Class)
15
+ ON EACH [n.name, n.snippet, n.docstring]
16
+ `);
17
+ }
18
+ finally {
19
+ await session.close();
20
+ }
21
+ }
22
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,EAAgB;IAChD,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,yBAAyB;QACzB,MAAM,OAAO,CAAC,GAAG,CACf,uFAAuF,CACxF,CAAC;QACF,MAAM,OAAO,CAAC,GAAG,CACf,iFAAiF,CAClF,CAAC;QAEF,0BAA0B;QAC1B,MAAM,OAAO,CAAC,GAAG,CACf,uEAAuE,CACxE,CAAC;QACF,MAAM,OAAO,CAAC,GAAG,CACf,iEAAiE,CAClE,CAAC;QACF,MAAM,OAAO,CAAC,GAAG,CACf,uEAAuE,CACxE,CAAC;QAEF,kCAAkC;QAClC,MAAM,OAAO,CAAC,GAAG,CAAC;;;;KAIjB,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function isDockerAvailable(): boolean;
2
+ export declare function getContainerStatus(): "running" | "stopped" | "not_found";
3
+ export declare function startNeo4j(composeFilePath: string): void;
4
+ export declare function stopNeo4j(): void;
5
+ export declare function waitForNeo4j(uri: string, username: string, password: string, maxAttempts?: number): Promise<boolean>;
@@ -0,0 +1,85 @@
1
+ // src/docker/neo4j.ts
2
+ import { execFileSync } from "node:child_process";
3
+ import { resolve } from "node:path";
4
+ const CONTAINER_NAME = "code-graph-rag-neo4j";
5
+ function runDocker(...args) {
6
+ return execFileSync("docker", args, {
7
+ encoding: "utf-8",
8
+ stdio: "pipe",
9
+ });
10
+ }
11
+ export function isDockerAvailable() {
12
+ try {
13
+ runDocker("info");
14
+ return true;
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ export function getContainerStatus() {
21
+ try {
22
+ const result = runDocker("inspect", "--format", "{{.State.Running}}", CONTAINER_NAME).trim();
23
+ return result === "true" ? "running" : "stopped";
24
+ }
25
+ catch {
26
+ return "not_found";
27
+ }
28
+ }
29
+ export function startNeo4j(composeFilePath) {
30
+ const status = getContainerStatus();
31
+ if (status === "running")
32
+ return;
33
+ if (status === "stopped") {
34
+ runDocker("start", CONTAINER_NAME);
35
+ return;
36
+ }
37
+ const composePath = resolve(composeFilePath);
38
+ execFileSync("docker", ["compose", "-f", composePath, "up", "-d"], {
39
+ encoding: "utf-8",
40
+ stdio: "pipe",
41
+ });
42
+ }
43
+ export function stopNeo4j() {
44
+ const status = getContainerStatus();
45
+ if (status === "running") {
46
+ runDocker("stop", CONTAINER_NAME);
47
+ }
48
+ }
49
+ export async function waitForNeo4j(uri, username, password, maxAttempts = 60) {
50
+ // First wait for the process to start via admin check
51
+ let processReady = false;
52
+ for (let i = 0; i < maxAttempts; i++) {
53
+ try {
54
+ execFileSync("docker", ["exec", CONTAINER_NAME, "neo4j-admin", "server", "status"], { encoding: "utf-8", stdio: "pipe" });
55
+ processReady = true;
56
+ break;
57
+ }
58
+ catch {
59
+ await new Promise((r) => setTimeout(r, 1000));
60
+ }
61
+ }
62
+ if (!processReady)
63
+ return false;
64
+ // Then wait for the Bolt port to accept connections
65
+ const neo4j = await import("neo4j-driver");
66
+ const driver = neo4j.default.driver(uri, neo4j.default.auth.basic(username, password));
67
+ try {
68
+ for (let i = 0; i < maxAttempts; i++) {
69
+ try {
70
+ const session = driver.session();
71
+ await session.run("RETURN 1");
72
+ await session.close();
73
+ return true;
74
+ }
75
+ catch {
76
+ await new Promise((r) => setTimeout(r, 1000));
77
+ }
78
+ }
79
+ return false;
80
+ }
81
+ finally {
82
+ await driver.close();
83
+ }
84
+ }
85
+ //# sourceMappingURL=neo4j.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neo4j.js","sourceRoot":"","sources":["../../src/docker/neo4j.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { DbConnection } from "../db/connection.js";
2
+ import type { GraphEntities } from "./extractor.js";
3
+ import type { FileMetadata } from "./graph-writer.js";
4
+ export declare class BatchGraphWriter {
5
+ private readonly db;
6
+ private fileMetas;
7
+ private allFunctions;
8
+ private allClasses;
9
+ private allCalls;
10
+ private allImports;
11
+ private _estimatedMemoryBytes;
12
+ private _flushSem;
13
+ private _inFlight;
14
+ private _flushError;
15
+ private readonly batchSize;
16
+ private _flushesScheduled;
17
+ private _flushesCompleted;
18
+ onFlushProgress?: (completed: number, total: number) => void;
19
+ constructor(db: DbConnection, options?: {
20
+ batchSize?: number;
21
+ filePathSet?: Set<string>;
22
+ });
23
+ private readonly filePathSet;
24
+ add(entities: GraphEntities, meta: FileMetadata): void;
25
+ private _snapshot;
26
+ private _scheduleFlush;
27
+ get flushesScheduled(): number;
28
+ get flushesCompleted(): number;
29
+ private _runFlush;
30
+ private _doFlush;
31
+ flush(): Promise<void>;
32
+ waitForPendingFlush(): Promise<void>;
33
+ get pendingFileCount(): number;
34
+ get estimatedMemoryBytes(): number;
35
+ }
@@ -0,0 +1,202 @@
1
+ import { Semaphore } from "./parallel-pipeline.js";
2
+ import { batchDeleteFileChildren, batchUpsertFiles, batchUpsertClasses, batchUpsertFunctions, batchUpsertMethods, batchUpsertCallRelationships, batchUpsertImportRelationships, } from "../db/queries.js";
3
+ import { resolveImport } from "./import-resolver.js";
4
+ export class BatchGraphWriter {
5
+ db;
6
+ fileMetas = [];
7
+ allFunctions = [];
8
+ allClasses = [];
9
+ allCalls = [];
10
+ allImports = [];
11
+ _estimatedMemoryBytes = 0;
12
+ _flushSem = new Semaphore(1);
13
+ _inFlight = new Set();
14
+ _flushError = null;
15
+ batchSize;
16
+ _flushesScheduled = 0;
17
+ _flushesCompleted = 0;
18
+ onFlushProgress;
19
+ constructor(db, options = {}) {
20
+ this.db = db;
21
+ this.batchSize = options.batchSize ?? 200;
22
+ this.filePathSet = options.filePathSet ?? new Set();
23
+ }
24
+ filePathSet;
25
+ add(entities, meta) {
26
+ if (this._flushError) {
27
+ const err = this._flushError;
28
+ this._flushError = null;
29
+ throw err;
30
+ }
31
+ this.fileMetas.push(meta);
32
+ const validFunctions = entities.functions.filter((fn) => fn.name !== "");
33
+ const validClasses = entities.classes.filter((cls) => cls.name !== "");
34
+ this.allFunctions.push(...validFunctions);
35
+ this.allClasses.push(...validClasses);
36
+ this.allCalls.push(...entities.calls);
37
+ for (const imp of entities.imports) {
38
+ const target = resolveImport(imp.source, meta.filePath, meta.language, this.filePathSet);
39
+ if (target)
40
+ this.allImports.push({ sourceFilePath: meta.filePath, targetFilePath: target });
41
+ }
42
+ for (const fn of validFunctions) {
43
+ this._estimatedMemoryBytes += fn.snippet.length;
44
+ }
45
+ if (this.fileMetas.length >= this.batchSize) {
46
+ this._scheduleFlush(this._snapshot());
47
+ }
48
+ }
49
+ _snapshot() {
50
+ const snapshot = {
51
+ fileMetas: this.fileMetas,
52
+ functions: this.allFunctions,
53
+ classes: this.allClasses,
54
+ calls: this.allCalls,
55
+ imports: this.allImports,
56
+ };
57
+ this.fileMetas = [];
58
+ this.allFunctions = [];
59
+ this.allClasses = [];
60
+ this.allCalls = [];
61
+ this.allImports = [];
62
+ this._estimatedMemoryBytes = 0;
63
+ return snapshot;
64
+ }
65
+ _scheduleFlush(snapshot) {
66
+ if (snapshot.fileMetas.length === 0)
67
+ return;
68
+ this._flushesScheduled++;
69
+ const p = this._runFlush(snapshot)
70
+ .then(() => {
71
+ this._flushesCompleted++;
72
+ this.onFlushProgress?.(this._flushesCompleted, this._flushesScheduled);
73
+ })
74
+ .catch((err) => {
75
+ this._flushesCompleted++;
76
+ this._flushError = err instanceof Error ? err : new Error(String(err));
77
+ });
78
+ this._inFlight.add(p);
79
+ p.finally(() => this._inFlight.delete(p));
80
+ }
81
+ get flushesScheduled() { return this._flushesScheduled; }
82
+ get flushesCompleted() { return this._flushesCompleted; }
83
+ async _runFlush(snapshot) {
84
+ const release = await this._flushSem.acquire();
85
+ try {
86
+ await this._doFlush(snapshot);
87
+ }
88
+ finally {
89
+ release();
90
+ }
91
+ }
92
+ async _doFlush(snapshot) {
93
+ const { fileMetas, functions: allFunctions, classes: allClasses, calls: allCalls, imports: allImports } = snapshot;
94
+ const session = this.db.session();
95
+ const tx = session.beginTransaction();
96
+ try {
97
+ const filePaths = fileMetas.map((m) => m.filePath);
98
+ const deleteQ = batchDeleteFileChildren(filePaths);
99
+ await tx.run(deleteQ.cypher, deleteQ.params);
100
+ const fileItems = fileMetas.map((m) => ({
101
+ path: m.filePath,
102
+ relativePath: m.relativePath,
103
+ repoPath: m.repoPath,
104
+ language: m.language,
105
+ hash: m.hash,
106
+ lastModified: m.lastModified,
107
+ }));
108
+ const filesQ = batchUpsertFiles(fileItems);
109
+ await tx.run(filesQ.cypher, filesQ.params);
110
+ if (allClasses.length > 0) {
111
+ const classItems = allClasses.map((c) => ({
112
+ name: c.name,
113
+ filePath: c.filePath,
114
+ startLine: c.startLine,
115
+ endLine: c.endLine,
116
+ docstring: c.docstring,
117
+ }));
118
+ const classesQ = batchUpsertClasses(classItems);
119
+ await tx.run(classesQ.cypher, classesQ.params);
120
+ }
121
+ const topLevelFns = allFunctions.filter((fn) => fn.className === null);
122
+ if (topLevelFns.length > 0) {
123
+ const fnItems = topLevelFns.map((fn) => ({
124
+ name: fn.name,
125
+ filePath: fn.filePath,
126
+ startLine: fn.startLine,
127
+ endLine: fn.endLine,
128
+ signature: fn.signature,
129
+ docstring: fn.docstring,
130
+ snippet: fn.snippet,
131
+ className: null,
132
+ }));
133
+ const fnsQ = batchUpsertFunctions(fnItems);
134
+ await tx.run(fnsQ.cypher, fnsQ.params);
135
+ }
136
+ const methods = allFunctions.filter((fn) => fn.className !== null);
137
+ if (methods.length > 0) {
138
+ const methodItems = methods.map((fn) => ({
139
+ name: fn.name,
140
+ filePath: fn.filePath,
141
+ startLine: fn.startLine,
142
+ endLine: fn.endLine,
143
+ signature: fn.signature,
144
+ docstring: fn.docstring,
145
+ snippet: fn.snippet,
146
+ className: fn.className,
147
+ }));
148
+ const methodsQ = batchUpsertMethods(methodItems);
149
+ await tx.run(methodsQ.cypher, methodsQ.params);
150
+ }
151
+ if (allCalls.length > 0) {
152
+ const callsQ = batchUpsertCallRelationships(allCalls);
153
+ await tx.run(callsQ.cypher, callsQ.params);
154
+ }
155
+ if (allImports.length > 0) {
156
+ const importsQ = batchUpsertImportRelationships(allImports);
157
+ await tx.run(importsQ.cypher, importsQ.params);
158
+ }
159
+ await tx.commit();
160
+ }
161
+ catch (err) {
162
+ await tx.rollback();
163
+ throw err;
164
+ }
165
+ finally {
166
+ await session.close();
167
+ }
168
+ }
169
+ async flush() {
170
+ if (this._flushError) {
171
+ const err = this._flushError;
172
+ this._flushError = null;
173
+ throw err;
174
+ }
175
+ // Flush any remaining buffered files
176
+ if (this.fileMetas.length > 0) {
177
+ this._scheduleFlush(this._snapshot());
178
+ }
179
+ // Drain all in-flight flushes
180
+ while (this._inFlight.size > 0) {
181
+ await Promise.all([...this._inFlight]);
182
+ }
183
+ if (this._flushError) {
184
+ const err = this._flushError;
185
+ this._flushError = null;
186
+ throw err;
187
+ }
188
+ }
189
+ // kept for API compatibility — flush() now drains everything
190
+ async waitForPendingFlush() {
191
+ while (this._inFlight.size > 0) {
192
+ await Promise.all([...this._inFlight]);
193
+ }
194
+ }
195
+ get pendingFileCount() {
196
+ return this.fileMetas.length;
197
+ }
198
+ get estimatedMemoryBytes() {
199
+ return this._estimatedMemoryBytes;
200
+ }
201
+ }
202
+ //# sourceMappingURL=batch-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-writer.js","sourceRoot":"","sources":["../../src/indexer/batch-writer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAUrD,MAAM,OAAO,gBAAgB;IAgBR;IAfX,SAAS,GAAmB,EAAE,CAAC;IAC/B,YAAY,GAAwB,EAAE,CAAC;IACvC,UAAU,GAAqB,EAAE,CAAC;IAClC,QAAQ,GAAoB,EAAE,CAAC;IAC/B,UAAU,GAA8D,EAAE,CAAC;IAC3E,qBAAqB,GAAG,CAAC,CAAC;IAC1B,SAAS,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;IAC7B,SAAS,GAAG,IAAI,GAAG,EAAiB,CAAC;IACrC,WAAW,GAAiB,IAAI,CAAC;IACxB,SAAS,CAAS;IAC3B,iBAAiB,GAAG,CAAC,CAAC;IACtB,iBAAiB,GAAG,CAAC,CAAC;IAC9B,eAAe,CAA8C;IAE7D,YACmB,EAAgB,EACjC,UAA6D,EAAE;QAD9C,OAAE,GAAF,EAAE,CAAc;QAGjC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC;QAC1C,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,IAAI,GAAG,EAAE,CAAC;IACtD,CAAC;IAEgB,WAAW,CAAc;IAE1C,GAAG,CAAC,QAAuB,EAAE,IAAkB;QAC7C,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC;YAC7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE1B,MAAM,cAAc,GAAG,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;QACzE,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;QAEvE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;QAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEtC,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;YACzF,IAAI,MAAM;gBAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9F,CAAC;QAED,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;YAChC,IAAI,CAAC,qBAAqB,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;QAClD,CAAC;QAED,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC5C,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAEO,SAAS;QACf,MAAM,QAAQ,GAAkB;YAC9B,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,IAAI,CAAC,YAAY;YAC5B,OAAO,EAAE,IAAI,CAAC,UAAU;YACxB,KAAK,EAAE,IAAI,CAAC,QAAQ;YACpB,OAAO,EAAE,IAAI,CAAC,UAAU;SACzB,CAAC;QACF,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,qBAAqB,GAAG,CAAC,CAAC;QAC/B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,cAAc,CAAC,QAAuB;QAC5C,IAAI,QAAQ,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE5C,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;aAC/B,IAAI,CAAC,GAAG,EAAE;YACT,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzB,IAAI,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACzE,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzB,IAAI,CAAC,WAAW,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;QACL,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACtB,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,gBAAgB,KAAa,OAAO,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACjE,IAAI,gBAAgB,KAAa,OAAO,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAEzD,KAAK,CAAC,SAAS,CAAC,QAAuB;QAC7C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QAC/C,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,QAAuB;QAC5C,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC;QAEnH,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;QACtC,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,OAAO,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;YACnD,MAAM,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAE7C,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtC,IAAI,EAAE,CAAC,CAAC,QAAQ;gBAChB,YAAY,EAAE,CAAC,CAAC,YAAY;gBAC5B,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,YAAY,EAAE,CAAC,CAAC,YAAY;aAC7B,CAAC,CAAC,CAAC;YACJ,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAC3C,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAE3C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACxC,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;oBACpB,SAAS,EAAE,CAAC,CAAC,SAAS;oBACtB,OAAO,EAAE,CAAC,CAAC,OAAO;oBAClB,SAAS,EAAE,CAAC,CAAC,SAAS;iBACvB,CAAC,CAAC,CAAC;gBACJ,MAAM,QAAQ,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;gBAChD,MAAM,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YACjD,CAAC;YAED,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;YACvE,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3B,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;oBACvC,IAAI,EAAE,EAAE,CAAC,IAAI;oBACb,QAAQ,EAAE,EAAE,CAAC,QAAQ;oBACrB,SAAS,EAAE,EAAE,CAAC,SAAS;oBACvB,OAAO,EAAE,EAAE,CAAC,OAAO;oBACnB,SAAS,EAAE,EAAE,CAAC,SAAS;oBACvB,SAAS,EAAE,EAAE,CAAC,SAAS;oBACvB,OAAO,EAAE,EAAE,CAAC,OAAO;oBACnB,SAAS,EAAE,IAAqB;iBACjC,CAAC,CAAC,CAAC;gBACJ,MAAM,IAAI,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;gBAC3C,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACzC,CAAC;YAED,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;YACnE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;oBACvC,IAAI,EAAE,EAAE,CAAC,IAAI;oBACb,QAAQ,EAAE,EAAE,CAAC,QAAQ;oBACrB,SAAS,EAAE,EAAE,CAAC,SAAS;oBACvB,OAAO,EAAE,EAAE,CAAC,OAAO;oBACnB,SAAS,EAAE,EAAE,CAAC,SAAS;oBACvB,SAAS,EAAE,EAAE,CAAC,SAAS;oBACvB,OAAO,EAAE,EAAE,CAAC,OAAO;oBACnB,SAAS,EAAE,EAAE,CAAC,SAAmB;iBAClC,CAAC,CAAC,CAAC;gBACJ,MAAM,QAAQ,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;gBACjD,MAAM,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YACjD,CAAC;YAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,MAAM,GAAG,4BAA4B,CAAC,QAAQ,CAAC,CAAC;gBACtD,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7C,CAAC;YAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,MAAM,QAAQ,GAAG,8BAA8B,CAAC,UAAU,CAAC,CAAC;gBAC5D,MAAM,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YACjD,CAAC;YAED,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC;YACpB,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC;YAC7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,qCAAqC;QACrC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACxC,CAAC;QAED,8BAA8B;QAC9B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QACzC,CAAC;QAED,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC;YAC7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,6DAA6D;IAC7D,KAAK,CAAC,mBAAmB;QACvB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,IAAI,oBAAoB;QACtB,OAAO,IAAI,CAAC,qBAAqB,CAAC;IACpC,CAAC;CACF"}
@@ -0,0 +1,35 @@
1
+ import type Parser from "web-tree-sitter";
2
+ export interface ExtractedFunction {
3
+ name: string;
4
+ filePath: string;
5
+ startLine: number;
6
+ endLine: number;
7
+ signature: string;
8
+ docstring: string | null;
9
+ snippet: string;
10
+ className: string | null;
11
+ }
12
+ export interface ExtractedClass {
13
+ name: string;
14
+ filePath: string;
15
+ startLine: number;
16
+ endLine: number;
17
+ docstring: string | null;
18
+ }
19
+ export interface ExtractedImport {
20
+ source: string;
21
+ specifiers: string[];
22
+ isDefault: boolean;
23
+ }
24
+ export interface ExtractedCall {
25
+ callerName: string;
26
+ callerFilePath: string;
27
+ calleeName: string;
28
+ }
29
+ export interface GraphEntities {
30
+ functions: ExtractedFunction[];
31
+ classes: ExtractedClass[];
32
+ imports: ExtractedImport[];
33
+ calls: ExtractedCall[];
34
+ }
35
+ export declare function extractGraphEntities(tree: Parser.Tree, language: string, source: string, filePath: string): GraphEntities;
@@ -0,0 +1,141 @@
1
+ // src/indexer/extractor.ts
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve, join, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const languageMap = JSON.parse(readFileSync(join(__dirname, "language-map.json"), "utf-8"));
7
+ function getNodeText(node, source) {
8
+ return source.slice(node.startIndex, node.endIndex);
9
+ }
10
+ function getDocstring(node, source) {
11
+ const prev = node.previousNamedSibling;
12
+ if (prev && prev.type === "comment") {
13
+ return getNodeText(prev, source).replace(/^\/\*\*?|\*\/$/g, "").trim();
14
+ }
15
+ // Python docstrings: first child of body is expression_statement > string
16
+ const body = node.childForFieldName("body");
17
+ if (body) {
18
+ const first = body.firstNamedChild;
19
+ if (first?.type === "expression_statement") {
20
+ const str = first.firstNamedChild;
21
+ if (str?.type === "string") {
22
+ return getNodeText(str, source)
23
+ .replace(/^['"]|['"]$/g, "")
24
+ .replace(/^"""|"""$/g, "")
25
+ .trim();
26
+ }
27
+ }
28
+ }
29
+ return null;
30
+ }
31
+ function extractSignature(node, source) {
32
+ const lines = getNodeText(node, source).split("\n");
33
+ return lines[0].trim();
34
+ }
35
+ function walkForCalls(node, source, callerName, callerFilePath, callTypes) {
36
+ const calls = [];
37
+ function walk(n) {
38
+ if (callTypes.includes(n.type)) {
39
+ const fnNode = n.childForFieldName("function") || n.firstNamedChild;
40
+ if (fnNode) {
41
+ let calleeName;
42
+ if (fnNode.type === "member_expression" || fnNode.type === "attribute") {
43
+ const prop = fnNode.childForFieldName("property") ||
44
+ fnNode.childForFieldName("attribute");
45
+ calleeName = prop
46
+ ? getNodeText(prop, source)
47
+ : getNodeText(fnNode, source);
48
+ }
49
+ else if (fnNode.type === "identifier" ||
50
+ fnNode.type === "property_identifier") {
51
+ calleeName = getNodeText(fnNode, source);
52
+ }
53
+ else {
54
+ calleeName = getNodeText(fnNode, source);
55
+ }
56
+ if (calleeName && calleeName !== callerName) {
57
+ calls.push({ callerName, callerFilePath, calleeName });
58
+ }
59
+ }
60
+ }
61
+ for (let i = 0; i < n.childCount; i++) {
62
+ walk(n.child(i));
63
+ }
64
+ }
65
+ walk(node);
66
+ return calls;
67
+ }
68
+ export function extractGraphEntities(tree, language, source, filePath) {
69
+ const absPath = resolve(filePath);
70
+ const mapping = languageMap[language];
71
+ const functions = [];
72
+ const classes = [];
73
+ const imports = [];
74
+ const calls = [];
75
+ if (!mapping) {
76
+ return { functions, classes, imports, calls };
77
+ }
78
+ const functionTypes = new Set(mapping.function);
79
+ const classTypes = new Set(mapping.class);
80
+ const importTypes = new Set(mapping.import);
81
+ function walkNode(node, currentClassName) {
82
+ if (classTypes.has(node.type)) {
83
+ const nameNode = node.childForFieldName(mapping.name_field);
84
+ if (nameNode) {
85
+ const className = getNodeText(nameNode, source);
86
+ classes.push({
87
+ name: className,
88
+ filePath: absPath,
89
+ startLine: node.startPosition.row + 1,
90
+ endLine: node.endPosition.row + 1,
91
+ docstring: getDocstring(node, source),
92
+ });
93
+ for (let i = 0; i < node.childCount; i++) {
94
+ walkNode(node.child(i), className);
95
+ }
96
+ return;
97
+ }
98
+ }
99
+ if (functionTypes.has(node.type)) {
100
+ const nameNode = node.childForFieldName(mapping.name_field);
101
+ if (nameNode) {
102
+ const funcName = getNodeText(nameNode, source);
103
+ const snippet = getNodeText(node, source);
104
+ const signature = extractSignature(node, source);
105
+ functions.push({
106
+ name: funcName,
107
+ filePath: absPath,
108
+ startLine: node.startPosition.row + 1,
109
+ endLine: node.endPosition.row + 1,
110
+ signature,
111
+ docstring: getDocstring(node, source),
112
+ snippet,
113
+ className: currentClassName,
114
+ });
115
+ const funcCalls = walkForCalls(node, source, funcName, absPath, mapping.call);
116
+ calls.push(...funcCalls);
117
+ return;
118
+ }
119
+ }
120
+ if (importTypes.has(node.type)) {
121
+ const text = getNodeText(node, source);
122
+ const sourceNode = node.childForFieldName("source") ||
123
+ node.childForFieldName("module_name") ||
124
+ node.childForFieldName("path");
125
+ const importSource = sourceNode
126
+ ? getNodeText(sourceNode, source).replace(/['"]/g, "")
127
+ : text;
128
+ imports.push({
129
+ source: importSource,
130
+ specifiers: [],
131
+ isDefault: text.includes("import default") || !text.includes("{"),
132
+ });
133
+ }
134
+ for (let i = 0; i < node.childCount; i++) {
135
+ walkNode(node.child(i), currentClassName);
136
+ }
137
+ }
138
+ walkNode(tree.rootNode, null);
139
+ return { functions, classes, imports, calls };
140
+ }
141
+ //# sourceMappingURL=extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/indexer/extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { DbConnection } from "../db/connection.js";
2
+ import type { GraphEntities } from "./extractor.js";
3
+ export interface FileMetadata {
4
+ filePath: string;
5
+ relativePath: string;
6
+ repoPath: string;
7
+ language: string;
8
+ hash: string;
9
+ lastModified: number;
10
+ }
11
+ export declare function writeRepoOnce(db: DbConnection, repoPath: string): Promise<void>;
12
+ export declare function writeGraphEntities(db: DbConnection, entities: GraphEntities, meta: FileMetadata, filePathSet?: Set<string>): Promise<void>;
@@ -0,0 +1,75 @@
1
+ import { upsertRepository, upsertFile, upsertFunction, upsertClass, upsertCallRelationship, upsertImportRelationship, } from "../db/queries.js";
2
+ import { resolveImport } from "./import-resolver.js";
3
+ export async function writeRepoOnce(db, repoPath) {
4
+ const session = db.session();
5
+ try {
6
+ const repoQ = upsertRepository({ path: repoPath, name: repoPath.split("/").pop() || repoPath });
7
+ await session.run(repoQ.cypher, repoQ.params);
8
+ }
9
+ finally {
10
+ await session.close();
11
+ }
12
+ }
13
+ export async function writeGraphEntities(db, entities, meta, filePathSet = new Set()) {
14
+ const session = db.session();
15
+ try {
16
+ // Upsert file
17
+ const fileQ = upsertFile({
18
+ path: meta.filePath,
19
+ relativePath: meta.relativePath,
20
+ repoPath: meta.repoPath,
21
+ language: meta.language,
22
+ hash: meta.hash,
23
+ lastModified: meta.lastModified,
24
+ });
25
+ await session.run(fileQ.cypher, fileQ.params);
26
+ // Delete old children for this file (clean re-index)
27
+ await session.run(`
28
+ MATCH (f:File {path: $filePath})-[:CONTAINS]->(child)
29
+ OPTIONAL MATCH (child)-[:HAS_METHOD]->(method)
30
+ DETACH DELETE method, child
31
+ `, { filePath: meta.filePath });
32
+ // Upsert classes
33
+ for (const cls of entities.classes) {
34
+ const q = upsertClass({
35
+ name: cls.name,
36
+ filePath: meta.filePath,
37
+ startLine: cls.startLine,
38
+ endLine: cls.endLine,
39
+ docstring: cls.docstring,
40
+ });
41
+ await session.run(q.cypher, q.params);
42
+ }
43
+ // Upsert functions
44
+ for (const fn of entities.functions) {
45
+ const q = upsertFunction({
46
+ name: fn.name,
47
+ filePath: meta.filePath,
48
+ startLine: fn.startLine,
49
+ endLine: fn.endLine,
50
+ signature: fn.signature,
51
+ docstring: fn.docstring,
52
+ snippet: fn.snippet,
53
+ className: fn.className ?? undefined,
54
+ });
55
+ await session.run(q.cypher, q.params);
56
+ }
57
+ // Upsert call relationships
58
+ for (const call of entities.calls) {
59
+ const q = upsertCallRelationship(call);
60
+ await session.run(q.cypher, q.params);
61
+ }
62
+ // Upsert import relationships
63
+ for (const imp of entities.imports) {
64
+ const target = resolveImport(imp.source, meta.filePath, meta.language, filePathSet);
65
+ if (target) {
66
+ const q = upsertImportRelationship({ sourceFilePath: meta.filePath, targetFilePath: target });
67
+ await session.run(q.cypher, q.params);
68
+ }
69
+ }
70
+ }
71
+ finally {
72
+ await session.close();
73
+ }
74
+ }
75
+ //# sourceMappingURL=graph-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-writer.js","sourceRoot":"","sources":["../../src/indexer/graph-writer.ts"],"names":[],"mappings":"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"}