@optave/codegraph 1.1.0 → 1.4.1

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/src/export.js CHANGED
@@ -1,138 +1,150 @@
1
- import path from 'path';
2
-
3
- /**
4
- * Export the dependency graph in DOT (Graphviz) format.
5
- */
6
- export function exportDOT(db, opts = {}) {
7
- const fileLevel = opts.fileLevel !== false;
8
- const lines = [
9
- 'digraph codegraph {',
10
- ' rankdir=LR;',
11
- ' node [shape=box, fontname="monospace", fontsize=10];',
12
- ' edge [color="#666666"];',
13
- ''
14
- ];
15
-
16
- if (fileLevel) {
17
- const edges = db.prepare(`
18
- SELECT DISTINCT n1.file AS source, n2.file AS target
19
- FROM edges e
20
- JOIN nodes n1 ON e.source_id = n1.id
21
- JOIN nodes n2 ON e.target_id = n2.id
22
- WHERE n1.file != n2.file AND e.kind IN ('imports', 'imports-type', 'calls')
23
- `).all();
24
-
25
- const dirs = new Map();
26
- const allFiles = new Set();
27
- for (const { source, target } of edges) {
28
- allFiles.add(source);
29
- allFiles.add(target);
30
- }
31
- for (const file of allFiles) {
32
- const dir = path.dirname(file) || '.';
33
- if (!dirs.has(dir)) dirs.set(dir, []);
34
- dirs.get(dir).push(file);
35
- }
36
-
37
- let clusterIdx = 0;
38
- for (const [dir, files] of [...dirs].sort()) {
39
- lines.push(` subgraph cluster_${clusterIdx++} {`);
40
- lines.push(` label="${dir}";`);
41
- lines.push(` style=dashed;`);
42
- lines.push(` color="#999999";`);
43
- for (const f of files) {
44
- const label = path.basename(f);
45
- lines.push(` "${f}" [label="${label}"];`);
46
- }
47
- lines.push(` }`);
48
- lines.push('');
49
- }
50
-
51
- for (const { source, target } of edges) {
52
- lines.push(` "${source}" -> "${target}";`);
53
- }
54
- } else {
55
- const edges = db.prepare(`
56
- SELECT n1.name AS source_name, n1.kind AS source_kind, n1.file AS source_file,
57
- n2.name AS target_name, n2.kind AS target_kind, n2.file AS target_file,
58
- e.kind AS edge_kind
59
- FROM edges e
60
- JOIN nodes n1 ON e.source_id = n1.id
61
- JOIN nodes n2 ON e.target_id = n2.id
62
- WHERE n1.kind IN ('function', 'method', 'class') AND n2.kind IN ('function', 'method', 'class')
63
- AND e.kind = 'calls'
64
- `).all();
65
-
66
- for (const e of edges) {
67
- const sId = `${e.source_file}:${e.source_name}`.replace(/[^a-zA-Z0-9_]/g, '_');
68
- const tId = `${e.target_file}:${e.target_name}`.replace(/[^a-zA-Z0-9_]/g, '_');
69
- lines.push(` ${sId} [label="${e.source_name}\\n${path.basename(e.source_file)}"];`);
70
- lines.push(` ${tId} [label="${e.target_name}\\n${path.basename(e.target_file)}"];`);
71
- lines.push(` ${sId} -> ${tId};`);
72
- }
73
- }
74
-
75
- lines.push('}');
76
- return lines.join('\n');
77
- }
78
-
79
- /**
80
- * Export the dependency graph in Mermaid format.
81
- */
82
- export function exportMermaid(db, opts = {}) {
83
- const fileLevel = opts.fileLevel !== false;
84
- const lines = ['graph LR'];
85
-
86
- if (fileLevel) {
87
- const edges = db.prepare(`
88
- SELECT DISTINCT n1.file AS source, n2.file AS target
89
- FROM edges e
90
- JOIN nodes n1 ON e.source_id = n1.id
91
- JOIN nodes n2 ON e.target_id = n2.id
92
- WHERE n1.file != n2.file AND e.kind IN ('imports', 'imports-type', 'calls')
93
- `).all();
94
-
95
- for (const { source, target } of edges) {
96
- const s = source.replace(/[^a-zA-Z0-9]/g, '_');
97
- const t = target.replace(/[^a-zA-Z0-9]/g, '_');
98
- lines.push(` ${s}["${source}"] --> ${t}["${target}"]`);
99
- }
100
- } else {
101
- const edges = db.prepare(`
102
- SELECT n1.name AS source_name, n1.file AS source_file,
103
- n2.name AS target_name, n2.file AS target_file
104
- FROM edges e
105
- JOIN nodes n1 ON e.source_id = n1.id
106
- JOIN nodes n2 ON e.target_id = n2.id
107
- WHERE n1.kind IN ('function', 'method', 'class') AND n2.kind IN ('function', 'method', 'class')
108
- AND e.kind = 'calls'
109
- `).all();
110
-
111
- for (const e of edges) {
112
- const sId = `${e.source_file}_${e.source_name}`.replace(/[^a-zA-Z0-9]/g, '_');
113
- const tId = `${e.target_file}_${e.target_name}`.replace(/[^a-zA-Z0-9]/g, '_');
114
- lines.push(` ${sId}["${e.source_name}"] --> ${tId}["${e.target_name}"]`);
115
- }
116
- }
117
-
118
- return lines.join('\n');
119
- }
120
-
121
- /**
122
- * Export as JSON adjacency list.
123
- */
124
- export function exportJSON(db) {
125
- const nodes = db.prepare(`
126
- SELECT id, name, kind, file, line FROM nodes WHERE kind = 'file'
127
- `).all();
128
-
129
- const edges = db.prepare(`
130
- SELECT DISTINCT n1.file AS source, n2.file AS target, e.kind
131
- FROM edges e
132
- JOIN nodes n1 ON e.source_id = n1.id
133
- JOIN nodes n2 ON e.target_id = n2.id
134
- WHERE n1.file != n2.file
135
- `).all();
136
-
137
- return { nodes, edges };
138
- }
1
+ import path from 'node:path';
2
+
3
+ /**
4
+ * Export the dependency graph in DOT (Graphviz) format.
5
+ */
6
+ export function exportDOT(db, opts = {}) {
7
+ const fileLevel = opts.fileLevel !== false;
8
+ const lines = [
9
+ 'digraph codegraph {',
10
+ ' rankdir=LR;',
11
+ ' node [shape=box, fontname="monospace", fontsize=10];',
12
+ ' edge [color="#666666"];',
13
+ '',
14
+ ];
15
+
16
+ if (fileLevel) {
17
+ const edges = db
18
+ .prepare(`
19
+ SELECT DISTINCT n1.file AS source, n2.file AS target
20
+ FROM edges e
21
+ JOIN nodes n1 ON e.source_id = n1.id
22
+ JOIN nodes n2 ON e.target_id = n2.id
23
+ WHERE n1.file != n2.file AND e.kind IN ('imports', 'imports-type', 'calls')
24
+ `)
25
+ .all();
26
+
27
+ const dirs = new Map();
28
+ const allFiles = new Set();
29
+ for (const { source, target } of edges) {
30
+ allFiles.add(source);
31
+ allFiles.add(target);
32
+ }
33
+ for (const file of allFiles) {
34
+ const dir = path.dirname(file) || '.';
35
+ if (!dirs.has(dir)) dirs.set(dir, []);
36
+ dirs.get(dir).push(file);
37
+ }
38
+
39
+ let clusterIdx = 0;
40
+ for (const [dir, files] of [...dirs].sort()) {
41
+ lines.push(` subgraph cluster_${clusterIdx++} {`);
42
+ lines.push(` label="${dir}";`);
43
+ lines.push(` style=dashed;`);
44
+ lines.push(` color="#999999";`);
45
+ for (const f of files) {
46
+ const label = path.basename(f);
47
+ lines.push(` "${f}" [label="${label}"];`);
48
+ }
49
+ lines.push(` }`);
50
+ lines.push('');
51
+ }
52
+
53
+ for (const { source, target } of edges) {
54
+ lines.push(` "${source}" -> "${target}";`);
55
+ }
56
+ } else {
57
+ const edges = db
58
+ .prepare(`
59
+ SELECT n1.name AS source_name, n1.kind AS source_kind, n1.file AS source_file,
60
+ n2.name AS target_name, n2.kind AS target_kind, n2.file AS target_file,
61
+ e.kind AS edge_kind
62
+ FROM edges e
63
+ JOIN nodes n1 ON e.source_id = n1.id
64
+ JOIN nodes n2 ON e.target_id = n2.id
65
+ WHERE n1.kind IN ('function', 'method', 'class') AND n2.kind IN ('function', 'method', 'class')
66
+ AND e.kind = 'calls'
67
+ `)
68
+ .all();
69
+
70
+ for (const e of edges) {
71
+ const sId = `${e.source_file}:${e.source_name}`.replace(/[^a-zA-Z0-9_]/g, '_');
72
+ const tId = `${e.target_file}:${e.target_name}`.replace(/[^a-zA-Z0-9_]/g, '_');
73
+ lines.push(` ${sId} [label="${e.source_name}\\n${path.basename(e.source_file)}"];`);
74
+ lines.push(` ${tId} [label="${e.target_name}\\n${path.basename(e.target_file)}"];`);
75
+ lines.push(` ${sId} -> ${tId};`);
76
+ }
77
+ }
78
+
79
+ lines.push('}');
80
+ return lines.join('\n');
81
+ }
82
+
83
+ /**
84
+ * Export the dependency graph in Mermaid format.
85
+ */
86
+ export function exportMermaid(db, opts = {}) {
87
+ const fileLevel = opts.fileLevel !== false;
88
+ const lines = ['graph LR'];
89
+
90
+ if (fileLevel) {
91
+ const edges = db
92
+ .prepare(`
93
+ SELECT DISTINCT n1.file AS source, n2.file AS target
94
+ FROM edges e
95
+ JOIN nodes n1 ON e.source_id = n1.id
96
+ JOIN nodes n2 ON e.target_id = n2.id
97
+ WHERE n1.file != n2.file AND e.kind IN ('imports', 'imports-type', 'calls')
98
+ `)
99
+ .all();
100
+
101
+ for (const { source, target } of edges) {
102
+ const s = source.replace(/[^a-zA-Z0-9]/g, '_');
103
+ const t = target.replace(/[^a-zA-Z0-9]/g, '_');
104
+ lines.push(` ${s}["${source}"] --> ${t}["${target}"]`);
105
+ }
106
+ } else {
107
+ const edges = db
108
+ .prepare(`
109
+ SELECT n1.name AS source_name, n1.file AS source_file,
110
+ n2.name AS target_name, n2.file AS target_file
111
+ FROM edges e
112
+ JOIN nodes n1 ON e.source_id = n1.id
113
+ JOIN nodes n2 ON e.target_id = n2.id
114
+ WHERE n1.kind IN ('function', 'method', 'class') AND n2.kind IN ('function', 'method', 'class')
115
+ AND e.kind = 'calls'
116
+ `)
117
+ .all();
118
+
119
+ for (const e of edges) {
120
+ const sId = `${e.source_file}_${e.source_name}`.replace(/[^a-zA-Z0-9]/g, '_');
121
+ const tId = `${e.target_file}_${e.target_name}`.replace(/[^a-zA-Z0-9]/g, '_');
122
+ lines.push(` ${sId}["${e.source_name}"] --> ${tId}["${e.target_name}"]`);
123
+ }
124
+ }
125
+
126
+ return lines.join('\n');
127
+ }
128
+
129
+ /**
130
+ * Export as JSON adjacency list.
131
+ */
132
+ export function exportJSON(db) {
133
+ const nodes = db
134
+ .prepare(`
135
+ SELECT id, name, kind, file, line FROM nodes WHERE kind = 'file'
136
+ `)
137
+ .all();
138
+
139
+ const edges = db
140
+ .prepare(`
141
+ SELECT DISTINCT n1.file AS source, n2.file AS target, e.kind
142
+ FROM edges e
143
+ JOIN nodes n1 ON e.source_id = n1.id
144
+ JOIN nodes n2 ON e.target_id = n2.id
145
+ WHERE n1.file != n2.file
146
+ `)
147
+ .all();
148
+
149
+ return { nodes, edges };
150
+ }
package/src/index.js CHANGED
@@ -1,39 +1,50 @@
1
- /**
2
- * codegraph — Programmatic API
3
- *
4
- * Usage:
5
- * import { buildGraph, queryNameData, findCycles, exportDOT } from 'codegraph';
6
- */
7
-
8
- // Graph building
9
- export { buildGraph, resolveImportPath, collectFiles, loadPathAliases } from './builder.js';
10
-
11
- // Query functions (data-returning)
12
- export {
13
- queryNameData, impactAnalysisData, moduleMapData,
14
- fileDepsData, fnDepsData, fnImpactData, diffImpactData
15
- } from './queries.js';
16
-
17
- // Watch mode
18
- export { watchProject } from './watcher.js';
19
-
20
- // Export (DOT/Mermaid/JSON)
21
- export { exportDOT, exportMermaid, exportJSON } from './export.js';
22
-
23
- // Circular dependency detection
24
- export { findCycles, formatCycles } from './cycles.js';
25
-
26
- // Embeddings
27
- export { buildEmbeddings, search, embed, cosineSim, MODELS, DEFAULT_MODEL } from './embedder.js';
28
-
29
- // Database utilities
30
- export { openDb, initSchema, findDbPath, openReadonlyOrFail } from './db.js';
31
-
32
- // Configuration
33
- export { loadConfig } from './config.js';
34
-
35
- // Shared constants
36
- export { EXTENSIONS, IGNORE_DIRS, normalizePath } from './constants.js';
37
-
38
- // Logger
39
- export { setVerbose } from './logger.js';
1
+ /**
2
+ * codegraph — Programmatic API
3
+ *
4
+ * Usage:
5
+ * import { buildGraph, queryNameData, findCycles, exportDOT } from 'codegraph';
6
+ */
7
+
8
+ // Graph building
9
+ export { buildGraph, collectFiles, loadPathAliases, resolveImportPath } from './builder.js';
10
+ // Configuration
11
+ export { loadConfig } from './config.js';
12
+ // Shared constants
13
+ export { EXTENSIONS, IGNORE_DIRS, normalizePath } from './constants.js';
14
+ // Circular dependency detection
15
+ export { findCycles, formatCycles } from './cycles.js';
16
+ // Database utilities
17
+ export { findDbPath, initSchema, openDb, openReadonlyOrFail } from './db.js';
18
+
19
+ // Embeddings
20
+ export {
21
+ buildEmbeddings,
22
+ cosineSim,
23
+ DEFAULT_MODEL,
24
+ embed,
25
+ MODELS,
26
+ multiSearchData,
27
+ search,
28
+ searchData,
29
+ } from './embedder.js';
30
+ // Export (DOT/Mermaid/JSON)
31
+ export { exportDOT, exportJSON, exportMermaid } from './export.js';
32
+ // Logger
33
+ export { setVerbose } from './logger.js';
34
+ // Native engine
35
+ export { isNativeAvailable } from './native.js';
36
+
37
+ // Unified parser API
38
+ export { getActiveEngine, parseFileAuto, parseFilesAuto } from './parser.js';
39
+ // Query functions (data-returning)
40
+ export {
41
+ diffImpactData,
42
+ fileDepsData,
43
+ fnDepsData,
44
+ fnImpactData,
45
+ impactAnalysisData,
46
+ moduleMapData,
47
+ queryNameData,
48
+ } from './queries.js';
49
+ // Watch mode
50
+ export { watchProject } from './watcher.js';
package/src/logger.js CHANGED
@@ -1,20 +1,24 @@
1
- let verbose = false;
2
-
3
- export function setVerbose(v) { verbose = v; }
4
- export function isVerbose() { return verbose; }
5
-
6
- export function warn(msg) {
7
- process.stderr.write(`[codegraph WARN] ${msg}\n`);
8
- }
9
-
10
- export function debug(msg) {
11
- if (verbose) process.stderr.write(`[codegraph DEBUG] ${msg}\n`);
12
- }
13
-
14
- export function info(msg) {
15
- process.stderr.write(`[codegraph] ${msg}\n`);
16
- }
17
-
18
- export function error(msg) {
19
- process.stderr.write(`[codegraph ERROR] ${msg}\n`);
20
- }
1
+ let verbose = false;
2
+
3
+ export function setVerbose(v) {
4
+ verbose = v;
5
+ }
6
+ export function isVerbose() {
7
+ return verbose;
8
+ }
9
+
10
+ export function warn(msg) {
11
+ process.stderr.write(`[codegraph WARN] ${msg}\n`);
12
+ }
13
+
14
+ export function debug(msg) {
15
+ if (verbose) process.stderr.write(`[codegraph DEBUG] ${msg}\n`);
16
+ }
17
+
18
+ export function info(msg) {
19
+ process.stderr.write(`[codegraph] ${msg}\n`);
20
+ }
21
+
22
+ export function error(msg) {
23
+ process.stderr.write(`[codegraph ERROR] ${msg}\n`);
24
+ }