sourcesailor
Version:
A CLI tool for analyzing and documenting codebases
110 lines (109 loc) • 4.64 kB
JavaScript
import fs from 'fs';
import path from "path";
import ignore from 'ignore';
const pathsToIgnore = ['.git'];
const extentionsToSkipContent = ['.jpg', '.jpeg', '.png', '.gif', '.ico', '.mp4', '.svg', '.pdf', '.doc', '.db', '.sqlite', '.docx', '.xls', '.xlsx'];
export async function getDirStructure(dirPath, otherIgnorePaths, verbose = false) {
const isGitingore = fs.existsSync(`${dirPath}/.gitignore`);
if (isGitingore) {
const gitIgnore = fs.readFileSync(`${dirPath}/.gitignore`, 'utf8')
.split('\n')
.filter(line => !line.startsWith('#') && line !== '');
pathsToIgnore.push(...gitIgnore);
}
if (verbose) {
console.log({ otherIgnorePaths });
}
if (otherIgnorePaths.length > 0) {
pathsToIgnore.push(...otherIgnorePaths);
}
if (verbose) {
console.log(pathsToIgnore);
}
const ig = ignore.default({
allowRelativePaths: true,
ignoreCase: true,
ignorecase: true,
}).add(pathsToIgnore);
function matchesWildcard(path, pattern) {
const regexPattern = pattern.replace(/\*/g, '.*').replace(/\?/g, '.');
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(path);
}
function customIgnores(path) {
if (path.includes('node_modules'))
return true;
return pathsToIgnore.some(ignoredPath => {
if (ignoredPath.includes('*') || ignoredPath.includes('?')) {
return matchesWildcard(path, ignoredPath);
}
if (ignoredPath.endsWith('/')) {
return path.startsWith(ignoredPath) || path === ignoredPath.slice(0, -1);
}
return path === ignoredPath || path.startsWith(`${ignoredPath}/`);
});
}
function getJsonFromDirectory(dirPath) {
const rootFile = dirPath.split('/').pop() || '';
const dirPathWithoutRootDir = dirPath.substring(dirPath.indexOf('/') + 1);
if (verbose)
console.log({ dirPath, dirPathWithoutRootDir, ignoresRoot: customIgnores(dirPathWithoutRootDir), ignores: customIgnores(dirPath) });
if (customIgnores(`${rootFile}/`) || customIgnores(rootFile) || customIgnores(`${dirPathWithoutRootDir}/`)) {
return undefined;
}
const result = {
name: rootFile,
content: null,
children: []
};
// Check if the current directory is 'node_modules'
if (rootFile === 'node_modules') {
return undefined;
}
// Check for .gitignore in the current directory
const gitignorePath = path.join(dirPath, '.gitignore');
if (fs.existsSync(gitignorePath)) {
const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
ig.add(gitignoreContent.split('\n')); // Add new rules to the ignore object
}
const files = fs.readdirSync(dirPath);
for (const file of files) {
const fullPath = `${dirPath}/${file}`;
const relativePath = path.relative(dirPath, fullPath);
if (verbose)
console.log({
file, fullPath, relativePath, ignores: customIgnores(relativePath),
fullPathIg: customIgnores(fullPath), dirPathIg: customIgnores(dirPath),
fileIg: customIgnores(file)
});
if (customIgnores(relativePath)) {
if (verbose)
console.log({ ignored: file });
continue;
}
const isDirectory = fs.statSync(fullPath).isDirectory();
if (isDirectory) {
const dirChildren = getJsonFromDirectory(fullPath);
if (dirChildren && dirChildren.children && dirChildren.children.length > 0) {
result.children?.push(dirChildren);
}
}
else {
const fileExtension = path.extname(file).toLowerCase();
if (extentionsToSkipContent.includes(fileExtension)) {
result.children?.push({ name: file, content: null });
}
else {
const fileContent = fs.readFileSync(fullPath, 'utf8');
result.children?.push({ name: file, content: fileContent });
}
}
}
return result.children && result.children.length > 0 ? result : undefined;
}
const dirToReturn = getJsonFromDirectory(dirPath);
if (verbose) {
console.log({ dirs: JSON.stringify(dirToReturn) });
}
return dirToReturn;
}