Files
Ashim Kumar 11d715eb85 first commit
2026-01-09 21:06:30 +06:00

257 lines
9.8 KiB
Python

import os
from pathlib import Path
import mimetypes
import markdown
# INPUT: Set your Application folder path here
APPLICATION_FOLDER = f'../Audio Transcription Editor' # Replace with your actual folder path
# Add these new variables
EXCLUDE_FOLDERS = {
'node_modules',
# 'node_modules',
# 'venv',
# 'env',
# '__pycache__',
# 'dist',
# 'build',
# '.pytest_cache'
}
EXCLUDE_FILES = {
'doc.py'
# '.DS_Store',
# 'Thumbs.db',
# 'package-lock.json'
}
# File extensions to exclude
EXCLUDE_EXTENSIONS = {
# '.pyc',
# '.pyo',
# '.log',
# '.tmp'
}
def is_text_file(file_path):
"""Check if a file is likely a text/code file based on extension and mime type."""
# Common code file extensions
code_extensions = {
'.py', '.js', '.html', '.css', '.java', '.cpp', '.c', '.h', '.hpp',
'.cs', '.php', '.rb', '.go', '.rs', '.swift', '.kt', '.ts', '.jsx',
'.tsx', '.vue', '.scss', '.sass', '.less', '.sql', '.json', '.xml',
'.yaml', '.yml', '.toml', '.ini', '.cfg', '.conf', '.sh', '.bat',
'.ps1', '.r', '.R', '.m', '.scala', '.clj', '.hs', '.elm', '.dart',
'.lua', '.pl', '.pm', '.tcl', '.awk', '.sed', '.dockerfile', '.md',
'.txt', '.log', '.gitignore', '.env', '.properties'
}
file_ext = Path(file_path).suffix.lower()
# Check by extension first
if file_ext in code_extensions:
return True
# Check by mime type for files without extension
if not file_ext:
mime_type, _ = mimetypes.guess_type(file_path)
if mime_type and mime_type.startswith('text/'):
return True
return False
def generate_tree_structure(root_path, prefix="", is_last=True, max_depth=None, current_depth=0):
"""Generate a tree-like directory structure."""
if max_depth is not None and current_depth > max_depth:
return ""
root = Path(root_path)
tree_str = ""
if current_depth == 0:
tree_str += f"{root.name}/\n"
try:
# Get all items and sort them (directories first, then files)
items = list(root.iterdir())
dirs = [item for item in items if item.is_dir() and not item.name.startswith('.') and item.name not in EXCLUDE_FOLDERS]
files = [item for item in items if item.is_file() and not item.name.startswith('.') and item.name not in EXCLUDE_FILES and item.suffix not in EXCLUDE_EXTENSIONS]
all_items = sorted(dirs) + sorted(files)
for i, item in enumerate(all_items):
is_last_item = i == len(all_items) - 1
if item.is_dir():
tree_str += f"{prefix}{'└── ' if is_last_item else '├── '}{item.name}/\n"
extension = " " if is_last_item else ""
tree_str += generate_tree_structure(
item,
prefix + extension,
is_last_item,
max_depth,
current_depth + 1
)
else:
tree_str += f"{prefix}{'└── ' if is_last_item else '├── '}{item.name}\n"
except PermissionError:
tree_str += f"{prefix}[Permission Denied]\n"
return tree_str
def generate_bash_command(root_folder):
"""Generate a bash command to recreate the directory and file structure."""
root_path = Path(root_folder)
dirs_to_create = []
files_to_create = []
for root, dirs, files in os.walk(root_folder, topdown=True):
# Skip hidden directories
dirs[:] = [d for d in dirs if not d.startswith('.') and d not in EXCLUDE_FOLDERS]
for name in dirs:
dir_path = Path(root) / name
relative_dir = dir_path.relative_to(root_path)
dirs_to_create.append(f'"{relative_dir}"')
# Skip hidden files
files[:] = [f for f in files if not f.startswith('.') and f not in EXCLUDE_FILES and Path(f).suffix not in EXCLUDE_EXTENSIONS]
for name in files:
file_path = Path(root) / name
relative_file = file_path.relative_to(root_path)
files_to_create.append(f'"{relative_file}"')
command_parts = []
if dirs_to_create:
command_parts.append(f"mkdir -p {' '.join(dirs_to_create)}")
if files_to_create:
command_parts.append(f"touch {' '.join(files_to_create)}")
if not command_parts:
return "# No directories or files to create."
return " && ".join(command_parts)
def read_file_content(file_path):
"""Safely read file content with encoding detection."""
encodings = ['utf-8', 'utf-16', 'latin-1', 'cp1252']
for encoding in encodings:
try:
with open(file_path, 'r', encoding=encoding) as file:
return file.read()
except (UnicodeDecodeError, UnicodeError):
continue
except Exception as e:
return f"Error reading file: {str(e)}"
return "Unable to decode file content"
def get_language_from_extension(file_path):
"""Get the appropriate language identifier for markdown code blocks."""
ext = Path(file_path).suffix.lower()
language_map = {
'.py': 'python', '.js': 'javascript', '.ts': 'typescript', '.jsx': 'jsx',
'.tsx': 'tsx', '.html': 'html', '.css': 'css', '.scss': 'scss',
'.sass': 'sass', '.java': 'java', '.cpp': 'cpp', '.c': 'c', '.h': 'c',
'.hpp': 'cpp', '.cs': 'csharp', '.php': 'php', '.rb': 'ruby', '.go': 'go',
'.rs': 'rust', '.swift': 'swift', '.kt': 'kotlin', '.sql': 'sql',
'.json': 'json', '.xml': 'xml', '.yaml': 'yaml', '.yml': 'yaml',
'.toml': 'toml', '.sh': 'bash', '.bat': 'batch', '.ps1': 'powershell',
'.dockerfile': 'dockerfile', '.md': 'markdown', '.r': 'r', '.R': 'r',
'.scala': 'scala', '.clj': 'clojure', '.hs': 'haskell', '.lua': 'lua',
'.pl': 'perl', '.tcl': 'tcl',
}
return language_map.get(ext, 'text')
def generate_documentation(root_folder):
"""Generate complete markdown and HTML documentation for the project."""
root_path = Path(root_folder)
if not root_path.exists() or not root_path.is_dir():
print(f"Error: The folder '{root_folder}' does not exist or is not a directory.")
return
# Start building markdown content
markdown_content = [f"# {root_path.name} - Project Documentation\n"]
# Add project structure
markdown_content.append("## 📂 Project Structure\n")
markdown_content.append("```")
markdown_content.append(generate_tree_structure(root_path))
markdown_content.append("```\n")
# # Add bash command to recreate structure
# markdown_content.append("## ⚙️ Bash Command to Recreate Structure\n")
# markdown_content.append("```bash")
# markdown_content.append(generate_bash_command(root_path))
# markdown_content.append("```\n")
# Add files content
markdown_content.append("## 📄 Files Content\n")
for root, dirs, files in os.walk(root_folder):
dirs[:] = [d for d in dirs if not d.startswith('.') and d not in EXCLUDE_FOLDERS]
for file in sorted(files):
if file.startswith('.') or file in EXCLUDE_FILES or Path(file).suffix in EXCLUDE_EXTENSIONS : continue
file_path = Path(root) / file
if is_text_file(file_path):
relative_path = file_path.relative_to(root_path)
markdown_content.append(f"### 📜 `{relative_path}`\n")
content = read_file_content(file_path)
language = get_language_from_extension(file_path)
markdown_content.append(f"```{language}\n{content}\n```\n")
final_markdown = '\n'.join(markdown_content)
# Write to markdown file
output_md_file = f"../{root_path.name}_documentation.md"
try:
with open(output_md_file, 'w', encoding='utf-8') as f:
f.write(final_markdown)
print(f"✅ Markdown documentation generated: {Path(output_md_file).resolve()}")
except Exception as e:
print(f"❌ Error writing markdown file: {str(e)}")
# Generate and write HTML file
html_template = """
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>{title}</title>
<style>
body {{ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; line-height: 1.6; padding: 2em; max-width: 1024px; margin: 0 auto; color: #333; }}
h1, h2, h3 {{ border-bottom: 1px solid #eaecef; padding-bottom: 0.3em; }}
code {{ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; background-color: #f6f8fa; padding: 0.2em 0.4em; margin: 0; font-size: 85%; border-radius: 6px; }}
pre {{ background-color: #f6f8fa; padding: 16px; overflow: auto; border-radius: 6px; }}
pre code {{ padding: 0; margin: 0; font-size: 100%; background-color: transparent; border: none; }}
</style></head><body>{content}</body></html>
"""
html_content = markdown.markdown(final_markdown, extensions=['fenced_code', 'tables'])
final_html = html_template.format(title=f"{root_path.name} Documentation", content=html_content)
output_html_file = f"../{root_path.name}_documentation.html"
try:
with open(output_html_file, 'w', encoding='utf-8') as f:
f.write(final_html)
print(f"✅ HTML documentation generated: {Path(output_html_file).resolve()}")
except Exception as e:
print(f"❌ Error writing HTML file: {str(e)}")
# Main execution
if __name__ == "__main__":
if not APPLICATION_FOLDER or APPLICATION_FOLDER == "/path/to/your/Application":
print("⚠️ Please set the APPLICATION_FOLDER variable to your actual folder path.")
else:
print(f"🚀 Generating documentation for: {APPLICATION_FOLDER}")
generate_documentation(APPLICATION_FOLDER)