project-structure-cli
Version:
It is a lightweight app to create project structure so that it can be used optimally with LLMs or in creating README
97 lines (80 loc) • 3.47 kB
JavaScript
const fs = require("fs");
const path = require("path");
const OUTPUT_FILE = "project-structure.txt";
/**
* Generates the directory structure as a formatted tree.
* @param {string} dir - Directory path to scan.
* @param {string} prefix - Prefix for indentation.
* @param {Set<string>} ignorePaths - Paths to ignore.
* @param {Set<string>} includePaths - Paths to explicitly include.
* @returns {string} - Directory structure.
*/
function generateStructure(dir, prefix = "", ignorePaths = new Set(), includePaths = new Set()) {
let structure = "";
const files = fs.readdirSync(dir)
.filter(file => {
const fullPath = path.join(dir, file);
const isHidden = file.startsWith("."); // Check if it's a dotfile
return (
(!ignorePaths.has(file) || includePaths.has(file)) && // Ignore only if not explicitly included
(!isHidden || includePaths.has(file)) // Allow hidden files if explicitly included
);
});
files.forEach((file, index) => {
const fullPath = path.join(dir, file);
const isLast = index === files.length - 1;
const newPrefix = prefix + (isLast ? " " : "| ");
structure += `${prefix}${isLast ? "└── " : "├── "}${file}\n`;
if (fs.statSync(fullPath).isDirectory()) {
structure += generateStructure(fullPath, newPrefix, ignorePaths, includePaths);
}
});
return structure;
}
/**
* Parses command-line arguments for --include and --ignore.
* @returns {Object} - Contains ignorePaths and includePaths.
*/
function parseArgs() {
const args = process.argv.slice(2);
const ignorePaths = new Set([ "node_modules" ,".git"]); // Default ignored paths
const includePaths = new Set();
let includeIndex = args.indexOf("--include");
let ignoreIndex = args.indexOf("--exclude");
if (includeIndex !== -1) {
args.slice(includeIndex + 1).forEach(item => {
if (!item.startsWith("--")) {
includePaths.add(item);
ignorePaths.delete(item); // Ensure included items are not ignored
}
});
}
if (ignoreIndex !== -1) {
args.slice(ignoreIndex + 1).forEach(item => {
if (!item.startsWith("--") && !includePaths.has(item)) {
ignorePaths.add(item); // Add to ignore list only if not included
}
});
}
// If no `--exclude` or `--include` is present but arguments exist, treat them as excluded paths
if (includeIndex === -1 && ignoreIndex === -1 && args.length > 0) {
args.forEach(item => ignorePaths.add(item));
}
return { ignorePaths, includePaths };
}
/**
* Writes the project structure to a file.
* @param {Set<string>} ignorePaths - Set of paths to ignore.
* @param {Set<string>} includePaths - Set of paths to explicitly include.
*/
function saveStructureToFile(ignorePaths, includePaths) {
const projectRoot = process.cwd();
const structure = `${path.basename(projectRoot)}\n${generateStructure(projectRoot, "", ignorePaths, includePaths)}`;
fs.writeFileSync(path.join(projectRoot, OUTPUT_FILE), structure, "utf8");
console.log(`✅ Project structure saved to ${OUTPUT_FILE}`);
}
// Parse CLI arguments
const { ignorePaths, includePaths } = parseArgs();
// Run the function when the script is executed
saveStructureToFile(ignorePaths, includePaths);