sourcesailor
Version:
A CLI tool for analyzing and documenting codebases
177 lines (176 loc) • 7.32 kB
JavaScript
// @ts-nocheck
import { describe, it, expect, vi } from 'vitest';
import { getDirStructure } from '../directoryProcessor.mjs';
import fs from 'fs';
import ignore from 'ignore';
vi.mock('fs');
vi.mock('ignore');
describe('directoryProcessor', () => {
describe('getDirStructure', () => {
it('should return undefined for ignored directories', async () => {
const mockStructure = {
'root': {
'node_modules': {
'package': {
'index.js': 'module.exports = {};',
},
},
},
};
setupMocks(mockStructure);
const result = await getDirStructure('root/node_modules', []);
expect(result).toBeUndefined();
});
it('should handle .gitignore file correctly', async () => {
const mockStructure = {
'root': {
'.gitignore': 'node_modules\n*.log',
'file1.txt': 'content of file1',
'file2.js': 'console.log("Hello");',
'debug.log': 'debug info',
'node_modules': {
'package': {
'index.js': 'module.exports = {};',
},
},
},
};
setupMocks(mockStructure);
const result = await getDirStructure('root', [], true);
expect(result?.children).not.toContainEqual(expect.objectContaining({ name: 'node_modules' }));
expect(result?.children).not.toContainEqual(expect.objectContaining({ name: 'debug.log' }));
expect(result?.children).toContainEqual(expect.objectContaining({ name: '.gitignore' }));
expect(result?.children).toContainEqual(expect.objectContaining({ name: 'file1.txt' }));
expect(result?.children).toContainEqual(expect.objectContaining({ name: 'file2.js' }));
expect(result?.children).toHaveLength(3);
});
it('should handle additional ignore paths', async () => {
const mockStructure = {
'root': {
'.gitignore': 'node_modules\n*.log',
'file1.txt': 'content of file1',
'file2.js': 'console.log("Hello");',
'file3.js': 'console.log("Hello");',
'ignored_dir': {
'ignored_file.txt': 'should be ignored',
},
},
};
setupMocks(mockStructure);
const result = await getDirStructure('root', ['ignored_dir/', 'file3.js'], true);
expect(result?.children).not.toContainEqual(expect.objectContaining({ name: 'ignored_dir' }));
expect(result?.children).not.toContainEqual(expect.objectContaining({ name: 'file3.js' }));
expect(result?.children).toContainEqual(expect.objectContaining({ name: 'file1.txt' }));
expect(result?.children).toContainEqual(expect.objectContaining({ name: 'file2.js' }));
expect(result?.children).toContainEqual(expect.objectContaining({ name: '.gitignore' }));
});
it('should process directory structure correctly', async () => {
const mockStructure = {
'root': {
'file1.txt': 'content of file1',
'file2.js': 'console.log("Hello");',
'subdir': {
'subfile1.txt': 'content of subfile1',
},
},
};
setupMocks(mockStructure);
const result = await getDirStructure('root', []);
expect(result).toEqual(expect.objectContaining({
name: 'root',
content: null,
children: expect.arrayContaining([
expect.objectContaining({ name: 'file1.txt', content: 'content of file1' }),
expect.objectContaining({ name: 'file2.js', content: 'console.log("Hello");' }),
expect.objectContaining({
name: 'subdir',
content: null,
children: expect.arrayContaining([
expect.objectContaining({ name: 'subfile1.txt', content: 'content of subfile1' })
])
})
])
}));
});
// Add more tests here...
});
});
function setupMocks(mockStructure) {
vi.mocked(fs.existsSync).mockImplementation((path) => {
return pathExists(mockStructure, path);
});
vi.mocked(fs.readFileSync).mockImplementation((path) => {
return getFileContent(mockStructure, path);
});
vi.mocked(fs.readdirSync).mockImplementation((path) => {
return getDirectoryContents(mockStructure, path);
});
vi.mocked(fs.statSync).mockImplementation((path) => {
return {
isDirectory: () => isDirectory(mockStructure, path),
};
});
vi.mocked(ignore.default).mockImplementation(() => {
const ignoredPaths = new Set();
ignoredPaths.add('node_modules'); // Always ignore node_modules
const ig = {
add: (patterns) => {
if (typeof patterns === 'string') {
patterns = patterns.split('\n');
}
patterns.forEach(pattern => {
pattern = pattern.trim();
if (pattern && !pattern.startsWith('#')) {
ignoredPaths.add(pattern);
}
});
return ig;
},
ignores: (path) => {
if (path.includes('node_modules'))
return true; // Explicitly ignore any path containing node_modules
return Array.from(ignoredPaths).some(ignoredPath => {
if (ignoredPath.endsWith('/')) {
return path.startsWith(ignoredPath) || path === ignoredPath.slice(0, -1);
}
return path === ignoredPath || path.startsWith(`${ignoredPath}/`);
});
}
};
return ig;
});
}
function pathExists(structure, path) {
const parts = path.toString().split('/').filter(p => p !== '');
let current = structure;
for (const part of parts) {
if (current[part] === undefined)
return false;
current = current[part];
}
return true;
}
function getFileContent(structure, path) {
const parts = path.split('/').filter(p => p !== '');
let current = structure;
for (const part of parts) {
current = current[part];
}
return current;
}
function getDirectoryContents(structure, path) {
const parts = path.split('/').filter(p => p !== '');
let current = structure;
for (const part of parts) {
current = current[part];
}
return Object.keys(current);
}
function isDirectory(structure, path) {
const parts = path.split('/').filter(p => p !== '');
let current = structure;
for (const part of parts) {
current = current[part];
}
return typeof current === 'object';
}