symref
Version:
Static code checker for AI code agents (Windsurf, Cline, etc.)
118 lines • 5.28 kB
JavaScript
import { SymbolReferenceAnalyzer } from '../../analyzer/SymbolReferenceAnalyzer';
import * as fs from 'fs';
import * as path from 'path';
/**
* シンボルの呼び出し元を分析するコマンド
*/
export class CallersCommand {
/**
* コマンドを実行する
* @param symbol 分析対象のシンボル
* @param options コマンドオプション
*/
static execute(symbol, options) {
try {
const analyzerOptions = {
basePath: options.dir,
tsConfigPath: options.project,
includePatterns: options.include ? options.include.split(',') : undefined,
excludePatterns: options.exclude ? options.exclude.split(',') : undefined
};
// アナライザーを初期化
const analyzer = new SymbolReferenceAnalyzer(analyzerOptions);
console.log(`\n=== '${symbol}' の呼び出し元を分析中... ===\n`);
// 呼び出しグラフを構築
const nodeCount = analyzer.buildCallGraph();
console.log(`${nodeCount} 個のシンボルを分析しました。\n`);
// 呼び出し元を分析
const result = analyzer.findCallers(symbol);
// 結果を表示
CallersCommand.displayResult(result, symbol);
// Mermaidファイルを生成(オプション)
if (options.mermaid) {
CallersCommand.generateMermaidFile(result, options.mermaid);
}
}
catch (error) {
console.error(`エラー: ${error.message}`);
process.exit(1);
}
}
/**
* 分析結果を表示
* @param result 分析結果
* @param symbol 対象シンボル
*/
static displayResult(result, symbol) {
if (result.paths.length === 0) {
console.log(`'${symbol}' の呼び出し元は見つかりませんでした。`);
return;
}
console.log(`${result.paths.length} 個の呼び出し経路が見つかりました:\n`);
// 各経路を表示
result.paths.forEach((path, index) => {
console.log(`経路 ${index + 1}:`);
// 経路上のノードを表示(逆順)
for (let i = 0; i < path.nodes.length; i++) {
const node = path.nodes[i];
const location = node.location;
const locationStr = location.filePath && location.line > 0
? `${location.filePath}:${location.line}`
: '不明な位置';
// 最初のノード(エントリーポイント)
if (i === 0) {
console.log(`${node.symbol} (${locationStr})`);
}
// 中間ノードと最後のノード
else {
// エッジ情報を表示
const edge = path.edges[i - 1];
const edgeLocation = edge?.location;
const callLocationStr = edgeLocation?.filePath && edgeLocation?.line > 0
? `${edgeLocation.filePath}:${edgeLocation.line}`
: locationStr;
console.log(` ↑ called by (${callLocationStr})`);
console.log(`${node.symbol} (${locationStr})`);
}
}
console.log('\n');
});
}
/**
* Mermaidファイルを生成
* @param result 分析結果
* @param outputPath 出力パス
*/
static generateMermaidFile(result, outputPath) {
if (!result.graphMermaidFormat) {
console.warn('警告: Mermaidグラフデータを生成できませんでした。');
return;
}
try {
// 出力ディレクトリを.symbolsに変更
const outputDir = '.symbols';
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const timestamp = `${year}${month}${day}_${hours}${minutes}`;
const safeBaseName = outputPath.replace(/[^a-zA-Z0-9]/g, '_');
const fileName = `${safeBaseName}_${timestamp}.md`;
const resolvedPath = path.resolve(process.cwd(), outputDir, fileName);
// 出力ディレクトリを確保
const dir = path.dirname(resolvedPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(resolvedPath, result.graphMermaidFormat);
console.log(`Mermaidグラフファイルを生成しました: ${resolvedPath}`);
console.log('可視化するには: GitHubで表示するか、https://mermaid.live で開いてください');
}
catch (error) {
console.error(`Mermaidファイルの生成中にエラーが発生しました: ${error.message}`);
}
}
}
//# sourceMappingURL=CallersCommand.js.map