Add .toak-ignore to .gitignore and implement updateGitignore method

Enhanced MarkdownGenerator to update .gitignore programmatically when required, introduced tests for updateGitignore functionality, and ensured `.toak-ignore` is added.
This commit is contained in:
geoffsee
2025-06-13 13:02:44 -04:00
committed by Geoff Seemueller
parent 6f9d37a292
commit c282d80fe0
3 changed files with 138 additions and 2 deletions

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@
/dist/
prompt.md
todo
.toak-ignore

View File

@@ -64,6 +64,7 @@ export class MarkdownGenerator {
private async initialize(): Promise<void> {
if (!this.initialized) {
await this.loadNestedIgnoreFiles();
await this.updateGitignore();
this.initialized = true;
}
}
@@ -260,6 +261,58 @@ export class MarkdownGenerator {
}
}
async updateGitignore(): Promise<void> {
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

View File

@@ -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';