generate-readme-template.ts•14.1 kB
import { z } from "zod";
// Template types
export const TemplateType = z.enum([
"library",
"application",
"cli-tool",
"api",
"documentation",
]);
export type TemplateType = z.infer<typeof TemplateType>;
// Input schema
export const GenerateReadmeTemplateSchema = z.object({
projectName: z.string().min(1, "Project name is required"),
description: z.string().min(1, "Project description is required"),
templateType: TemplateType,
author: z.string().optional(),
license: z.string().default("MIT"),
includeScreenshots: z.boolean().default(false),
includeBadges: z.boolean().default(true),
includeContributing: z.boolean().default(true),
outputPath: z.string().optional(),
});
export type GenerateReadmeTemplateInput = z.infer<
typeof GenerateReadmeTemplateSchema
>;
interface TemplateSection {
title: string;
content: string;
required: boolean;
}
interface ReadmeTemplate {
sections: TemplateSection[];
badges: string[];
metadata: {
type: TemplateType;
estimatedLength: number;
};
}
export class ReadmeTemplateGenerator {
private templates: Map<TemplateType, ReadmeTemplate> = new Map();
constructor() {
this.initializeTemplates();
}
private initializeTemplates(): void {
// Library/Package Template
this.templates.set("library", {
sections: [
{
title: "Header",
content: "# {{projectName}}\n\n> {{description}}",
required: true,
},
{
title: "Badges",
content: "{{badges}}",
required: false,
},
{
title: "TL;DR",
content:
"## TL;DR\n\nWhat it does in 2-3 sentences. Who should use it.\n\n- ✅ Perfect for X use cases\n- ✅ Solves Y problems\n- ❌ Not suitable for Z (consider [alternative] instead)",
required: true,
},
{
title: "Quick Start",
content:
"## Quick Start\n\n### Install\n\n```bash\nnpm install {{projectName}}\n```\n\n### Use\n\n```javascript\nconst {{camelCaseName}} = require('{{projectName}}');\n\n// Basic usage example\nconst result = {{camelCaseName}}.doSomething();\nconsole.log(result);\n```",
required: true,
},
{
title: "API Documentation",
content:
"## API Documentation\n\n[Link to full API documentation]\n\n### Core Methods\n\n#### `methodName(param)`\n\n- **param** `{Type}` - Description\n- **Returns** `{Type}` - Description\n\nExample:\n```javascript\n// Example usage\n```",
required: true,
},
{
title: "Contributing",
content:
"## Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n### Development Setup\n\n```bash\ngit clone https://github.com/{{author}}/{{projectName}}.git\ncd {{projectName}}\nnpm install\nnpm test\n```",
required: false,
},
{
title: "License",
content: "## License\n\n{{license}} © {{author}}",
required: true,
},
],
badges: [
"[](https://badge.fury.io/js/{{projectName}})",
"[](https://travis-ci.org/{{author}}/{{projectName}})",
"[](https://opensource.org/licenses/{{license}})",
],
metadata: {
type: "library",
estimatedLength: 150,
},
});
// Application Template
this.templates.set("application", {
sections: [
{
title: "Header",
content: "# {{projectName}}\n\n> {{description}}",
required: true,
},
{
title: "Screenshot",
content: "{{screenshot}}",
required: false,
},
{
title: "What This Does",
content:
"## What This Does\n\n{{projectName}} helps you:\n\n- 🎯 **Feature 1** - Brief explanation\n- ⚡ **Feature 2** - Brief explanation\n- 🔧 **Feature 3** - Brief explanation",
required: true,
},
{
title: "Quick Start",
content:
"## Quick Start\n\n### Prerequisites\n\n- Node.js 18+ \n- npm or yarn\n- [Additional requirements]\n\n### Install & Run\n\n```bash\ngit clone https://github.com/{{author}}/{{projectName}}.git\ncd {{projectName}}\nnpm install\nnpm start\n```\n\nOpen http://localhost:3000 in your browser.",
required: true,
},
{
title: "Configuration",
content:
"## Configuration\n\nCreate a `.env` file in the root directory:\n\n```env\n# Required settings\nPORT=3000\nNODE_ENV=development\n\n# Optional settings\nDATABASE_URL=your_database_url\nAPI_KEY=your_api_key\n```\n\nSee [Configuration Guide](docs/configuration.md) for all options.",
required: true,
},
{
title: "Usage",
content:
"## Usage\n\n### Basic Operations\n\n1. **Step 1** - Description\n2. **Step 2** - Description\n3. **Step 3** - Description\n\n### Advanced Features\n\n[Link to advanced documentation]",
required: true,
},
{
title: "Contributing",
content:
"## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and contribution guidelines.",
required: false,
},
{
title: "License",
content: "## License\n\n{{license}} © {{author}}",
required: true,
},
],
badges: [
"[](https://github.com/{{author}}/{{projectName}}/actions)",
"[](LICENSE)",
],
metadata: {
type: "application",
estimatedLength: 200,
},
});
// CLI Tool Template
this.templates.set("cli-tool", {
sections: [
{
title: "Header",
content: "# {{projectName}}\n\n> {{description}}",
required: true,
},
{
title: "Installation",
content:
"## Installation\n\n```bash\n# Global installation\nnpm install -g {{projectName}}\n\n# Or use with npx\nnpx {{projectName}} --help\n```",
required: true,
},
{
title: "Usage",
content:
"## Usage\n\n### Basic Commands\n\n```bash\n# Basic usage\n{{projectName}} [options] [arguments]\n\n# Show help\n{{projectName}} --help\n\n# Show version\n{{projectName}} --version\n```\n\n### Examples\n\n```bash\n# Example 1\n{{projectName}} command --option value\n\n# Example 2\n{{projectName}} another-command file.txt\n```",
required: true,
},
{
title: "Options",
content:
"## Options\n\n| Option | Description | Default |\n|--------|-------------|----------|\n| `-h, --help` | Show help | |\n| `-v, --version` | Show version | |\n| `--config <path>` | Config file path | `./config.json` |\n| `--verbose` | Verbose output | `false` |",
required: true,
},
{
title: "Configuration",
content:
'## Configuration\n\nCreate a config file:\n\n```json\n{\n "setting1": "value1",\n "setting2": "value2"\n}\n```',
required: false,
},
{
title: "Contributing",
content:
"## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development guidelines.",
required: false,
},
{
title: "License",
content: "## License\n\n{{license}} © {{author}}",
required: true,
},
],
badges: [
"[](https://www.npmjs.com/package/{{projectName}})",
"[](LICENSE)",
],
metadata: {
type: "cli-tool",
estimatedLength: 180,
},
});
}
generateTemplate(input: GenerateReadmeTemplateInput): string {
const template = this.templates.get(input.templateType);
if (!template) {
throw new Error(`Template type "${input.templateType}" not supported`);
}
let readme = "";
const camelCaseName = this.toCamelCase(input.projectName);
// Process each section
for (const section of template.sections) {
if (section.title === "Badges" && input.includeBadges) {
readme += this.processBadges(template.badges, input) + "\n\n";
} else if (section.title === "Screenshot" && input.includeScreenshots) {
readme += this.processScreenshot(input) + "\n\n";
} else if (
section.title === "Contributing" &&
!input.includeContributing
) {
continue;
} else {
readme +=
this.processSection(section.content, input, camelCaseName) + "\n\n";
}
}
return readme.trim();
}
private processBadges(
badges: string[],
input: GenerateReadmeTemplateInput,
): string {
return badges
.map((badge) => this.replaceVariables(badge, input))
.join("\n");
}
private processScreenshot(input: GenerateReadmeTemplateInput): string {
return `\n\n*Add a screenshot or demo GIF here*`;
}
private processSection(
content: string,
input: GenerateReadmeTemplateInput,
camelCaseName: string,
): string {
let processed = this.replaceVariables(content, input);
processed = processed.replace(/\{\{camelCaseName\}\}/g, camelCaseName);
return processed;
}
private replaceVariables(
content: string,
input: GenerateReadmeTemplateInput,
): string {
return content
.replace(/\{\{projectName\}\}/g, input.projectName)
.replace(/\{\{description\}\}/g, input.description)
.replace(/\{\{author\}\}/g, input.author || "your-username")
.replace(/\{\{license\}\}/g, input.license);
}
private toCamelCase(str: string): string {
return str
.replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ""))
.replace(/^./, (c) => c.toLowerCase());
}
getAvailableTemplates(): TemplateType[] {
return Array.from(this.templates.keys());
}
getTemplateInfo(type: TemplateType): ReadmeTemplate["metadata"] | null {
const template = this.templates.get(type);
return template ? template.metadata : null;
}
}
/**
* Generates standardized README templates for different project types with best practices.
*
* Creates comprehensive README templates tailored to specific project types (library,
* application, CLI tool, API, documentation) following community best practices. Includes
* customizable sections, badges, contributing guidelines, and project-specific content
* to ensure professional documentation standards.
*
* @param input - The input parameters for README template generation
* @param input.projectName - Name of the project (required)
* @param input.description - Brief description of what the project does (required)
* @param input.templateType - Type of project template to generate
* @param input.author - Optional project author/organization name
* @param input.license - Project license (default: "MIT")
* @param input.includeScreenshots - Whether to include screenshot placeholders (default: false)
* @param input.includeBadges - Whether to include status badges (default: true)
* @param input.includeContributing - Whether to include contributing section (default: true)
* @param input.outputPath - Optional path to write the generated README.md file
*
* @returns Promise resolving to README template generation results
* @returns template - The generated README template content
* @returns metadata - Template metadata including type and estimated length
* @returns filePath - Path where the README was written (if outputPath provided)
*
* @throws {Error} When required parameters are missing
* @throws {Error} When output path is inaccessible
* @throws {Error} When template generation fails
*
* @example
* ```typescript
* // Generate library README template
* const result = await generateReadmeTemplate({
* projectName: "MyAwesomeLibrary",
* description: "A powerful utility library for data processing",
* templateType: "library",
* author: "Your Name",
* license: "MIT",
* includeBadges: true
* });
*
* console.log(`Generated ${result.metadata.estimatedLength} line README`);
*
* // Generate CLI tool template with output file
* const cliTemplate = await generateReadmeTemplate({
* projectName: "my-cli-tool",
* description: "Command-line interface for project management",
* templateType: "cli-tool",
* outputPath: "./README.md"
* });
* ```
*
* @since 1.0.0
*/
export async function generateReadmeTemplate(
input: GenerateReadmeTemplateInput,
): Promise<{
content: string;
metadata: {
templateType: TemplateType;
estimatedLength: number;
sectionsIncluded: number;
};
}> {
const validatedInput = GenerateReadmeTemplateSchema.parse(input);
const generator = new ReadmeTemplateGenerator();
const content = generator.generateTemplate(validatedInput);
const templateInfo = generator.getTemplateInfo(validatedInput.templateType);
if (!templateInfo) {
throw new Error(`Template type "${validatedInput.templateType}" not found`);
}
// Write to file if output path specified
if (validatedInput.outputPath) {
const fs = await import("fs/promises");
await fs.writeFile(validatedInput.outputPath, content, "utf-8");
}
return {
content,
metadata: {
templateType: validatedInput.templateType,
estimatedLength: templateInfo.estimatedLength,
sectionsIncluded: content.split("##").length - 1,
},
};
}