scai
Version:
> AI-powered CLI tool for commit messages **and** pull request reviews — using local models.
73 lines (72 loc) • 3.17 kB
JavaScript
import { Project, SyntaxKind } from 'ts-morph';
import path from 'path';
import { generateEmbedding } from '../../lib/generateEmbedding.js';
import { log } from '../../utils/log.js';
import { getDbForRepo } from '../client.js';
import { markFileAsSkippedTemplate, markFileAsExtractedTemplate, markFileAsFailedTemplate } from '../sqlTemplates.js';
export async function extractFromTS(filePath, content, fileId) {
const db = getDbForRepo();
try {
const project = new Project({ useInMemoryFileSystem: true });
const sourceFile = project.createSourceFile(filePath, content);
const functions = [];
const allFuncs = [
...sourceFile.getDescendantsOfKind(SyntaxKind.FunctionDeclaration),
...sourceFile.getDescendantsOfKind(SyntaxKind.FunctionExpression),
...sourceFile.getDescendantsOfKind(SyntaxKind.ArrowFunction),
];
for (const fn of allFuncs) {
const name = fn.getSymbol()?.getName() ?? `${path.basename(filePath)}:<anon>`;
const start = fn.getStartLineNumber();
const end = fn.getEndLineNumber();
const code = fn.getText();
functions.push({ name, start_line: start, end_line: end, content: code });
}
if (functions.length === 0) {
log(`⚠️ No functions found in TS file: ${filePath}`);
db.prepare(markFileAsSkippedTemplate).run({ id: fileId });
return false;
}
log(`🔍 Found ${functions.length} TypeScript functions in ${filePath}`);
for (const fn of functions) {
const embedding = await generateEmbedding(fn.content);
const result = db.prepare(`
INSERT INTO functions (
file_id, name, start_line, end_line, content, embedding, lang
) VALUES (
@file_id, @name, @start_line, @end_line, @content, @embedding, @lang
)
`).run({
file_id: fileId,
name: fn.name,
start_line: fn.start_line,
end_line: fn.end_line,
content: fn.content,
embedding: JSON.stringify(embedding),
lang: 'ts'
});
const callerId = result.lastInsertRowid;
// Simplified call detection (no walking for now)
const callMatches = fn.content.matchAll(/(\w+)\s*\(/g);
for (const match of callMatches) {
db.prepare(`
INSERT INTO function_calls (caller_id, callee_name)
VALUES (@caller_id, @callee_name)
`).run({
caller_id: callerId,
callee_name: match[1],
});
}
log(`📌 Indexed TS function: ${fn.name}`);
}
db.prepare(markFileAsExtractedTemplate).run({ id: fileId });
log(`✅ Marked TS functions as extracted for ${filePath}`);
return true;
}
catch (err) {
log(`❌ Failed to extract from TS file: ${filePath}`);
log(` ↳ ${String(err.message)}`);
db.prepare(markFileAsFailedTemplate).run({ id: fileId });
return false;
}
}