diff --git a/.gitignore b/.gitignore index e643c91..4076ee1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /dist/ prompt.md todo +.toak-ignore diff --git a/src/MarkdownGenerator.ts b/src/MarkdownGenerator.ts index 398854b..c05e683 100644 --- a/src/MarkdownGenerator.ts +++ b/src/MarkdownGenerator.ts @@ -64,6 +64,7 @@ export class MarkdownGenerator { private async initialize(): Promise { if (!this.initialized) { await this.loadNestedIgnoreFiles(); + await this.updateGitignore(); this.initialized = true; } } @@ -260,6 +261,58 @@ export class MarkdownGenerator { } } + async updateGitignore(): Promise { + const gitignorePath = path.join(this.dir, '.gitignore'); + try { + let content = ''; + try { + content = await readFile(gitignorePath, 'utf-8'); + } catch (error: any) { + if (error.code === 'ENOENT') { + // .gitignore doesn't exist, create it + if (this.verbose) { + console.log('File not found, creating a \'.gitignore\' file.'); + } + content = ''; + } else { + throw error; + } + } + + // Check if entries already exist + const lines = content.split('\n'); + const needsPromptMd = !lines.some(line => line.trim() === 'prompt.md'); + const needsToakIgnore = !lines.some(line => line.trim() === '.toak-ignore'); + + // Add entries if needed + if (needsPromptMd || needsToakIgnore) { + if (this.verbose) { + console.log('Updating .gitignore with prompt.md and .toak-ignore'); + } + + let newContent = content; + if (newContent && !newContent.endsWith('\n')) { + newContent += '\n'; + } + + if (needsPromptMd) { + newContent += 'prompt.md\n'; + } + + if (needsToakIgnore) { + newContent += '.toak-ignore\n'; + } + + await writeFile(gitignorePath, newContent); + } + } catch (error) { + if (this.verbose) { + console.error('Error updating .gitignore:', error); + } + throw error; + } + } + /** * Creates a complete markdown document combining code documentation and todos. * @async diff --git a/test/core.test.ts b/test/core.test.ts index 4c4071d..d7d4c57 100644 --- a/test/core.test.ts +++ b/test/core.test.ts @@ -50,8 +50,8 @@ const a = 1;`; it('should trim whitespace and empty lines', () => { const code = `const a = 1; - - + + const b = 2; `; const expected = `const a = 1; const b = 2;`; @@ -381,6 +381,88 @@ const a = 1; }); }); + describe('updateGitignore', () => { + it('should update .gitignore with prompt.md and .toak-ignore on first run', async () => { + const gitignorePath = path.join('.', '.gitignore'); + + // Mock readFile to simulate .gitignore exists but doesn't have the entries + const readFileSpy = spyOn(fs, 'readFile').mockResolvedValue('node_modules\ndist\n'); + + // Spy on fs.writeFile + const writeFileSpy = spyOn(fs, 'writeFile').mockResolvedValue(undefined); + + // Call the method + await markdownGenerator.updateGitignore(); + + // Verify readFile was called + expect(readFileSpy).toHaveBeenCalledWith(gitignorePath, 'utf-8'); + + // Verify writeFile was called with correct content + expect(writeFileSpy).toHaveBeenCalledWith( + gitignorePath, + 'node_modules\ndist\nprompt.md\n.toak-ignore\n' + ); + + // Restore the original implementations + readFileSpy.mockRestore(); + writeFileSpy.mockRestore(); + }); + + it('should not update .gitignore if entries already exist', async () => { + const gitignorePath = path.join('.', '.gitignore'); + + // Mock readFile to simulate .gitignore already has the entries + const readFileSpy = spyOn(fs, 'readFile') + .mockResolvedValue('node_modules\ndist\nprompt.md\n.toak-ignore\n'); + + // Spy on fs.writeFile + const writeFileSpy = spyOn(fs, 'writeFile').mockResolvedValue(undefined); + + // Call the method + await markdownGenerator.updateGitignore(); + + // Verify readFile was called + expect(readFileSpy).toHaveBeenCalledWith(gitignorePath, 'utf-8'); + + // Verify writeFile was NOT called + expect(writeFileSpy).not.toHaveBeenCalled(); + + // Restore the original implementations + readFileSpy.mockRestore(); + writeFileSpy.mockRestore(); + }); + + it('should create .gitignore if it does not exist', async () => { + const gitignorePath = path.join('.', '.gitignore'); + + // Mock readFile to throw ENOENT error + const readFileSpy = spyOn(fs, 'readFile').mockImplementation(() => { + const error: any = new Error('File not found'); + error.code = 'ENOENT'; + return Promise.reject(error); + }); + + // Spy on fs.writeFile + const writeFileSpy = spyOn(fs, 'writeFile').mockResolvedValue(undefined); + + // Call the method + await markdownGenerator.updateGitignore(); + + // Verify readFile was called + expect(readFileSpy).toHaveBeenCalledWith(gitignorePath, 'utf-8'); + + // Verify writeFile was called with correct content + expect(writeFileSpy).toHaveBeenCalledWith( + gitignorePath, + 'prompt.md\n.toak-ignore\n' + ); + + // Restore the original implementations + readFileSpy.mockRestore(); + writeFileSpy.mockRestore(); + }); + }); + describe('createMarkdownDocument', () => { it('should create markdown document successfully', async () => { const mockContent = '# Project Files\n\n## test.txt\n~~~\ntest\n~~~\n\n';