Files
ai-context-generator-cli/.ai-context-generator-cli/src/generators/contextGenerator.ts
7000pctAUTO e9453c3956
Some checks failed
CI / test (push) Has been cancelled
fix: resolve CI test failures
2026-02-01 01:45:30 +00:00

165 lines
4.6 KiB
TypeScript

import * as path from 'path';
import yaml from 'js-yaml';
import {
ProjectInfo,
ContextConfig,
TemplateData,
FileInfo,
ConventionInfo,
} from '../types';
import { ProjectTypeDetector } from '../analyzers/projectTypeDetector';
import { DependencyAnalyzer } from '../analyzers/dependencyAnalyzer';
import { ConventionExtractor } from '../analyzers/conventionExtractor';
import { FileUtils } from '../utils/fileUtils';
import { ConfigLoader } from '../config/configLoader';
export class ContextGenerator {
private projectTypeDetector: ProjectTypeDetector;
private dependencyAnalyzer: DependencyAnalyzer;
private conventionExtractor: ConventionExtractor;
private fileUtils: FileUtils;
constructor() {
this.projectTypeDetector = new ProjectTypeDetector();
this.dependencyAnalyzer = new DependencyAnalyzer();
this.conventionExtractor = new ConventionExtractor();
this.fileUtils = FileUtils.getInstance();
}
async generate(
dir: string,
config?: ContextConfig
): Promise<ProjectInfo> {
const resolvedDir = this.fileUtils.resolveDirectory(dir);
const contextConfig = config ?? await ConfigLoader.load();
if (contextConfig.respectGitignore) {
await this.fileUtils.loadGitignore(resolvedDir);
this.fileUtils.addCustomPatterns(contextConfig.excludes);
}
const files = await this.fileUtils.getFiles(
resolvedDir,
contextConfig.includes,
contextConfig.excludes
);
const projectType = await this.projectTypeDetector.detect(resolvedDir);
const dependencies = await this.dependencyAnalyzer.analyze(
resolvedDir,
contextConfig.includeDevDependencies
);
let conventions: ConventionInfo | null = null;
if (contextConfig.analyzeConventions) {
conventions = await this.conventionExtractor.extract(resolvedDir, files) ?? null;
}
return {
projectType,
language: projectType.primaryLanguage,
framework: projectType.frameworks[0] || null,
dependencies,
conventions,
fileCount: files.length,
analysisDate: new Date().toISOString(),
};
}
async generateWithFiles(
dir: string,
config?: ContextConfig
): Promise<TemplateData> {
const projectInfo = await this.generate(dir, config);
const contextConfig = config ?? await ConfigLoader.load();
const resolvedDir = this.fileUtils.resolveDirectory(dir);
const files = await this.fileUtils.getFiles(
resolvedDir,
contextConfig.includes,
contextConfig.excludes
);
const fileInfos: FileInfo[] = [];
for (const file of files) {
try {
const size = await this.fileUtils.getFileSize(file);
fileInfos.push({
path: path.relative(resolvedDir, file),
size,
type: this.fileUtils.getFileExtension(file),
language: this.detectLanguage(file),
});
} catch {
// Skip files that can't be read
}
}
return {
projectInfo,
files: fileInfos,
config: contextConfig,
generatedAt: new Date().toISOString(),
};
}
async generateJson(dir: string, config?: ContextConfig): Promise<string> {
const data = await this.generateWithFiles(dir, config);
return JSON.stringify(data, null, 2);
}
async generateYaml(dir: string, config?: ContextConfig): Promise<string> {
const data = await this.generateWithFiles(dir, config);
return yaml.dump(data, { indent: 2, lineWidth: -1 });
}
async saveContext(
dir: string,
outputPath: string,
format: 'json' | 'yaml',
config?: ContextConfig
): Promise<void> {
let content: string;
let finalPath = outputPath;
if (format === 'json') {
content = await this.generateJson(dir, config);
if (!finalPath.endsWith('.json')) {
finalPath = `${finalPath}.json`;
}
} else {
content = await this.generateYaml(dir, config);
if (!finalPath.endsWith('.yaml') && !finalPath.endsWith('.yml')) {
finalPath = `${finalPath}.yaml`;
}
}
await this.fileUtils.writeFile(finalPath, content);
}
private detectLanguage(filePath: string): string {
const ext = this.fileUtils.getFileExtension(filePath);
const languageMap: Record<string, string> = {
'.ts': 'TypeScript',
'.tsx': 'TypeScript',
'.js': 'JavaScript',
'.jsx': 'JavaScript',
'.py': 'Python',
'.go': 'Go',
'.rs': 'Rust',
'.java': 'Java',
'.c': 'C',
'.cpp': 'C++',
'.h': 'C',
'.hpp': 'C++',
'.cs': 'C#',
'.rb': 'Ruby',
'.php': 'PHP',
'.swift': 'Swift',
};
return languageMap[ext] || 'Unknown';
}
}