@ophan/core 0.0.2 → 0.0.4
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/community-detectors/index.d.ts +20 -0
- package/dist/community-detectors/index.d.ts.map +1 -0
- package/dist/community-detectors/index.js +45 -0
- package/dist/community-detectors/label-prop.d.ts +20 -0
- package/dist/community-detectors/label-prop.d.ts.map +1 -0
- package/dist/community-detectors/label-prop.js +77 -0
- package/dist/community-detectors/leiden.d.ts +22 -0
- package/dist/community-detectors/leiden.d.ts.map +1 -0
- package/dist/community-detectors/leiden.js +312 -0
- package/dist/community-detectors/louvain.d.ts +13 -0
- package/dist/community-detectors/louvain.d.ts.map +1 -0
- package/dist/community-detectors/louvain.js +29 -0
- package/dist/community-detectors/types.d.ts +36 -0
- package/dist/community-detectors/types.d.ts.map +1 -0
- package/dist/{parsers/__fixtures__/no-functions.js → community-detectors/types.js} +0 -2
- package/dist/edge-resolvers/call.d.ts +13 -0
- package/dist/edge-resolvers/call.d.ts.map +1 -0
- package/dist/edge-resolvers/call.js +40 -0
- package/dist/edge-resolvers/co-location.d.ts +16 -0
- package/dist/edge-resolvers/co-location.d.ts.map +1 -0
- package/dist/edge-resolvers/co-location.js +129 -0
- package/dist/edge-resolvers/import.d.ts +16 -0
- package/dist/edge-resolvers/import.d.ts.map +1 -0
- package/dist/edge-resolvers/import.js +118 -0
- package/dist/edge-resolvers/index.d.ts +9 -0
- package/dist/edge-resolvers/index.d.ts.map +1 -0
- package/dist/edge-resolvers/index.js +29 -0
- package/dist/edge-resolvers/jsx-ref.d.ts +13 -0
- package/dist/edge-resolvers/jsx-ref.d.ts.map +1 -0
- package/dist/edge-resolvers/jsx-ref.js +40 -0
- package/dist/edge-resolvers/types.d.ts +40 -0
- package/dist/edge-resolvers/types.d.ts.map +1 -0
- package/dist/edge-resolvers/types.js +2 -0
- package/dist/graph.d.ts +293 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +1295 -0
- package/dist/index.d.ts +37 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +385 -183
- package/dist/migrations.d.ts +25 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +323 -0
- package/dist/module-resolvers/index.d.ts +11 -0
- package/dist/module-resolvers/index.d.ts.map +1 -0
- package/dist/module-resolvers/index.js +67 -0
- package/dist/module-resolvers/javascript.d.ts +18 -0
- package/dist/module-resolvers/javascript.d.ts.map +1 -0
- package/dist/module-resolvers/javascript.js +130 -0
- package/dist/module-resolvers/types.d.ts +18 -0
- package/dist/module-resolvers/types.d.ts.map +1 -0
- package/dist/module-resolvers/types.js +2 -0
- package/dist/parsers/python.d.ts.map +1 -1
- package/dist/parsers/python.js +38 -4
- package/dist/parsers/typescript.d.ts.map +1 -1
- package/dist/parsers/typescript.js +133 -0
- package/dist/practices.d.ts +28 -0
- package/dist/practices.d.ts.map +1 -0
- package/dist/practices.js +95 -0
- package/dist/schemas.d.ts +251 -3
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +121 -6
- package/dist/shared.d.ts +8 -0
- package/dist/shared.d.ts.map +1 -1
- package/dist/summarize.d.ts +165 -0
- package/dist/summarize.d.ts.map +1 -0
- package/dist/summarize.js +1067 -0
- package/ophan_logo.png +0 -0
- package/package.json +9 -2
- package/dist/parsers/__fixtures__/arrow-functions.d.ts +0 -5
- package/dist/parsers/__fixtures__/arrow-functions.d.ts.map +0 -1
- package/dist/parsers/__fixtures__/arrow-functions.js +0 -16
- package/dist/parsers/__fixtures__/class-methods.d.ts +0 -6
- package/dist/parsers/__fixtures__/class-methods.d.ts.map +0 -1
- package/dist/parsers/__fixtures__/class-methods.js +0 -12
- package/dist/parsers/__fixtures__/no-functions.d.ts +0 -9
- package/dist/parsers/__fixtures__/no-functions.d.ts.map +0 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
export interface Migration {
|
|
3
|
+
id: string;
|
|
4
|
+
up: (db: Database.Database) => void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Run pending migrations in order. Each migration runs in a transaction —
|
|
8
|
+
* if it fails, the transaction rolls back and the migration is NOT recorded.
|
|
9
|
+
* Returns the list of newly applied migration IDs.
|
|
10
|
+
*/
|
|
11
|
+
export declare function runMigrations(db: Database.Database, migrations: Migration[], appliedBy: string): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Record all migrations as applied WITHOUT running them.
|
|
14
|
+
* Used when creating a fresh DB with createFreshSchema() — the schema
|
|
15
|
+
* is already at the latest state, so migrations don't need to run.
|
|
16
|
+
*/
|
|
17
|
+
export declare function bootstrapMigrations(db: Database.Database, migrations: Migration[], appliedBy: string): void;
|
|
18
|
+
export declare const CORE_MIGRATIONS: Migration[];
|
|
19
|
+
/**
|
|
20
|
+
* Migrate from single-blob function_analysis to split analysis types.
|
|
21
|
+
* Called from core_002_analysis_types migration on databases that predate
|
|
22
|
+
* the analysis_type column. Exported for testing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function migrateToAnalysisTypes(db: Database.Database): void;
|
|
25
|
+
//# sourceMappingURL=migrations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,UAAU,EAAE,SAAS,EAAE,EACvB,SAAS,EAAE,MAAM,GAChB,MAAM,EAAE,CAgCV;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,UAAU,EAAE,SAAS,EAAE,EACvB,SAAS,EAAE,MAAM,GAChB,IAAI,CAgBN;AAcD,eAAO,MAAM,eAAe,EAAE,SAAS,EAkLtC,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,QA8D3D"}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Migration runner for @ophan/core.
|
|
3
|
+
//
|
|
4
|
+
// Mirrors the extension's migration runner (packages/vscode/src/migrations.ts).
|
|
5
|
+
// Both share the _ophan_migrations table format but maintain independent
|
|
6
|
+
// migration lists — core prefixes with "core_", extension with "ext_".
|
|
7
|
+
//
|
|
8
|
+
// Each migration is idempotent (uses IF NOT EXISTS, try-catch for ADD COLUMN)
|
|
9
|
+
// and runs in a transaction.
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.CORE_MIGRATIONS = void 0;
|
|
12
|
+
exports.runMigrations = runMigrations;
|
|
13
|
+
exports.bootstrapMigrations = bootstrapMigrations;
|
|
14
|
+
exports.migrateToAnalysisTypes = migrateToAnalysisTypes;
|
|
15
|
+
/**
|
|
16
|
+
* Run pending migrations in order. Each migration runs in a transaction —
|
|
17
|
+
* if it fails, the transaction rolls back and the migration is NOT recorded.
|
|
18
|
+
* Returns the list of newly applied migration IDs.
|
|
19
|
+
*/
|
|
20
|
+
function runMigrations(db, migrations, appliedBy) {
|
|
21
|
+
db.exec(`
|
|
22
|
+
CREATE TABLE IF NOT EXISTS _ophan_migrations (
|
|
23
|
+
migration_id TEXT PRIMARY KEY,
|
|
24
|
+
applied_at INTEGER NOT NULL,
|
|
25
|
+
applied_by TEXT NOT NULL
|
|
26
|
+
)
|
|
27
|
+
`);
|
|
28
|
+
const applied = new Set(db.prepare("SELECT migration_id FROM _ophan_migrations").all().map((r) => r.migration_id));
|
|
29
|
+
const ran = [];
|
|
30
|
+
const insert = db.prepare("INSERT INTO _ophan_migrations (migration_id, applied_at, applied_by) VALUES (?, ?, ?)");
|
|
31
|
+
for (const m of migrations) {
|
|
32
|
+
if (applied.has(m.id))
|
|
33
|
+
continue;
|
|
34
|
+
db.transaction(() => {
|
|
35
|
+
m.up(db);
|
|
36
|
+
insert.run(m.id, Date.now(), appliedBy);
|
|
37
|
+
})();
|
|
38
|
+
ran.push(m.id);
|
|
39
|
+
}
|
|
40
|
+
return ran;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Record all migrations as applied WITHOUT running them.
|
|
44
|
+
* Used when creating a fresh DB with createFreshSchema() — the schema
|
|
45
|
+
* is already at the latest state, so migrations don't need to run.
|
|
46
|
+
*/
|
|
47
|
+
function bootstrapMigrations(db, migrations, appliedBy) {
|
|
48
|
+
db.exec(`
|
|
49
|
+
CREATE TABLE IF NOT EXISTS _ophan_migrations (
|
|
50
|
+
migration_id TEXT PRIMARY KEY,
|
|
51
|
+
applied_at INTEGER NOT NULL,
|
|
52
|
+
applied_by TEXT NOT NULL
|
|
53
|
+
)
|
|
54
|
+
`);
|
|
55
|
+
const insert = db.prepare("INSERT OR IGNORE INTO _ophan_migrations (migration_id, applied_at, applied_by) VALUES (?, ?, ?)");
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
for (const m of migrations) {
|
|
58
|
+
insert.run(m.id, now, appliedBy);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// ============ CORE MIGRATIONS ============
|
|
62
|
+
//
|
|
63
|
+
// These run on existing databases to bring them up to the current schema.
|
|
64
|
+
// For fresh databases, createFreshSchema() creates the latest schema directly
|
|
65
|
+
// and bootstrapMigrations() records all of these as applied.
|
|
66
|
+
//
|
|
67
|
+
// RULES:
|
|
68
|
+
// 1. Migrations are immutable — once shipped, never modify. Fix forward.
|
|
69
|
+
// 2. Migrations are idempotent — safe to run twice (IF NOT EXISTS, try-catch).
|
|
70
|
+
// 3. Each runs in a transaction — rolls back on failure.
|
|
71
|
+
// 4. Never rename tables or columns — add new, deprecate old.
|
|
72
|
+
exports.CORE_MIGRATIONS = [
|
|
73
|
+
{
|
|
74
|
+
id: "core_001_fresh_schema",
|
|
75
|
+
up: (db) => {
|
|
76
|
+
// Base tables — CREATE IF NOT EXISTS is a no-op on existing DBs
|
|
77
|
+
db.exec(`
|
|
78
|
+
CREATE TABLE IF NOT EXISTS function_analysis (
|
|
79
|
+
content_hash TEXT NOT NULL,
|
|
80
|
+
analysis_type TEXT NOT NULL,
|
|
81
|
+
analysis JSON NOT NULL,
|
|
82
|
+
model_version TEXT NOT NULL,
|
|
83
|
+
schema_version INTEGER NOT NULL DEFAULT 1,
|
|
84
|
+
created_at INTEGER NOT NULL,
|
|
85
|
+
last_seen_at INTEGER NOT NULL,
|
|
86
|
+
language TEXT NOT NULL DEFAULT 'typescript',
|
|
87
|
+
entity_type TEXT NOT NULL DEFAULT 'function',
|
|
88
|
+
synced_at INTEGER,
|
|
89
|
+
PRIMARY KEY (content_hash, analysis_type)
|
|
90
|
+
)
|
|
91
|
+
`);
|
|
92
|
+
db.exec(`
|
|
93
|
+
CREATE TABLE IF NOT EXISTS file_functions (
|
|
94
|
+
file_path TEXT NOT NULL,
|
|
95
|
+
function_name TEXT NOT NULL,
|
|
96
|
+
content_hash TEXT NOT NULL,
|
|
97
|
+
file_mtime INTEGER NOT NULL,
|
|
98
|
+
language TEXT NOT NULL DEFAULT 'typescript',
|
|
99
|
+
entity_type TEXT NOT NULL DEFAULT 'function',
|
|
100
|
+
start_line INTEGER NOT NULL DEFAULT 0,
|
|
101
|
+
PRIMARY KEY (file_path, function_name)
|
|
102
|
+
)
|
|
103
|
+
`);
|
|
104
|
+
db.exec(`
|
|
105
|
+
CREATE TABLE IF NOT EXISTS function_gc (
|
|
106
|
+
content_hash TEXT NOT NULL,
|
|
107
|
+
analysis_type TEXT,
|
|
108
|
+
gc_at INTEGER NOT NULL,
|
|
109
|
+
synced_at INTEGER,
|
|
110
|
+
PRIMARY KEY (content_hash, analysis_type)
|
|
111
|
+
)
|
|
112
|
+
`);
|
|
113
|
+
db.exec(`
|
|
114
|
+
CREATE TABLE IF NOT EXISTS sync_meta (
|
|
115
|
+
key TEXT PRIMARY KEY,
|
|
116
|
+
value TEXT NOT NULL
|
|
117
|
+
)
|
|
118
|
+
`);
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: "core_002_analysis_types",
|
|
123
|
+
up: (db) => {
|
|
124
|
+
// Detect if we need the monolithic→typed migration by checking for analysis_type column
|
|
125
|
+
const columns = db
|
|
126
|
+
.prepare("PRAGMA table_info(function_analysis)")
|
|
127
|
+
.all();
|
|
128
|
+
if (columns.length > 0 && !columns.some((c) => c.name === "analysis_type")) {
|
|
129
|
+
// Import the migration function — it handles the full transform
|
|
130
|
+
// This is the only migration that needs the complex table replacement logic
|
|
131
|
+
migrateToAnalysisTypes(db);
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
id: "core_003_file_functions_columns",
|
|
137
|
+
up: (db) => {
|
|
138
|
+
const cols = db
|
|
139
|
+
.prepare("PRAGMA table_info(file_functions)")
|
|
140
|
+
.all();
|
|
141
|
+
if (!cols.some((c) => c.name === "language")) {
|
|
142
|
+
try {
|
|
143
|
+
db.exec("ALTER TABLE file_functions ADD COLUMN language TEXT NOT NULL DEFAULT 'typescript'");
|
|
144
|
+
}
|
|
145
|
+
catch (_) { }
|
|
146
|
+
try {
|
|
147
|
+
db.exec("ALTER TABLE file_functions ADD COLUMN entity_type TEXT NOT NULL DEFAULT 'function'");
|
|
148
|
+
}
|
|
149
|
+
catch (_) { }
|
|
150
|
+
}
|
|
151
|
+
if (!cols.some((c) => c.name === "start_line")) {
|
|
152
|
+
try {
|
|
153
|
+
db.exec("ALTER TABLE file_functions ADD COLUMN start_line INTEGER NOT NULL DEFAULT 0");
|
|
154
|
+
}
|
|
155
|
+
catch (_) { }
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: "core_004_gc_analysis_type",
|
|
161
|
+
up: (db) => {
|
|
162
|
+
const cols = db
|
|
163
|
+
.prepare("PRAGMA table_info(function_gc)")
|
|
164
|
+
.all();
|
|
165
|
+
if (!cols.some((c) => c.name === "analysis_type")) {
|
|
166
|
+
try {
|
|
167
|
+
db.exec("ALTER TABLE function_gc ADD COLUMN analysis_type TEXT");
|
|
168
|
+
}
|
|
169
|
+
catch (_) { }
|
|
170
|
+
// Rebuild PK by recreating table
|
|
171
|
+
db.exec(`
|
|
172
|
+
CREATE TABLE IF NOT EXISTS function_gc_v2 (
|
|
173
|
+
content_hash TEXT NOT NULL,
|
|
174
|
+
analysis_type TEXT,
|
|
175
|
+
gc_at INTEGER NOT NULL,
|
|
176
|
+
synced_at INTEGER,
|
|
177
|
+
PRIMARY KEY (content_hash, analysis_type)
|
|
178
|
+
)
|
|
179
|
+
`);
|
|
180
|
+
db.exec("INSERT OR IGNORE INTO function_gc_v2 SELECT content_hash, NULL, gc_at, synced_at FROM function_gc");
|
|
181
|
+
db.exec("DROP TABLE function_gc");
|
|
182
|
+
db.exec("ALTER TABLE function_gc_v2 RENAME TO function_gc");
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: "core_005_graph_tables",
|
|
188
|
+
up: (db) => {
|
|
189
|
+
db.exec(`
|
|
190
|
+
CREATE TABLE IF NOT EXISTS function_edges (
|
|
191
|
+
source_hash TEXT NOT NULL,
|
|
192
|
+
target_hash TEXT NOT NULL,
|
|
193
|
+
edge_type TEXT NOT NULL,
|
|
194
|
+
weight REAL NOT NULL DEFAULT 1.0,
|
|
195
|
+
PRIMARY KEY (source_hash, target_hash, edge_type)
|
|
196
|
+
)
|
|
197
|
+
`);
|
|
198
|
+
db.exec(`
|
|
199
|
+
CREATE TABLE IF NOT EXISTS communities (
|
|
200
|
+
content_hash TEXT NOT NULL,
|
|
201
|
+
level INTEGER NOT NULL,
|
|
202
|
+
community_id TEXT NOT NULL,
|
|
203
|
+
algorithm TEXT NOT NULL DEFAULT 'louvain',
|
|
204
|
+
PRIMARY KEY (content_hash, level, algorithm)
|
|
205
|
+
)
|
|
206
|
+
`);
|
|
207
|
+
db.exec(`
|
|
208
|
+
CREATE TABLE IF NOT EXISTS community_summaries (
|
|
209
|
+
community_id TEXT NOT NULL,
|
|
210
|
+
level INTEGER NOT NULL,
|
|
211
|
+
algorithm TEXT NOT NULL DEFAULT 'louvain',
|
|
212
|
+
input_hash TEXT NOT NULL,
|
|
213
|
+
summary JSON NOT NULL,
|
|
214
|
+
model_version TEXT,
|
|
215
|
+
created_at INTEGER NOT NULL,
|
|
216
|
+
PRIMARY KEY (community_id, level, algorithm)
|
|
217
|
+
)
|
|
218
|
+
`);
|
|
219
|
+
db.exec(`
|
|
220
|
+
CREATE TABLE IF NOT EXISTS graph_config (
|
|
221
|
+
key TEXT PRIMARY KEY,
|
|
222
|
+
value TEXT NOT NULL
|
|
223
|
+
)
|
|
224
|
+
`);
|
|
225
|
+
db.exec(`
|
|
226
|
+
CREATE TABLE IF NOT EXISTS community_edges (
|
|
227
|
+
source_community TEXT NOT NULL,
|
|
228
|
+
target_community TEXT NOT NULL,
|
|
229
|
+
algorithm TEXT NOT NULL DEFAULT 'louvain',
|
|
230
|
+
weight REAL NOT NULL DEFAULT 0,
|
|
231
|
+
edge_count INTEGER NOT NULL DEFAULT 0,
|
|
232
|
+
PRIMARY KEY (source_community, target_community, algorithm)
|
|
233
|
+
)
|
|
234
|
+
`);
|
|
235
|
+
db.exec(`
|
|
236
|
+
CREATE TABLE IF NOT EXISTS community_signatures (
|
|
237
|
+
community_id TEXT NOT NULL,
|
|
238
|
+
algorithm TEXT NOT NULL DEFAULT 'louvain',
|
|
239
|
+
signatures JSON NOT NULL,
|
|
240
|
+
PRIMARY KEY (community_id, algorithm)
|
|
241
|
+
)
|
|
242
|
+
`);
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
id: "core_006_practices_table",
|
|
247
|
+
up: (db) => {
|
|
248
|
+
db.exec(`
|
|
249
|
+
CREATE TABLE IF NOT EXISTS practices (
|
|
250
|
+
practice_id TEXT PRIMARY KEY,
|
|
251
|
+
rule TEXT NOT NULL,
|
|
252
|
+
severity TEXT NOT NULL DEFAULT 'warning'
|
|
253
|
+
)
|
|
254
|
+
`);
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
];
|
|
258
|
+
// ============ LEGACY MIGRATION HELPER ============
|
|
259
|
+
/**
|
|
260
|
+
* Migrate from single-blob function_analysis to split analysis types.
|
|
261
|
+
* Called from core_002_analysis_types migration on databases that predate
|
|
262
|
+
* the analysis_type column. Exported for testing.
|
|
263
|
+
*/
|
|
264
|
+
function migrateToAnalysisTypes(db) {
|
|
265
|
+
db.exec(`
|
|
266
|
+
CREATE TABLE function_analysis_v2 (
|
|
267
|
+
content_hash TEXT NOT NULL,
|
|
268
|
+
analysis_type TEXT NOT NULL,
|
|
269
|
+
analysis JSON NOT NULL,
|
|
270
|
+
model_version TEXT NOT NULL,
|
|
271
|
+
schema_version INTEGER NOT NULL DEFAULT 1,
|
|
272
|
+
created_at INTEGER NOT NULL,
|
|
273
|
+
last_seen_at INTEGER NOT NULL,
|
|
274
|
+
language TEXT NOT NULL DEFAULT 'typescript',
|
|
275
|
+
entity_type TEXT NOT NULL DEFAULT 'function',
|
|
276
|
+
synced_at INTEGER,
|
|
277
|
+
PRIMARY KEY (content_hash, analysis_type)
|
|
278
|
+
)
|
|
279
|
+
`);
|
|
280
|
+
// Split documentation fields
|
|
281
|
+
db.exec(`
|
|
282
|
+
INSERT OR IGNORE INTO function_analysis_v2
|
|
283
|
+
(content_hash, analysis_type, analysis, model_version, schema_version, created_at, last_seen_at, language, entity_type, synced_at)
|
|
284
|
+
SELECT
|
|
285
|
+
content_hash,
|
|
286
|
+
'documentation',
|
|
287
|
+
json_object(
|
|
288
|
+
'description', json_extract(analysis, '$.description'),
|
|
289
|
+
'params', json_extract(analysis, '$.params'),
|
|
290
|
+
'returns', json_extract(analysis, '$.returns')
|
|
291
|
+
),
|
|
292
|
+
model_version,
|
|
293
|
+
1,
|
|
294
|
+
created_at,
|
|
295
|
+
last_seen_at,
|
|
296
|
+
COALESCE(language, 'typescript'),
|
|
297
|
+
COALESCE(entity_type, 'function'),
|
|
298
|
+
NULL
|
|
299
|
+
FROM function_analysis
|
|
300
|
+
`);
|
|
301
|
+
// Split security fields
|
|
302
|
+
db.exec(`
|
|
303
|
+
INSERT OR IGNORE INTO function_analysis_v2
|
|
304
|
+
(content_hash, analysis_type, analysis, model_version, schema_version, created_at, last_seen_at, language, entity_type, synced_at)
|
|
305
|
+
SELECT
|
|
306
|
+
content_hash,
|
|
307
|
+
'security',
|
|
308
|
+
json_object(
|
|
309
|
+
'dataTags', json_extract(analysis, '$.dataTags'),
|
|
310
|
+
'securityFlags', json_extract(analysis, '$.securityFlags')
|
|
311
|
+
),
|
|
312
|
+
model_version,
|
|
313
|
+
1,
|
|
314
|
+
created_at,
|
|
315
|
+
last_seen_at,
|
|
316
|
+
COALESCE(language, 'typescript'),
|
|
317
|
+
COALESCE(entity_type, 'function'),
|
|
318
|
+
NULL
|
|
319
|
+
FROM function_analysis
|
|
320
|
+
`);
|
|
321
|
+
db.exec("DROP TABLE function_analysis");
|
|
322
|
+
db.exec("ALTER TABLE function_analysis_v2 RENAME TO function_analysis");
|
|
323
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type { LanguageModuleResolver } from "./types";
|
|
2
|
+
export { JavaScriptModuleResolver } from "./javascript";
|
|
3
|
+
import type { LanguageModuleResolver } from "./types";
|
|
4
|
+
export declare function registerModuleResolver(resolver: LanguageModuleResolver): void;
|
|
5
|
+
export declare function getModuleResolver(language: string): LanguageModuleResolver | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Find the module resolver that handles a given file path,
|
|
8
|
+
* matched by file extension against resolver.extensions.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getModuleResolverForFile(filePath: string): LanguageModuleResolver | undefined;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/module-resolvers/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAMtD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAE7E;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,GACf,sBAAsB,GAAG,SAAS,CAEpC;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,GACf,sBAAsB,GAAG,SAAS,CAMpC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.JavaScriptModuleResolver = void 0;
|
|
37
|
+
exports.registerModuleResolver = registerModuleResolver;
|
|
38
|
+
exports.getModuleResolver = getModuleResolver;
|
|
39
|
+
exports.getModuleResolverForFile = getModuleResolverForFile;
|
|
40
|
+
var javascript_1 = require("./javascript");
|
|
41
|
+
Object.defineProperty(exports, "JavaScriptModuleResolver", { enumerable: true, get: function () { return javascript_1.JavaScriptModuleResolver; } });
|
|
42
|
+
const javascript_2 = require("./javascript");
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const registry = new Map();
|
|
45
|
+
function registerModuleResolver(resolver) {
|
|
46
|
+
registry.set(resolver.language, resolver);
|
|
47
|
+
}
|
|
48
|
+
function getModuleResolver(language) {
|
|
49
|
+
return registry.get(language);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Find the module resolver that handles a given file path,
|
|
53
|
+
* matched by file extension against resolver.extensions.
|
|
54
|
+
*/
|
|
55
|
+
function getModuleResolverForFile(filePath) {
|
|
56
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
57
|
+
for (const resolver of registry.values()) {
|
|
58
|
+
if (resolver.extensions.includes(ext))
|
|
59
|
+
return resolver;
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
// Register built-in resolvers
|
|
64
|
+
const jsResolver = new javascript_2.JavaScriptModuleResolver();
|
|
65
|
+
registerModuleResolver(jsResolver);
|
|
66
|
+
// Also register under "javascript" alias
|
|
67
|
+
registry.set("javascript", jsResolver);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LanguageModuleResolver } from "./types";
|
|
2
|
+
import type { ModuleResolver } from "../graph";
|
|
3
|
+
/**
|
|
4
|
+
* Module resolution for JavaScript/TypeScript ecosystems.
|
|
5
|
+
* Handles relative imports, workspace packages (via package.json exports),
|
|
6
|
+
* and path aliases (via tsconfig.json paths).
|
|
7
|
+
*/
|
|
8
|
+
export declare class JavaScriptModuleResolver implements LanguageModuleResolver {
|
|
9
|
+
readonly language = "typescript";
|
|
10
|
+
readonly extensions: readonly [".ts", ".tsx", ".js", ".jsx"];
|
|
11
|
+
/**
|
|
12
|
+
* Try resolving a base path to an actual file, probing JS/TS extensions
|
|
13
|
+
* and index file patterns.
|
|
14
|
+
*/
|
|
15
|
+
private tryResolveWithExtensions;
|
|
16
|
+
resolveModuleToFile(importModule: string, importerFilePath: string, fileToHashes: Map<string, Set<string>>, resolver?: ModuleResolver): string | undefined;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=javascript.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"javascript.d.ts","sourceRoot":"","sources":["../../src/module-resolvers/javascript.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C;;;;GAIG;AACH,qBAAa,wBAAyB,YAAW,sBAAsB;IACrE,QAAQ,CAAC,QAAQ,gBAAgB;IACjC,QAAQ,CAAC,UAAU,0CAA2C;IAE9D;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAoBhC,mBAAmB,CACjB,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,EACtC,QAAQ,CAAC,EAAE,cAAc,GACxB,MAAM,GAAG,SAAS;CAoEtB"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.JavaScriptModuleResolver = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
/**
|
|
39
|
+
* Module resolution for JavaScript/TypeScript ecosystems.
|
|
40
|
+
* Handles relative imports, workspace packages (via package.json exports),
|
|
41
|
+
* and path aliases (via tsconfig.json paths).
|
|
42
|
+
*/
|
|
43
|
+
class JavaScriptModuleResolver {
|
|
44
|
+
constructor() {
|
|
45
|
+
this.language = "typescript";
|
|
46
|
+
this.extensions = [".ts", ".tsx", ".js", ".jsx"];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Try resolving a base path to an actual file, probing JS/TS extensions
|
|
50
|
+
* and index file patterns.
|
|
51
|
+
*/
|
|
52
|
+
tryResolveWithExtensions(resolvedBase, fileToHashes) {
|
|
53
|
+
for (const candidate of [
|
|
54
|
+
resolvedBase,
|
|
55
|
+
resolvedBase + ".ts",
|
|
56
|
+
resolvedBase + ".tsx",
|
|
57
|
+
resolvedBase + ".js",
|
|
58
|
+
resolvedBase + ".jsx",
|
|
59
|
+
resolvedBase + ".py",
|
|
60
|
+
]) {
|
|
61
|
+
if (fileToHashes.has(candidate))
|
|
62
|
+
return candidate;
|
|
63
|
+
}
|
|
64
|
+
for (const idx of ["/index.ts", "/index.tsx", "/index.js", "/index.jsx"]) {
|
|
65
|
+
if (fileToHashes.has(resolvedBase + idx))
|
|
66
|
+
return resolvedBase + idx;
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
resolveModuleToFile(importModule, importerFilePath, fileToHashes, resolver) {
|
|
71
|
+
// Case 1: Relative imports
|
|
72
|
+
if (importModule.startsWith("./") || importModule.startsWith("../")) {
|
|
73
|
+
const resolvedBase = path.resolve(path.dirname(importerFilePath), importModule);
|
|
74
|
+
return this.tryResolveWithExtensions(resolvedBase, fileToHashes);
|
|
75
|
+
}
|
|
76
|
+
if (!resolver)
|
|
77
|
+
return undefined;
|
|
78
|
+
// Case 2: Workspace package imports (e.g. "@ophan/core/schemas")
|
|
79
|
+
for (const [pkgName, pkg] of resolver.workspacePackages) {
|
|
80
|
+
if (importModule === pkgName || importModule.startsWith(pkgName + "/")) {
|
|
81
|
+
const subpath = importModule === pkgName
|
|
82
|
+
? "."
|
|
83
|
+
: "./" + importModule.slice(pkgName.length + 1);
|
|
84
|
+
// Look up in exports map
|
|
85
|
+
const exportTarget = pkg.exports[subpath];
|
|
86
|
+
if (exportTarget) {
|
|
87
|
+
const resolved = path.resolve(pkg.dir, exportTarget);
|
|
88
|
+
return this.tryResolveWithExtensions(resolved, fileToHashes);
|
|
89
|
+
}
|
|
90
|
+
// Fallback: conventional src/ resolution
|
|
91
|
+
if (subpath === ".") {
|
|
92
|
+
return this.tryResolveWithExtensions(path.resolve(pkg.dir, "src/index"), fileToHashes);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const srcFile = path.resolve(pkg.dir, "src", subpath.slice(2));
|
|
96
|
+
return this.tryResolveWithExtensions(srcFile, fileToHashes);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Case 3: Path alias imports (e.g. "@/components/ui/button")
|
|
101
|
+
for (const [pkgDir, aliases] of resolver.pathAliases) {
|
|
102
|
+
if (!importerFilePath.startsWith(pkgDir + "/"))
|
|
103
|
+
continue;
|
|
104
|
+
for (const [aliasPattern, targets] of Object.entries(aliases.paths)) {
|
|
105
|
+
const hasStar = aliasPattern.endsWith("/*");
|
|
106
|
+
const prefix = hasStar ? aliasPattern.slice(0, -1) : aliasPattern;
|
|
107
|
+
if (hasStar && importModule.startsWith(prefix)) {
|
|
108
|
+
const remainder = importModule.slice(prefix.length);
|
|
109
|
+
for (const targetPattern of targets) {
|
|
110
|
+
const targetBase = targetPattern.replace("/*", "/" + remainder);
|
|
111
|
+
const resolved = path.resolve(aliases.baseUrl, targetBase);
|
|
112
|
+
const result = this.tryResolveWithExtensions(resolved, fileToHashes);
|
|
113
|
+
if (result)
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (!hasStar && importModule === aliasPattern) {
|
|
118
|
+
for (const targetPattern of targets) {
|
|
119
|
+
const resolved = path.resolve(aliases.baseUrl, targetPattern);
|
|
120
|
+
const result = this.tryResolveWithExtensions(resolved, fileToHashes);
|
|
121
|
+
if (result)
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.JavaScriptModuleResolver = JavaScriptModuleResolver;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ModuleResolver } from "../graph";
|
|
2
|
+
/**
|
|
3
|
+
* Strategy interface for language-specific module resolution.
|
|
4
|
+
* Each implementation handles import specifier → file path resolution
|
|
5
|
+
* for one language ecosystem (JS/TS, Python, Go, etc.).
|
|
6
|
+
*/
|
|
7
|
+
export interface LanguageModuleResolver {
|
|
8
|
+
/** Language identifier (e.g., "typescript", "python") */
|
|
9
|
+
readonly language: string;
|
|
10
|
+
/** File extensions this resolver handles (e.g., [".ts", ".tsx", ".js", ".jsx"]) */
|
|
11
|
+
readonly extensions: readonly string[];
|
|
12
|
+
/**
|
|
13
|
+
* Resolve an import module specifier to an absolute file path.
|
|
14
|
+
* Returns undefined if the specifier can't be resolved.
|
|
15
|
+
*/
|
|
16
|
+
resolveModuleToFile(importModule: string, importerFilePath: string, fileToHashes: Map<string, Set<string>>, workspaceResolver?: ModuleResolver): string | undefined;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/module-resolvers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mFAAmF;IACnF,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC;;;OAGG;IACH,mBAAmB,CACjB,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,EACtC,iBAAiB,CAAC,EAAE,cAAc,GACjC,MAAM,GAAG,SAAS,CAAC;CACvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../src/parsers/python.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../src/parsers/python.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAiG9C,qBAAa,YAAa,YAAW,cAAc;IACjD,QAAQ,CAAC,QAAQ,YAAY;IAC7B,QAAQ,CAAC,UAAU,WAAW;IAE9B,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE;CAsCnD"}
|