print-project
Advanced tools
Comparing version 1.0.8 to 1.0.10
@@ -5,6 +5,41 @@ "use strict"; | ||
exports.defaultIgnorePatterns = [ | ||
"node_modules", "*.log", "dist", "coverage", "documentation", ".prettierrc", ".gitignore", "dist", | ||
"scripts", ".serverless", ".idea", ".git", ".DS_Store", ".husky", "package-lock.json", ".vscode", | ||
"*.env", "*.bak", "*.tmp", "*.swp", ".eslintcache", ".yarn", ".yarnrc", ".yarn.lock", | ||
".editorconfig", ".npmrc", ".babelrc", ".nyc_output", ".cache, project-print.txt", | ||
"node_modules", | ||
"*.log", | ||
"dist", | ||
"coverage", | ||
"documentation", | ||
".prettierrc", | ||
".gitignore", | ||
"scripts", | ||
".serverless", | ||
".idea", | ||
".git", | ||
".DS_Store", | ||
".husky", | ||
"package-lock.json", | ||
".vscode", | ||
"*.env", | ||
"*.bak", | ||
"*.tmp", | ||
"*.swp", | ||
".eslintcache", | ||
".yarn", | ||
".yarnrc", | ||
".yarn.lock", | ||
".editorconfig", | ||
".npmrc", | ||
".babelrc", | ||
".nyc_output", | ||
".cache", | ||
"project-print.txt", | ||
".eslintrc", | ||
".eslintrc.js", | ||
".eslintrc.json", | ||
".eslintrc.yml", | ||
".eslintrc.yaml", | ||
".npmignore", | ||
".babelrc.js", | ||
".babelrc.json", | ||
".babelrc.yml", | ||
".babelrc.yaml", | ||
]; |
@@ -35,24 +35,29 @@ #!/usr/bin/env node | ||
const program = new commander_1.Command(); | ||
program.argument("<startPath>", "Starting directory path").argument("[ignorePatterns]", "Comma-separated list of patterns to ignore").option("--ignore-default", "Use default ignore patterns").parse(process.argv); | ||
program | ||
.argument("<startPath>", "Starting directory path") | ||
.option("--ignore <patterns>", "Comma-separated list of patterns to ignore") | ||
.option("--include <patterns>", "Comma-separated list of patterns to include") | ||
.option("--ignore-default", "Use default ignore patterns") | ||
.parse(process.argv); | ||
const startPath = program.args[0] && path.resolve(program.args[0]); | ||
const userPatterns = program.args[1] ? program.args[1].split(",").filter(Boolean).map(pattern => pattern.trim()) : []; | ||
const useDefaultIgnore = program.opts().ignoreDefault; | ||
let patterns = useDefaultIgnore ? [...constants_1.defaultIgnorePatterns, ...userPatterns] : userPatterns; | ||
patterns.push("project-print.txt"); | ||
const options = program.opts(); | ||
const userIgnorePatterns = options.ignore ? options.ignore.split(",").filter(Boolean).map((pattern) => pattern.trim()) : []; | ||
const includePatterns = options.include ? options.include.split(",").filter(Boolean).map((pattern) => pattern.trim()) : []; | ||
const useDefaultIgnore = options.ignoreDefault; | ||
let ignorePatterns = useDefaultIgnore ? [...constants_1.defaultIgnorePatterns, ...userIgnorePatterns] : userIgnorePatterns; | ||
ignorePatterns.push("project-print.txt"); | ||
console.log("Start Path:", startPath); | ||
console.log("Patterns:", patterns); | ||
function isIgnored(filePath, patterns) { | ||
try { | ||
return patterns.some(pattern => { | ||
const parsedPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*"); | ||
const regex = new RegExp(parsedPattern); | ||
return regex.test(filePath); | ||
}); | ||
} | ||
catch (e) { | ||
console.error(`Failed to check if ignored: ${filePath}`, e); | ||
return false; | ||
} | ||
console.log("Ignore Patterns:", ignorePatterns); | ||
console.log("Include Patterns:", includePatterns); | ||
function matchesPattern(filePath, patterns) { | ||
return patterns.some(pattern => { | ||
const parsedPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*"); | ||
const regex = new RegExp(parsedPattern); | ||
return regex.test(filePath); | ||
}); | ||
} | ||
function readDirectory(dirPath, patterns = [], treeStructure = {}, currentPath = "") { | ||
function shouldIncludeFile(filePath, ignorePatterns, includePatterns) { | ||
return !matchesPattern(filePath, ignorePatterns) || matchesPattern(filePath, includePatterns); | ||
} | ||
function readDirectory(dirPath, ignorePatterns, includePatterns, treeStructure = {}, currentPath = "") { | ||
try { | ||
@@ -62,3 +67,3 @@ const dirents = fs.readdirSync(dirPath, { withFileTypes: true }); | ||
const fullPath = path.relative(process.cwd(), path.join(dirPath, dirent.name)).replace(/\\/g, "/"); | ||
if (isIgnored(fullPath, patterns)) { | ||
if (!shouldIncludeFile(fullPath, ignorePatterns, includePatterns)) { | ||
return; | ||
@@ -69,3 +74,3 @@ } | ||
treeStructure[relativePath] = {}; | ||
readDirectory(path.join(dirPath, dirent.name), patterns, treeStructure[relativePath], relativePath); | ||
readDirectory(path.join(dirPath, dirent.name), ignorePatterns, includePatterns, treeStructure[relativePath], relativePath); | ||
} | ||
@@ -99,6 +104,7 @@ else if (dirent.isFile()) { | ||
console.log(`Starting directory read from ${startPath}`); | ||
console.log(`Ignoring: ${patterns.join(", ")}`); | ||
console.log(`Ignoring: ${ignorePatterns.join(", ")}`); | ||
console.log(`Including: ${includePatterns.length > 0 ? includePatterns.join(", ") : "All files (except ignored)"}`); | ||
console.log(`Using default ignore: ${useDefaultIgnore}`); | ||
readDirectory(startPath, patterns, treeStructure); | ||
console.log("\nNon-ignored file structure:\n"); | ||
readDirectory(startPath, ignorePatterns, includePatterns, treeStructure); | ||
console.log("\nProcessed file structure:\n"); | ||
buildTreeStructure(treeStructure); | ||
@@ -105,0 +111,0 @@ console.log(treeStructureString); |
{ | ||
"name": "print-project", | ||
"version": "1.0.8", | ||
"version": "1.0.10", | ||
"description": "A simple CLI tool to print the project tree structure and file contents", | ||
@@ -18,3 +18,3 @@ "main": "dist/index.js", | ||
"build": "tsc", | ||
"start": "ts-node src/index.ts", | ||
"start": "ts-node src/index.ts . --ignore-default --include dist,src", | ||
"bump": "npm version patch", | ||
@@ -21,0 +21,0 @@ "package": "npm run build && npm run bump && npm publish" |
@@ -6,5 +6,9 @@ File structure: | ||
README.md | ||
dist | ||
dist/constants.d.ts | ||
dist/constants.js | ||
dist/index.d.ts | ||
dist/index.js | ||
jest.config.js | ||
package.json | ||
project-print.txt | ||
src | ||
@@ -354,396 +358,143 @@ src/constants.ts | ||
jest.config.js: | ||
module.exports = { | ||
preset: 'ts-jest', | ||
testEnvironment: 'node', | ||
}; | ||
dist/constants.d.ts: | ||
export declare const defaultIgnorePatterns: string[]; | ||
package.json: | ||
{ | ||
"name": "print-project", | ||
"version": "1.0.7", | ||
"description": "A simple CLI tool to print the project tree structure and file contents", | ||
"main": "dist/index.js", | ||
"bin": { | ||
"print-project": "./dist/index.js", | ||
"pprint": "./dist/index.js" | ||
}, | ||
"types": "dist/index.d.ts", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/nitaiaharoni1/print-project.git" | ||
}, | ||
"keywords": [], | ||
"scripts": { | ||
"build": "tsc", | ||
"start": "ts-node src/index.ts", | ||
"bump": "npm version patch", | ||
"package": "npm run build && npm run bump && npm publish" | ||
}, | ||
"author": "Nitai Aharoni", | ||
"license": "MIT", | ||
"dependencies": { | ||
"commander": "^12.1.0" | ||
}, | ||
"devDependencies": { | ||
"ts-node": "^10.9.2", | ||
"typescript": "^5.0.4" | ||
} | ||
} | ||
dist/constants.js: | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.defaultIgnorePatterns = void 0; | ||
exports.defaultIgnorePatterns = [ | ||
"node_modules", "*.log", "coverage", "documentation", ".prettierrc", ".gitignore", | ||
"scripts", ".serverless", ".idea", ".git", ".DS_Store", ".husky", "package-lock.json", ".vscode", | ||
"*.env", "*.bak", "*.tmp", "*.swp", ".eslintcache", ".yarn", ".yarnrc", ".yarn.lock", | ||
".editorconfig", ".npmrc", ".babelrc", ".nyc_output", ".cache, project-print.txt", | ||
]; | ||
project-print.txt: | ||
File structure: | ||
.eslintrc.json | ||
.npmignore | ||
LICENSE | ||
README.md | ||
jest.config.js | ||
package.json | ||
project-print.txt | ||
src | ||
src/constants.ts | ||
src/index.ts | ||
tsconfig.json | ||
dist/index.d.ts: | ||
#!/usr/bin/env node | ||
export {}; | ||
Project print: | ||
.eslintrc.json: | ||
{ | ||
"root": true, | ||
"env": { | ||
"browser": true, | ||
"es2021": true, | ||
"node": true | ||
}, | ||
"parserOptions": { | ||
"ecmaVersion": 6, | ||
"sourceType": "module", | ||
"project": "./tsconfig.json" | ||
}, | ||
"ignorePatterns": [ | ||
"node_modules/", | ||
"dist/", | ||
"build/", | ||
"coverage/", | ||
"public/" | ||
], | ||
"extends": [ | ||
"standard-with-typescript", | ||
"eslint:all", | ||
"prettier", | ||
"plugin:import/errors", | ||
"plugin:import/warnings", | ||
"plugin:import/typescript" | ||
], | ||
"plugins": [ | ||
"prettier", | ||
"sort-keys-fix", | ||
"sort-imports-es6-autofix" | ||
], | ||
"rules": { | ||
"line-comment-position": "off", | ||
"import/no-unresolved": "off", | ||
"no-return-await": "off", | ||
"@typescript-eslint/restrict-template-expressions": "off", | ||
"no-continue": "off", | ||
"max-params": [ | ||
"error", | ||
4 | ||
], | ||
"no-underscore-dangle": "off", | ||
"init-declarations": "off", | ||
"sort-keys-fix/sort-keys-fix": "error", | ||
"no-inline-comments": "off", | ||
"no-console": [ | ||
"error", | ||
{ | ||
"allow": [ | ||
"debug", | ||
"warn", | ||
"error" | ||
] | ||
} | ||
], | ||
"no-undefined": "off", | ||
"no-undef": "off", | ||
"@typescript-eslint/no-this-alias": "off", | ||
"func-names": "off", | ||
"consistent-this": "off", | ||
"no-invalid-this": "off", | ||
"prefer-named-capture-group": "off", | ||
"@typescript-eslint/no-confusing-void-expression": "off", | ||
"@typescript-eslint/await-thenable": "off", | ||
"@typescript-eslint/no-misused-promises": "off", | ||
"sort-imports": "off", | ||
"no-magic-numbers": "off", | ||
"@typescript-eslint/no-non-null-assertion": "off", | ||
"no-ternary": "off", | ||
"max-statements": [ | ||
"error", | ||
50 | ||
], | ||
"id-length": "off", | ||
"sort-imports-es6-autofix/sort-imports-es6": [ | ||
2, | ||
{ | ||
"ignoreCase": false, | ||
"ignoreMemberSort": false, | ||
"memberSyntaxSortOrder": [ | ||
"none", | ||
"all", | ||
"multiple", | ||
"single" | ||
] | ||
} | ||
], | ||
"no-shadow": "off", | ||
"no-param-reassign": "off", | ||
"no-nested-ternary": "off", | ||
"guard-for-in": "off", | ||
"@typescript-eslint/ban-ts-comment": "off", | ||
"@typescript-eslint/consistent-type-imports": "off", | ||
"class-methods-use-this": "off", | ||
"@typescript-eslint/no-floating-promises": "off", | ||
"@typescript-eslint/strict-boolean-expressions": "off", | ||
"@typescript-eslint/restrict-plus-operands": "off", | ||
"multiline-comment-style": "off", | ||
"require-jsdoc": "off", | ||
"no-warning-comments": "off", | ||
"capitalized-comments": "off", | ||
"func-style": "off", | ||
"max-lines-per-function": [ | ||
"error", | ||
{ | ||
"max": 100, | ||
"skipBlankLines": true, | ||
"skipComments": true | ||
} | ||
], | ||
"prettier/prettier": [ | ||
"error", | ||
{ | ||
"singleQuote": true, | ||
"printWidth": 180, | ||
"trailingComma": "all", | ||
"bracketSpacing": true, | ||
"bracketSameLine": true, | ||
"quoteProps": "as-needed", | ||
"jsxSingleQuote": true, | ||
"jsxBracketSameLine": false, | ||
"jsxBracketSpacing": true | ||
} | ||
], | ||
"no-use-before-define": "off" | ||
} | ||
dist/index.js: | ||
#!/usr/bin/env node | ||
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs = __importStar(require("fs")); | ||
const path = __importStar(require("path")); | ||
const commander_1 = require("commander"); | ||
const constants_1 = require("./constants"); | ||
let projectPrint = ""; | ||
let treeStructure = {}; | ||
let treeStructureString = ""; | ||
const program = new commander_1.Command(); | ||
program | ||
.argument("<startPath>", "Starting directory path") | ||
.option("--ignore <patterns>", "Comma-separated list of patterns to ignore") | ||
.option("--include <patterns>", "Comma-separated list of patterns to include") | ||
.option("--ignore-default", "Use default ignore patterns") | ||
.parse(process.argv); | ||
const startPath = program.args[0] && path.resolve(program.args[0]); | ||
const options = program.opts(); | ||
const userIgnorePatterns = options.ignore ? options.ignore.split(",").filter(Boolean).map((pattern) => pattern.trim()) : []; | ||
const includePatterns = options.include ? options.include.split(",").filter(Boolean).map((pattern) => pattern.trim()) : []; | ||
const useDefaultIgnore = options.ignoreDefault; | ||
let ignorePatterns = useDefaultIgnore ? [...constants_1.defaultIgnorePatterns, ...userIgnorePatterns] : userIgnorePatterns; | ||
ignorePatterns.push("project-print.txt"); | ||
console.log("Start Path:", startPath); | ||
console.log("Ignore Patterns:", ignorePatterns); | ||
console.log("Include Patterns:", includePatterns); | ||
function matchesPattern(filePath, patterns) { | ||
return patterns.some(pattern => { | ||
const parsedPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*"); | ||
const regex = new RegExp(parsedPattern); | ||
return regex.test(filePath); | ||
}); | ||
} | ||
function shouldIncludeFile(filePath, ignorePatterns, includePatterns) { | ||
// If include patterns are specified, they take precedence | ||
if (includePatterns.length > 0) { | ||
return matchesPattern(filePath, includePatterns); | ||
} | ||
// If no include patterns, include the file unless it matches an ignore pattern | ||
return !matchesPattern(filePath, ignorePatterns); | ||
} | ||
function readDirectory(dirPath, ignorePatterns, includePatterns, treeStructure = {}, currentPath = "") { | ||
try { | ||
const dirents = fs.readdirSync(dirPath, { withFileTypes: true }); | ||
dirents.forEach((dirent) => { | ||
const fullPath = path.relative(process.cwd(), path.join(dirPath, dirent.name)).replace(/\\/g, "/"); | ||
if (!shouldIncludeFile(fullPath, ignorePatterns, includePatterns)) { | ||
return; | ||
} | ||
const relativePath = path.join(currentPath, dirent.name).replace(/\\/g, "/"); | ||
if (dirent.isDirectory()) { | ||
treeStructure[relativePath] = {}; | ||
readDirectory(path.join(dirPath, dirent.name), ignorePatterns, includePatterns, treeStructure[relativePath], relativePath); | ||
} | ||
else if (dirent.isFile()) { | ||
treeStructure[relativePath] = {}; | ||
const content = fs.readFileSync(path.join(dirPath, dirent.name), "utf8"); | ||
if (content.length > 0) { | ||
projectPrint += `${fullPath}:\n${content}\n\n`; | ||
} | ||
} | ||
}); | ||
} | ||
catch (e) { | ||
console.error(`Failed to read directory: ${dirPath}`, e); | ||
} | ||
} | ||
function buildTreeStructure(tree, indent = "") { | ||
for (const key in tree) { | ||
treeStructureString += indent + key + "\n"; | ||
if (typeof tree[key] === "object" && Object.keys(tree[key]).length > 0) { | ||
buildTreeStructure(tree[key], indent + " "); | ||
} | ||
} | ||
} | ||
function main() { | ||
if (!startPath) { | ||
console.error("Starting directory path is required."); | ||
process.exit(1); | ||
} | ||
console.log(`Starting directory read from ${startPath}`); | ||
console.log(`Ignoring: ${ignorePatterns.join(", ")}`); | ||
console.log(`Including: ${includePatterns.length > 0 ? includePatterns.join(", ") : "All files (except ignored)"}`); | ||
console.log(`Using default ignore: ${useDefaultIgnore}`); | ||
readDirectory(startPath, ignorePatterns, includePatterns, treeStructure); | ||
console.log("\nProcessed file structure:\n"); | ||
buildTreeStructure(treeStructure); | ||
console.log(treeStructureString); | ||
const finalContents = `File structure:\n${treeStructureString}\n\nProject print:\n${projectPrint}`; | ||
fs.writeFileSync("project-print.txt", finalContents); | ||
console.log(`\nProject print size: ${(projectPrint.length / 1024).toFixed(2)}KB`); | ||
} | ||
main(); | ||
.npmignore: | ||
# .npmignore | ||
# Ignore the node_modules directory | ||
node_modules/ | ||
# Ignore the build and dist directories | ||
build/ | ||
dist/ | ||
# Ignore any .log files | ||
*.log | ||
# Ignore any .env files | ||
*.env | ||
# Ignore any .DS_Store files (macOS metadata) | ||
.DS_Store | ||
# Ignore the .git directory | ||
.git/ | ||
# Ignore the .gitignore file | ||
.gitignore | ||
# Ignore any editor configuration files | ||
.editorconfig | ||
.vscode/ | ||
# Ignore any test files and directories | ||
test/ | ||
__tests__/ | ||
# Ignore any documentation files | ||
docs/ | ||
README.md | ||
LICENSE | ||
LICENSE: | ||
The MIT License (MIT) | ||
Copyright (c) 2023 Nitai Aharoni | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. | ||
README.md: | ||
# Print-Project | ||
The `print-project` command-line tool scans a specified directory and generates a report including the tree structure | ||
and content of files that do not match given ignore patterns. It is useful for documenting or analyzing the file layout | ||
of projects, especially in development environments. | ||
## Installation | ||
You can install `print-project` using npm: | ||
```bash | ||
npm install -g print-project | ||
``` | ||
Ensure you have Node.js installed on your machine to use this package. | ||
## Usage | ||
After installation, the `print-project` tool can be run from the command line. | ||
### Basic Command | ||
```bash | ||
print-project <startPath> [ignorePatterns] | ||
``` | ||
- `<startPath>`: Required. The path to the directory you want to scan. | ||
e.g., `/path/to/project` | ||
- `[ignorePatterns]`: Optional. A comma-separated list of glob patterns to ignore files and directories. | ||
e.g., `"node_modules,*.log,dist,coverage"` | ||
### Command Aliases | ||
You can use either `print-project` or `pp` to run the tool: | ||
```bash | ||
print-project <startPath> [ignorePatterns] | ||
``` | ||
or | ||
```bash | ||
pp <startPath> [ignorePatterns] | ||
``` | ||
### Using Default Ignore Patterns | ||
To use the default ignore patterns, add the `--ignore-default` flag: | ||
```bash | ||
print-project <startPath> --ignore-default | ||
``` | ||
You can also combine default patterns with your own: | ||
```bash | ||
print-project <startPath> "your,custom,patterns" --ignore-default | ||
``` | ||
### Default Ignore Patterns | ||
The following patterns are ignored by default when using the `--ignore-default` flag: | ||
``` | ||
node_modules,*.log,dist,coverage,documentation,.prettierrc,.gitignore,dist,scripts,.serverless,.idea,.git,.DS_Store,.husky,package-lock.json | ||
``` | ||
### Examples | ||
- **Print all files and directories**: | ||
```bash | ||
print-project ./src | ||
``` | ||
or | ||
```bash | ||
pp ./src | ||
``` | ||
- **Ignore specific patterns**: | ||
```bash | ||
print-project ./src "node_modules,*.log,dist,coverage" | ||
``` | ||
or | ||
```bash | ||
pp ./src "node_modules,*.log,dist,coverage" | ||
``` | ||
- **Use default ignore patterns**: | ||
```bash | ||
print-project ./src --ignore-default | ||
``` | ||
or | ||
```bash | ||
pp ./src --ignore-default | ||
``` | ||
- **Use default ignore patterns and add custom ones**: | ||
```bash | ||
print-project ./src "*.tmp,*.bak" --ignore-default | ||
``` | ||
or | ||
```bash | ||
pp ./src "*.tmp,*.bak" --ignore-default | ||
``` | ||
## Features | ||
- **Directory Scanning**: Recursively scans the provided directory path. | ||
- **Ignore Patterns**: Supports glob patterns to exclude specific files or directories from the output. | ||
- **Default Ignore Patterns**: Provides a set of commonly ignored patterns for convenience. | ||
- **Output Generation**: Creates a text file `project-print.txt` in the current working directory containing: | ||
- The structured list of non-ignored files and directories. | ||
- The content of non-empty files. | ||
- **Command Alias**: Can be run using either `print-project` or `pp` for convenience. | ||
## How It Works | ||
1. Parses the command line arguments for the starting directory path and ignore patterns. | ||
2. Scans the specified directory, applying the ignore patterns to filter out unwanted files or directories. | ||
3. Builds a tree structure of the directory and captures file content. | ||
4. Outputs the directory structure and file content into `project-print.txt`. | ||
## Output File Format | ||
The output `project-print.txt` includes: | ||
- **File Structure**: A tree showing the organization of files and directories. | ||
- **Project Print**: Actual content of non-empty files within the project directory. | ||
## License | ||
This project is licensed under the MIT License - see the LICENSE file for details. | ||
## Contributing | ||
Contributions are welcome. Please open an issue first to discuss what you would like to change, or directly submit a | ||
pull request. | ||
jest.config.js: | ||
@@ -759,3 +510,3 @@ module.exports = { | ||
"name": "print-project", | ||
"version": "1.0.6", | ||
"version": "1.0.7", | ||
"description": "A simple CLI tool to print the project tree structure and file contents", | ||
@@ -765,3 +516,3 @@ "main": "dist/index.js", | ||
"print-project": "./dist/index.js", | ||
"pp": "./dist/index.js" | ||
"pprint": "./dist/index.js" | ||
}, | ||
@@ -776,3 +527,3 @@ "types": "dist/index.d.ts", | ||
"build": "tsc", | ||
"start": "ts-node src/index.ts", | ||
"start": "ts-node src/index.ts . --ignore-default --include dist,src", | ||
"bump": "npm version patch", | ||
@@ -793,6 +544,2 @@ "package": "npm run build && npm run bump && npm publish" | ||
project-print.txt: | ||
asdasd | ||
src/constants.ts: | ||
@@ -803,3 +550,3 @@ export const defaultIgnorePatterns: string[] = [ | ||
"*.env", "*.bak", "*.tmp", "*.swp", ".eslintcache", ".yarn", ".yarnrc", ".yarn.lock", | ||
".editorconfig", ".npmrc", ".babelrc", ".nyc_output", ".cache", | ||
".editorconfig", ".npmrc", ".babelrc", ".nyc_output", ".cache, project-print.txt", | ||
]; | ||
@@ -820,160 +567,40 @@ | ||
const program = new Command(); | ||
program.argument("<startPath>", "Starting directory path").argument("[ignorePatterns]", "Comma-separated list of patterns to ignore").option("--ignore-default", "Use default ignore patterns").parse(process.argv); | ||
program | ||
.argument("<startPath>", "Starting directory path") | ||
.option("--ignore <patterns>", "Comma-separated list of patterns to ignore") | ||
.option("--include <patterns>", "Comma-separated list of patterns to include") | ||
.option("--ignore-default", "Use default ignore patterns") | ||
.parse(process.argv); | ||
const startPath: string | undefined = program.args[0] && path.resolve(program.args[0]); | ||
const userPatterns: string[] = program.args[1] ? program.args[1].split(",").filter(Boolean).map(pattern => pattern.trim()) : []; | ||
const useDefaultIgnore: boolean = program.opts().ignoreDefault; | ||
const options = program.opts(); | ||
const userIgnorePatterns: string[] = options.ignore ? options.ignore.split(",").filter(Boolean).map((pattern: string) => pattern.trim()) : []; | ||
const includePatterns: string[] = options.include ? options.include.split(",").filter(Boolean).map((pattern: string) => pattern.trim()) : []; | ||
const useDefaultIgnore: boolean = options.ignoreDefault; | ||
let ignorePatterns: string[] = useDefaultIgnore ? [...defaultIgnorePatterns, ...userIgnorePatterns] : userIgnorePatterns; | ||
ignorePatterns.push("project-print.txt"); | ||
const patterns: string[] = useDefaultIgnore ? [...defaultIgnorePatterns, ...userPatterns] : userPatterns; | ||
console.log("Start Path:", startPath); | ||
console.log("Patterns:", patterns); | ||
console.log("Ignore Patterns:", ignorePatterns); | ||
console.log("Include Patterns:", includePatterns); | ||
function isIgnored(filePath: string, patterns: string[]): boolean { | ||
try { | ||
return patterns.some(pattern => { | ||
const parsedPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*"); | ||
const regex = new RegExp(parsedPattern); | ||
return regex.test(filePath); | ||
}); | ||
} catch (e) { | ||
console.error(`Failed to check if ignored: ${filePath}`, e); | ||
return false; | ||
} | ||
function matchesPattern(filePath: string, patterns: string[]): boolean { | ||
return patterns.some(pattern => { | ||
const parsedPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*"); | ||
const regex = new RegExp(parsedPattern); | ||
return regex.test(filePath); | ||
}); | ||
} | ||
function readDirectory(dirPath: string, patterns: string[] = [], treeStructure: Record<string, any> = {}, currentPath: string = ""): void { | ||
try { | ||
const dirents = fs.readdirSync(dirPath, { withFileTypes: true }); | ||
dirents.forEach((dirent) => { | ||
const fullPath = path.relative(process.cwd(), path.join(dirPath, dirent.name)).replace(/\\/g, "/"); | ||
if (isIgnored(fullPath, patterns)) { | ||
return; | ||
} | ||
const relativePath = path.join(currentPath, dirent.name).replace(/\\/g, "/"); | ||
if (dirent.isDirectory()) { | ||
treeStructure[relativePath] = {}; | ||
readDirectory(path.join(dirPath, dirent.name), patterns, treeStructure[relativePath], relativePath); | ||
} else if (dirent.isFile()) { | ||
treeStructure[relativePath] = {}; | ||
const content = fs.readFileSync(path.join(dirPath, dirent.name), "utf8"); | ||
if (content.length > 0) { | ||
projectPrint += `${fullPath}:\n${content}\n\n`; | ||
} | ||
} | ||
}); | ||
} catch (e) { | ||
console.error(`Failed to read directory: ${dirPath}`, e); | ||
} | ||
function shouldIncludeFile(filePath: string, ignorePatterns: string[], includePatterns: string[]): boolean { | ||
return !matchesPattern(filePath, ignorePatterns) || matchesPattern(filePath, includePatterns); | ||
} | ||
function buildTreeStructure(tree: Record<string, any>, indent: string = ""): void { | ||
for (const key in tree) { | ||
treeStructureString += indent + key + "\n"; | ||
if (typeof tree[key] === "object" && Object.keys(tree[key]).length > 0) { | ||
buildTreeStructure(tree[key], indent + " "); | ||
} | ||
} | ||
} | ||
function main(): void { | ||
if (!startPath) { | ||
console.error("Starting directory path is required."); | ||
process.exit(1); | ||
} | ||
console.log(`Starting directory read from ${startPath}`); | ||
console.log(`Ignoring: ${patterns.join(", ")}`); | ||
console.log(`Using default ignore: ${useDefaultIgnore}`); | ||
readDirectory(startPath, patterns, treeStructure); | ||
console.log("\nNon-ignored file structure:\n"); | ||
buildTreeStructure(treeStructure); | ||
console.log(treeStructureString); | ||
const finalContents = `File structure:\n${treeStructureString}\n\nProject print:\n${projectPrint}`; | ||
fs.writeFileSync("project-print.txt", finalContents); | ||
console.log(`\nProject print size: ${(projectPrint.length / 1024).toFixed(2)}KB`); | ||
} | ||
main(); | ||
tsconfig.json: | ||
{ | ||
"compilerOptions": { | ||
"target": "es6", | ||
"module": "commonjs", | ||
"declaration": true, | ||
"outDir": "dist", | ||
"strict": true, | ||
"esModuleInterop": true, | ||
"lib": [ | ||
"ES2016", | ||
"DOM" | ||
] | ||
}, | ||
"include": [ | ||
"src/**/*.ts" | ||
], | ||
"exclude": [ | ||
"node_modules" | ||
] | ||
} | ||
src/constants.ts: | ||
export const defaultIgnorePatterns: string[] = [ | ||
"node_modules", "*.log", "dist", "coverage", "documentation", ".prettierrc", ".gitignore", "dist", | ||
"scripts", ".serverless", ".idea", ".git", ".DS_Store", ".husky", "package-lock.json", ".vscode", | ||
"*.env", "*.bak", "*.tmp", "*.swp", ".eslintcache", ".yarn", ".yarnrc", ".yarn.lock", | ||
".editorconfig", ".npmrc", ".babelrc", ".nyc_output", ".cache", | ||
]; | ||
src/index.ts: | ||
#!/usr/bin/env node | ||
import * as fs from "fs"; | ||
import * as path from "path"; | ||
import { Command } from "commander"; | ||
import { defaultIgnorePatterns } from "./constants"; | ||
let projectPrint: string = ""; | ||
let treeStructure: Record<string, any> = {}; | ||
let treeStructureString: string = ""; | ||
const program = new Command(); | ||
program.argument("<startPath>", "Starting directory path").argument("[ignorePatterns]", "Comma-separated list of patterns to ignore").option("--ignore-default", "Use default ignore patterns").parse(process.argv); | ||
const startPath: string | undefined = program.args[0] && path.resolve(program.args[0]); | ||
const userPatterns: string[] = program.args[1] ? program.args[1].split(",").filter(Boolean).map(pattern => pattern.trim()) : []; | ||
const useDefaultIgnore: boolean = program.opts().ignoreDefault; | ||
const patterns: string[] = useDefaultIgnore ? [...defaultIgnorePatterns, ...userPatterns] : userPatterns; | ||
console.log("Start Path:", startPath); | ||
console.log("Patterns:", patterns); | ||
function isIgnored(filePath: string, patterns: string[]): boolean { | ||
function readDirectory(dirPath: string, ignorePatterns: string[], includePatterns: string[], treeStructure: Record<string, any> = {}, currentPath: string = ""): void { | ||
try { | ||
return patterns.some(pattern => { | ||
const parsedPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*"); | ||
const regex = new RegExp(parsedPattern); | ||
return regex.test(filePath); | ||
}); | ||
} catch (e) { | ||
console.error(`Failed to check if ignored: ${filePath}`, e); | ||
return false; | ||
} | ||
} | ||
function readDirectory(dirPath: string, patterns: string[] = [], treeStructure: Record<string, any> = {}, currentPath: string = ""): void { | ||
try { | ||
const dirents = fs.readdirSync(dirPath, { withFileTypes: true }); | ||
dirents.forEach((dirent) => { | ||
const fullPath = path.relative(process.cwd(), path.join(dirPath, dirent.name)).replace(/\\/g, "/"); | ||
if (isIgnored(fullPath, patterns)) { | ||
if (!shouldIncludeFile(fullPath, ignorePatterns, includePatterns)) { | ||
return; | ||
@@ -984,3 +611,3 @@ } | ||
treeStructure[relativePath] = {}; | ||
readDirectory(path.join(dirPath, dirent.name), patterns, treeStructure[relativePath], relativePath); | ||
readDirectory(path.join(dirPath, dirent.name), ignorePatterns, includePatterns, treeStructure[relativePath], relativePath); | ||
} else if (dirent.isFile()) { | ||
@@ -1015,7 +642,8 @@ treeStructure[relativePath] = {}; | ||
console.log(`Starting directory read from ${startPath}`); | ||
console.log(`Ignoring: ${patterns.join(", ")}`); | ||
console.log(`Ignoring: ${ignorePatterns.join(", ")}`); | ||
console.log(`Including: ${includePatterns.length > 0 ? includePatterns.join(", ") : "All files (except ignored)"}`); | ||
console.log(`Using default ignore: ${useDefaultIgnore}`); | ||
readDirectory(startPath, patterns, treeStructure); | ||
console.log("\nNon-ignored file structure:\n"); | ||
readDirectory(startPath, ignorePatterns, includePatterns, treeStructure); | ||
console.log("\nProcessed file structure:\n"); | ||
buildTreeStructure(treeStructure); | ||
@@ -1022,0 +650,0 @@ console.log(treeStructureString); |
export const defaultIgnorePatterns: string[] = [ | ||
"node_modules", "*.log", "dist", "coverage", "documentation", ".prettierrc", ".gitignore", "dist", | ||
"scripts", ".serverless", ".idea", ".git", ".DS_Store", ".husky", "package-lock.json", ".vscode", | ||
"*.env", "*.bak", "*.tmp", "*.swp", ".eslintcache", ".yarn", ".yarnrc", ".yarn.lock", | ||
".editorconfig", ".npmrc", ".babelrc", ".nyc_output", ".cache, project-print.txt", | ||
]; | ||
"node_modules", | ||
"*.log", | ||
"dist", | ||
"coverage", | ||
"documentation", | ||
".prettierrc", | ||
".gitignore", | ||
"scripts", | ||
".serverless", | ||
".idea", | ||
".git", | ||
".DS_Store", | ||
".husky", | ||
"package-lock.json", | ||
".vscode", | ||
"*.env", | ||
"*.bak", | ||
"*.tmp", | ||
"*.swp", | ||
".eslintcache", | ||
".yarn", | ||
".yarnrc", | ||
".yarn.lock", | ||
".editorconfig", | ||
".npmrc", | ||
".babelrc", | ||
".nyc_output", | ||
".cache", | ||
"project-print.txt", | ||
".eslintrc", | ||
".eslintrc.js", | ||
".eslintrc.json", | ||
".eslintrc.yml", | ||
".eslintrc.yaml", | ||
".npmignore", | ||
".babelrc.js", | ||
".babelrc.json", | ||
".babelrc.yml", | ||
".babelrc.yaml", | ||
]; |
@@ -12,29 +12,35 @@ #!/usr/bin/env node | ||
const program = new Command(); | ||
program.argument("<startPath>", "Starting directory path").argument("[ignorePatterns]", "Comma-separated list of patterns to ignore").option("--ignore-default", "Use default ignore patterns").parse(process.argv); | ||
program | ||
.argument("<startPath>", "Starting directory path") | ||
.option("--ignore <patterns>", "Comma-separated list of patterns to ignore") | ||
.option("--include <patterns>", "Comma-separated list of patterns to include") | ||
.option("--ignore-default", "Use default ignore patterns") | ||
.parse(process.argv); | ||
const startPath: string | undefined = program.args[0] && path.resolve(program.args[0]); | ||
const userPatterns: string[] = program.args[1] ? program.args[1].split(",").filter(Boolean).map(pattern => pattern.trim()) : []; | ||
const useDefaultIgnore: boolean = program.opts().ignoreDefault; | ||
const options = program.opts(); | ||
const userIgnorePatterns: string[] = options.ignore ? options.ignore.split(",").filter(Boolean).map((pattern: string) => pattern.trim()) : []; | ||
const includePatterns: string[] = options.include ? options.include.split(",").filter(Boolean).map((pattern: string) => pattern.trim()) : []; | ||
const useDefaultIgnore: boolean = options.ignoreDefault; | ||
let ignorePatterns: string[] = useDefaultIgnore ? [...defaultIgnorePatterns, ...userIgnorePatterns] : userIgnorePatterns; | ||
ignorePatterns.push("project-print.txt"); | ||
let patterns: string[] = useDefaultIgnore ? [...defaultIgnorePatterns, ...userPatterns] : userPatterns; | ||
patterns.push("project-print.txt"); | ||
console.log("Start Path:", startPath); | ||
console.log("Patterns:", patterns); | ||
console.log("Ignore Patterns:", ignorePatterns); | ||
console.log("Include Patterns:", includePatterns); | ||
function isIgnored(filePath: string, patterns: string[]): boolean { | ||
try { | ||
return patterns.some(pattern => { | ||
const parsedPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*"); | ||
const regex = new RegExp(parsedPattern); | ||
return regex.test(filePath); | ||
}); | ||
} catch (e) { | ||
console.error(`Failed to check if ignored: ${filePath}`, e); | ||
return false; | ||
} | ||
function matchesPattern(filePath: string, patterns: string[]): boolean { | ||
return patterns.some(pattern => { | ||
const parsedPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*"); | ||
const regex = new RegExp(parsedPattern); | ||
return regex.test(filePath); | ||
}); | ||
} | ||
function readDirectory(dirPath: string, patterns: string[] = [], treeStructure: Record<string, any> = {}, currentPath: string = ""): void { | ||
function shouldIncludeFile(filePath: string, ignorePatterns: string[], includePatterns: string[]): boolean { | ||
return !matchesPattern(filePath, ignorePatterns) || matchesPattern(filePath, includePatterns); | ||
} | ||
function readDirectory(dirPath: string, ignorePatterns: string[], includePatterns: string[], treeStructure: Record<string, any> = {}, currentPath: string = ""): void { | ||
try { | ||
@@ -44,3 +50,3 @@ const dirents = fs.readdirSync(dirPath, { withFileTypes: true }); | ||
const fullPath = path.relative(process.cwd(), path.join(dirPath, dirent.name)).replace(/\\/g, "/"); | ||
if (isIgnored(fullPath, patterns)) { | ||
if (!shouldIncludeFile(fullPath, ignorePatterns, includePatterns)) { | ||
return; | ||
@@ -51,3 +57,3 @@ } | ||
treeStructure[relativePath] = {}; | ||
readDirectory(path.join(dirPath, dirent.name), patterns, treeStructure[relativePath], relativePath); | ||
readDirectory(path.join(dirPath, dirent.name), ignorePatterns, includePatterns, treeStructure[relativePath], relativePath); | ||
} else if (dirent.isFile()) { | ||
@@ -82,7 +88,8 @@ treeStructure[relativePath] = {}; | ||
console.log(`Starting directory read from ${startPath}`); | ||
console.log(`Ignoring: ${patterns.join(", ")}`); | ||
console.log(`Ignoring: ${ignorePatterns.join(", ")}`); | ||
console.log(`Including: ${includePatterns.length > 0 ? includePatterns.join(", ") : "All files (except ignored)"}`); | ||
console.log(`Using default ignore: ${useDefaultIgnore}`); | ||
readDirectory(startPath, patterns, treeStructure); | ||
console.log("\nNon-ignored file structure:\n"); | ||
readDirectory(startPath, ignorePatterns, includePatterns, treeStructure); | ||
console.log("\nProcessed file structure:\n"); | ||
buildTreeStructure(treeStructure); | ||
@@ -89,0 +96,0 @@ console.log(treeStructureString); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
42034
17
435