Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
342 changes: 342 additions & 0 deletions src/core/project-scanner/DocumentationGenerator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
import { ProjectInfo, Technology, ConfigFile, DirectoryInfo } from "./ProjectScanner"

export class DocumentationGenerator {
async generateDocumentation(projectInfo: ProjectInfo): Promise<string> {
const sections: string[] = []

// Header
sections.push(`# ${projectInfo.name}`)
sections.push("")
sections.push(projectInfo.description)
sections.push("")

// Project Overview
sections.push("## Project Overview")
sections.push("")
sections.push(
`This document provides a comprehensive overview of the **${projectInfo.name}** project structure, technologies, and setup instructions. This file is automatically generated by Roo Code's \`/init\` command to help maintain consistent project documentation.`,
)
sections.push("")

// Table of Contents
sections.push("## Table of Contents")
sections.push("")
sections.push("- [Technologies](#technologies)")
sections.push("- [Project Structure](#project-structure)")
sections.push("- [Configuration Files](#configuration-files)")
sections.push("- [Dependencies](#dependencies)")
sections.push("- [Available Scripts](#available-scripts)")
sections.push("- [Development Setup](#development-setup)")
sections.push("- [Architecture Patterns](#architecture-patterns)")
if (projectInfo.gitInfo.hasGit) {
sections.push("- [Git Information](#git-information)")
}
sections.push("")

// Technologies
sections.push("## Technologies")
sections.push("")
sections.push("This project uses the following technologies:")
sections.push("")

const techByType = this.groupTechnologiesByType(projectInfo.technologies)
for (const [type, techs] of Object.entries(techByType)) {
sections.push(`### ${this.formatTechType(type)}`)
sections.push("")
for (const tech of techs) {
const version = tech.version ? ` (${tech.version})` : ""
const config = tech.configFile ? ` - Config: \`${tech.configFile}\`` : ""
sections.push(`- **${tech.name}**${version}${config}`)
}
sections.push("")
}

// Project Structure
sections.push("## Project Structure")
sections.push("")
sections.push("```")
sections.push(this.generateTreeStructure(projectInfo.structure.directories))
sections.push("```")
sections.push("")

// File statistics
sections.push("### File Statistics")
sections.push("")
sections.push(`- Total files: ${projectInfo.structure.fileCount}`)
sections.push(`- File types:`)
const sortedFileTypes = Object.entries(projectInfo.structure.fileTypes)
.sort(([, a], [, b]) => b - a)
.slice(0, 10)
for (const [ext, count] of sortedFileTypes) {
const extName = ext || "(no extension)"
sections.push(` - ${extName}: ${count} files`)
}
sections.push("")

// Configuration Files
sections.push("## Configuration Files")
sections.push("")
sections.push("The following configuration files are present in the project:")
sections.push("")

const configByType = this.groupConfigsByType(projectInfo.configFiles)
for (const [type, configs] of Object.entries(configByType)) {
sections.push(`### ${this.formatConfigType(type)}`)
sections.push("")
for (const config of configs) {
sections.push(`- \`${config.path}\``)
}
sections.push("")
}

// Dependencies
if (
Object.keys(projectInfo.dependencies.production).length > 0 ||
Object.keys(projectInfo.dependencies.development).length > 0
) {
sections.push("## Dependencies")
sections.push("")

if (Object.keys(projectInfo.dependencies.production).length > 0) {
sections.push("### Production Dependencies")
sections.push("")
sections.push("```json")
sections.push(JSON.stringify(projectInfo.dependencies.production, null, 2))
sections.push("```")
sections.push("")
}

if (Object.keys(projectInfo.dependencies.development).length > 0) {
sections.push("### Development Dependencies")
sections.push("")
sections.push("```json")
sections.push(JSON.stringify(projectInfo.dependencies.development, null, 2))
sections.push("```")
sections.push("")
}
}

// Available Scripts
if (Object.keys(projectInfo.scripts).length > 0) {
sections.push("## Available Scripts")
sections.push("")
sections.push("The following scripts are available:")
sections.push("")

for (const [name, command] of Object.entries(projectInfo.scripts)) {
if (command === "Makefile target") {
sections.push(`- \`${name}\` - Makefile target`)
} else {
sections.push(`- \`npm run ${name}\` - ${command}`)
}
}
sections.push("")
}

// Development Setup
sections.push("## Development Setup")
sections.push("")
sections.push("To set up this project for development:")
sections.push("")

const setupSteps = this.generateSetupSteps(projectInfo)
setupSteps.forEach((step, index) => {
sections.push(`${index + 1}. ${step}`)
})
sections.push("")

// Architecture Patterns
if (
projectInfo.patterns.architecture ||
projectInfo.patterns.testingFramework ||
projectInfo.patterns.buildTool ||
projectInfo.patterns.cicd
) {
sections.push("## Architecture Patterns")
sections.push("")

if (projectInfo.patterns.architecture) {
sections.push(`- **Architecture**: ${projectInfo.patterns.architecture}`)
}
if (projectInfo.patterns.testingFramework) {
sections.push(`- **Testing Framework**: ${projectInfo.patterns.testingFramework}`)
}
if (projectInfo.patterns.buildTool) {
sections.push(`- **Build Tool**: ${projectInfo.patterns.buildTool}`)
}
if (projectInfo.patterns.packageManager) {
sections.push(`- **Package Manager**: ${projectInfo.patterns.packageManager}`)
}
if (projectInfo.patterns.cicd && projectInfo.patterns.cicd.length > 0) {
sections.push(`- **CI/CD**: ${projectInfo.patterns.cicd.join(", ")}`)
}
sections.push("")
}

// Git Information
if (projectInfo.gitInfo.hasGit) {
sections.push("## Git Information")
sections.push("")
if (projectInfo.gitInfo.branch) {
sections.push(`- **Current Branch**: ${projectInfo.gitInfo.branch}`)
}
if (projectInfo.gitInfo.remote) {
sections.push(`- **Remote Repository**: ${projectInfo.gitInfo.remote}`)
}
sections.push("")
}

// Footer
sections.push("---")
sections.push("")
sections.push(`*This documentation was automatically generated by Roo Code on ${new Date().toISOString()}*`)
sections.push("")

return sections.join("\n")
}

private groupTechnologiesByType(technologies: Technology[]): Record<string, Technology[]> {
const grouped: Record<string, Technology[]> = {}
for (const tech of technologies) {
if (!grouped[tech.type]) {
grouped[tech.type] = []
}
grouped[tech.type].push(tech)
}
return grouped
}

private groupConfigsByType(configs: ConfigFile[]): Record<string, ConfigFile[]> {
const grouped: Record<string, ConfigFile[]> = {}
for (const config of configs) {
if (!grouped[config.type]) {
grouped[config.type] = []
}
grouped[config.type].push(config)
}
return grouped
}

private formatTechType(type: string): string {
const typeMap: Record<string, string> = {
language: "Languages",
framework: "Frameworks",
tool: "Tools",
database: "Databases",
service: "Services",
}
return typeMap[type] || type
}

private formatConfigType(type: string): string {
const typeMap: Record<string, string> = {
npm: "NPM Configuration",
typescript: "TypeScript Configuration",
eslint: "ESLint Configuration",
prettier: "Prettier Configuration",
webpack: "Webpack Configuration",
vite: "Vite Configuration",
jest: "Jest Configuration",
vitest: "Vitest Configuration",
git: "Git Configuration",
docker: "Docker Configuration",
environment: "Environment Configuration",
python: "Python Configuration",
go: "Go Configuration",
rust: "Rust Configuration",
}
return typeMap[type] || type
}

private generateTreeStructure(directories: DirectoryInfo[], prefix: string = ""): string {
const lines: string[] = []

// Add root indicator
if (prefix === "") {
lines.push(".")
}

// Sort directories by name
const sorted = directories.sort((a, b) => a.name.localeCompare(b.name))

for (let i = 0; i < sorted.length; i++) {
const dir = sorted[i]
const isLast = i === sorted.length - 1
const connector = isLast ? "└── " : "├── "
const extension = isLast ? " " : "│ "

lines.push(`${prefix}${connector}${dir.name}/`)

// Add file count if directory has files
if (dir.fileCount > 0) {
lines.push(`${prefix}${extension} (${dir.fileCount} files)`)
}
}

return lines.join("\n")
}

private generateSetupSteps(projectInfo: ProjectInfo): string[] {
const steps: string[] = []

// Clone repository if git remote exists
if (projectInfo.gitInfo.remote) {
steps.push(`Clone the repository: \`git clone ${projectInfo.gitInfo.remote}\``)
steps.push(`Navigate to the project directory: \`cd ${projectInfo.name}\``)
}

// Install dependencies based on package manager
if (projectInfo.patterns.packageManager) {
const pm = projectInfo.patterns.packageManager
if (pm === "npm") {
steps.push("Install dependencies: `npm install`")
} else if (pm === "yarn") {
steps.push("Install dependencies: `yarn install`")
} else if (pm === "pnpm") {
steps.push("Install dependencies: `pnpm install`")
}
} else if (projectInfo.technologies.some((t) => t.name === "Node.js")) {
steps.push("Install dependencies: `npm install`")
}

// Python setup
if (projectInfo.technologies.some((t) => t.name === "Python")) {
steps.push("Create a virtual environment: `python -m venv venv`")
steps.push("Activate the virtual environment:")
steps.push(" - On Windows: `venv\\Scripts\\activate`")
steps.push(" - On macOS/Linux: `source venv/bin/activate`")
if (projectInfo.configFiles.some((c) => c.name === "requirements.txt")) {
steps.push("Install Python dependencies: `pip install -r requirements.txt`")
}
}

// Go setup
if (projectInfo.technologies.some((t) => t.name === "Go")) {
steps.push("Download Go dependencies: `go mod download`")
}

// Rust setup
if (projectInfo.technologies.some((t) => t.name === "Rust")) {
steps.push("Build the project: `cargo build`")
}

// Environment setup
if (projectInfo.configFiles.some((c) => c.name === ".env.example")) {
steps.push("Copy the example environment file: `cp .env.example .env`")
steps.push("Update the `.env` file with your local configuration")
}

// Add common development scripts
if (projectInfo.scripts["dev"]) {
steps.push("Start the development server: `npm run dev`")
} else if (projectInfo.scripts["start"]) {
steps.push("Start the development server: `npm run start`")
}

if (projectInfo.scripts["test"]) {
steps.push("Run tests: `npm run test`")
}

return steps
}
}
Loading