UNPKG

@autodev/backend-generator

Version:

Backend project generator with support for parsing and generating project configurations

132 lines (101 loc) 8.22 kB
"use strict";const r=require("zod"),v=require("fs-extra"),y=require("path"),p=require("handlebars");function u(a){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(a){for(const e in a)if(e!=="default"){const o=Object.getOwnPropertyDescriptor(a,e);Object.defineProperty(t,e,o.get?o:{enumerable:!0,get:()=>a[e]})}}return t.default=a,Object.freeze(t)}const n=u(v),s=u(y),g=r.z.object({name:r.z.string().min(1,"Project name is required"),description:r.z.string().min(1,"Project description is required"),type:r.z.enum(["microservice","monolith","library"]),language:r.z.enum(["java","typescript","python","go","csharp"]),framework:r.z.string().min(1,"Framework is required")}),d=r.z.array(r.z.string()),m=r.z.object({directories:r.z.array(r.z.string()),files:r.z.array(r.z.string())}),h=r.z.record(r.z.string(),r.z.string()),f=r.z.record(r.z.string(),r.z.array(r.z.string())),j=r.z.object({projectConfig:g,features:d,structure:m,dependencies:h,configurations:f}),P=["microservice","monolith","library"],S=["java","typescript","python","go","csharp"],b=["authentication-authorization","database-integration","api-documentation","data-validation","docker-support","ci-cd-pipeline","testing-framework","logging-system","monitoring-metrics","caching","message-queue","file-upload","email-service","notification-service"];class c extends Error{constructor(t,e){super(t),this.details=e,this.name="ProjectParseError"}}class k{static parseFromJson(t){try{const e=JSON.parse(t);return this.parseFromObject(e)}catch(e){throw e instanceof SyntaxError?new c("Invalid JSON format",e.message):e}}static parseFromObject(t){try{return j.parse(t)}catch(e){if(e instanceof r.ZodError){const o=e.errors.map(i=>`${i.path.join(".")}: ${i.message}`).join(", ");throw new c(`Validation failed: ${o}`,e.errors)}throw e}}static validate(t){try{return{success:!0,data:this.parseFromObject(t)}}catch(e){return e instanceof c?{success:!1,error:e.message}:{success:!1,error:"Unknown validation error"}}}static async parseFromFile(t){try{const e=await n.readFile(t,"utf-8");return this.parseFromJson(e)}catch(e){throw e instanceof Error&&"code"in e&&e.code==="ENOENT"?new c(`File not found: ${t}`):e}}}class l extends Error{constructor(t,e){super(t),this.details=e,this.name="ProjectGenerateError"}}class O{constructor(t,e){this.project=t,this.options=e}async generate(){try{await this.validateOptions(),await this.createDirectories(),await this.generateFiles(),await this.generateConfigurationFiles()}catch(t){throw t instanceof Error?new l(`Generation failed: ${t.message}`,t):t}}static generateJson(t,e=!0){return JSON.stringify(t,null,e?2:0)}static async saveToFile(t,e,o=!0){const i=this.generateJson(t,o);await n.ensureDir(s.dirname(e)),await n.writeFile(e,i,"utf-8")}async validateOptions(){if(!this.options.outputDir)throw new l("Output directory is required");if(await n.pathExists(this.options.outputDir)&&!this.options.overwrite&&(await n.readdir(this.options.outputDir)).length>0)throw new l(`Output directory ${this.options.outputDir} is not empty. Use --overwrite to force.`)}async createDirectories(){const{directories:t}=this.project.structure;for(const e of t){const o=s.join(this.options.outputDir,e);this.options.dryRun?console.log(`[DRY RUN] Would create directory: ${o}`):(await n.ensureDir(o),console.log(`Created directory: ${o}`))}}async generateFiles(){const{files:t}=this.project.structure;for(const e of t){const o=s.join(this.options.outputDir,e);if(this.options.dryRun)console.log(`[DRY RUN] Would create file: ${o}`);else{await n.ensureDir(s.dirname(o));const i=await this.generateFileContent(e);await n.writeFile(o,i,"utf-8"),console.log(`Created file: ${o}`)}}}async generateConfigurationFiles(){const{configurations:t}=this.project;for(const[e,o]of Object.entries(t)){const i=s.join(this.options.outputDir,e),w=o.join(` `);this.options.dryRun?console.log(`[DRY RUN] Would create configuration file: ${i}`):(await n.ensureDir(s.dirname(i)),await n.writeFile(i,w,"utf-8"),console.log(`Created configuration file: ${i}`))}}async generateFileContent(t){const{projectConfig:e,dependencies:o}=this.project,i={projectName:e.name,description:e.description,language:e.language,framework:e.framework,dependencies:o,packageName:this.getPackageName(e.name),className:this.getClassName(e.name)};return t.endsWith(".java")?this.generateJavaFile(t,i):t==="pom.xml"?this.generatePomXml(i):t==="build.gradle"?this.generateBuildGradle(i):t.endsWith(".md")?this.generateMarkdownFile(t,i):`// Generated file: ${t} // TODO: Implement content for ${t}`}generateJavaFile(t,e){return t.includes("Application.java")?this.generateSpringBootApplication(e):`package ${e.packageName}; // TODO: Implement ${t}`}generateSpringBootApplication(t){return p.compile(`package {{packageName}}; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * {{description}} */ @SpringBootApplication public class {{className}}Application { public static void main(String[] args) { SpringApplication.run({{className}}Application.class, args); } }`)(t)}generatePomXml(t){return p.compile(`<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>{{projectName}}</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>{{projectName}}</name> <description>{{description}}</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.0</version> <relativePath/> </parent> <properties> <java.version>11</java.version> </properties> <dependencies> {{#each dependencies}} <dependency> <groupId>org.springframework.boot</groupId> <artifactId>{{@key}}</artifactId> <version>{{this}}</version> </dependency> {{/each}} </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>`)(t)}generateBuildGradle(t){return p.compile(`plugins { id 'java' id 'org.springframework.boot' version '3.0.0' id 'io.spring.dependency-management' version '1.1.0' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' repositories { mavenCentral() } dependencies { {{#each dependencies}} implementation '{{@key}}:{{this}}' {{/each}} } tasks.named('test') { useJUnitPlatform() }`)(t)}generateMarkdownFile(t,e){return t.toLowerCase()==="readme.md"?p.compile(`# {{projectName}} {{description}} ## Features - Microservice architecture - Spring Boot 3.0 - RESTful API - Database integration - Docker support ## Getting Started ### Prerequisites - Java 11 or higher - Maven 3.6 or higher - Docker (optional) ### Running the application \`\`\`bash mvn spring-boot:run \`\`\` ### Building for production \`\`\`bash mvn clean package \`\`\` ### Docker \`\`\`bash docker build -t {{projectName}} . docker run -p 8080:8080 {{projectName}} \`\`\` ## API Documentation The API documentation is available at: http://localhost:8080/swagger-ui.html ## License This project is licensed under the MIT License.`)(e):`# ${t} TODO: Add content for ${t}`}getPackageName(t){return`com.example.${t.toLowerCase().replace(/-/g,"")}`}getClassName(t){return t.split("-").map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join("")}}exports.COMMON_FEATURES=b;exports.ConfigurationsSchema=f;exports.DependenciesSchema=h;exports.FeaturesSchema=d;exports.LANGUAGES=S;exports.PROJECT_TYPES=P;exports.ProjectConfigSchema=g;exports.ProjectGenerateError=l;exports.ProjectGenerator=O;exports.ProjectParseError=c;exports.ProjectParser=k;exports.ProjectSchema=j;exports.StructureSchema=m;