-
Notifications
You must be signed in to change notification settings - Fork 3
MVP Implementation
Garot Conklin edited this page Jan 17, 2025
·
1 revision
The implementation follows a modular structure with clear separation of concerns:
// Extension entry point
export function activate(context: vscode.ExtensionContext): void {
// Register commands
const commands = [
vscode.commands.registerCommand('cursor-rules-dynamic.showStatus', showStatus),
vscode.commands.registerCommand('cursor-rules-dynamic.convertToJson', convertToJson),
vscode.commands.registerCommand('cursor-rules-dynamic.browseTemplates', browseTemplates),
vscode.commands.registerCommand('cursor-rules-dynamic.scanProject', scanProject)
];
// Add to subscriptions
context.subscriptions.push(...commands);
}export class TextConverter {
public static async convertToJson(content: string): Promise<CursorRules> {
return {
version: '1.0.0',
languages: {
default: {
rules: [{
id: 'rule-1',
level: 'error',
description: content.trim()
}]
}
}
};
}
public static async convertFile(uri: vscode.Uri): Promise<vscode.Uri> {
// Implementation details
}
}export class TemplateService {
private readonly rulesPath: string;
constructor(extensionPath: string) {
this.rulesPath = path.join(extensionPath, 'rules');
}
public async getTemplateCategories(): Promise<string[]> {
// Implementation details
}
public async getTemplatesInCategory(category: string): Promise<RuleTemplate[]> {
// Implementation details
}
}async function analyzeProject(): Promise<ProjectAnalysis> {
const workspaceFiles = await vscode.workspace.findFiles('**/*');
const analysis: ProjectAnalysis = {
codePatterns: {
naming: { variables: [], functions: [], classes: [] },
structure: { directories: [], fileTypes: [] },
conventions: { formatting: [], documentation: [], testing: [] }
},
timestamp: new Date().toISOString()
};
// Implementation details
return analysis;
}function analyzeNamingConventions(content: string, analysis: ProjectAnalysis): void {
// Function names
const functionMatches = content.match(/function\s+([a-zA-Z][a-zA-Z0-9]*)/g);
if (functionMatches) {
functionMatches.forEach(match => {
const name = match.replace('function ', '');
if (!analysis.codePatterns.naming.functions.includes(name)) {
analysis.codePatterns.naming.functions.push(name);
}
});
}
// Class names
const classMatches = content.match(/class\s+([a-zA-Z][a-zA-Z0-9]*)/g);
if (classMatches) {
classMatches.forEach(match => {
const name = match.replace('class ', '');
if (!analysis.codePatterns.naming.classes.includes(name)) {
analysis.codePatterns.naming.classes.push(name);
}
});
}
}const watcher = vscode.workspace.createFileSystemWatcher('**/*');
watcher.onDidChange((uri) => {
try {
const message = `Processing file: ${uri.fsPath}`;
console.log(message);
void vscode.window.showInformationMessage(message);
updateStatusBar(statusBarItem);
} catch (error) {
console.error('Error processing file:', error);
}
});public async saveTemplateToWorkspace(template: RuleTemplate, targetUri?: vscode.Uri): Promise<void> {
try {
if (!targetUri) {
const workspaceFolders = vscode.workspace.workspaceFolders;
if (!workspaceFolders) {
throw new Error('No workspace folder found');
}
targetUri = vscode.Uri.joinPath(workspaceFolders[0].uri, '.cursorrules');
}
// Convert template content
const convertedContent = this.convertTemplateContent(template.content);
// Write content
await vscode.workspace.fs.writeFile(targetUri, Buffer.from(convertedContent, 'utf-8'));
// Show success message
void vscode.window.showInformationMessage('Template saved successfully');
// Open the file
const document = await vscode.workspace.openTextDocument(targetUri);
await vscode.window.showTextDocument(document);
} catch (error) {
throw new Error(`Failed to save template: ${error instanceof Error ? error.message : String(error)}`);
}
}suite('TextConverter Test Suite', () => {
test('should convert text to JSON format', async () => {
const content = 'Test content';
const result = await TextConverter.convertToJson(content);
assert.ok(result.languages.default, 'Should have default rules');
assert.strictEqual(result.languages.default.rules[0].description, content, 'Should preserve content');
});
});suite('Extension Test Suite', () => {
test('Extension activation should register commands', async () => {
await new Promise(resolve => setTimeout(resolve, 1000));
const commands = await vscode.commands.getCommands();
assert.ok(
commands.includes('cursor-rules-dynamic.showStatus'),
'Show status command should be registered'
);
assert.ok(
commands.includes('cursor-rules-dynamic.scanProject'),
'Scan project command should be registered'
);
});
});try {
await operation();
} catch (error) {
void vscode.window.showErrorMessage(
`Failed to perform operation: ${error instanceof Error ? error.message : String(error)}`,
{ modal: true }
);
}// Debounced file watcher
let timeout: NodeJS.Timeout | undefined;
watcher.onDidChange((uri) => {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
processFileChange(uri);
}, 500);
});private static async ensureBackupDirectory(workspaceUri: vscode.Uri): Promise<vscode.Uri> {
const backupDirUri = vscode.Uri.joinPath(workspaceUri, '.cursorrules-backup');
try {
await vscode.workspace.fs.stat(backupDirUri);
} catch {
await vscode.workspace.fs.createDirectory(backupDirUri);
}
return backupDirUri;
}/**
* Converts markdown-formatted .cursorrules content to JSON format
* @param content The markdown content to convert
* @returns The converted JSON content as a CursorRules object
*/
public static convertToJson(content: string): Promise<CursorRules> {
// Implementation
}