import { BaseFormatter } from '../classes.baseformatter.js'; import type { IPlannedChange } from '../interfaces.format.js'; import * as plugins from '../mod.plugins.js'; import * as paths from '../../paths.js'; import { logger } from '../../gitzone.logging.js'; export class GitignoreFormatter extends BaseFormatter { get name(): string { return 'gitignore'; } /** * Read the standard gitignore template from the asset file, * stripping the YAML frontmatter. */ private async getStandardTemplate(): Promise { const templatePath = plugins.path.join(paths.templatesDir, 'gitignore', '_gitignore'); const raw = (await plugins.smartfs .file(templatePath) .encoding('utf8') .read()) as string; // Strip YAML frontmatter (---\n...\n---) const frontmatterEnd = raw.indexOf('---', 3); if (frontmatterEnd !== -1) { return raw.slice(frontmatterEnd + 3).trimStart(); } return raw; } async analyze(): Promise { const changes: IPlannedChange[] = []; const gitignorePath = '.gitignore'; const standardTemplate = await this.getStandardTemplate(); // Check if file exists and extract custom content let customContent = ''; const exists = await plugins.smartfs.file(gitignorePath).exists(); if (exists) { const existingContent = (await plugins.smartfs .file(gitignorePath) .encoding('utf8') .read()) as string; // Extract custom section content const customMarkers = ['#------# custom', '# custom']; for (const marker of customMarkers) { const splitResult = existingContent.split(marker); if (splitResult.length > 1) { customContent = splitResult[1].trim(); break; } } } // Compute new content let newContent = standardTemplate; if (customContent) { newContent = standardTemplate + '\n' + customContent + '\n'; } else { newContent = standardTemplate + '\n'; } // Read current content to compare let currentContent = ''; if (exists) { currentContent = (await plugins.smartfs .file(gitignorePath) .encoding('utf8') .read()) as string; } if (!exists) { changes.push({ type: 'create', path: gitignorePath, module: this.name, description: 'Create .gitignore', content: newContent, }); } else if (newContent !== currentContent) { changes.push({ type: 'modify', path: gitignorePath, module: this.name, description: 'Update .gitignore (preserving custom section)', content: newContent, }); } return changes; } async applyChange(change: IPlannedChange): Promise { if (!change.content) return; if (change.type === 'create') { await this.createFile(change.path, change.content); logger.log('info', 'Created .gitignore'); } else if (change.type === 'modify') { await this.modifyFile(change.path, change.content); logger.log('info', 'Updated .gitignore (preserved custom section)'); } } }