@saptools/service-flow 0.1.0 → 0.1.2
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/CHANGELOG.md +9 -0
- package/README.md +343 -31
- package/dist/{chunk-RFBHT6BQ.js → chunk-6U4QKQEL.js} +202 -146
- package/dist/chunk-6U4QKQEL.js.map +1 -0
- package/dist/cli.js +61 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-RFBHT6BQ.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
parsePackageJson,
|
|
11
11
|
parseServiceBindings,
|
|
12
12
|
trace
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-6U4QKQEL.js";
|
|
14
14
|
|
|
15
15
|
// src/cli.ts
|
|
16
16
|
import { Command } from "commander";
|
|
@@ -124,8 +124,31 @@ function bind(sql, params) {
|
|
|
124
124
|
let index = 0;
|
|
125
125
|
return sql.replaceAll("?", () => quote(params[index++]));
|
|
126
126
|
}
|
|
127
|
-
function
|
|
128
|
-
return
|
|
127
|
+
function isBusy(error) {
|
|
128
|
+
return error instanceof Error && /SQLITE_BUSY|database is locked|database is busy/i.test(error.message);
|
|
129
|
+
}
|
|
130
|
+
function sleep(ms) {
|
|
131
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
132
|
+
}
|
|
133
|
+
function call(dbPath, args, attempt = 0) {
|
|
134
|
+
try {
|
|
135
|
+
return execFileSync("sqlite3", [dbPath, ...args], {
|
|
136
|
+
encoding: "utf8",
|
|
137
|
+
maxBuffer: 128 * 1024 * 1024,
|
|
138
|
+
env: { ...process.env, SQLITE_BUSY_TIMEOUT: "10000" }
|
|
139
|
+
});
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (isBusy(error) && attempt < 5) {
|
|
142
|
+
sleep(50 * 2 ** attempt);
|
|
143
|
+
return call(dbPath, args, attempt + 1);
|
|
144
|
+
}
|
|
145
|
+
if (isBusy(error))
|
|
146
|
+
throw new Error(
|
|
147
|
+
"SQLite database is busy or locked. Another service-flow writer may be active; retry after it finishes.",
|
|
148
|
+
{ cause: error }
|
|
149
|
+
);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
129
152
|
}
|
|
130
153
|
function jsonRows(dbPath, sql) {
|
|
131
154
|
const out = call(dbPath, ["-json", sql]);
|
|
@@ -155,6 +178,7 @@ function openDatabase(dbPath) {
|
|
|
155
178
|
close() {
|
|
156
179
|
}
|
|
157
180
|
};
|
|
181
|
+
db.pragma("busy_timeout = 10000");
|
|
158
182
|
db.pragma("journal_mode = WAL");
|
|
159
183
|
db.pragma("foreign_keys = ON");
|
|
160
184
|
migrate(db);
|
|
@@ -213,6 +237,7 @@ function clearRepoFacts(db, repoId) {
|
|
|
213
237
|
"files"
|
|
214
238
|
])
|
|
215
239
|
db.prepare(`DELETE FROM ${t} WHERE repo_id=?`).run(repoId);
|
|
240
|
+
db.prepare("DELETE FROM search_index WHERE repo=?").run(String(repoId));
|
|
216
241
|
}
|
|
217
242
|
function insertRequires(db, repoId, rows) {
|
|
218
243
|
const stmt = db.prepare(
|
|
@@ -248,6 +273,12 @@ function insertService(db, repoId, s) {
|
|
|
248
273
|
const stmt = db.prepare(
|
|
249
274
|
"INSERT INTO cds_operations(service_id,operation_type,operation_name,operation_path,params_json,return_type,source_file,source_line) VALUES(?,?,?,?,?,?,?,?)"
|
|
250
275
|
);
|
|
276
|
+
db.prepare("INSERT INTO search_index(kind,name,path,repo) VALUES(?,?,?,?)").run(
|
|
277
|
+
"service",
|
|
278
|
+
s.qualifiedName,
|
|
279
|
+
s.servicePath,
|
|
280
|
+
String(repoId)
|
|
281
|
+
);
|
|
251
282
|
for (const o of s.operations)
|
|
252
283
|
stmt.run(
|
|
253
284
|
id,
|
|
@@ -259,6 +290,11 @@ function insertService(db, repoId, s) {
|
|
|
259
290
|
o.sourceFile,
|
|
260
291
|
o.sourceLine
|
|
261
292
|
);
|
|
293
|
+
const search = db.prepare(
|
|
294
|
+
"INSERT INTO search_index(kind,name,path,repo) VALUES(?,?,?,?)"
|
|
295
|
+
);
|
|
296
|
+
for (const o of s.operations)
|
|
297
|
+
search.run("operation", o.operationName, o.operationPath, String(repoId));
|
|
262
298
|
return id;
|
|
263
299
|
}
|
|
264
300
|
function insertHandler(db, repoId, h) {
|
|
@@ -328,7 +364,7 @@ function insertBindings(db, repoId, rows) {
|
|
|
328
364
|
}
|
|
329
365
|
function insertCalls(db, repoId, rows) {
|
|
330
366
|
const stmt = db.prepare(
|
|
331
|
-
"INSERT INTO outbound_calls(repo_id,call_type,method,operation_path_expr,query_entity,event_name_expr,payload_summary,source_file,source_line,confidence,unresolved_reason,service_binding_id) VALUES(?,?,?,?,?,?,?,?,?,?,?,(SELECT id FROM service_bindings WHERE repo_id=? AND variable_name=? ORDER BY id DESC LIMIT 1))"
|
|
367
|
+
"INSERT INTO outbound_calls(repo_id,call_type,method,operation_path_expr,query_entity,event_name_expr,payload_summary,source_file,source_line,confidence,unresolved_reason,service_binding_id) VALUES(?,?,?,?,?,?,?,?,?,?,?,(SELECT id FROM service_bindings WHERE repo_id=? AND variable_name=? AND source_file=? ORDER BY CASE WHEN source_line<=? THEN 0 ELSE 1 END, ABS(source_line-?) ASC, id DESC LIMIT 1))"
|
|
332
368
|
);
|
|
333
369
|
for (const r of rows)
|
|
334
370
|
stmt.run(
|
|
@@ -344,7 +380,10 @@ function insertCalls(db, repoId, rows) {
|
|
|
344
380
|
r.confidence,
|
|
345
381
|
r.unresolvedReason,
|
|
346
382
|
repoId,
|
|
347
|
-
r.serviceVariableName
|
|
383
|
+
r.serviceVariableName,
|
|
384
|
+
r.sourceFile,
|
|
385
|
+
r.sourceLine,
|
|
386
|
+
r.sourceLine
|
|
348
387
|
);
|
|
349
388
|
}
|
|
350
389
|
|
|
@@ -631,11 +670,11 @@ function createProgram() {
|
|
|
631
670
|
const program = new Command();
|
|
632
671
|
program.name("service-flow").description(
|
|
633
672
|
"Trace SAP CAP service-to-service flows across multi-repository workspaces"
|
|
634
|
-
).version("0.1.
|
|
673
|
+
).version("0.1.2");
|
|
635
674
|
program.command("init").argument("<workspace>").option("--db <path>").option("--ignore <pattern...>").action(
|
|
636
675
|
(workspace, opts) => void init(workspace, opts).catch(fail)
|
|
637
676
|
);
|
|
638
|
-
program.command("index").option("--workspace <path>").option("--repo <name>").option("--force").
|
|
677
|
+
program.command("index").option("--workspace <path>").option("--repo <name>").option("--force").action(
|
|
639
678
|
(opts) => void withWorkspace(opts.workspace, async (db, workspaceId) => {
|
|
640
679
|
const r = await indexWorkspace(db, workspaceId, {
|
|
641
680
|
repo: opts.repo,
|
|
@@ -717,8 +756,8 @@ function createProgram() {
|
|
|
717
756
|
(opts) => void withWorkspace(opts.workspace, (db) => {
|
|
718
757
|
const repo = opts.repo ? repoByName(db, opts.repo) : void 0;
|
|
719
758
|
const rows = db.prepare(
|
|
720
|
-
"SELECT r.name repo,c.call_type type,c.operation_path_expr path,c.source_file file,c.source_line line FROM outbound_calls c JOIN repositories r ON r.id=c.repo_id WHERE (? IS NULL OR c.repo_id=?)"
|
|
721
|
-
).all(repo?.id, repo?.id);
|
|
759
|
+
"SELECT r.name repo,c.call_type type,c.operation_path_expr path,c.source_file file,c.source_line line FROM outbound_calls c JOIN repositories r ON r.id=c.repo_id WHERE (? IS NULL OR c.repo_id=?) AND (? IS NULL OR c.operation_path_expr=? OR c.operation_path_expr=? OR c.payload_summary LIKE ?)"
|
|
760
|
+
).all(repo?.id, repo?.id, opts.operation, opts.operation, opts.operation ? `/${opts.operation}` : void 0, opts.operation ? `%${opts.operation}%` : void 0);
|
|
722
761
|
process.stdout.write(renderJson(rows));
|
|
723
762
|
}).catch(fail)
|
|
724
763
|
);
|
|
@@ -766,8 +805,20 @@ function createProgram() {
|
|
|
766
805
|
const diagnostics = db.prepare(
|
|
767
806
|
"SELECT severity,code,message,source_file sourceFile,source_line sourceLine FROM diagnostics ORDER BY id"
|
|
768
807
|
).all();
|
|
808
|
+
const health = db.prepare(
|
|
809
|
+
`SELECT 'warning' severity,'service_without_operations' code,'CDS service has no indexed operations' message,s.source_file sourceFile,s.source_line sourceLine
|
|
810
|
+
FROM cds_services s LEFT JOIN cds_operations o ON o.service_id=s.id WHERE o.id IS NULL
|
|
811
|
+
UNION ALL
|
|
812
|
+
SELECT 'warning','handler_without_service','Repository has handlers but no CDS services',hc.source_file,hc.source_line
|
|
813
|
+
FROM handler_classes hc JOIN repositories r ON r.id=hc.repo_id
|
|
814
|
+
WHERE r.kind IN ('cap-service','mixed') AND NOT EXISTS (SELECT 1 FROM cds_services s WHERE s.repo_id=hc.repo_id)
|
|
815
|
+
UNION ALL
|
|
816
|
+
SELECT 'warning','search_index_empty','Search index is empty after indexing',NULL,NULL
|
|
817
|
+
WHERE NOT EXISTS (SELECT 1 FROM search_index)`
|
|
818
|
+
).all();
|
|
819
|
+
const allDiagnostics = [...diagnostics, ...health];
|
|
769
820
|
process.stdout.write(
|
|
770
|
-
|
|
821
|
+
allDiagnostics.length ? renderJson(allDiagnostics) : `${pc.green("No diagnostics recorded")}
|
|
771
822
|
`
|
|
772
823
|
);
|
|
773
824
|
}).catch(fail)
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/config/defaults.ts","../src/config/workspace-config.ts","../src/db/connection.ts","../src/db/schema.ts","../src/db/migrations.ts","../src/db/repositories.ts","../src/discovery/classify-repository.ts","../src/indexer/repository-indexer.ts","../src/indexer/incremental-index.ts","../src/utils/hashing.ts","../src/utils/diagnostics.ts","../src/indexer/workspace-indexer.ts","../src/trace/selectors.ts","../src/output/table-output.ts","../src/output/json-output.ts","../src/output/mermaid-output.ts"],"sourcesContent":["import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'node:fs/promises';\nimport pc from 'picocolors';\nimport { DEFAULT_IGNORES } from './config/defaults.js';\nimport {\n createWorkspaceConfig,\n loadWorkspaceConfig,\n saveWorkspaceConfig\n} from './config/workspace-config.js';\nimport { openDatabase } from './db/connection.js';\nimport {\n getWorkspace,\n listRepositories,\n repoByName,\n upsertRepository,\n upsertWorkspace\n} from './db/repositories.js';\nimport { discoverRepositories } from './discovery/discover-repositories.js';\nimport { parsePackageJson } from './parsers/package-json-parser.js';\nimport { classifyRepository } from './discovery/classify-repository.js';\nimport { indexWorkspace } from './indexer/workspace-indexer.js';\nimport { linkWorkspace } from './linker/cross-repo-linker.js';\nimport { trace } from './trace/trace-engine.js';\nimport { parseVars } from './trace/selectors.js';\nimport { renderTraceTable } from './output/table-output.js';\nimport { renderTraceJson, renderJson } from './output/json-output.js';\nimport { renderMermaid } from './output/mermaid-output.js';\nasync function init(\n workspace: string,\n options: { db?: string; ignore?: string[] }\n): Promise<void> {\n const config = createWorkspaceConfig(\n workspace,\n options.db,\n options.ignore?.length ? options.ignore : [...DEFAULT_IGNORES]\n );\n const repos = await discoverRepositories(config.rootPath, config.ignore);\n await saveWorkspaceConfig(config);\n const db = openDatabase(config.dbPath);\n const workspaceId = upsertWorkspace(db, config.rootPath, config.dbPath);\n for (const repo of repos) {\n const pkg = await parsePackageJson(repo.absolutePath);\n const kind = await classifyRepository(repo.absolutePath, pkg);\n upsertRepository(db, workspaceId, {\n ...repo,\n packageName: pkg.packageName,\n packageVersion: pkg.packageVersion,\n dependencies: pkg.dependencies,\n kind\n });\n }\n db.close();\n process.stdout.write(\n `Workspace: ${config.rootPath}\\nDatabase: ${config.dbPath}\\nRepositories: ${repos.length}\\nIgnored: ${config.ignore.join(', ')}\\nNext: service-flow index --workspace ${config.rootPath}\\n`\n );\n}\nasync function withWorkspace<T>(\n workspace: string | undefined,\n fn: (\n db: ReturnType<typeof openDatabase>,\n workspaceId: number,\n rootPath: string\n ) => Promise<T> | T\n): Promise<T> {\n const config = await loadWorkspaceConfig(workspace);\n const db = openDatabase(config.dbPath);\n try {\n const row = getWorkspace(db, config.rootPath);\n const workspaceId =\n row?.id ?? upsertWorkspace(db, config.rootPath, config.dbPath);\n return await fn(db, workspaceId, config.rootPath);\n } finally {\n db.close();\n }\n}\nexport function createProgram(): Command {\n const program = new Command();\n program\n .name('service-flow')\n .description(\n 'Trace SAP CAP service-to-service flows across multi-repository workspaces'\n )\n .version('0.1.0');\n program\n .command('init')\n .argument('<workspace>')\n .option('--db <path>')\n .option('--ignore <pattern...>')\n .action(\n (workspace: string, opts: { db?: string; ignore?: string[] }) =>\n void init(workspace, opts).catch(fail)\n );\n program\n .command('index')\n .option('--workspace <path>')\n .option('--repo <name>')\n .option('--force')\n .option('--concurrency <n>', 'reserved for future parallel indexing', '1')\n .action(\n (opts: { workspace?: string; repo?: string; force?: boolean }) =>\n void withWorkspace(opts.workspace, async (db, workspaceId) => {\n const r = await indexWorkspace(db, workspaceId, {\n repo: opts.repo,\n force: Boolean(opts.force)\n });\n process.stdout.write(\n `Indexed ${r.repoCount} repositories, ${r.fileCount} files, ${r.diagnosticCount} diagnostics\\n`\n );\n }).catch(fail)\n );\n program\n .command('link')\n .option('--workspace <path>')\n .option('--force')\n .action(\n (opts: { workspace?: string }) =>\n void withWorkspace(opts.workspace, (db, workspaceId) => {\n const r = linkWorkspace(db, workspaceId);\n process.stdout.write(\n `Linked ${r.edgeCount} edges, ${r.unresolvedCount} unresolved\\n`\n );\n }).catch(fail)\n );\n program\n .command('trace')\n .option('--workspace <path>')\n .option('--repo <name>')\n .option('--operation <name>')\n .option('--service <path>')\n .option('--path <operationPath>')\n .option('--handler <name>')\n .option('--depth <n>', 'trace depth', '25')\n .option('--format <format>', 'table|json|mermaid', 'table')\n .option('--include-external')\n .option('--include-db')\n .option('--include-async')\n .option('--var <key=value>', 'dynamic variable', collect, [])\n .action(\n (opts: {\n workspace?: string;\n repo?: string;\n operation?: string;\n service?: string;\n path?: string;\n handler?: string;\n depth: string;\n format: string;\n includeExternal?: boolean;\n includeDb?: boolean;\n includeAsync?: boolean;\n var: string[];\n }) =>\n void withWorkspace(opts.workspace, (db) => {\n const result = trace(\n db,\n {\n repo: opts.repo,\n servicePath: opts.service,\n operation: opts.operation,\n operationPath: opts.path,\n handler: opts.handler\n },\n {\n depth: Number(opts.depth),\n vars: parseVars(opts.var),\n includeExternal: Boolean(opts.includeExternal),\n includeDb: Boolean(opts.includeDb),\n includeAsync: Boolean(opts.includeAsync)\n }\n );\n process.stdout.write(\n opts.format === 'json'\n ? renderTraceJson(result)\n : opts.format === 'mermaid'\n ? renderMermaid(result)\n : renderTraceTable(result)\n );\n }).catch(fail)\n );\n const list = program.command('list');\n list\n .command('repos')\n .option('--workspace <path>')\n .action(\n (opts: { workspace?: string }) =>\n void withWorkspace(opts.workspace, (db) =>\n process.stdout.write(\n renderJson(\n listRepositories(db).map((r) => ({\n name: r.name,\n kind: r.kind,\n packageName: r.package_name\n }))\n )\n )\n ).catch(fail)\n );\n list\n .command('services')\n .option('--workspace <path>')\n .option('--repo <name>')\n .action(\n (opts: { workspace?: string; repo?: string }) =>\n void withWorkspace(opts.workspace, (db) => {\n const repo = opts.repo ? repoByName(db, opts.repo) : undefined;\n const rows = db\n .prepare(\n 'SELECT r.name repo,s.service_path servicePath,s.qualified_name qualifiedName FROM cds_services s JOIN repositories r ON r.id=s.repo_id WHERE (? IS NULL OR s.repo_id=?) ORDER BY r.name,s.service_path'\n )\n .all(repo?.id, repo?.id);\n process.stdout.write(renderJson(rows));\n }).catch(fail)\n );\n list\n .command('operations')\n .option('--workspace <path>')\n .option('--repo <name>')\n .option('--service <path>')\n .action(\n (opts: { workspace?: string; repo?: string; service?: string }) =>\n void withWorkspace(opts.workspace, (db) => {\n const repo = opts.repo ? repoByName(db, opts.repo) : undefined;\n const rows = db\n .prepare(\n 'SELECT r.name repo,s.service_path servicePath,o.operation_name operation,o.operation_path path FROM cds_operations o JOIN cds_services s ON s.id=o.service_id JOIN repositories r ON r.id=s.repo_id WHERE (? IS NULL OR s.repo_id=?) AND (? IS NULL OR s.service_path=?)'\n )\n .all(repo?.id, repo?.id, opts.service, opts.service);\n process.stdout.write(renderJson(rows));\n }).catch(fail)\n );\n list\n .command('calls')\n .option('--workspace <path>')\n .option('--repo <name>')\n .option('--operation <name>')\n .action(\n (opts: { workspace?: string; repo?: string }) =>\n void withWorkspace(opts.workspace, (db) => {\n const repo = opts.repo ? repoByName(db, opts.repo) : undefined;\n const rows = db\n .prepare(\n 'SELECT r.name repo,c.call_type type,c.operation_path_expr path,c.source_file file,c.source_line line FROM outbound_calls c JOIN repositories r ON r.id=c.repo_id WHERE (? IS NULL OR c.repo_id=?)'\n )\n .all(repo?.id, repo?.id);\n process.stdout.write(renderJson(rows));\n }).catch(fail)\n );\n program\n .command('graph')\n .option('--workspace <path>')\n .option('--repo <name>')\n .option('--operation <name>')\n .option('--service <path>')\n .option('--path <operationPath>')\n .option('--format <format>', 'mermaid|json', 'mermaid')\n .action(\n (opts: {\n workspace?: string;\n repo?: string;\n operation?: string;\n service?: string;\n path?: string;\n format: string;\n }) =>\n void withWorkspace(opts.workspace, (db) => {\n const result = trace(\n db,\n {\n repo: opts.repo,\n operation: opts.operation,\n servicePath: opts.service,\n operationPath: opts.path\n },\n {\n depth: 100,\n includeAsync: true,\n includeDb: true,\n includeExternal: true\n }\n );\n process.stdout.write(\n opts.format === 'json'\n ? renderTraceJson(result)\n : renderMermaid(result)\n );\n }).catch(fail)\n );\n const inspect = program.command('inspect');\n inspect\n .command('repo')\n .argument('<name>')\n .option('--workspace <path>')\n .action(\n (name: string, opts: { workspace?: string }) =>\n void withWorkspace(opts.workspace, (db) =>\n process.stdout.write(\n renderJson(repoByName(db, name) ?? { error: 'repo not found' })\n )\n ).catch(fail)\n );\n inspect\n .command('operation')\n .argument('<selector>')\n .option('--workspace <path>')\n .action(\n (selector: string, opts: { workspace?: string }) =>\n void withWorkspace(opts.workspace, (db) => {\n const rows = db\n .prepare(\n 'SELECT * FROM cds_operations WHERE operation_name=? OR operation_path=?'\n )\n .all(selector, selector);\n process.stdout.write(renderJson(rows));\n }).catch(fail)\n );\n program\n .command('doctor')\n .option('--workspace <path>')\n .action(\n (opts: { workspace?: string }) =>\n void withWorkspace(opts.workspace, (db) => {\n const diagnostics = db\n .prepare(\n 'SELECT severity,code,message,source_file sourceFile,source_line sourceLine FROM diagnostics ORDER BY id'\n )\n .all();\n process.stdout.write(\n diagnostics.length\n ? renderJson(diagnostics)\n : `${pc.green('No diagnostics recorded')}\\n`\n );\n }).catch(fail)\n );\n program\n .command('clean')\n .option('--workspace <path>')\n .option('--db-only')\n .action(\n (opts: { workspace?: string; dbOnly?: boolean }) =>\n void (async () => {\n const config = await loadWorkspaceConfig(opts.workspace);\n await fs.rm(config.dbPath, { force: true });\n if (!opts.dbOnly)\n await fs.rm(path.dirname(config.dbPath), {\n recursive: true,\n force: true\n });\n process.stdout.write('Cleaned service-flow state\\n');\n })().catch(fail)\n );\n return program;\n}\nfunction collect(value: string, previous: string[]): string[] {\n previous.push(value);\n return previous;\n}\nfunction fail(error: unknown): void {\n process.stderr.write(\n `${error instanceof Error ? error.message : String(error)}\\n`\n );\n process.exitCode = 1;\n}\ncreateProgram().parse(process.argv);\n","export const DEFAULT_IGNORES = [\n 'node_modules',\n 'gen',\n 'dist',\n 'coverage',\n '.git',\n '.turbo',\n '.next',\n '.cache',\n '.service-flow'\n] as const;\nexport const CONFIG_DIR = '.service-flow';\nexport const CONFIG_FILE = 'config.json';\nexport const DEFAULT_DB_FILE = 'service-flow.db';\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport {\n CONFIG_DIR,\n CONFIG_FILE,\n DEFAULT_DB_FILE,\n DEFAULT_IGNORES\n} from './defaults.js';\nconst schema = z.object({\n rootPath: z.string(),\n dbPath: z.string(),\n ignore: z.array(z.string()),\n createdAt: z.string(),\n updatedAt: z.string()\n});\nexport type WorkspaceConfig = z.infer<typeof schema>;\nexport function configPath(rootPath: string): string {\n return path.join(rootPath, CONFIG_DIR, CONFIG_FILE);\n}\nexport function defaultDbPath(rootPath: string): string {\n return path.join(rootPath, CONFIG_DIR, DEFAULT_DB_FILE);\n}\nexport async function saveWorkspaceConfig(\n config: WorkspaceConfig\n): Promise<void> {\n await fs.mkdir(path.dirname(configPath(config.rootPath)), {\n recursive: true\n });\n await fs.writeFile(\n configPath(config.rootPath),\n `${JSON.stringify(config, null, 2)}\\n`\n );\n}\nexport async function loadWorkspaceConfig(\n workspace?: string\n): Promise<WorkspaceConfig> {\n const root = path.resolve(workspace ?? process.cwd());\n const data = await fs.readFile(configPath(root), 'utf8');\n return schema.parse(JSON.parse(data) as unknown);\n}\nexport function createWorkspaceConfig(\n rootPath: string,\n dbPath?: string,\n ignore: string[] = [...DEFAULT_IGNORES]\n): WorkspaceConfig {\n const now = new Date().toISOString();\n const root = path.resolve(rootPath);\n return {\n rootPath: root,\n dbPath: path.resolve(dbPath ?? defaultDbPath(root)),\n ignore,\n createdAt: now,\n updatedAt: now\n };\n}\n","import { execFileSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { migrate } from './migrations.js';\nexport interface Statement {\n run: (...params: unknown[]) => { changes: number };\n get: (...params: unknown[]) => Record<string, unknown> | undefined;\n all: (...params: unknown[]) => Array<Record<string, unknown>>;\n}\nexport interface Db {\n path: string;\n exec: (sql: string) => void;\n prepare: (sql: string) => Statement;\n pragma: (sql: string) => void;\n close: () => void;\n}\nfunction quote(value: unknown): string {\n if (value === null || value === undefined) return 'NULL';\n if (typeof value === 'number')\n return Number.isFinite(value) ? String(value) : 'NULL';\n if (typeof value === 'boolean') return value ? '1' : '0';\n return `'${String(value).replaceAll(\"'\", \"''\")}'`;\n}\nfunction bind(sql: string, params: unknown[]): string {\n let index = 0;\n return sql.replaceAll('?', () => quote(params[index++]));\n}\nfunction call(dbPath: string, args: string[]): string {\n return execFileSync('sqlite3', [dbPath, ...args], { encoding: 'utf8' });\n}\nfunction jsonRows(dbPath: string, sql: string): Array<Record<string, unknown>> {\n const out = call(dbPath, ['-json', sql]);\n if (!out.trim()) return [];\n return JSON.parse(out) as Array<Record<string, unknown>>;\n}\nexport function openDatabase(dbPath: string): Db {\n fs.mkdirSync(path.dirname(dbPath), { recursive: true });\n const db: Db = {\n path: dbPath,\n exec(sql: string): void {\n call(dbPath, [sql]);\n },\n prepare(sql: string): Statement {\n return {\n run: (...params: unknown[]) => {\n call(dbPath, [bind(sql, params)]);\n return { changes: 0 };\n },\n get: (...params: unknown[]) => jsonRows(dbPath, bind(sql, params))[0],\n all: (...params: unknown[]) => jsonRows(dbPath, bind(sql, params))\n };\n },\n pragma(sql: string): void {\n call(dbPath, [`PRAGMA ${sql}`]);\n },\n close(): void {\n /* sqlite3 CLI opens per statement */\n }\n };\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n migrate(db);\n return db;\n}\n","export const schemaSql = `\nCREATE TABLE IF NOT EXISTS workspaces (id INTEGER PRIMARY KEY, root_path TEXT UNIQUE NOT NULL, db_path TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL);\nCREATE TABLE IF NOT EXISTS repositories (id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, name TEXT NOT NULL, absolute_path TEXT NOT NULL, relative_path TEXT NOT NULL, package_name TEXT, package_version TEXT, dependencies_json TEXT DEFAULT '{}', kind TEXT NOT NULL, is_git_repo INTEGER NOT NULL, last_indexed_at TEXT, index_status TEXT DEFAULT 'pending', error_count INTEGER DEFAULT 0, UNIQUE(workspace_id, absolute_path));\nCREATE TABLE IF NOT EXISTS files (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, relative_path TEXT NOT NULL, extension TEXT NOT NULL, sha256 TEXT NOT NULL, size_bytes INTEGER NOT NULL, last_indexed_at TEXT NOT NULL, UNIQUE(repo_id, relative_path));\nCREATE TABLE IF NOT EXISTS cds_requires (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, alias TEXT NOT NULL, kind TEXT, model TEXT, destination TEXT, service_path TEXT, request_timeout INTEGER, raw_json TEXT NOT NULL);\nCREATE TABLE IF NOT EXISTS cds_services (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, namespace TEXT, service_name TEXT NOT NULL, qualified_name TEXT NOT NULL, service_path TEXT NOT NULL, is_extend INTEGER NOT NULL, source_file TEXT NOT NULL, source_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS cds_operations (id INTEGER PRIMARY KEY, service_id INTEGER NOT NULL, operation_type TEXT NOT NULL, operation_name TEXT NOT NULL, operation_path TEXT NOT NULL, params_json TEXT NOT NULL, return_type TEXT, source_file TEXT NOT NULL, source_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS symbols (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, file_id INTEGER, kind TEXT NOT NULL, name TEXT NOT NULL, qualified_name TEXT NOT NULL, exported INTEGER NOT NULL, start_line INTEGER NOT NULL, end_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS handler_classes (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, symbol_id INTEGER, class_name TEXT NOT NULL, source_file TEXT NOT NULL, source_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS handler_methods (id INTEGER PRIMARY KEY, handler_class_id INTEGER NOT NULL, method_name TEXT NOT NULL, decorator_kind TEXT NOT NULL, decorator_value TEXT, decorator_raw_expression TEXT NOT NULL, source_file TEXT NOT NULL, source_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS handler_registrations (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, handler_class_id INTEGER, registration_file TEXT NOT NULL, registration_line INTEGER NOT NULL, registration_kind TEXT NOT NULL, confidence REAL NOT NULL);\nCREATE TABLE IF NOT EXISTS service_bindings (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, symbol_id INTEGER, variable_name TEXT NOT NULL, alias TEXT, destination_expr TEXT, service_path_expr TEXT, is_dynamic INTEGER NOT NULL, placeholders_json TEXT NOT NULL, source_file TEXT NOT NULL, source_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS outbound_calls (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, source_symbol_id INTEGER, call_type TEXT NOT NULL, service_binding_id INTEGER, method TEXT, operation_path_expr TEXT, query_entity TEXT, event_name_expr TEXT, payload_summary TEXT, source_file TEXT NOT NULL, source_line INTEGER NOT NULL, confidence REAL NOT NULL, unresolved_reason TEXT);\nCREATE TABLE IF NOT EXISTS graph_edges (id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, edge_type TEXT NOT NULL, from_kind TEXT NOT NULL, from_id TEXT NOT NULL, to_kind TEXT NOT NULL, to_id TEXT NOT NULL, confidence REAL NOT NULL, evidence_json TEXT NOT NULL, is_dynamic INTEGER NOT NULL, unresolved_reason TEXT);\nCREATE TABLE IF NOT EXISTS index_runs (id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, started_at TEXT NOT NULL, finished_at TEXT, status TEXT NOT NULL, repo_count INTEGER NOT NULL, file_count INTEGER NOT NULL, diagnostic_count INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS diagnostics (id INTEGER PRIMARY KEY, repo_id INTEGER, file_id INTEGER, severity TEXT NOT NULL, code TEXT NOT NULL, message TEXT NOT NULL, source_file TEXT, source_line INTEGER);\nCREATE INDEX IF NOT EXISTS idx_repo_name ON repositories(name);\nCREATE INDEX IF NOT EXISTS idx_service_path ON cds_services(service_path);\nCREATE INDEX IF NOT EXISTS idx_operation_name ON cds_operations(operation_name, operation_path);\nCREATE INDEX IF NOT EXISTS idx_calls_repo ON outbound_calls(repo_id, call_type);\nCREATE VIRTUAL TABLE IF NOT EXISTS search_index USING fts5(kind, name, path, repo);\n`;\n","import type { Db } from './connection.js';\nimport { schemaSql } from './schema.js';\nexport function migrate(db: Db): void {\n db.exec(schemaSql);\n}\n","import type { Db } from './connection.js';\nimport type {\n CdsRequire,\n CdsServiceFact,\n HandlerClassFact,\n HandlerRegistrationFact,\n OutboundCallFact,\n ServiceBindingFact\n} from '../types.js';\nexport interface RepoRow {\n id: number;\n name: string;\n absolute_path: string;\n relative_path: string;\n package_name: string | null;\n package_version: string | null;\n dependencies_json: string;\n kind: string;\n}\nexport interface WorkspaceRow {\n id: number;\n root_path: string;\n db_path: string;\n}\nexport function upsertWorkspace(\n db: Db,\n rootPath: string,\n dbPath: string\n): number {\n const now = new Date().toISOString();\n db.prepare(\n 'INSERT INTO workspaces(root_path,db_path,created_at,updated_at) VALUES(?,?,?,?) ON CONFLICT(root_path) DO UPDATE SET db_path=excluded.db_path,updated_at=excluded.updated_at'\n ).run(rootPath, dbPath, now, now);\n return Number(\n db.prepare('SELECT id FROM workspaces WHERE root_path=?').get(rootPath)?.id\n );\n}\nexport function getWorkspace(\n db: Db,\n rootPath: string\n): WorkspaceRow | undefined {\n return db\n .prepare('SELECT * FROM workspaces WHERE root_path=?')\n .get(rootPath) as WorkspaceRow | undefined;\n}\nexport function upsertRepository(\n db: Db,\n workspaceId: number,\n r: {\n name: string;\n absolutePath: string;\n relativePath: string;\n isGitRepo: boolean;\n packageName?: string;\n packageVersion?: string;\n dependencies?: Record<string, string>;\n kind?: string;\n }\n): number {\n db.prepare(\n `INSERT INTO repositories(workspace_id,name,absolute_path,relative_path,package_name,package_version,dependencies_json,kind,is_git_repo) VALUES(?,?,?,?,?,?,?,?,?) ON CONFLICT(workspace_id,absolute_path) DO UPDATE SET name=excluded.name,relative_path=excluded.relative_path,package_name=excluded.package_name,package_version=excluded.package_version,dependencies_json=excluded.dependencies_json,kind=excluded.kind`\n ).run(\n workspaceId,\n r.name,\n r.absolutePath,\n r.relativePath,\n r.packageName,\n r.packageVersion,\n JSON.stringify(r.dependencies ?? {}),\n r.kind ?? 'unknown',\n r.isGitRepo ? 1 : 0\n );\n return Number(\n db\n .prepare(\n 'SELECT id FROM repositories WHERE workspace_id=? AND absolute_path=?'\n )\n .get(workspaceId, r.absolutePath)?.id\n );\n}\nexport function listRepositories(db: Db): RepoRow[] {\n return db\n .prepare('SELECT * FROM repositories ORDER BY name')\n .all() as unknown as RepoRow[];\n}\nexport function repoByName(db: Db, name: string): RepoRow | undefined {\n return db\n .prepare('SELECT * FROM repositories WHERE name=? OR package_name=?')\n .get(name, name) as RepoRow | undefined;\n}\nexport function clearRepoFacts(db: Db, repoId: number): void {\n for (const t of [\n 'cds_requires',\n 'cds_services',\n 'symbols',\n 'handler_classes',\n 'handler_registrations',\n 'service_bindings',\n 'outbound_calls',\n 'diagnostics',\n 'files'\n ])\n db.prepare(`DELETE FROM ${t} WHERE repo_id=?`).run(repoId);\n}\nexport function insertRequires(\n db: Db,\n repoId: number,\n rows: CdsRequire[]\n): void {\n const stmt = db.prepare(\n 'INSERT INTO cds_requires(repo_id,alias,kind,model,destination,service_path,request_timeout,raw_json) VALUES(?,?,?,?,?,?,?,?)'\n );\n for (const r of rows)\n stmt.run(\n repoId,\n r.alias,\n r.kind,\n r.model,\n r.destination,\n r.servicePath,\n r.requestTimeout,\n r.rawJson\n );\n}\nexport function insertService(\n db: Db,\n repoId: number,\n s: CdsServiceFact\n): number {\n const id = Number(\n db\n .prepare(\n 'INSERT INTO cds_services(repo_id,namespace,service_name,qualified_name,service_path,is_extend,source_file,source_line) VALUES(?,?,?,?,?,?,?,?) RETURNING id'\n )\n .get(\n repoId,\n s.namespace,\n s.serviceName,\n s.qualifiedName,\n s.servicePath,\n s.isExtend ? 1 : 0,\n s.sourceFile,\n s.sourceLine\n )?.id\n );\n const stmt = db.prepare(\n 'INSERT INTO cds_operations(service_id,operation_type,operation_name,operation_path,params_json,return_type,source_file,source_line) VALUES(?,?,?,?,?,?,?,?)'\n );\n for (const o of s.operations)\n stmt.run(\n id,\n o.operationType,\n o.operationName,\n o.operationPath,\n o.paramsJson,\n o.returnType,\n o.sourceFile,\n o.sourceLine\n );\n return id;\n}\nexport function insertHandler(\n db: Db,\n repoId: number,\n h: HandlerClassFact\n): number {\n const sid = Number(\n db\n .prepare(\n 'INSERT INTO symbols(repo_id,kind,name,qualified_name,exported,start_line,end_line) VALUES(?,?,?,?,?,?,?) RETURNING id'\n )\n .get(\n repoId,\n 'class',\n h.className,\n h.className,\n 1,\n h.sourceLine,\n h.sourceLine\n )?.id\n );\n const hid = Number(\n db\n .prepare(\n 'INSERT INTO handler_classes(repo_id,symbol_id,class_name,source_file,source_line) VALUES(?,?,?,?,?) RETURNING id'\n )\n .get(repoId, sid, h.className, h.sourceFile, h.sourceLine)?.id\n );\n const stmt = db.prepare(\n 'INSERT INTO handler_methods(handler_class_id,method_name,decorator_kind,decorator_value,decorator_raw_expression,source_file,source_line) VALUES(?,?,?,?,?,?,?)'\n );\n for (const m of h.methods)\n stmt.run(\n hid,\n m.methodName,\n m.decoratorKind,\n m.decoratorValue,\n m.decoratorRawExpression,\n m.sourceFile,\n m.sourceLine\n );\n return hid;\n}\nexport function insertRegistrations(\n db: Db,\n repoId: number,\n rows: HandlerRegistrationFact[]\n): void {\n const stmt = db.prepare(\n 'INSERT INTO handler_registrations(repo_id,handler_class_id,registration_file,registration_line,registration_kind,confidence) VALUES(?,?,?,?,?,?)'\n );\n for (const r of rows)\n stmt.run(\n repoId,\n null,\n r.registrationFile,\n r.registrationLine,\n r.registrationKind,\n r.confidence\n );\n}\nexport function insertBindings(\n db: Db,\n repoId: number,\n rows: ServiceBindingFact[]\n): void {\n const stmt = db.prepare(\n 'INSERT INTO service_bindings(repo_id,variable_name,alias,destination_expr,service_path_expr,is_dynamic,placeholders_json,source_file,source_line) VALUES(?,?,?,?,?,?,?,?,?)'\n );\n for (const r of rows)\n stmt.run(\n repoId,\n r.variableName,\n r.alias,\n r.destinationExpr,\n r.servicePathExpr,\n r.isDynamic ? 1 : 0,\n JSON.stringify(r.placeholders),\n r.sourceFile,\n r.sourceLine\n );\n}\nexport function insertCalls(\n db: Db,\n repoId: number,\n rows: OutboundCallFact[]\n): void {\n const stmt = db.prepare(\n 'INSERT INTO outbound_calls(repo_id,call_type,method,operation_path_expr,query_entity,event_name_expr,payload_summary,source_file,source_line,confidence,unresolved_reason,service_binding_id) VALUES(?,?,?,?,?,?,?,?,?,?,?,(SELECT id FROM service_bindings WHERE repo_id=? AND variable_name=? ORDER BY id DESC LIMIT 1))'\n );\n for (const r of rows)\n stmt.run(\n repoId,\n r.callType,\n r.method,\n r.operationPathExpr,\n r.queryEntity,\n r.eventNameExpr,\n r.payloadSummary,\n r.sourceFile,\n r.sourceLine,\n r.confidence,\n r.unresolvedReason,\n repoId,\n r.serviceVariableName\n );\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { PackageFacts, RepoKind } from '../types.js';\nexport async function classifyRepository(\n repoPath: string,\n facts: PackageFacts\n): Promise<RepoKind> {\n const hasCdsDep = Boolean(\n facts.dependencies['@sap/cds'] ??\n facts.dependencies.cds ??\n facts.dependencies['cds-routing-handlers']\n );\n const cdsFiles = await findFiles(repoPath, '.cds');\n const serverFiles = await Promise.all(\n ['srv/server.ts', 'srv/server.js', 'src/server.ts', 'src/server.js'].map(\n async (f) =>\n fs\n .access(path.join(repoPath, f))\n .then(() => true)\n .catch(() => false)\n )\n );\n const helper =\n Object.keys(facts.dependencies).includes('cds-routing-handlers') ||\n facts.packageName?.includes('helper') === true;\n if (helper && cdsFiles.length > 0) return 'mixed';\n if (helper) return 'helper-package';\n if (hasCdsDep && (cdsFiles.length > 0 || serverFiles.some(Boolean)))\n return 'cap-service';\n if (cdsFiles.length > 0)\n return serverFiles.some(Boolean) ? 'cap-service' : 'cap-db-model';\n return 'unknown';\n}\n\nasync function findFiles(root: string, suffix: string): Promise<string[]> {\n const out: string[] = [];\n async function walk(dir: string): Promise<void> {\n const entries = await fs\n .readdir(dir, { withFileTypes: true })\n .catch(() => []);\n for (const e of entries) {\n if (e.isDirectory()) {\n if (!['node_modules', 'dist', 'gen', '.git'].includes(e.name))\n await walk(path.join(dir, e.name));\n } else if (e.name.endsWith(suffix)) out.push(path.join(dir, e.name));\n }\n }\n await walk(root);\n return out;\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Db } from '../db/connection.js';\nimport {\n clearRepoFacts,\n insertBindings,\n insertCalls,\n insertHandler,\n insertRegistrations,\n insertRequires,\n insertService,\n type RepoRow\n} from '../db/repositories.js';\nimport { classifyRepository } from '../discovery/classify-repository.js';\nimport { parseCdsFile } from '../parsers/cds-parser.js';\nimport { parseDecorators } from '../parsers/decorator-parser.js';\nimport { parseHandlerRegistrations } from '../parsers/handler-registration-parser.js';\nimport { parseOutboundCalls } from '../parsers/outbound-call-parser.js';\nimport { parsePackageJson } from '../parsers/package-json-parser.js';\nimport { parseServiceBindings } from '../parsers/service-binding-parser.js';\nimport { recordFile } from './incremental-index.js';\nimport { errorMessage } from '../utils/diagnostics.js';\nexport interface IndexRepoResult {\n fileCount: number;\n diagnosticCount: number;\n}\nexport async function indexRepository(\n db: Db,\n repo: RepoRow,\n force: boolean\n): Promise<IndexRepoResult> {\n void force;\n let diagnostics = 0;\n let files = 0;\n const facts = await parsePackageJson(repo.absolute_path);\n const kind = await classifyRepository(repo.absolute_path, facts);\n db.prepare(\n 'UPDATE repositories SET package_name=?, package_version=?, dependencies_json=?, kind=?, index_status=? WHERE id=?'\n ).run(\n facts.packageName,\n facts.packageVersion,\n JSON.stringify(facts.dependencies),\n kind,\n 'indexing',\n repo.id\n );\n clearRepoFacts(db, repo.id);\n insertRequires(db, repo.id, facts.cdsRequires);\n const sourceFiles = await findSourceFiles(repo.absolute_path);\n for (const file of sourceFiles) {\n try {\n await recordFile(db, repo.id, repo.absolute_path, file);\n files += 1;\n if (file.endsWith('.cds'))\n for (const s of await parseCdsFile(repo.absolute_path, file))\n insertService(db, repo.id, s);\n if (/\\.[jt]s$/.test(file)) {\n for (const h of await parseDecorators(repo.absolute_path, file))\n insertHandler(db, repo.id, h);\n insertRegistrations(\n db,\n repo.id,\n await parseHandlerRegistrations(repo.absolute_path, file)\n );\n insertBindings(\n db,\n repo.id,\n await parseServiceBindings(repo.absolute_path, file)\n );\n insertCalls(\n db,\n repo.id,\n await parseOutboundCalls(repo.absolute_path, file)\n );\n }\n } catch (error) {\n diagnostics += 1;\n db.prepare(\n 'INSERT INTO diagnostics(repo_id,severity,code,message,source_file) VALUES(?,?,?,?,?)'\n ).run(repo.id, 'warning', 'parse_failed', errorMessage(error), file);\n }\n }\n db.prepare(\n 'UPDATE repositories SET last_indexed_at=?, index_status=?, error_count=? WHERE id=?'\n ).run(\n new Date().toISOString(),\n diagnostics ? 'partial' : 'indexed',\n diagnostics,\n repo.id\n );\n return { fileCount: files, diagnosticCount: diagnostics };\n}\n\nasync function findSourceFiles(root: string): Promise<string[]> {\n const out: string[] = [];\n async function walk(dir: string, prefix = ''): Promise<void> {\n const entries = await fs\n .readdir(dir, { withFileTypes: true })\n .catch(() => []);\n for (const e of entries) {\n const rel = prefix ? `${prefix}/${e.name}` : e.name;\n if (e.isDirectory()) {\n if (\n !['node_modules', 'dist', 'gen', 'coverage', '.git'].includes(e.name)\n )\n await walk(path.join(dir, e.name), rel);\n } else if (/\\.(cds|ts|js)$/.test(e.name)) out.push(rel);\n }\n }\n await walk(root);\n return out.sort();\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { sha256File } from '../utils/hashing.js';\nimport { normalizePath } from '../utils/path-utils.js';\nimport type { Db } from '../db/connection.js';\nexport async function recordFile(\n db: Db,\n repoId: number,\n repoPath: string,\n relativeFile: string\n): Promise<void> {\n const abs = path.join(repoPath, relativeFile);\n const stat = await fs.stat(abs);\n const hash = await sha256File(abs);\n db.prepare(\n 'INSERT INTO files(repo_id,relative_path,extension,sha256,size_bytes,last_indexed_at) VALUES(?,?,?,?,?,?) ON CONFLICT(repo_id,relative_path) DO UPDATE SET sha256=excluded.sha256,size_bytes=excluded.size_bytes,last_indexed_at=excluded.last_indexed_at'\n ).run(\n repoId,\n normalizePath(relativeFile),\n path.extname(relativeFile),\n hash,\n stat.size,\n new Date().toISOString()\n );\n}\n","import { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nexport async function sha256File(filePath: string): Promise<string> {\n return createHash('sha256')\n .update(await readFile(filePath))\n .digest('hex');\n}\nexport function sha256Text(text: string): string {\n return createHash('sha256').update(text).digest('hex');\n}\n","export interface DiagnosticInput {\n severity: 'info' | 'warning' | 'error';\n code: string;\n message: string;\n sourceFile?: string;\n sourceLine?: number;\n}\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","import type { Db } from '../db/connection.js';\nimport { listRepositories, repoByName } from '../db/repositories.js';\nimport { indexRepository } from './repository-indexer.js';\nexport async function indexWorkspace(\n db: Db,\n workspaceId: number,\n options: { repo?: string; force: boolean }\n): Promise<{ repoCount: number; fileCount: number; diagnosticCount: number }> {\n const started = new Date().toISOString();\n const repos = options.repo\n ? [repoByName(db, options.repo)].filter((r) => r !== undefined)\n : listRepositories(db);\n const runId = Number(\n db\n .prepare(\n 'INSERT INTO index_runs(workspace_id,started_at,status,repo_count,file_count,diagnostic_count) VALUES(?,?,?,?,?,?) RETURNING id'\n )\n .get(workspaceId, started, 'running', repos.length, 0, 0)?.id\n );\n let fileCount = 0;\n let diagnosticCount = 0;\n for (const repo of repos) {\n const result = await indexRepository(db, repo, options.force);\n fileCount += result.fileCount;\n diagnosticCount += result.diagnosticCount;\n }\n db.prepare(\n 'UPDATE index_runs SET finished_at=?, status=?, file_count=?, diagnostic_count=? WHERE id=?'\n ).run(\n new Date().toISOString(),\n diagnosticCount ? 'partial' : 'success',\n fileCount,\n diagnosticCount,\n runId\n );\n return { repoCount: repos.length, fileCount, diagnosticCount };\n}\n","import type { TraceStart } from '../types.js';\nexport function parseVars(\n values: string[] | undefined\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const value of values ?? []) {\n const [key, ...rest] = value.split('=');\n if (key && rest.length > 0) out[key] = rest.join('=');\n }\n return out;\n}\nexport function startLabel(start: TraceStart): string {\n return [\n start.repo,\n start.servicePath,\n start.operation ?? start.operationPath ?? start.handler\n ]\n .filter(Boolean)\n .join(' ');\n}\n","import type { TraceResult } from '../types.js';\nimport { startLabel } from '../trace/selectors.js';\nexport function renderTraceTable(trace: TraceResult): string {\n const lines = [\n `Start: ${startLabel(trace.start)}`,\n '',\n 'Step Type From To Evidence'\n ];\n for (const e of trace.edges)\n lines.push(\n `${String(e.step).padEnd(5)} ${e.type.padEnd(20)} ${e.from.slice(0, 34).padEnd(35)} ${e.to.slice(0, 35).padEnd(36)} ${String(e.evidence.file ?? '')}:${String(e.evidence.line ?? '')}`\n );\n return `${lines.join('\\n')}\\n`;\n}\n","import type { TraceResult } from '../types.js';\nexport function renderJson(value: unknown): string {\n return `${JSON.stringify(value, null, 2)}\\n`;\n}\nexport function renderTraceJson(trace: TraceResult): string {\n return renderJson(trace);\n}\n","import type { TraceResult } from '../types.js';\nfunction safe(value: string): string {\n return value.replace(/[^\\w-]/g, '_').slice(0, 60);\n}\nexport function renderMermaid(trace: TraceResult): string {\n const lines = ['flowchart TD'];\n for (const e of trace.edges)\n lines.push(\n ` ${safe(e.from)}[\"${e.from}\"] -->|${e.type}| ${safe(e.to)}[\"${e.to}\"]`\n );\n return `${lines.join('\\n')}\\n`;\n}\n"],"mappings":"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","names":["path","fs","fs","path","fs","path","fs","path","fs","path","fs","path","path","fs","fs","path","trace","trace","trace","fs","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/config/defaults.ts","../src/config/workspace-config.ts","../src/db/connection.ts","../src/db/schema.ts","../src/db/migrations.ts","../src/db/repositories.ts","../src/discovery/classify-repository.ts","../src/indexer/repository-indexer.ts","../src/indexer/incremental-index.ts","../src/utils/hashing.ts","../src/utils/diagnostics.ts","../src/indexer/workspace-indexer.ts","../src/trace/selectors.ts","../src/output/table-output.ts","../src/output/json-output.ts","../src/output/mermaid-output.ts"],"sourcesContent":["import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'node:fs/promises';\nimport pc from 'picocolors';\nimport { DEFAULT_IGNORES } from './config/defaults.js';\nimport {\n createWorkspaceConfig,\n loadWorkspaceConfig,\n saveWorkspaceConfig\n} from './config/workspace-config.js';\nimport { openDatabase } from './db/connection.js';\nimport {\n getWorkspace,\n listRepositories,\n repoByName,\n upsertRepository,\n upsertWorkspace\n} from './db/repositories.js';\nimport { discoverRepositories } from './discovery/discover-repositories.js';\nimport { parsePackageJson } from './parsers/package-json-parser.js';\nimport { classifyRepository } from './discovery/classify-repository.js';\nimport { indexWorkspace } from './indexer/workspace-indexer.js';\nimport { linkWorkspace } from './linker/cross-repo-linker.js';\nimport { trace } from './trace/trace-engine.js';\nimport { parseVars } from './trace/selectors.js';\nimport { renderTraceTable } from './output/table-output.js';\nimport { renderTraceJson, renderJson } from './output/json-output.js';\nimport { renderMermaid } from './output/mermaid-output.js';\nasync function init(\n workspace: string,\n options: { db?: string; ignore?: string[] }\n): Promise<void> {\n const config = createWorkspaceConfig(\n workspace,\n options.db,\n options.ignore?.length ? options.ignore : [...DEFAULT_IGNORES]\n );\n const repos = await discoverRepositories(config.rootPath, config.ignore);\n await saveWorkspaceConfig(config);\n const db = openDatabase(config.dbPath);\n const workspaceId = upsertWorkspace(db, config.rootPath, config.dbPath);\n for (const repo of repos) {\n const pkg = await parsePackageJson(repo.absolutePath);\n const kind = await classifyRepository(repo.absolutePath, pkg);\n upsertRepository(db, workspaceId, {\n ...repo,\n packageName: pkg.packageName,\n packageVersion: pkg.packageVersion,\n dependencies: pkg.dependencies,\n kind\n });\n }\n db.close();\n process.stdout.write(\n `Workspace: ${config.rootPath}\\nDatabase: ${config.dbPath}\\nRepositories: ${repos.length}\\nIgnored: ${config.ignore.join(', ')}\\nNext: service-flow index --workspace ${config.rootPath}\\n`\n );\n}\nasync function withWorkspace<T>(\n workspace: string | undefined,\n fn: (\n db: ReturnType<typeof openDatabase>,\n workspaceId: number,\n rootPath: string\n ) => Promise<T> | T\n): Promise<T> {\n const config = await loadWorkspaceConfig(workspace);\n const db = openDatabase(config.dbPath);\n try {\n const row = getWorkspace(db, config.rootPath);\n const workspaceId =\n row?.id ?? upsertWorkspace(db, config.rootPath, config.dbPath);\n return await fn(db, workspaceId, config.rootPath);\n } finally {\n db.close();\n }\n}\nexport function createProgram(): Command {\n const program = new Command();\n program\n .name('service-flow')\n .description(\n 'Trace SAP CAP service-to-service flows across multi-repository workspaces'\n )\n .version('0.1.2');\n program\n .command('init')\n .argument('<workspace>')\n .option('--db <path>')\n .option('--ignore <pattern...>')\n .action(\n (workspace: string, opts: { db?: string; ignore?: string[] }) =>\n void init(workspace, opts).catch(fail)\n );\n program\n .command('index')\n .option('--workspace <path>')\n .option('--repo <name>')\n .option('--force')\n .action(\n (opts: { workspace?: string; repo?: string; force?: boolean }) =>\n void withWorkspace(opts.workspace, async (db, workspaceId) => {\n const r = await indexWorkspace(db, workspaceId, {\n repo: opts.repo,\n force: Boolean(opts.force)\n });\n process.stdout.write(\n `Indexed ${r.repoCount} repositories, ${r.fileCount} files, ${r.diagnosticCount} diagnostics\\n`\n );\n }).catch(fail)\n );\n program\n .command('link')\n .option('--workspace <path>')\n .option('--force')\n .action(\n (opts: { workspace?: string }) =>\n void withWorkspace(opts.workspace, (db, workspaceId) => {\n const r = linkWorkspace(db, workspaceId);\n process.stdout.write(\n `Linked ${r.edgeCount} edges, ${r.unresolvedCount} unresolved\\n`\n );\n }).catch(fail)\n );\n program\n .command('trace')\n .option('--workspace <path>')\n .option('--repo <name>')\n .option('--operation <name>')\n .option('--service <path>')\n .option('--path <operationPath>')\n .option('--handler <name>')\n .option('--depth <n>', 'trace depth', '25')\n .option('--format <format>', 'table|json|mermaid', 'table')\n .option('--include-external')\n .option('--include-db')\n .option('--include-async')\n .option('--var <key=value>', 'dynamic variable', collect, [])\n .action(\n (opts: {\n workspace?: string;\n repo?: string;\n operation?: string;\n service?: string;\n path?: string;\n handler?: string;\n depth: string;\n format: string;\n includeExternal?: boolean;\n includeDb?: boolean;\n includeAsync?: boolean;\n var: string[];\n }) =>\n void withWorkspace(opts.workspace, (db) => {\n const result = trace(\n db,\n {\n repo: opts.repo,\n servicePath: opts.service,\n operation: opts.operation,\n operationPath: opts.path,\n handler: opts.handler\n },\n {\n depth: Number(opts.depth),\n vars: parseVars(opts.var),\n includeExternal: Boolean(opts.includeExternal),\n includeDb: Boolean(opts.includeDb),\n includeAsync: Boolean(opts.includeAsync)\n }\n );\n process.stdout.write(\n opts.format === 'json'\n ? renderTraceJson(result)\n : opts.format === 'mermaid'\n ? renderMermaid(result)\n : renderTraceTable(result)\n );\n }).catch(fail)\n );\n const list = program.command('list');\n list\n .command('repos')\n .option('--workspace <path>')\n .action(\n (opts: { workspace?: string }) =>\n void withWorkspace(opts.workspace, (db) =>\n process.stdout.write(\n renderJson(\n listRepositories(db).map((r) => ({\n name: r.name,\n kind: r.kind,\n packageName: r.package_name\n }))\n )\n )\n ).catch(fail)\n );\n list\n .command('services')\n .option('--workspace <path>')\n .option('--repo <name>')\n .action(\n (opts: { workspace?: string; repo?: string }) =>\n void withWorkspace(opts.workspace, (db) => {\n const repo = opts.repo ? repoByName(db, opts.repo) : undefined;\n const rows = db\n .prepare(\n 'SELECT r.name repo,s.service_path servicePath,s.qualified_name qualifiedName FROM cds_services s JOIN repositories r ON r.id=s.repo_id WHERE (? IS NULL OR s.repo_id=?) ORDER BY r.name,s.service_path'\n )\n .all(repo?.id, repo?.id);\n process.stdout.write(renderJson(rows));\n }).catch(fail)\n );\n list\n .command('operations')\n .option('--workspace <path>')\n .option('--repo <name>')\n .option('--service <path>')\n .action(\n (opts: { workspace?: string; repo?: string; service?: string }) =>\n void withWorkspace(opts.workspace, (db) => {\n const repo = opts.repo ? repoByName(db, opts.repo) : undefined;\n const rows = db\n .prepare(\n 'SELECT r.name repo,s.service_path servicePath,o.operation_name operation,o.operation_path path FROM cds_operations o JOIN cds_services s ON s.id=o.service_id JOIN repositories r ON r.id=s.repo_id WHERE (? IS NULL OR s.repo_id=?) AND (? IS NULL OR s.service_path=?)'\n )\n .all(repo?.id, repo?.id, opts.service, opts.service);\n process.stdout.write(renderJson(rows));\n }).catch(fail)\n );\n list\n .command('calls')\n .option('--workspace <path>')\n .option('--repo <name>')\n .option('--operation <name>')\n .action(\n (opts: { workspace?: string; repo?: string; operation?: string }) =>\n void withWorkspace(opts.workspace, (db) => {\n const repo = opts.repo ? repoByName(db, opts.repo) : undefined;\n const rows = db\n .prepare(\n 'SELECT r.name repo,c.call_type type,c.operation_path_expr path,c.source_file file,c.source_line line FROM outbound_calls c JOIN repositories r ON r.id=c.repo_id WHERE (? IS NULL OR c.repo_id=?) AND (? IS NULL OR c.operation_path_expr=? OR c.operation_path_expr=? OR c.payload_summary LIKE ?)'\n )\n .all(repo?.id, repo?.id, opts.operation, opts.operation, opts.operation ? `/${opts.operation}` : undefined, opts.operation ? `%${opts.operation}%` : undefined);\n process.stdout.write(renderJson(rows));\n }).catch(fail)\n );\n program\n .command('graph')\n .option('--workspace <path>')\n .option('--repo <name>')\n .option('--operation <name>')\n .option('--service <path>')\n .option('--path <operationPath>')\n .option('--format <format>', 'mermaid|json', 'mermaid')\n .action(\n (opts: {\n workspace?: string;\n repo?: string;\n operation?: string;\n service?: string;\n path?: string;\n format: string;\n }) =>\n void withWorkspace(opts.workspace, (db) => {\n const result = trace(\n db,\n {\n repo: opts.repo,\n operation: opts.operation,\n servicePath: opts.service,\n operationPath: opts.path\n },\n {\n depth: 100,\n includeAsync: true,\n includeDb: true,\n includeExternal: true\n }\n );\n process.stdout.write(\n opts.format === 'json'\n ? renderTraceJson(result)\n : renderMermaid(result)\n );\n }).catch(fail)\n );\n const inspect = program.command('inspect');\n inspect\n .command('repo')\n .argument('<name>')\n .option('--workspace <path>')\n .action(\n (name: string, opts: { workspace?: string }) =>\n void withWorkspace(opts.workspace, (db) =>\n process.stdout.write(\n renderJson(repoByName(db, name) ?? { error: 'repo not found' })\n )\n ).catch(fail)\n );\n inspect\n .command('operation')\n .argument('<selector>')\n .option('--workspace <path>')\n .action(\n (selector: string, opts: { workspace?: string }) =>\n void withWorkspace(opts.workspace, (db) => {\n const rows = db\n .prepare(\n 'SELECT * FROM cds_operations WHERE operation_name=? OR operation_path=?'\n )\n .all(selector, selector);\n process.stdout.write(renderJson(rows));\n }).catch(fail)\n );\n program\n .command('doctor')\n .option('--workspace <path>')\n .action(\n (opts: { workspace?: string }) =>\n void withWorkspace(opts.workspace, (db) => {\n const diagnostics = db\n .prepare(\n 'SELECT severity,code,message,source_file sourceFile,source_line sourceLine FROM diagnostics ORDER BY id'\n )\n .all() as Array<Record<string, unknown>>;\n const health = db\n .prepare(\n `SELECT 'warning' severity,'service_without_operations' code,'CDS service has no indexed operations' message,s.source_file sourceFile,s.source_line sourceLine\n FROM cds_services s LEFT JOIN cds_operations o ON o.service_id=s.id WHERE o.id IS NULL\n UNION ALL\n SELECT 'warning','handler_without_service','Repository has handlers but no CDS services',hc.source_file,hc.source_line\n FROM handler_classes hc JOIN repositories r ON r.id=hc.repo_id\n WHERE r.kind IN ('cap-service','mixed') AND NOT EXISTS (SELECT 1 FROM cds_services s WHERE s.repo_id=hc.repo_id)\n UNION ALL\n SELECT 'warning','search_index_empty','Search index is empty after indexing',NULL,NULL\n WHERE NOT EXISTS (SELECT 1 FROM search_index)`\n )\n .all() as Array<Record<string, unknown>>;\n const allDiagnostics = [...diagnostics, ...health];\n process.stdout.write(\n allDiagnostics.length\n ? renderJson(allDiagnostics)\n : `${pc.green('No diagnostics recorded')}\\n`\n );\n }).catch(fail)\n );\n program\n .command('clean')\n .option('--workspace <path>')\n .option('--db-only')\n .action(\n (opts: { workspace?: string; dbOnly?: boolean }) =>\n void (async () => {\n const config = await loadWorkspaceConfig(opts.workspace);\n await fs.rm(config.dbPath, { force: true });\n if (!opts.dbOnly)\n await fs.rm(path.dirname(config.dbPath), {\n recursive: true,\n force: true\n });\n process.stdout.write('Cleaned service-flow state\\n');\n })().catch(fail)\n );\n return program;\n}\nfunction collect(value: string, previous: string[]): string[] {\n previous.push(value);\n return previous;\n}\nfunction fail(error: unknown): void {\n process.stderr.write(\n `${error instanceof Error ? error.message : String(error)}\\n`\n );\n process.exitCode = 1;\n}\ncreateProgram().parse(process.argv);\n","export const DEFAULT_IGNORES = [\n 'node_modules',\n 'gen',\n 'dist',\n 'coverage',\n '.git',\n '.turbo',\n '.next',\n '.cache',\n '.service-flow'\n] as const;\nexport const CONFIG_DIR = '.service-flow';\nexport const CONFIG_FILE = 'config.json';\nexport const DEFAULT_DB_FILE = 'service-flow.db';\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { z } from 'zod';\nimport {\n CONFIG_DIR,\n CONFIG_FILE,\n DEFAULT_DB_FILE,\n DEFAULT_IGNORES\n} from './defaults.js';\nconst schema = z.object({\n rootPath: z.string(),\n dbPath: z.string(),\n ignore: z.array(z.string()),\n createdAt: z.string(),\n updatedAt: z.string()\n});\nexport type WorkspaceConfig = z.infer<typeof schema>;\nexport function configPath(rootPath: string): string {\n return path.join(rootPath, CONFIG_DIR, CONFIG_FILE);\n}\nexport function defaultDbPath(rootPath: string): string {\n return path.join(rootPath, CONFIG_DIR, DEFAULT_DB_FILE);\n}\nexport async function saveWorkspaceConfig(\n config: WorkspaceConfig\n): Promise<void> {\n await fs.mkdir(path.dirname(configPath(config.rootPath)), {\n recursive: true\n });\n await fs.writeFile(\n configPath(config.rootPath),\n `${JSON.stringify(config, null, 2)}\\n`\n );\n}\nexport async function loadWorkspaceConfig(\n workspace?: string\n): Promise<WorkspaceConfig> {\n const root = path.resolve(workspace ?? process.cwd());\n const data = await fs.readFile(configPath(root), 'utf8');\n return schema.parse(JSON.parse(data) as unknown);\n}\nexport function createWorkspaceConfig(\n rootPath: string,\n dbPath?: string,\n ignore: string[] = [...DEFAULT_IGNORES]\n): WorkspaceConfig {\n const now = new Date().toISOString();\n const root = path.resolve(rootPath);\n return {\n rootPath: root,\n dbPath: path.resolve(dbPath ?? defaultDbPath(root)),\n ignore,\n createdAt: now,\n updatedAt: now\n };\n}\n","import { execFileSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { migrate } from './migrations.js';\nexport interface Statement {\n run: (...params: unknown[]) => { changes: number };\n get: (...params: unknown[]) => Record<string, unknown> | undefined;\n all: (...params: unknown[]) => Array<Record<string, unknown>>;\n}\nexport interface Db {\n path: string;\n exec: (sql: string) => void;\n prepare: (sql: string) => Statement;\n pragma: (sql: string) => void;\n close: () => void;\n}\nfunction quote(value: unknown): string {\n if (value === null || value === undefined) return 'NULL';\n if (typeof value === 'number')\n return Number.isFinite(value) ? String(value) : 'NULL';\n if (typeof value === 'boolean') return value ? '1' : '0';\n return `'${String(value).replaceAll(\"'\", \"''\")}'`;\n}\nfunction bind(sql: string, params: unknown[]): string {\n let index = 0;\n return sql.replaceAll('?', () => quote(params[index++]));\n}\nfunction isBusy(error: unknown): boolean {\n return error instanceof Error && /SQLITE_BUSY|database is locked|database is busy/i.test(error.message);\n}\nfunction sleep(ms: number): void {\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n}\nfunction call(dbPath: string, args: string[], attempt = 0): string {\n try {\n return execFileSync('sqlite3', [dbPath, ...args], {\n encoding: 'utf8',\n maxBuffer: 128 * 1024 * 1024,\n env: { ...process.env, SQLITE_BUSY_TIMEOUT: '10000' }\n });\n } catch (error) {\n if (isBusy(error) && attempt < 5) {\n sleep(50 * 2 ** attempt);\n return call(dbPath, args, attempt + 1);\n }\n if (isBusy(error))\n throw new Error(\n 'SQLite database is busy or locked. Another service-flow writer may be active; retry after it finishes.',\n { cause: error }\n );\n throw error;\n }\n}\nfunction jsonRows(dbPath: string, sql: string): Array<Record<string, unknown>> {\n const out = call(dbPath, ['-json', sql]);\n if (!out.trim()) return [];\n return JSON.parse(out) as Array<Record<string, unknown>>;\n}\nexport function openDatabase(dbPath: string): Db {\n fs.mkdirSync(path.dirname(dbPath), { recursive: true });\n const db: Db = {\n path: dbPath,\n exec(sql: string): void {\n call(dbPath, [sql]);\n },\n prepare(sql: string): Statement {\n return {\n run: (...params: unknown[]) => {\n call(dbPath, [bind(sql, params)]);\n return { changes: 0 };\n },\n get: (...params: unknown[]) => jsonRows(dbPath, bind(sql, params))[0],\n all: (...params: unknown[]) => jsonRows(dbPath, bind(sql, params))\n };\n },\n pragma(sql: string): void {\n call(dbPath, [`PRAGMA ${sql}`]);\n },\n close(): void {\n /* sqlite3 CLI opens per statement */\n }\n };\n db.pragma('busy_timeout = 10000');\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n migrate(db);\n return db;\n}\n","export const schemaSql = `\nCREATE TABLE IF NOT EXISTS workspaces (id INTEGER PRIMARY KEY, root_path TEXT UNIQUE NOT NULL, db_path TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL);\nCREATE TABLE IF NOT EXISTS repositories (id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, name TEXT NOT NULL, absolute_path TEXT NOT NULL, relative_path TEXT NOT NULL, package_name TEXT, package_version TEXT, dependencies_json TEXT DEFAULT '{}', kind TEXT NOT NULL, is_git_repo INTEGER NOT NULL, last_indexed_at TEXT, index_status TEXT DEFAULT 'pending', error_count INTEGER DEFAULT 0, UNIQUE(workspace_id, absolute_path));\nCREATE TABLE IF NOT EXISTS files (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, relative_path TEXT NOT NULL, extension TEXT NOT NULL, sha256 TEXT NOT NULL, size_bytes INTEGER NOT NULL, last_indexed_at TEXT NOT NULL, UNIQUE(repo_id, relative_path));\nCREATE TABLE IF NOT EXISTS cds_requires (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, alias TEXT NOT NULL, kind TEXT, model TEXT, destination TEXT, service_path TEXT, request_timeout INTEGER, raw_json TEXT NOT NULL);\nCREATE TABLE IF NOT EXISTS cds_services (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, namespace TEXT, service_name TEXT NOT NULL, qualified_name TEXT NOT NULL, service_path TEXT NOT NULL, is_extend INTEGER NOT NULL, source_file TEXT NOT NULL, source_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS cds_operations (id INTEGER PRIMARY KEY, service_id INTEGER NOT NULL, operation_type TEXT NOT NULL, operation_name TEXT NOT NULL, operation_path TEXT NOT NULL, params_json TEXT NOT NULL, return_type TEXT, source_file TEXT NOT NULL, source_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS symbols (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, file_id INTEGER, kind TEXT NOT NULL, name TEXT NOT NULL, qualified_name TEXT NOT NULL, exported INTEGER NOT NULL, start_line INTEGER NOT NULL, end_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS handler_classes (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, symbol_id INTEGER, class_name TEXT NOT NULL, source_file TEXT NOT NULL, source_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS handler_methods (id INTEGER PRIMARY KEY, handler_class_id INTEGER NOT NULL, method_name TEXT NOT NULL, decorator_kind TEXT NOT NULL, decorator_value TEXT, decorator_raw_expression TEXT NOT NULL, source_file TEXT NOT NULL, source_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS handler_registrations (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, handler_class_id INTEGER, registration_file TEXT NOT NULL, registration_line INTEGER NOT NULL, registration_kind TEXT NOT NULL, confidence REAL NOT NULL);\nCREATE TABLE IF NOT EXISTS service_bindings (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, symbol_id INTEGER, variable_name TEXT NOT NULL, alias TEXT, destination_expr TEXT, service_path_expr TEXT, is_dynamic INTEGER NOT NULL, placeholders_json TEXT NOT NULL, source_file TEXT NOT NULL, source_line INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS outbound_calls (id INTEGER PRIMARY KEY, repo_id INTEGER NOT NULL, source_symbol_id INTEGER, call_type TEXT NOT NULL, service_binding_id INTEGER, method TEXT, operation_path_expr TEXT, query_entity TEXT, event_name_expr TEXT, payload_summary TEXT, source_file TEXT NOT NULL, source_line INTEGER NOT NULL, confidence REAL NOT NULL, unresolved_reason TEXT);\nCREATE TABLE IF NOT EXISTS graph_edges (id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, edge_type TEXT NOT NULL, from_kind TEXT NOT NULL, from_id TEXT NOT NULL, to_kind TEXT NOT NULL, to_id TEXT NOT NULL, confidence REAL NOT NULL, evidence_json TEXT NOT NULL, is_dynamic INTEGER NOT NULL, unresolved_reason TEXT);\nCREATE TABLE IF NOT EXISTS index_runs (id INTEGER PRIMARY KEY, workspace_id INTEGER NOT NULL, started_at TEXT NOT NULL, finished_at TEXT, status TEXT NOT NULL, repo_count INTEGER NOT NULL, file_count INTEGER NOT NULL, diagnostic_count INTEGER NOT NULL);\nCREATE TABLE IF NOT EXISTS diagnostics (id INTEGER PRIMARY KEY, repo_id INTEGER, file_id INTEGER, severity TEXT NOT NULL, code TEXT NOT NULL, message TEXT NOT NULL, source_file TEXT, source_line INTEGER);\nCREATE INDEX IF NOT EXISTS idx_repo_name ON repositories(name);\nCREATE INDEX IF NOT EXISTS idx_service_path ON cds_services(service_path);\nCREATE INDEX IF NOT EXISTS idx_operation_name ON cds_operations(operation_name, operation_path);\nCREATE INDEX IF NOT EXISTS idx_calls_repo ON outbound_calls(repo_id, call_type);\nCREATE VIRTUAL TABLE IF NOT EXISTS search_index USING fts5(kind, name, path, repo);\n`;\n","import type { Db } from './connection.js';\nimport { schemaSql } from './schema.js';\nexport function migrate(db: Db): void {\n db.exec(schemaSql);\n}\n","import type { Db } from './connection.js';\nimport type {\n CdsRequire,\n CdsServiceFact,\n HandlerClassFact,\n HandlerRegistrationFact,\n OutboundCallFact,\n ServiceBindingFact\n} from '../types.js';\nexport interface RepoRow {\n id: number;\n name: string;\n absolute_path: string;\n relative_path: string;\n package_name: string | null;\n package_version: string | null;\n dependencies_json: string;\n kind: string;\n}\nexport interface WorkspaceRow {\n id: number;\n root_path: string;\n db_path: string;\n}\nexport function upsertWorkspace(\n db: Db,\n rootPath: string,\n dbPath: string\n): number {\n const now = new Date().toISOString();\n db.prepare(\n 'INSERT INTO workspaces(root_path,db_path,created_at,updated_at) VALUES(?,?,?,?) ON CONFLICT(root_path) DO UPDATE SET db_path=excluded.db_path,updated_at=excluded.updated_at'\n ).run(rootPath, dbPath, now, now);\n return Number(\n db.prepare('SELECT id FROM workspaces WHERE root_path=?').get(rootPath)?.id\n );\n}\nexport function getWorkspace(\n db: Db,\n rootPath: string\n): WorkspaceRow | undefined {\n return db\n .prepare('SELECT * FROM workspaces WHERE root_path=?')\n .get(rootPath) as WorkspaceRow | undefined;\n}\nexport function upsertRepository(\n db: Db,\n workspaceId: number,\n r: {\n name: string;\n absolutePath: string;\n relativePath: string;\n isGitRepo: boolean;\n packageName?: string;\n packageVersion?: string;\n dependencies?: Record<string, string>;\n kind?: string;\n }\n): number {\n db.prepare(\n `INSERT INTO repositories(workspace_id,name,absolute_path,relative_path,package_name,package_version,dependencies_json,kind,is_git_repo) VALUES(?,?,?,?,?,?,?,?,?) ON CONFLICT(workspace_id,absolute_path) DO UPDATE SET name=excluded.name,relative_path=excluded.relative_path,package_name=excluded.package_name,package_version=excluded.package_version,dependencies_json=excluded.dependencies_json,kind=excluded.kind`\n ).run(\n workspaceId,\n r.name,\n r.absolutePath,\n r.relativePath,\n r.packageName,\n r.packageVersion,\n JSON.stringify(r.dependencies ?? {}),\n r.kind ?? 'unknown',\n r.isGitRepo ? 1 : 0\n );\n return Number(\n db\n .prepare(\n 'SELECT id FROM repositories WHERE workspace_id=? AND absolute_path=?'\n )\n .get(workspaceId, r.absolutePath)?.id\n );\n}\nexport function listRepositories(db: Db): RepoRow[] {\n return db\n .prepare('SELECT * FROM repositories ORDER BY name')\n .all() as unknown as RepoRow[];\n}\nexport function repoByName(db: Db, name: string): RepoRow | undefined {\n return db\n .prepare('SELECT * FROM repositories WHERE name=? OR package_name=?')\n .get(name, name) as RepoRow | undefined;\n}\nexport function clearRepoFacts(db: Db, repoId: number): void {\n for (const t of [\n 'cds_requires',\n 'cds_services',\n 'symbols',\n 'handler_classes',\n 'handler_registrations',\n 'service_bindings',\n 'outbound_calls',\n 'diagnostics',\n 'files'\n ])\n db.prepare(`DELETE FROM ${t} WHERE repo_id=?`).run(repoId);\n db.prepare('DELETE FROM search_index WHERE repo=?').run(String(repoId));\n}\nexport function insertRequires(\n db: Db,\n repoId: number,\n rows: CdsRequire[]\n): void {\n const stmt = db.prepare(\n 'INSERT INTO cds_requires(repo_id,alias,kind,model,destination,service_path,request_timeout,raw_json) VALUES(?,?,?,?,?,?,?,?)'\n );\n for (const r of rows)\n stmt.run(\n repoId,\n r.alias,\n r.kind,\n r.model,\n r.destination,\n r.servicePath,\n r.requestTimeout,\n r.rawJson\n );\n}\nexport function insertService(\n db: Db,\n repoId: number,\n s: CdsServiceFact\n): number {\n const id = Number(\n db\n .prepare(\n 'INSERT INTO cds_services(repo_id,namespace,service_name,qualified_name,service_path,is_extend,source_file,source_line) VALUES(?,?,?,?,?,?,?,?) RETURNING id'\n )\n .get(\n repoId,\n s.namespace,\n s.serviceName,\n s.qualifiedName,\n s.servicePath,\n s.isExtend ? 1 : 0,\n s.sourceFile,\n s.sourceLine\n )?.id\n );\n const stmt = db.prepare(\n 'INSERT INTO cds_operations(service_id,operation_type,operation_name,operation_path,params_json,return_type,source_file,source_line) VALUES(?,?,?,?,?,?,?,?)'\n );\n db.prepare('INSERT INTO search_index(kind,name,path,repo) VALUES(?,?,?,?)').run(\n 'service',\n s.qualifiedName,\n s.servicePath,\n String(repoId)\n );\n for (const o of s.operations)\n stmt.run(\n id,\n o.operationType,\n o.operationName,\n o.operationPath,\n o.paramsJson,\n o.returnType,\n o.sourceFile,\n o.sourceLine\n );\n const search = db.prepare(\n 'INSERT INTO search_index(kind,name,path,repo) VALUES(?,?,?,?)'\n );\n for (const o of s.operations)\n search.run('operation', o.operationName, o.operationPath, String(repoId));\n return id;\n}\nexport function insertHandler(\n db: Db,\n repoId: number,\n h: HandlerClassFact\n): number {\n const sid = Number(\n db\n .prepare(\n 'INSERT INTO symbols(repo_id,kind,name,qualified_name,exported,start_line,end_line) VALUES(?,?,?,?,?,?,?) RETURNING id'\n )\n .get(\n repoId,\n 'class',\n h.className,\n h.className,\n 1,\n h.sourceLine,\n h.sourceLine\n )?.id\n );\n const hid = Number(\n db\n .prepare(\n 'INSERT INTO handler_classes(repo_id,symbol_id,class_name,source_file,source_line) VALUES(?,?,?,?,?) RETURNING id'\n )\n .get(repoId, sid, h.className, h.sourceFile, h.sourceLine)?.id\n );\n const stmt = db.prepare(\n 'INSERT INTO handler_methods(handler_class_id,method_name,decorator_kind,decorator_value,decorator_raw_expression,source_file,source_line) VALUES(?,?,?,?,?,?,?)'\n );\n for (const m of h.methods)\n stmt.run(\n hid,\n m.methodName,\n m.decoratorKind,\n m.decoratorValue,\n m.decoratorRawExpression,\n m.sourceFile,\n m.sourceLine\n );\n return hid;\n}\nexport function insertRegistrations(\n db: Db,\n repoId: number,\n rows: HandlerRegistrationFact[]\n): void {\n const stmt = db.prepare(\n 'INSERT INTO handler_registrations(repo_id,handler_class_id,registration_file,registration_line,registration_kind,confidence) VALUES(?,?,?,?,?,?)'\n );\n for (const r of rows)\n stmt.run(\n repoId,\n null,\n r.registrationFile,\n r.registrationLine,\n r.registrationKind,\n r.confidence\n );\n}\nexport function insertBindings(\n db: Db,\n repoId: number,\n rows: ServiceBindingFact[]\n): void {\n const stmt = db.prepare(\n 'INSERT INTO service_bindings(repo_id,variable_name,alias,destination_expr,service_path_expr,is_dynamic,placeholders_json,source_file,source_line) VALUES(?,?,?,?,?,?,?,?,?)'\n );\n for (const r of rows)\n stmt.run(\n repoId,\n r.variableName,\n r.alias,\n r.destinationExpr,\n r.servicePathExpr,\n r.isDynamic ? 1 : 0,\n JSON.stringify(r.placeholders),\n r.sourceFile,\n r.sourceLine\n );\n}\nexport function insertCalls(\n db: Db,\n repoId: number,\n rows: OutboundCallFact[]\n): void {\n const stmt = db.prepare(\n 'INSERT INTO outbound_calls(repo_id,call_type,method,operation_path_expr,query_entity,event_name_expr,payload_summary,source_file,source_line,confidence,unresolved_reason,service_binding_id) VALUES(?,?,?,?,?,?,?,?,?,?,?,(SELECT id FROM service_bindings WHERE repo_id=? AND variable_name=? AND source_file=? ORDER BY CASE WHEN source_line<=? THEN 0 ELSE 1 END, ABS(source_line-?) ASC, id DESC LIMIT 1))'\n );\n for (const r of rows)\n stmt.run(\n repoId,\n r.callType,\n r.method,\n r.operationPathExpr,\n r.queryEntity,\n r.eventNameExpr,\n r.payloadSummary,\n r.sourceFile,\n r.sourceLine,\n r.confidence,\n r.unresolvedReason,\n repoId,\n r.serviceVariableName,\n r.sourceFile,\n r.sourceLine,\n r.sourceLine\n );\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { PackageFacts, RepoKind } from '../types.js';\nexport async function classifyRepository(\n repoPath: string,\n facts: PackageFacts\n): Promise<RepoKind> {\n const hasCdsDep = Boolean(\n facts.dependencies['@sap/cds'] ??\n facts.dependencies.cds ??\n facts.dependencies['cds-routing-handlers']\n );\n const cdsFiles = await findFiles(repoPath, '.cds');\n const serverFiles = await Promise.all(\n ['srv/server.ts', 'srv/server.js', 'src/server.ts', 'src/server.js'].map(\n async (f) =>\n fs\n .access(path.join(repoPath, f))\n .then(() => true)\n .catch(() => false)\n )\n );\n const helper =\n Object.keys(facts.dependencies).includes('cds-routing-handlers') ||\n facts.packageName?.includes('helper') === true;\n if (helper && cdsFiles.length > 0) return 'mixed';\n if (helper) return 'helper-package';\n if (hasCdsDep && (cdsFiles.length > 0 || serverFiles.some(Boolean)))\n return 'cap-service';\n if (cdsFiles.length > 0)\n return serverFiles.some(Boolean) ? 'cap-service' : 'cap-db-model';\n return 'unknown';\n}\n\nasync function findFiles(root: string, suffix: string): Promise<string[]> {\n const out: string[] = [];\n async function walk(dir: string): Promise<void> {\n const entries = await fs\n .readdir(dir, { withFileTypes: true })\n .catch(() => []);\n for (const e of entries) {\n if (e.isDirectory()) {\n if (!['node_modules', 'dist', 'gen', '.git'].includes(e.name))\n await walk(path.join(dir, e.name));\n } else if (e.name.endsWith(suffix)) out.push(path.join(dir, e.name));\n }\n }\n await walk(root);\n return out;\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Db } from '../db/connection.js';\nimport {\n clearRepoFacts,\n insertBindings,\n insertCalls,\n insertHandler,\n insertRegistrations,\n insertRequires,\n insertService,\n type RepoRow\n} from '../db/repositories.js';\nimport { classifyRepository } from '../discovery/classify-repository.js';\nimport { parseCdsFile } from '../parsers/cds-parser.js';\nimport { parseDecorators } from '../parsers/decorator-parser.js';\nimport { parseHandlerRegistrations } from '../parsers/handler-registration-parser.js';\nimport { parseOutboundCalls } from '../parsers/outbound-call-parser.js';\nimport { parsePackageJson } from '../parsers/package-json-parser.js';\nimport { parseServiceBindings } from '../parsers/service-binding-parser.js';\nimport { recordFile } from './incremental-index.js';\nimport { errorMessage } from '../utils/diagnostics.js';\nexport interface IndexRepoResult {\n fileCount: number;\n diagnosticCount: number;\n}\nexport async function indexRepository(\n db: Db,\n repo: RepoRow,\n force: boolean\n): Promise<IndexRepoResult> {\n void force;\n let diagnostics = 0;\n let files = 0;\n const facts = await parsePackageJson(repo.absolute_path);\n const kind = await classifyRepository(repo.absolute_path, facts);\n db.prepare(\n 'UPDATE repositories SET package_name=?, package_version=?, dependencies_json=?, kind=?, index_status=? WHERE id=?'\n ).run(\n facts.packageName,\n facts.packageVersion,\n JSON.stringify(facts.dependencies),\n kind,\n 'indexing',\n repo.id\n );\n clearRepoFacts(db, repo.id);\n insertRequires(db, repo.id, facts.cdsRequires);\n const sourceFiles = await findSourceFiles(repo.absolute_path);\n for (const file of sourceFiles) {\n try {\n await recordFile(db, repo.id, repo.absolute_path, file);\n files += 1;\n if (file.endsWith('.cds'))\n for (const s of await parseCdsFile(repo.absolute_path, file))\n insertService(db, repo.id, s);\n if (/\\.[jt]s$/.test(file)) {\n for (const h of await parseDecorators(repo.absolute_path, file))\n insertHandler(db, repo.id, h);\n insertRegistrations(\n db,\n repo.id,\n await parseHandlerRegistrations(repo.absolute_path, file)\n );\n insertBindings(\n db,\n repo.id,\n await parseServiceBindings(repo.absolute_path, file)\n );\n insertCalls(\n db,\n repo.id,\n await parseOutboundCalls(repo.absolute_path, file)\n );\n }\n } catch (error) {\n diagnostics += 1;\n db.prepare(\n 'INSERT INTO diagnostics(repo_id,severity,code,message,source_file) VALUES(?,?,?,?,?)'\n ).run(repo.id, 'warning', 'parse_failed', errorMessage(error), file);\n }\n }\n db.prepare(\n 'UPDATE repositories SET last_indexed_at=?, index_status=?, error_count=? WHERE id=?'\n ).run(\n new Date().toISOString(),\n diagnostics ? 'partial' : 'indexed',\n diagnostics,\n repo.id\n );\n return { fileCount: files, diagnosticCount: diagnostics };\n}\n\nasync function findSourceFiles(root: string): Promise<string[]> {\n const out: string[] = [];\n async function walk(dir: string, prefix = ''): Promise<void> {\n const entries = await fs\n .readdir(dir, { withFileTypes: true })\n .catch(() => []);\n for (const e of entries) {\n const rel = prefix ? `${prefix}/${e.name}` : e.name;\n if (e.isDirectory()) {\n if (\n !['node_modules', 'dist', 'gen', 'coverage', '.git'].includes(e.name)\n )\n await walk(path.join(dir, e.name), rel);\n } else if (/\\.(cds|ts|js)$/.test(e.name)) out.push(rel);\n }\n }\n await walk(root);\n return out.sort();\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { sha256File } from '../utils/hashing.js';\nimport { normalizePath } from '../utils/path-utils.js';\nimport type { Db } from '../db/connection.js';\nexport async function recordFile(\n db: Db,\n repoId: number,\n repoPath: string,\n relativeFile: string\n): Promise<void> {\n const abs = path.join(repoPath, relativeFile);\n const stat = await fs.stat(abs);\n const hash = await sha256File(abs);\n db.prepare(\n 'INSERT INTO files(repo_id,relative_path,extension,sha256,size_bytes,last_indexed_at) VALUES(?,?,?,?,?,?) ON CONFLICT(repo_id,relative_path) DO UPDATE SET sha256=excluded.sha256,size_bytes=excluded.size_bytes,last_indexed_at=excluded.last_indexed_at'\n ).run(\n repoId,\n normalizePath(relativeFile),\n path.extname(relativeFile),\n hash,\n stat.size,\n new Date().toISOString()\n );\n}\n","import { createHash } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nexport async function sha256File(filePath: string): Promise<string> {\n return createHash('sha256')\n .update(await readFile(filePath))\n .digest('hex');\n}\nexport function sha256Text(text: string): string {\n return createHash('sha256').update(text).digest('hex');\n}\n","export interface DiagnosticInput {\n severity: 'info' | 'warning' | 'error';\n code: string;\n message: string;\n sourceFile?: string;\n sourceLine?: number;\n}\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","import type { Db } from '../db/connection.js';\nimport { listRepositories, repoByName } from '../db/repositories.js';\nimport { indexRepository } from './repository-indexer.js';\nexport async function indexWorkspace(\n db: Db,\n workspaceId: number,\n options: { repo?: string; force: boolean }\n): Promise<{ repoCount: number; fileCount: number; diagnosticCount: number }> {\n const started = new Date().toISOString();\n const repos = options.repo\n ? [repoByName(db, options.repo)].filter((r) => r !== undefined)\n : listRepositories(db);\n const runId = Number(\n db\n .prepare(\n 'INSERT INTO index_runs(workspace_id,started_at,status,repo_count,file_count,diagnostic_count) VALUES(?,?,?,?,?,?) RETURNING id'\n )\n .get(workspaceId, started, 'running', repos.length, 0, 0)?.id\n );\n let fileCount = 0;\n let diagnosticCount = 0;\n for (const repo of repos) {\n const result = await indexRepository(db, repo, options.force);\n fileCount += result.fileCount;\n diagnosticCount += result.diagnosticCount;\n }\n db.prepare(\n 'UPDATE index_runs SET finished_at=?, status=?, file_count=?, diagnostic_count=? WHERE id=?'\n ).run(\n new Date().toISOString(),\n diagnosticCount ? 'partial' : 'success',\n fileCount,\n diagnosticCount,\n runId\n );\n return { repoCount: repos.length, fileCount, diagnosticCount };\n}\n","import type { TraceStart } from '../types.js';\nexport function parseVars(\n values: string[] | undefined\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const value of values ?? []) {\n const [key, ...rest] = value.split('=');\n if (key && rest.length > 0) out[key] = rest.join('=');\n }\n return out;\n}\nexport function startLabel(start: TraceStart): string {\n return [\n start.repo,\n start.servicePath,\n start.operation ?? start.operationPath ?? start.handler\n ]\n .filter(Boolean)\n .join(' ');\n}\n","import type { TraceResult } from '../types.js';\nimport { startLabel } from '../trace/selectors.js';\nexport function renderTraceTable(trace: TraceResult): string {\n const lines = [\n `Start: ${startLabel(trace.start)}`,\n '',\n 'Step Type From To Evidence'\n ];\n for (const e of trace.edges)\n lines.push(\n `${String(e.step).padEnd(5)} ${e.type.padEnd(20)} ${e.from.slice(0, 34).padEnd(35)} ${e.to.slice(0, 35).padEnd(36)} ${String(e.evidence.file ?? '')}:${String(e.evidence.line ?? '')}`\n );\n return `${lines.join('\\n')}\\n`;\n}\n","import type { TraceResult } from '../types.js';\nexport function renderJson(value: unknown): string {\n return `${JSON.stringify(value, null, 2)}\\n`;\n}\nexport function renderTraceJson(trace: TraceResult): string {\n return renderJson(trace);\n}\n","import type { TraceResult } from '../types.js';\nfunction safe(value: string): string {\n return value.replace(/[^\\w-]/g, '_').slice(0, 60);\n}\nexport function renderMermaid(trace: TraceResult): string {\n const lines = ['flowchart TD'];\n for (const e of trace.edges)\n lines.push(\n ` ${safe(e.from)}[\"${e.from}\"] -->|${e.type}| ${safe(e.to)}[\"${e.to}\"]`\n );\n return `${lines.join('\\n')}\\n`;\n}\n"],"mappings":"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","names":["path","fs","fs","path","fs","path","fs","path","fs","path","fs","path","path","fs","fs","path","trace","trace","trace","fs","path"]}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/discovery/discover-repositories.ts","../src/utils/path-utils.ts","../src/parsers/package-json-parser.ts","../src/parsers/cds-parser.ts","../src/parsers/decorator-parser.ts","../src/parsers/ts-project.ts","../src/parsers/handler-registration-parser.ts","../src/utils/redaction.ts","../src/parsers/outbound-call-parser.ts","../src/parsers/service-binding-parser.ts","../src/linker/dynamic-edge-resolver.ts","../src/linker/service-resolver.ts","../src/linker/helper-package-linker.ts","../src/linker/cross-repo-linker.ts","../src/trace/traversal.ts","../src/trace/trace-engine.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { DiscoveredRepository } from '../types.js';\nimport { relativePath } from '../utils/path-utils.js';\nexport async function discoverRepositories(\n rootPath: string,\n ignore: readonly string[]\n): Promise<DiscoveredRepository[]> {\n const root = path.resolve(rootPath);\n const ignored = new Set(ignore);\n const found: DiscoveredRepository[] = [];\n async function walk(dir: string): Promise<void> {\n const rel = relativePath(root, dir);\n if (rel !== '.' && rel.split('/').some((part) => ignored.has(part))) return;\n let entries: Array<{ name: string; isDirectory: () => boolean }>;\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n if (entries.some((e) => e.name === '.git' || e.name === '.git-fixture')) {\n found.push({\n name: path.basename(dir),\n absolutePath: dir,\n relativePath: relativePath(root, dir),\n isGitRepo: true\n });\n return;\n }\n for (const entry of entries)\n if (entry.isDirectory() && !ignore.includes(entry.name))\n await walk(path.join(dir, entry.name));\n }\n await walk(root);\n return found.sort((a, b) => a.relativePath.localeCompare(b.relativePath));\n}\n","import path from 'node:path';\nexport function normalizePath(value: string): string {\n return value.split(path.sep).join('/');\n}\nexport function relativePath(root: string, value: string): string {\n return normalizePath(path.relative(root, value) || '.');\n}\nexport function ensureLeadingSlash(value: string): string {\n return value.startsWith('/') ? value : `/${value}`;\n}\nexport function stripQuotes(value: string): string {\n return value.replace(/^['\"`]|['\"`]$/g, '');\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { CdsRequire, PackageFacts } from '../types.js';\nfunction recordOfString(value: unknown): Record<string, string> {\n if (!value || typeof value !== 'object') return {};\n return Object.fromEntries(\n Object.entries(value).filter(([, v]) => typeof v === 'string')\n ) as Record<string, string>;\n}\nfunction readRequires(cds: unknown): CdsRequire[] {\n const requires =\n cds && typeof cds === 'object' && 'requires' in cds\n ? (cds as { requires?: unknown }).requires\n : undefined;\n if (!requires || typeof requires !== 'object') return [];\n return Object.entries(requires).flatMap(([alias, raw]) => {\n if (!raw || typeof raw !== 'object') return [];\n const obj = raw as Record<string, unknown>;\n const credentials =\n obj.credentials && typeof obj.credentials === 'object'\n ? (obj.credentials as Record<string, unknown>)\n : {};\n return [\n {\n alias,\n kind: typeof obj.kind === 'string' ? obj.kind : undefined,\n model: typeof obj.model === 'string' ? obj.model : undefined,\n destination:\n typeof credentials.destination === 'string'\n ? credentials.destination\n : undefined,\n servicePath:\n typeof credentials.path === 'string' ? credentials.path : undefined,\n requestTimeout:\n typeof credentials.requestTimeout === 'number'\n ? credentials.requestTimeout\n : undefined,\n rawJson: JSON.stringify(raw)\n }\n ];\n });\n}\nexport async function parsePackageJson(\n repoPath: string\n): Promise<PackageFacts> {\n try {\n const raw = await fs.readFile(path.join(repoPath, 'package.json'), 'utf8');\n const json = JSON.parse(raw) as Record<string, unknown>;\n return {\n packageName: typeof json.name === 'string' ? json.name : undefined,\n packageVersion:\n typeof json.version === 'string' ? json.version : undefined,\n dependencies: {\n ...recordOfString(json.dependencies),\n ...recordOfString(json.devDependencies)\n },\n cdsRequires: readRequires(json.cds),\n scripts: recordOfString(json.scripts)\n };\n } catch {\n return { dependencies: {}, cdsRequires: [], scripts: {} };\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { CdsServiceFact } from '../types.js';\nimport { ensureLeadingSlash, normalizePath } from '../utils/path-utils.js';\nfunction lineOf(text: string, index: number): number {\n return text.slice(0, index).split('\\n').length;\n}\nfunction pathAnno(prefix: string): string | undefined {\n return /@\\s*\\(?\\s*path\\s*:\\s*['\"]([^'\"]+)['\"]\\s*\\)?/.exec(prefix)?.[1];\n}\nexport async function parseCdsFile(\n repoPath: string,\n filePath: string\n): Promise<CdsServiceFact[]> {\n const absolute = path.join(repoPath, filePath);\n const text = await fs.readFile(absolute, 'utf8');\n const namespace = /namespace\\s+([\\w.]+)\\s*;/.exec(text)?.[1];\n const services: CdsServiceFact[] = [];\n const serviceRegex =\n /((?:@\\s*\\(?\\s*path\\s*:\\s*['\"][^'\"]+['\"]\\s*\\)?\\s*)?)(extend\\s+)?service\\s+(\\w+)\\s*(?:@\\s*\\(?\\s*path\\s*:\\s*['\"]([^'\"]+)['\"]\\s*\\)?\\s*)?\\{/g;\n let match: RegExpExecArray | null;\n while ((match = serviceRegex.exec(text))) {\n const serviceName = match[3] ?? 'UnknownService';\n const start = match.index + match[0].length;\n let depth = 1;\n let end = start;\n for (; end < text.length; end += 1) {\n const c = text[end];\n if (c === '{') depth += 1;\n if (c === '}') depth -= 1;\n if (depth === 0) break;\n }\n const body = text.slice(start, end);\n const servicePath = ensureLeadingSlash(\n match[4] ?? pathAnno(match[1] ?? '') ?? serviceName\n );\n const ops = [\n ...body.matchAll(\n /\\b(action|function|event)\\s+(\\w+)\\s*(?:\\(([^)]*)\\))?\\s*(?:returns\\s+([^;{]+))?/g\n )\n ].map((m) => ({\n operationType: (m[1] as 'action' | 'function' | 'event') ?? 'action',\n operationName: m[2] ?? 'unknown',\n operationPath: ensureLeadingSlash(m[2] ?? 'unknown'),\n paramsJson: JSON.stringify(\n (m[3] ?? '')\n .split(',')\n .map((p) => p.trim())\n .filter(Boolean)\n ),\n returnType: m[4]?.trim(),\n sourceFile: normalizePath(filePath),\n sourceLine: lineOf(text, start + (m.index ?? 0))\n }));\n services.push({\n namespace,\n serviceName,\n qualifiedName: namespace ? `${namespace}.${serviceName}` : serviceName,\n servicePath,\n isExtend: Boolean(match[2]),\n sourceFile: normalizePath(filePath),\n sourceLine: lineOf(text, match.index),\n operations: ops\n });\n serviceRegex.lastIndex = end;\n }\n return services;\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport ts from 'typescript';\nimport type { HandlerClassFact } from '../types.js';\nimport { createSourceFile } from './ts-project.js';\nimport { normalizePath, stripQuotes } from '../utils/path-utils.js';\nfunction line(sf: ts.SourceFile, pos: number): number {\n return sf.getLineAndCharacterOfPosition(pos).line + 1;\n}\nfunction decs(node: ts.Node): ts.Decorator[] {\n return ts.canHaveDecorators(node) ? [...(ts.getDecorators(node) ?? [])] : [];\n}\nfunction callName(d: ts.Decorator): string {\n const e = d.expression;\n return ts.isCallExpression(e) ? e.expression.getText() : e.getText();\n}\nfunction firstArg(d: ts.Decorator): string {\n const e = d.expression;\n return ts.isCallExpression(e) && e.arguments[0]\n ? e.arguments[0].getText()\n : '';\n}\nexport async function parseDecorators(\n repoPath: string,\n filePath: string\n): Promise<HandlerClassFact[]> {\n const text = await fs.readFile(path.join(repoPath, filePath), 'utf8');\n const sf = createSourceFile(filePath, text);\n const constants = new Map<string, string>();\n const handlers: HandlerClassFact[] = [];\n function visit(node: ts.Node): void {\n if (\n ts.isVariableDeclaration(node) &&\n ts.isIdentifier(node.name) &&\n node.initializer &&\n ts.isStringLiteralLike(node.initializer)\n )\n constants.set(node.name.text, node.initializer.text);\n if (ts.isClassDeclaration(node)) {\n const className = node.name?.text ?? 'AnonymousHandler';\n const hasHandler = decs(node).some((d) => callName(d) === 'Handler');\n const methods = node.members.filter(ts.isMethodDeclaration).flatMap((m) =>\n decs(m)\n .filter((d) =>\n ['Func', 'Action', 'On', 'Event'].includes(callName(d))\n )\n .map((d) => {\n const raw = firstArg(d);\n const value =\n raw.startsWith('\"') || raw.startsWith(\"'\") || raw.startsWith('`')\n ? stripQuotes(raw)\n : (constants.get(raw) ??\n (raw.endsWith('.name') ? raw.split('.').at(-2) : undefined));\n return {\n methodName: m.name.getText(),\n decoratorKind: callName(d),\n decoratorValue: value,\n decoratorRawExpression: raw,\n sourceFile: normalizePath(filePath),\n sourceLine: line(sf, m.getStart())\n };\n })\n );\n if (hasHandler || methods.length > 0)\n handlers.push({\n className,\n sourceFile: normalizePath(filePath),\n sourceLine: line(sf, node.getStart()),\n methods\n });\n }\n ts.forEachChild(node, visit);\n }\n visit(sf);\n return handlers;\n}\n","import ts from 'typescript';\nexport function createSourceFile(\n filePath: string,\n text: string\n): ts.SourceFile {\n return ts.createSourceFile(\n filePath,\n text,\n ts.ScriptTarget.Latest,\n true,\n filePath.endsWith('.js') ? ts.ScriptKind.JS : ts.ScriptKind.TS\n );\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { HandlerRegistrationFact } from '../types.js';\nimport { normalizePath } from '../utils/path-utils.js';\nfunction lineOf(text: string, idx: number): number {\n return text.slice(0, idx).split('\\n').length;\n}\nexport async function parseHandlerRegistrations(\n repoPath: string,\n filePath: string\n): Promise<HandlerRegistrationFact[]> {\n const text = await fs.readFile(path.join(repoPath, filePath), 'utf8');\n const out: HandlerRegistrationFact[] = [];\n for (const m of text.matchAll(\n /createCombinedHandler\\s*\\(|srv\\.prepend\\s*\\(|cds\\.serve\\s*\\(/g\n ))\n out.push({\n registrationFile: normalizePath(filePath),\n registrationLine: lineOf(text, m.index ?? 0),\n registrationKind: m[0].startsWith('cds')\n ? 'cds.serve'\n : 'combined-handler',\n confidence: 0.8\n });\n for (const m of text.matchAll(\n /(?:const|export\\s+const)\\s+handlers\\s*=\\s*\\[([\\s\\S]*?)\\]/g\n ))\n for (const c of (m[1] ?? '').matchAll(/\\b(\\w+Handler)\\b/g))\n out.push({\n className: c[1],\n registrationFile: normalizePath(filePath),\n registrationLine: lineOf(text, (m.index ?? 0) + (c.index ?? 0)),\n registrationKind: 'handler-array',\n confidence: 0.9\n });\n return out;\n}\n","const SENSITIVE = /authorization|cookie|token|secret|password|key|credential/i;\nexport function redactText(text: string): string {\n return text.replace(\n /(authorization|cookie|token|secret|password|key|credential)\\s*[:=]\\s*(['\"`]?)[^,'\"`}\\s]+\\2/gi,\n '$1: [REDACTED]'\n );\n}\nexport function redactValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(redactValue);\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value))\n out[k] = SENSITIVE.test(k) ? '[REDACTED]' : redactValue(v);\n return out;\n }\n return typeof value === 'string' ? redactText(value) : value;\n}\nexport function summarizeExpression(text: string): string {\n return redactText(text).slice(0, 240);\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { OutboundCallFact } from '../types.js';\nimport { normalizePath, stripQuotes } from '../utils/path-utils.js';\nimport { summarizeExpression } from '../utils/redaction.js';\nfunction lineOf(text: string, idx: number): number {\n return text.slice(0, idx).split('\\n').length;\n}\nfunction firstArg(body: string, key: string): string | undefined {\n return new RegExp(`${key}\\\\s*:\\\\s*([^,}\\\\n]+)`).exec(body)?.[1]?.trim();\n}\nexport async function parseOutboundCalls(\n repoPath: string,\n filePath: string\n): Promise<OutboundCallFact[]> {\n const text = await fs.readFile(path.join(repoPath, filePath), 'utf8');\n const out: OutboundCallFact[] = [];\n for (const m of text.matchAll(/(\\w+)\\.send\\s*\\(\\s*\\{([\\s\\S]*?)\\}\\s*\\)/g)) {\n const body = m[2] ?? '';\n const query = firstArg(body, 'query');\n const op = firstArg(body, 'path');\n out.push({\n callType: query ? 'remote_query' : 'remote_action',\n serviceVariableName: m[1],\n method: stripQuotes(firstArg(body, 'method') ?? 'POST'),\n operationPathExpr: op ? stripQuotes(op) : undefined,\n queryEntity: /SELECT\\.from\\((\\w+)\\)/.exec(query ?? '')?.[1],\n payloadSummary: summarizeExpression(body),\n sourceFile: normalizePath(filePath),\n sourceLine: lineOf(text, m.index ?? 0),\n confidence: op || query ? 0.8 : 0.4\n });\n }\n for (const m of text.matchAll(/cds\\.run\\s*\\(([\\s\\S]*?)\\)/g))\n out.push({\n callType: 'local_db_query',\n queryEntity: /(?:SELECT\\.from|INSERT\\.into)\\((\\w+)\\)/.exec(\n m[1] ?? ''\n )?.[1],\n payloadSummary: summarizeExpression(m[1] ?? ''),\n sourceFile: normalizePath(filePath),\n sourceLine: lineOf(text, m.index ?? 0),\n confidence: 0.85\n });\n for (const m of text.matchAll(\n /(\\w+)\\.(emit|publish|on)\\s*\\(\\s*(['\"`])([^'\"`]+)\\3/g\n ))\n out.push({\n callType: m[2] === 'on' ? 'async_subscribe' : 'async_emit',\n serviceVariableName: m[1],\n eventNameExpr: m[4],\n sourceFile: normalizePath(filePath),\n sourceLine: lineOf(text, m.index ?? 0),\n confidence: 0.8\n });\n for (const m of text.matchAll(\n /(?:axios\\s*\\(|executeHttpRequest\\s*\\(|useOrFetchDestination\\s*\\()([\\s\\S]*?)\\)/g\n ))\n out.push({\n callType: 'external_http',\n payloadSummary: summarizeExpression(m[1] ?? ''),\n sourceFile: normalizePath(filePath),\n sourceLine: lineOf(text, m.index ?? 0),\n confidence: 0.7,\n unresolvedReason:\n 'External HTTP destination is outside indexed CAP services'\n });\n for (const m of text.matchAll(\n /cds\\.services(?:\\[['\"]([^'\"]+)['\"]\\]|\\.(\\w+))\\.(\\w+)\\s*\\(/g\n ))\n out.push({\n callType: 'local_service_call',\n operationPathExpr: `/${m[3] ?? ''}`,\n payloadSummary: m[1] ?? m[2],\n sourceFile: normalizePath(filePath),\n sourceLine: lineOf(text, m.index ?? 0),\n confidence: 0.75\n });\n return out;\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { ServiceBindingFact } from '../types.js';\nimport { normalizePath, stripQuotes } from '../utils/path-utils.js';\nfunction lineOf(text: string, idx: number): number {\n return text.slice(0, idx).split('\\n').length;\n}\nfunction placeholders(value?: string): string[] {\n return [...(value ?? '').matchAll(/\\$\\{\\s*(\\w+)\\s*\\}/g)]\n .map((m) => m[1] ?? '')\n .filter(Boolean);\n}\nexport async function parseServiceBindings(\n repoPath: string,\n filePath: string\n): Promise<ServiceBindingFact[]> {\n const text = await fs.readFile(path.join(repoPath, filePath), 'utf8');\n const out: ServiceBindingFact[] = [];\n for (const m of text.matchAll(\n /(?:const|let|this\\.)\\s*(\\w+)\\s*=\\s*(?:await\\s*)?cds\\.connect\\.to\\((['\"`])([^'\"`]+)\\2\\)/g\n ))\n out.push({\n variableName: m[1] ?? 'service',\n alias: m[3],\n isDynamic: false,\n placeholders: [],\n sourceFile: normalizePath(filePath),\n sourceLine: lineOf(text, m.index ?? 0)\n });\n for (const m of text.matchAll(\n /(?:const|let|this\\.)\\s*(\\w+)\\s*=\\s*(?:await\\s*)?cds\\.connect\\.to\\(\\{([\\s\\S]*?)\\}\\s*\\)/g\n )) {\n const body = m[2] ?? '';\n const destination = /destination\\s*:\\s*([^,\\n]+)/.exec(body)?.[1];\n const servicePath = /path\\s*:\\s*([^,\\n]+)/.exec(body)?.[1];\n const dest = destination ? stripQuotes(destination.trim()) : undefined;\n const svc = servicePath ? stripQuotes(servicePath.trim()) : undefined;\n const ph = [...placeholders(dest), ...placeholders(svc)];\n out.push({\n variableName: m[1] ?? 'service',\n destinationExpr: dest,\n servicePathExpr: svc,\n isDynamic: ph.length > 0,\n placeholders: ph,\n sourceFile: normalizePath(filePath),\n sourceLine: lineOf(text, m.index ?? 0)\n });\n }\n for (const m of text.matchAll(\n /function\\s+(\\w+)\\s*\\([^)]*\\)\\s*\\{[\\s\\S]*?return\\s+cds\\.connect\\.to\\((['\"])([^'\"]+)\\2\\)/g\n ))\n out.push({\n variableName: m[1] ?? 'connect',\n alias: m[3],\n isDynamic: false,\n placeholders: [],\n sourceFile: normalizePath(filePath),\n sourceLine: lineOf(text, m.index ?? 0)\n });\n return out;\n}\n","export function applyVariables(\n template: string | undefined,\n vars: Record<string, string>\n): string | undefined {\n if (!template) return undefined;\n return template.replace(\n /\\$\\{\\s*(\\w+)\\s*\\}/g,\n (_m, key: string) => vars[key] ?? `\\${${key}}`\n );\n}\nexport function extractPlaceholders(template: string | undefined): string[] {\n return [...(template ?? '').matchAll(/\\$\\{\\s*(\\w+)\\s*\\}/g)]\n .map((m) => m[1] ?? '')\n .filter(Boolean);\n}\n","import type { Db } from '../db/connection.js';\nexport interface OperationTarget {\n operationId: number;\n repoName: string;\n servicePath: string;\n operationPath: string;\n operationName: string;\n sourceFile: string;\n sourceLine: number;\n}\nexport function findOperation(\n db: Db,\n servicePath: string | undefined,\n operationPath: string | undefined,\n workspaceId?: number\n): OperationTarget | undefined {\n if (!operationPath) return undefined;\n const row = db\n .prepare(\n `SELECT o.id operationId,r.name repoName,s.service_path servicePath,o.operation_path operationPath,o.operation_name operationName,o.source_file sourceFile,o.source_line sourceLine\n FROM cds_operations o\n JOIN cds_services s ON s.id=o.service_id\n JOIN repositories r ON r.id=s.repo_id\n WHERE (? IS NULL OR r.workspace_id=?)\n AND (? IS NULL OR s.service_path=?)\n AND (o.operation_path=? OR o.operation_name=?)\n ORDER BY CASE WHEN s.service_path=? THEN 0 ELSE 1 END\n LIMIT 1`\n )\n .get(\n workspaceId,\n workspaceId,\n servicePath,\n servicePath,\n operationPath,\n operationPath.replace(/^\\//, ''),\n servicePath\n ) as OperationTarget | undefined;\n return row;\n}\n","import type { Db } from '../db/connection.js';\nexport function linkHelperPackages(db: Db, workspaceId: number): number {\n const repos = db\n .prepare(\n 'SELECT id,name,dependencies_json FROM repositories WHERE workspace_id=?'\n )\n .all(workspaceId) as Array<{\n id: number;\n name: string;\n dependencies_json: string;\n }>;\n let count = 0;\n for (const repo of repos) {\n const deps = JSON.parse(repo.dependencies_json) as Record<string, string>;\n for (const dep of Object.keys(deps)) {\n const helper = repos.find((r) => r.name === dep || dep.endsWith(r.name));\n if (helper) {\n db.prepare(\n 'INSERT INTO graph_edges(workspace_id,edge_type,from_kind,from_id,to_kind,to_id,confidence,evidence_json,is_dynamic) VALUES(?,?,?,?,?,?,?,?,?)'\n ).run(\n workspaceId,\n 'REPO_IMPORTS_HELPER_PACKAGE',\n 'repo',\n String(repo.id),\n 'repo',\n String(helper.id),\n 0.9,\n JSON.stringify({ dependency: dep }),\n 0\n );\n count += 1;\n }\n }\n }\n return count;\n}\n","import type { Db } from '../db/connection.js';\nimport { applyVariables } from './dynamic-edge-resolver.js';\nimport { findOperation } from './service-resolver.js';\nimport { linkHelperPackages } from './helper-package-linker.js';\nexport function linkWorkspace(\n db: Db,\n workspaceId: number,\n vars: Record<string, string> = {}\n): { edgeCount: number; unresolvedCount: number } {\n db.prepare('DELETE FROM graph_edges WHERE workspace_id=?').run(workspaceId);\n let edges = linkHelperPackages(db, workspaceId);\n let unresolved = 0;\n const calls = db\n .prepare(\n `SELECT c.*,r.name repoName,b.alias,b.destination_expr destinationExpr,b.service_path_expr servicePathExpr,b.is_dynamic isDynamic,b.placeholders_json placeholdersJson,req.service_path requireServicePath,req.destination requireDestination FROM outbound_calls c JOIN repositories r ON r.id=c.repo_id LEFT JOIN service_bindings b ON b.id=c.service_binding_id LEFT JOIN cds_requires req ON req.repo_id=c.repo_id AND req.alias=b.alias WHERE r.workspace_id=?`\n )\n .all(workspaceId) as Array<Record<string, unknown>>;\n for (const call of calls) {\n const callType = String(call.call_type);\n const op = applyVariables(String(call.operation_path_expr ?? ''), vars);\n const servicePath = applyVariables(\n (call.servicePathExpr as string | undefined) ??\n (call.requireServicePath as string | undefined),\n vars\n );\n const target = callType.startsWith('remote')\n ? findOperation(db, servicePath, op, workspaceId)\n : undefined;\n const evidence = {\n sourceFile: call.source_file,\n sourceLine: call.source_line,\n serviceAlias: call.alias,\n destination: call.destinationExpr ?? call.requireDestination,\n servicePath,\n operationPath: op,\n targetRepo: target?.repoName,\n targetOperation: target?.operationName\n };\n if (target) {\n db.prepare(\n 'INSERT INTO graph_edges(workspace_id,edge_type,from_kind,from_id,to_kind,to_id,confidence,evidence_json,is_dynamic) VALUES(?,?,?,?,?,?,?,?,?)'\n ).run(\n workspaceId,\n 'REMOTE_CALL_RESOLVES_TO_OPERATION',\n 'call',\n String(call.id),\n 'operation',\n String(target.operationId),\n call.isDynamic ? 0.6 : 0.9,\n JSON.stringify(evidence),\n call.isDynamic ? 1 : 0\n );\n edges += 1;\n } else {\n const edgeType =\n callType === 'local_db_query'\n ? 'HANDLER_RUNS_DB_QUERY'\n : callType === 'external_http'\n ? 'HANDLER_CALLS_EXTERNAL_HTTP'\n : callType === 'async_emit'\n ? 'HANDLER_EMITS_EVENT'\n : callType === 'async_subscribe'\n ? 'EVENT_CONSUMED_BY_HANDLER'\n : call.isDynamic\n ? 'DYNAMIC_EDGE_CANDIDATE'\n : 'UNRESOLVED_EDGE';\n db.prepare(\n 'INSERT INTO graph_edges(workspace_id,edge_type,from_kind,from_id,to_kind,to_id,confidence,evidence_json,is_dynamic,unresolved_reason) VALUES(?,?,?,?,?,?,?,?,?,?)'\n ).run(\n workspaceId,\n edgeType,\n 'call',\n String(call.id),\n callType.startsWith('async_') ? 'event' : 'external',\n String(call.event_name_expr ?? call.query_entity ?? op ?? call.id),\n Number(call.confidence ?? 0.2),\n JSON.stringify(evidence),\n call.isDynamic ? 1 : 0,\n String(call.unresolved_reason ?? 'No indexed target operation matched')\n );\n edges += 1;\n unresolved += edgeType === 'UNRESOLVED_EDGE' ? 1 : 0;\n }\n }\n return { edgeCount: edges, unresolvedCount: unresolved };\n}\n","import type { TraceEdge } from '../types.js';\nexport function limitDepth(edges: TraceEdge[], depth: number): TraceEdge[] {\n return edges.filter((edge) => edge.step <= depth);\n}\n","import type { Db } from '../db/connection.js';\nimport type { TraceResult, TraceStart } from '../types.js';\nimport { applyVariables } from '../linker/dynamic-edge-resolver.js';\nimport { limitDepth } from './traversal.js';\n\ninterface RepoRef {\n id: number;\n name: string;\n}\n\ninterface StartScope {\n repo?: RepoRef;\n sourceFiles?: Set<string>;\n selectorMatched: boolean;\n}\n\nfunction normalizeOperation(value: string | undefined): string | undefined {\n if (!value) return undefined;\n return value.startsWith('/') ? value.slice(1) : value;\n}\n\nfunction positiveDepth(value: number): number {\n return Number.isFinite(value) && value > 0 ? Math.floor(value) : 25;\n}\n\nfunction sourceFilesForStart(\n db: Db,\n repoId: number | undefined,\n start: TraceStart\n): Set<string> | undefined {\n const handler = start.handler;\n const operation = normalizeOperation(start.operation ?? start.operationPath);\n if (!handler && !operation) return undefined;\n\n const rows = db\n .prepare(\n `SELECT DISTINCT hc.source_file sourceFile\n FROM handler_classes hc\n LEFT JOIN handler_methods hm ON hm.handler_class_id=hc.id\n WHERE (? IS NULL OR hc.repo_id=?)\n AND (? IS NULL OR hc.class_name=? OR hm.method_name=?)\n AND (? IS NULL OR hm.decorator_value=? OR hm.method_name=?)`\n )\n .all(\n repoId,\n repoId,\n handler,\n handler,\n handler,\n operation,\n operation,\n operation\n ) as Array<{ sourceFile?: string }>;\n\n if (rows.length === 0) return undefined;\n return new Set(\n rows.map((row) => row.sourceFile).filter(Boolean) as string[]\n );\n}\n\nfunction startScope(db: Db, start: TraceStart): StartScope {\n const repo = start.repo\n ? (db\n .prepare(\n 'SELECT id,name FROM repositories WHERE name=? OR package_name=?'\n )\n .get(start.repo, start.repo) as RepoRef | undefined)\n : undefined;\n if (start.repo && !repo)\n return {\n repo,\n selectorMatched: false\n };\n const sourceFiles = sourceFilesForStart(db, repo?.id, start);\n const hasSelector = Boolean(\n start.handler ?? start.operation ?? start.operationPath\n );\n return {\n repo,\n sourceFiles,\n selectorMatched: !hasSelector || sourceFiles !== undefined\n };\n}\n\nexport function trace(\n db: Db,\n start: TraceStart,\n options: {\n depth: number;\n vars?: Record<string, string>;\n includeExternal?: boolean;\n includeDb?: boolean;\n includeAsync?: boolean;\n }\n): TraceResult {\n const scope = startScope(db, start);\n const calls = db\n .prepare(\n `SELECT c.*,r.name repoName,b.alias,b.destination_expr destinationExpr,b.service_path_expr servicePathExpr,b.is_dynamic isDynamic,req.service_path requireServicePath,req.destination requireDestination FROM outbound_calls c JOIN repositories r ON r.id=c.repo_id LEFT JOIN service_bindings b ON b.id=c.service_binding_id LEFT JOIN cds_requires req ON req.repo_id=c.repo_id AND req.alias=b.alias WHERE (? IS NULL OR c.repo_id=?) ORDER BY c.source_file,c.source_line`\n )\n .all(scope.repo?.id, scope.repo?.id) as Array<Record<string, unknown>>;\n const vars = options.vars ?? {};\n const filtered = calls.filter((c) => {\n if (!scope.selectorMatched) return false;\n if (scope.sourceFiles && !scope.sourceFiles.has(String(c.source_file)))\n return false;\n const type = String(c.call_type);\n if (!options.includeDb && type === 'local_db_query') return false;\n if (!options.includeExternal && type === 'external_http') return false;\n if (!options.includeAsync && type.startsWith('async_')) return false;\n return true;\n });\n const edges = filtered.map((c, index) => {\n const operation = applyVariables(\n c.operation_path_expr as string | undefined,\n vars\n );\n const servicePath = applyVariables(\n (c.servicePathExpr as string | undefined) ??\n (c.requireServicePath as string | undefined),\n vars\n );\n const type = String(c.call_type);\n const to =\n type === 'local_db_query'\n ? `Entity: ${String(c.query_entity ?? 'unknown')}`\n : type === 'async_emit'\n ? `Topic: ${String(c.event_name_expr ?? 'unknown')}`\n : type === 'async_subscribe'\n ? `Topic: ${String(c.event_name_expr ?? 'unknown')}`\n : type === 'external_http'\n ? 'External HTTP destination'\n : `${servicePath ?? ''}${operation ?? ''}` ||\n String(c.event_name_expr ?? 'unknown');\n return {\n step: index + 1,\n type: c.isDynamic ? 'dynamic_action' : type,\n from: `${String(c.repoName)}:${String(c.source_file)}`,\n to,\n evidence: {\n file: c.source_file,\n line: c.source_line,\n alias: c.alias,\n destination: c.destinationExpr ?? c.requireDestination,\n servicePath,\n operationPath: operation,\n method: c.method,\n payloadSummary: c.payload_summary\n },\n confidence: Number(c.confidence ?? 0.5),\n unresolvedReason: c.unresolved_reason as string | undefined\n };\n });\n const diagnostics = db\n .prepare(\n 'SELECT severity,code,message,source_file sourceFile,source_line sourceLine FROM diagnostics WHERE (? IS NULL OR repo_id=?)'\n )\n .all(scope.repo?.id, scope.repo?.id) as Array<Record<string, unknown>>;\n if (!scope.selectorMatched)\n diagnostics.unshift({\n severity: 'warning',\n code: 'trace_start_not_found',\n message: 'No handler source matched the requested trace start selector'\n });\n return {\n start,\n nodes: [],\n edges: limitDepth(edges, positiveDepth(options.depth)),\n diagnostics\n };\n}\n"],"mappings":"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","names":["path","path","fs","path","fs","path","path","fs","fs","path","ts","ts","fs","path","fs","path","lineOf","fs","path","fs","path","lineOf","firstArg","fs","path","fs","path","lineOf","fs","path"]}
|