From 38a7f39f08e0444b596386073d71635e14b21aad Mon Sep 17 00:00:00 2001 From: Yago Azevedo Borba <140000816+YagoBorba@users.noreply.github.com> Date: Fri, 22 Aug 2025 00:49:27 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20:sparkles:=20Implement=20compre?= =?UTF-8?q?hensive=20stack=20generator=20with=208=20technology=20stacks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add support for Node.js (JavaScript), React, Vue.js, Python (FastAPI), Java (Spring), Go (Gin), and PHP (Laravel) - Create complete project templates with modern folder structures and best practices - Implement smart package manager detection (npm, pip, maven, go mod, composer) - Add comprehensive documentation system for stack contributions - Modernize React templates with JSX Transform (remove React imports) - Include TailwindCSS integration for frontend stacks - Add extensive testing templates and configuration files - Create stack-specific .gitignore files and environment templates - Enhance CLI with interactive stack selection menu - Update type definitions and interfaces for multi-stack support Resolves: #29 Add Support for Additional Technology Stacks Resolves: #34 Integrate Automatic Folder Structure Creation into Stack Generator This implementation provides a complete scaffolding system supporting 8 technology stacks with automatic folder structure generation, package manager integration, and comprehensive documentation for future contributions. --- CONTRIBUTING.md | 235 ++++++++++++++++++ README.md | 2 +- docs/STACKS.md | 192 ++++++++++++++ packages/cli/dist/commands/init.js | 16 +- packages/cli/src/commands/init.ts | 12 +- packages/cli/src/commands/ui.ts | 13 +- packages/core/README.md | 2 +- packages/core/dist/scaffold.d.ts | 2 +- .../dist/templates/node-ts/package.json.tpl | 20 +- .../dist/templates/node-ts/src/index.ts.tpl | 25 +- .../results.json | 2 +- packages/core/src/scaffold.ts | 2 +- .../src/templates/common/.editorconfig.tpl | 27 ++ .../src/templates/common/.env.example.tpl | 28 +++ .../src/templates/common/CONTRIBUTING.md.tpl | 49 ++++ .../core/src/templates/gitignore/node-js.tpl | 116 +++++++++ packages/core/src/templates/go/go.mod.tpl | 35 +++ packages/core/src/templates/go/main.go.tpl | 78 ++++++ packages/core/src/templates/java/pom.xml.tpl | 58 +++++ .../java/com/example/app/Application.java.tpl | 17 ++ .../app/controller/MainController.java.tpl | 31 +++ .../src/templates/node-js/.env.example.tpl | 15 ++ .../src/templates/node-js/.eslintrc.cjs.tpl | 21 ++ .../core/src/templates/node-js/README.md.tpl | 96 +++++++ .../src/templates/node-js/jest.config.js.tpl | 13 + .../src/templates/node-js/package.json.tpl | 39 +++ .../src/controllers/userController.js.tpl | 157 ++++++++++++ .../src/templates/node-js/src/index.js.tpl | 61 +++++ .../src/middleware/errorHandler.js.tpl | 50 ++++ .../templates/node-js/src/routes/api.js.tpl | 28 +++ .../node-js/src/routes/health.js.tpl | 37 +++ .../templates/node-js/src/utils/logger.js.tpl | 42 ++++ .../templates/node-js/test/app.test.js.tpl | 93 +++++++ .../src/templates/node-ts/package.json.tpl | 20 +- .../src/controllers/example.controller.ts.tpl | 20 ++ .../src/templates/node-ts/src/index.ts.tpl | 25 +- .../templates/node-ts/src/utils/logger.ts.tpl | 16 ++ .../node-ts/tests/example.test.ts.tpl | 22 ++ .../core/src/templates/php/.env.example.tpl | 58 +++++ .../Http/Controllers/HomeController.php.tpl | 46 ++++ .../src/templates/php/bootstrap/app.php.tpl | 19 ++ .../core/src/templates/php/composer.json.tpl | 63 +++++ .../php/resources/views/welcome.blade.php.tpl | 68 +++++ .../core/src/templates/php/routes/api.php.tpl | 23 ++ .../core/src/templates/php/routes/web.php.tpl | 17 ++ .../src/templates/python/pyproject.toml.tpl | 42 ++++ .../core/src/templates/python/src/main.py.tpl | 35 +++ .../core/src/templates/react/index.html.tpl | 13 + .../core/src/templates/react/package.json.tpl | 39 +++ .../src/templates/react/postcss.config.js.tpl | 6 + .../core/src/templates/react/src/App.tsx.tpl | 20 ++ .../src/components/common/Layout.tsx.tpl | 32 +++ .../src/components/pages/AboutPage.tsx.tpl | 25 ++ .../src/components/pages/HomePage.tsx.tpl | 20 ++ .../core/src/templates/react/src/main.tsx.tpl | 10 + .../react/src/styles/globals.css.tpl | 73 ++++++ .../templates/react/tailwind.config.js.tpl | 11 + .../src/templates/react/tsconfig.json.tpl | 25 ++ .../templates/react/tsconfig.node.json.tpl | 10 + .../src/templates/react/vite.config.ts.tpl | 14 ++ .../core/src/templates/vue/index.html.tpl | 13 + .../core/src/templates/vue/package.json.tpl | 33 +++ .../src/templates/vue/postcss.config.js.tpl | 6 + .../core/src/templates/vue/src/App.vue.tpl | 15 ++ .../vue/src/components/Footer.vue.tpl | 11 + .../vue/src/components/Header.vue.tpl | 21 ++ .../core/src/templates/vue/src/main.ts.tpl | 19 ++ .../templates/vue/src/styles/globals.css.tpl | 26 ++ .../src/templates/vue/src/views/About.vue.tpl | 28 +++ .../src/templates/vue/src/views/Home.vue.tpl | 21 ++ .../src/templates/vue/tailwind.config.js.tpl | 11 + .../core/src/templates/vue/tsconfig.json.tpl | 25 ++ .../src/templates/vue/tsconfig.node.json.tpl | 10 + .../core/src/templates/vue/vite.config.ts.tpl | 14 ++ 74 files changed, 2620 insertions(+), 19 deletions(-) create mode 100644 docs/STACKS.md create mode 100644 packages/core/src/templates/common/.editorconfig.tpl create mode 100644 packages/core/src/templates/common/.env.example.tpl create mode 100644 packages/core/src/templates/common/CONTRIBUTING.md.tpl create mode 100644 packages/core/src/templates/gitignore/node-js.tpl create mode 100644 packages/core/src/templates/go/go.mod.tpl create mode 100644 packages/core/src/templates/go/main.go.tpl create mode 100644 packages/core/src/templates/java/pom.xml.tpl create mode 100644 packages/core/src/templates/java/src/main/java/com/example/app/Application.java.tpl create mode 100644 packages/core/src/templates/java/src/main/java/com/example/app/controller/MainController.java.tpl create mode 100644 packages/core/src/templates/node-js/.env.example.tpl create mode 100644 packages/core/src/templates/node-js/.eslintrc.cjs.tpl create mode 100644 packages/core/src/templates/node-js/README.md.tpl create mode 100644 packages/core/src/templates/node-js/jest.config.js.tpl create mode 100644 packages/core/src/templates/node-js/package.json.tpl create mode 100644 packages/core/src/templates/node-js/src/controllers/userController.js.tpl create mode 100644 packages/core/src/templates/node-js/src/index.js.tpl create mode 100644 packages/core/src/templates/node-js/src/middleware/errorHandler.js.tpl create mode 100644 packages/core/src/templates/node-js/src/routes/api.js.tpl create mode 100644 packages/core/src/templates/node-js/src/routes/health.js.tpl create mode 100644 packages/core/src/templates/node-js/src/utils/logger.js.tpl create mode 100644 packages/core/src/templates/node-js/test/app.test.js.tpl create mode 100644 packages/core/src/templates/node-ts/src/controllers/example.controller.ts.tpl create mode 100644 packages/core/src/templates/node-ts/src/utils/logger.ts.tpl create mode 100644 packages/core/src/templates/node-ts/tests/example.test.ts.tpl create mode 100644 packages/core/src/templates/php/.env.example.tpl create mode 100644 packages/core/src/templates/php/app/Http/Controllers/HomeController.php.tpl create mode 100644 packages/core/src/templates/php/bootstrap/app.php.tpl create mode 100644 packages/core/src/templates/php/composer.json.tpl create mode 100644 packages/core/src/templates/php/resources/views/welcome.blade.php.tpl create mode 100644 packages/core/src/templates/php/routes/api.php.tpl create mode 100644 packages/core/src/templates/php/routes/web.php.tpl create mode 100644 packages/core/src/templates/python/pyproject.toml.tpl create mode 100644 packages/core/src/templates/python/src/main.py.tpl create mode 100644 packages/core/src/templates/react/index.html.tpl create mode 100644 packages/core/src/templates/react/package.json.tpl create mode 100644 packages/core/src/templates/react/postcss.config.js.tpl create mode 100644 packages/core/src/templates/react/src/App.tsx.tpl create mode 100644 packages/core/src/templates/react/src/components/common/Layout.tsx.tpl create mode 100644 packages/core/src/templates/react/src/components/pages/AboutPage.tsx.tpl create mode 100644 packages/core/src/templates/react/src/components/pages/HomePage.tsx.tpl create mode 100644 packages/core/src/templates/react/src/main.tsx.tpl create mode 100644 packages/core/src/templates/react/src/styles/globals.css.tpl create mode 100644 packages/core/src/templates/react/tailwind.config.js.tpl create mode 100644 packages/core/src/templates/react/tsconfig.json.tpl create mode 100644 packages/core/src/templates/react/tsconfig.node.json.tpl create mode 100644 packages/core/src/templates/react/vite.config.ts.tpl create mode 100644 packages/core/src/templates/vue/index.html.tpl create mode 100644 packages/core/src/templates/vue/package.json.tpl create mode 100644 packages/core/src/templates/vue/postcss.config.js.tpl create mode 100644 packages/core/src/templates/vue/src/App.vue.tpl create mode 100644 packages/core/src/templates/vue/src/components/Footer.vue.tpl create mode 100644 packages/core/src/templates/vue/src/components/Header.vue.tpl create mode 100644 packages/core/src/templates/vue/src/main.ts.tpl create mode 100644 packages/core/src/templates/vue/src/styles/globals.css.tpl create mode 100644 packages/core/src/templates/vue/src/views/About.vue.tpl create mode 100644 packages/core/src/templates/vue/src/views/Home.vue.tpl create mode 100644 packages/core/src/templates/vue/tailwind.config.js.tpl create mode 100644 packages/core/src/templates/vue/tsconfig.json.tpl create mode 100644 packages/core/src/templates/vue/tsconfig.node.json.tpl create mode 100644 packages/core/src/templates/vue/vite.config.ts.tpl diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f8c5ee35..324340b0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,6 +7,7 @@ First off, thank you for considering contributing! It's people like you that mak - [Code of Conduct](#code-of-conduct) - [How Can I Contribute?](#how-can-i-contribute) - [Development Setup](#development-setup) +- [Adding New Technology Stacks](#adding-new-technology-stacks) - [Git Workflow and Pull Requests](#git-workflow-and-pull-requests) - [Coding Style and Principles](#coding-style-and-principles) - [Commit Message Guidelines](#commit-message-guidelines) @@ -58,6 +59,240 @@ You can now test your local changes by running the CLI from the root of the proj node packages/cli/dist/index.js ``` +## Adding New Technology Stacks + +StackCode currently supports multiple technology stacks (React, Vue, Node.js, Python, Java, Go, PHP). If you want to add support for a new technology stack, follow this comprehensive guide: + +### 1. Understanding the Stack Generator Architecture + +The stack generator system consists of several components: + +- **Templates**: Located in `packages/core/src/templates/` +- **Type Definitions**: In `packages/core/src/types.ts` and `packages/cli/src/commands/ui.ts` +- **Scaffolding Logic**: In `packages/core/src/scaffold.ts` +- **CLI Integration**: In `packages/cli/src/commands/init.ts` + +### 2. Step-by-Step Guide to Add a New Stack + +#### Step 1: Create Template Directory Structure + +Create a new directory under `packages/core/src/templates/` with your stack name (e.g., `angular`, `django`, `rails`): + +```bash +mkdir packages/core/src/templates/your-stack-name +``` + +#### Step 2: Create Template Files + +Create the necessary template files with `.tpl` extension. These files support variable replacement using `{{variableName}}` syntax: + +``` +packages/core/src/templates/your-stack-name/ +├── package.json.tpl # Or equivalent (requirements.txt, composer.json, etc.) +├── src/ +│ ├── main.ts.tpl # Main application file +│ ├── components/ # Component structure +│ │ └── Example.tsx.tpl +│ └── styles/ +│ └── globals.css.tpl +├── tsconfig.json.tpl # Configuration files +├── vite.config.ts.tpl # Build tool configuration +└── index.html.tpl # Entry point (for frontend stacks) +``` + +**Important**: Use these replacement variables in your templates: +- `{{projectName}}` - The project name +- `{{description}}` - Project description +- `{{authorName}}` - Author name + +**Example package.json.tpl:** +```json +{ + "name": "{{projectName}}", + "version": "1.0.0", + "description": "{{description}}", + "author": "{{authorName}}", + "scripts": { + "dev": "your-dev-command", + "build": "your-build-command" + } +} +``` + +#### Step 3: Create .gitignore Template + +Add a corresponding gitignore template in `packages/core/src/templates/gitignore/your-stack-name.tpl`: + +```bash +# Example: packages/core/src/templates/gitignore/angular.tpl +node_modules/ +dist/ +.angular/ +.env +*.log +``` + +#### Step 4: Update Type Definitions + +Add your new stack to the type definitions: + +**In `packages/core/src/scaffold.ts`:** +```typescript +export interface ProjectOptions { + projectPath: string; + stack: "node-js" | "node-ts" | "react" | "vue" | "python" | "java" | "go" | "php" | "your-stack-name"; + features: ("docker" | "husky")[]; + replacements: Record; +} +``` + +**In `packages/cli/src/commands/ui.ts`:** +```typescript +export interface InitAnswers { + projectName: string; + description: string; + authorName: string; + stack: "node-js" | "node-ts" | "react" | "vue" | "python" | "java" | "go" | "php" | "your-stack-name"; + features: ("docker" | "husky")[]; + commitValidation?: boolean; +} +``` + +#### Step 5: Add to CLI Options + +Update the stack choices in `packages/cli/src/commands/ui.ts`: + +```typescript +{ + type: "list", + name: "stack", + message: t("init.prompt.stack"), + choices: [ + { name: "Node.js + JavaScript", value: "node-js" }, + { name: "Node.js + TypeScript", value: "node-ts" }, + { name: "React + TypeScript", value: "react" }, + { name: "Vue.js + TypeScript", value: "vue" }, + { name: "Python + FastAPI", value: "python" }, + { name: "Java + Spring", value: "java" }, + { name: "Go + Gin", value: "go" }, + { name: "PHP + Laravel", value: "php" }, + { name: "Your Stack + Framework", value: "your-stack-name" }, + ], +} +``` + +#### Step 6: Update Package Manager Logic + +If your stack uses a different package manager, update the dependency installation logic in `packages/cli/src/commands/init.ts`: + +```typescript +// Install dependencies based on the stack type +if (answers.stack === "python") { + await runCommand("pip", ["install", "-e", "."], { cwd: projectPath }); +} else if (answers.stack === "java") { + await runCommand("mvn", ["install"], { cwd: projectPath }); +} else if (answers.stack === "go") { + await runCommand("go", ["mod", "tidy"], { cwd: projectPath }); +} else if (answers.stack === "php") { + await runCommand("composer", ["install"], { cwd: projectPath }); +} else if (answers.stack === "your-stack-name") { + await runCommand("your-package-manager", ["install"], { cwd: projectPath }); +} else { + // For Node.js-based stacks (node-js, node-ts, react, vue) + await runCommand("npm", ["install"], { cwd: projectPath }); +} +``` + +### 3. Best Practices for New Stacks + +#### Template Structure Guidelines: +- **Follow conventions**: Use the technology's standard project structure +- **Include essentials**: Configuration files, build tools, testing setup +- **Add documentation**: Include basic README template +- **Consider scalability**: Create folders for components, services, etc. +- **Modern practices**: Use latest stable versions and best practices + +#### Example Folder Structures: + +**Frontend Stack (SPA):** +``` +src/ +├── components/ +├── pages/ or views/ +├── services/ +├── styles/ +├── utils/ +└── main.ts +``` + +**Backend Stack (API):** +``` +src/ +├── controllers/ +├── models/ +├── services/ +├── middleware/ +├── routes/ +└── main.ts +``` + +**Full-Stack Framework:** +``` +src/ +├── components/ +├── pages/ +├── api/ +├── styles/ +└── utils/ +``` + +### 4. Testing Your New Stack + +1. **Build the project**: `npm run build` +2. **Test scaffolding**: Create a test project with your new stack +3. **Verify structure**: Check that all files are created correctly +4. **Test build**: Ensure the generated project builds/runs successfully +5. **Run tests**: Execute `npm test` to ensure no regressions + +### 5. Example: Adding Angular Support + +Here's a practical example of adding Angular support: + +```bash +# 1. Create template directory +mkdir packages/core/src/templates/angular + +# 2. Create basic structure +packages/core/src/templates/angular/ +├── package.json.tpl +├── angular.json.tpl +├── tsconfig.json.tpl +├── src/ +│ ├── app/ +│ │ ├── app.component.ts.tpl +│ │ ├── app.component.html.tpl +│ │ └── app.module.ts.tpl +│ ├── main.ts.tpl +│ └── index.html.tpl +└── .gitignore.tpl +``` + +### 6. Submission Guidelines + +When submitting a PR for a new stack: + +1. **Test thoroughly**: Ensure the generated project works end-to-end +2. **Include examples**: Provide sample output or screenshots +3. **Update documentation**: Add your stack to relevant docs +4. **Follow naming**: Use kebab-case for stack names +5. **Add tests**: Include unit tests if complex logic is added + +### 7. Internationalization + +If adding UI text, ensure it's properly internationalized using the `@stackcode/i18n` package. + +This system is designed to be extensible and maintainable. By following these guidelines, you'll ensure that new stacks integrate seamlessly with the existing codebase. + ## Git Workflow and Pull Requests We use the **Gitflow** workflow. All development for new features and bugfixes should happen on branches created from the `develop` branch. diff --git a/README.md b/README.md index 4ae48bb7..32a829db 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Our goal is to make best practices the easiest path. StackCode is a suite of tools designed to work together seamlessly: - 🚀 **Effortless Project Scaffolding (`init`):** - Generate a complete, production-ready project structure in seconds. Starts with a professional Node.js + TypeScript stack, with more to come. + Generate a complete, production-ready project structure in seconds. Choose from multiple technology stacks including Node.js, React, Vue.js, Python, Java, Go, and PHP—each with best practices and optimal folder structures. - 📝 **Intelligent File Generation (`generate`):** Need a `.gitignore`? Don't just get one—get a perfect one. Our composable template engine combines rules for your stack, IDE, and tools (like Docker) into a single, organized file. diff --git a/docs/STACKS.md b/docs/STACKS.md new file mode 100644 index 00000000..af66fd65 --- /dev/null +++ b/docs/STACKS.md @@ -0,0 +1,192 @@ +# Supported Technology Stacks + +StackCode supports multiple technology stacks, each designed with best practices and optimal project structures. This document provides an overview of all supported stacks and their features. + +## 📋 Available Stacks + +### Frontend Stacks + +#### React + TypeScript +- **Framework**: React 18 with TypeScript +- **Build Tool**: Vite +- **Styling**: TailwindCSS +- **Routing**: React Router DOM +- **Testing**: Vitest +- **Features**: Modern JSX Transform, ESLint configuration, component structure + +**Generated Structure:** +``` +├── src/ +│ ├── components/ +│ │ ├── common/ # Reusable components +│ │ └── pages/ # Page components +│ ├── styles/ +│ └── main.tsx +├── index.html +├── package.json +├── tsconfig.json +├── vite.config.ts +└── tailwind.config.js +``` + +#### Vue.js + TypeScript +- **Framework**: Vue 3 with Composition API and TypeScript +- **Build Tool**: Vite +- **Styling**: TailwindCSS +- **Routing**: Vue Router +- **Testing**: Vitest +- **Features**: SFC (Single File Components), modern Vue patterns + +**Generated Structure:** +``` +├── src/ +│ ├── components/ # Reusable components +│ ├── views/ # Page views +│ ├── styles/ +│ └── main.ts +├── index.html +├── package.json +├── tsconfig.json +├── vite.config.ts +└── tailwind.config.js +``` + +### Backend Stacks + +#### Node.js + JavaScript +- **Runtime**: Node.js with ES6+ +- **Testing**: Jest +- **Features**: Express.js structure, middleware, controllers, routes + +**Generated Structure:** +``` +├── src/ +│ ├── controllers/ # Request handlers +│ ├── middleware/ # Custom middleware +│ ├── routes/ # Route definitions +│ ├── utils/ # Utility functions +│ └── index.js +├── test/ +├── package.json +└── jest.config.js +``` + +#### Node.js + TypeScript +- **Runtime**: Node.js with TypeScript +- **Testing**: Vitest +- **Features**: Type-safe development, modern TypeScript configuration + +**Generated Structure:** +``` +├── src/ +│ ├── controllers/ # Type-safe controllers +│ ├── utils/ # Utility functions +│ └── index.ts +├── tests/ +├── package.json +└── tsconfig.json +``` + +#### Python + FastAPI +- **Framework**: FastAPI +- **Package Management**: pip with pyproject.toml +- **Features**: Modern Python async API development + +**Generated Structure:** +``` +├── src/ +│ └── main.py +└── pyproject.toml +``` + +#### Java + Spring +- **Framework**: Spring Boot +- **Build Tool**: Maven +- **Features**: Enterprise Java development structure + +**Generated Structure:** +``` +├── src/main/java/com/example/app/ +│ ├── Application.java +│ └── controller/ +│ └── MainController.java +└── pom.xml +``` + +#### Go + Gin +- **Framework**: Gin web framework +- **Package Management**: Go modules +- **Features**: High-performance Go web development + +**Generated Structure:** +``` +├── main.go +└── go.mod +``` + +#### PHP + Laravel +- **Framework**: Laravel +- **Package Management**: Composer +- **Features**: Modern PHP development with MVC structure + +**Generated Structure:** +``` +├── app/Http/Controllers/ +├── bootstrap/ +├── resources/views/ +├── routes/ +└── composer.json +``` + +## 🔧 Stack Features + +### Automatic Configuration +Each stack includes: +- ✅ **Optimized package.json** (or equivalent) with relevant dependencies +- ✅ **TypeScript configuration** (where applicable) +- ✅ **Build tool setup** (Vite, Maven, etc.) +- ✅ **Linting and formatting** configured +- ✅ **Testing framework** integrated +- ✅ **Best practice folder structure** + +### Smart Package Management +StackCode automatically uses the appropriate package manager: +- **npm** for Node.js-based stacks (React, Vue, Node.js) +- **pip** for Python projects +- **maven** for Java projects +- **go mod** for Go projects +- **composer** for PHP projects + +### Docker Support +All stacks can include Docker configuration when the Docker feature is selected during project initialization. + +### Git Integration +Every generated project includes: +- ✅ **Stack-specific .gitignore** files +- ✅ **Git repository initialization** +- ✅ **Conventional commit setup** (with Husky) + +## 🚀 Usage + +To create a project with any stack: + +```bash +stc init +``` + +Then select your preferred technology stack from the interactive menu. + +## 🛠️ Contributing New Stacks + +Interested in adding support for a new technology stack? Check out our comprehensive guide in [CONTRIBUTING.md](../CONTRIBUTING.md#adding-new-technology-stacks). + +The process involves: +1. Creating template files +2. Updating type definitions +3. Adding CLI options +4. Configuring package management +5. Testing thoroughly + +--- + +*For more information about StackCode, visit our [main documentation](../README.md).* diff --git a/packages/cli/dist/commands/init.js b/packages/cli/dist/commands/init.js index 270e89b1..dcaf9172 100644 --- a/packages/cli/dist/commands/init.js +++ b/packages/cli/dist/commands/init.js @@ -59,7 +59,21 @@ export const getInitCommand = () => ({ ui.log.info(` ${t("init.step.git")}`); await runCommand("git", ["init"], { cwd: projectPath }); ui.log.info(` ${t("init.step.deps")}`); - await runCommand("npm", ["install"], { cwd: projectPath }); + if (answers.stack === "python") { + await runCommand("pip", ["install", "-e", "."], { cwd: projectPath }); + } + else if (answers.stack === "java") { + await runCommand("mvn", ["install"], { cwd: projectPath }); + } + else if (answers.stack === "go") { + await runCommand("go", ["mod", "tidy"], { cwd: projectPath }); + } + else if (answers.stack === "php") { + await runCommand("composer", ["install"], { cwd: projectPath }); + } + else { + await runCommand("npm", ["install"], { cwd: projectPath }); + } ui.log.divider(); ui.log.success(t("init.success.ready")); ui.log.info(`\n${t("init.success.next_steps")}`); diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 12d4de5c..7f6d6758 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -84,7 +84,17 @@ export const getInitCommand = (): CommandModule => ({ await runCommand("git", ["init"], { cwd: projectPath }); ui.log.info(` ${t("init.step.deps")}`); - await runCommand("npm", ["install"], { cwd: projectPath }); + if (answers.stack === "python") { + await runCommand("pip", ["install", "-e", "."], { cwd: projectPath }); + } else if (answers.stack === "java") { + await runCommand("mvn", ["install"], { cwd: projectPath }); + } else if (answers.stack === "go") { + await runCommand("go", ["mod", "tidy"], { cwd: projectPath }); + } else if (answers.stack === "php") { + await runCommand("composer", ["install"], { cwd: projectPath }); + } else { + await runCommand("npm", ["install"], { cwd: projectPath }); + } ui.log.divider(); ui.log.success(t("init.success.ready")); diff --git a/packages/cli/src/commands/ui.ts b/packages/cli/src/commands/ui.ts index d490a941..a22fd0da 100644 --- a/packages/cli/src/commands/ui.ts +++ b/packages/cli/src/commands/ui.ts @@ -194,7 +194,7 @@ export interface InitAnswers { projectName: string; description: string; authorName: string; - stack: "node-ts"; + stack: "node-js" | "node-ts" | "react" | "vue" | "python" | "java" | "go" | "php"; features: ("docker" | "husky")[]; commitValidation?: boolean; } @@ -223,7 +223,16 @@ export async function promptForInitAnswers(): Promise { type: "list", name: "stack", message: t("init.prompt.stack"), - choices: [{ name: "Node.js + TypeScript", value: "node-ts" }], + choices: [ + { name: "Node.js + JavaScript", value: "node-js" }, + { name: "Node.js + TypeScript", value: "node-ts" }, + { name: "React + TypeScript", value: "react" }, + { name: "Vue.js + TypeScript", value: "vue" }, + { name: "Python + FastAPI", value: "python" }, + { name: "Java + Spring", value: "java" }, + { name: "Go + Gin", value: "go" }, + { name: "PHP + Laravel", value: "php" }, + ], }, { type: "checkbox", diff --git a/packages/core/README.md b/packages/core/README.md index 294def6c..b8027da6 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -20,7 +20,7 @@ Creates a complete project directory structure from predefined templates. - **`options`**: An object containing: - `projectPath: string`: The absolute path where the project will be created. - - `stack: 'node-ts'`: The technology stack to use. + - `stack: 'node-js' | 'node-ts' | 'react' | 'vue' | 'python' | 'java' | 'go' | 'php'`: The technology stack to use. - `features: ('docker' | 'husky')[]`: An array of additional features. - `replacements: Record`: Placeholders to replace in `.tpl` files. diff --git a/packages/core/dist/scaffold.d.ts b/packages/core/dist/scaffold.d.ts index e259a95a..8d2eec2b 100644 --- a/packages/core/dist/scaffold.d.ts +++ b/packages/core/dist/scaffold.d.ts @@ -1,6 +1,6 @@ export interface ProjectOptions { projectPath: string; - stack: "node-ts"; + stack: "node-js" | "node-ts" | "react" | "vue" | "python" | "java" | "go" | "php"; features: ("docker" | "husky")[]; replacements: Record; } diff --git a/packages/core/dist/templates/node-ts/package.json.tpl b/packages/core/dist/templates/node-ts/package.json.tpl index bf1c6e2a..090a680c 100644 --- a/packages/core/dist/templates/node-ts/package.json.tpl +++ b/packages/core/dist/templates/node-ts/package.json.tpl @@ -2,20 +2,32 @@ "name": "{{projectName}}", "version": "1.0.0", "description": "{{description}}", + "type": "module", "main": "dist/index.js", "scripts": { "clean": "rm -rf dist", "build": "tsc", "start": "node dist/index.js", "dev": "ts-node-dev --respawn --transpile-only src/index.ts", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "jest", + "test:watch": "jest --watch", + "lint": "eslint src/**/*.ts", + "lint:fix": "eslint src/**/*.ts --fix" }, - "keywords": [], + "keywords": ["nodejs", "typescript"], "author": "{{authorName}}", - "license": "ISC", - "dependencies": {}, + "license": "MIT", + "dependencies": { + "dotenv": "^16.3.1" + }, "devDependencies": { "@types/node": "^20.14.9", + "@types/jest": "^29.5.5", + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "eslint": "^8.49.0", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", "ts-node-dev": "^2.0.0", "typescript": "^5.5.2" } diff --git a/packages/core/dist/templates/node-ts/src/index.ts.tpl b/packages/core/dist/templates/node-ts/src/index.ts.tpl index 427cc75c..4206f6e2 100644 --- a/packages/core/dist/templates/node-ts/src/index.ts.tpl +++ b/packages/core/dist/templates/node-ts/src/index.ts.tpl @@ -1 +1,24 @@ -console.log('Hello, {{projectName}}!'); \ No newline at end of file +import { ExampleController } from './controllers/example.controller.js'; +import { Logger } from './utils/logger.js'; + +/** + * {{projectName}} - {{description}} + * + * A Node.js + TypeScript application generated by StackCode. + */ + +function main() { + Logger.info('Starting {{projectName}}...'); + + // Example usage of controller + const welcome = ExampleController.getWelcome(); + const health = ExampleController.getHealth(); + + Logger.info('Application initialized', { welcome, health }); + + // Your application logic goes here + Logger.info('{{projectName}} is running successfully!'); +} + +// Run the application +main(); \ No newline at end of file diff --git a/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json b/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json index cc43d702..1788a8a6 100644 --- a/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +++ b/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json @@ -1 +1 @@ -{"version":"3.2.4","results":[[":test/release.test.ts",{"duration":11.05421899999999,"failed":false}],[":test/github.test.ts",{"duration":12.256020999999976,"failed":false}],[":test/validator.test.ts",{"duration":4.313985000000002,"failed":false}]]} \ No newline at end of file +{"version":"3.2.4","results":[[":test/release.test.ts",{"duration":5.594452999999987,"failed":false}],[":test/github.test.ts",{"duration":9.374942999999973,"failed":false}],[":test/validator.test.ts",{"duration":3.7261689999999987,"failed":false}]]} \ No newline at end of file diff --git a/packages/core/src/scaffold.ts b/packages/core/src/scaffold.ts index 19c4e9c9..17cac670 100644 --- a/packages/core/src/scaffold.ts +++ b/packages/core/src/scaffold.ts @@ -39,7 +39,7 @@ async function copyTemplateFiles( export interface ProjectOptions { projectPath: string; - stack: "node-ts"; + stack: "node-js" | "node-ts" | "react" | "vue" | "python" | "java" | "go" | "php"; features: ("docker" | "husky")[]; replacements: Record; } diff --git a/packages/core/src/templates/common/.editorconfig.tpl b/packages/core/src/templates/common/.editorconfig.tpl new file mode 100644 index 00000000..38e456ea --- /dev/null +++ b/packages/core/src/templates/common/.editorconfig.tpl @@ -0,0 +1,27 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{js,ts,jsx,tsx,vue}] +indent_size = 2 + +[*.{py}] +indent_size = 4 + +[*.{java}] +indent_size = 4 + +[*.{go}] +indent_style = tab + +[*.{yml,yaml}] +indent_size = 2 diff --git a/packages/core/src/templates/common/.env.example.tpl b/packages/core/src/templates/common/.env.example.tpl new file mode 100644 index 00000000..1da87099 --- /dev/null +++ b/packages/core/src/templates/common/.env.example.tpl @@ -0,0 +1,28 @@ +# Example environment variables for {{projectName}} +# Copy this file to .env and fill in your actual values + +# Application +NODE_ENV=development +PORT=3000 +APP_NAME={{projectName}} + +# Database (if applicable) +# DATABASE_URL=postgresql://username:password@localhost:5432/database_name + +# API Keys (if applicable) +# API_KEY=your_api_key_here +# SECRET_KEY=your_secret_key_here + +# External Services (if applicable) +# REDIS_URL=redis://localhost:6379 +# MONGODB_URI=mongodb://localhost:27017/your_database + +# Email (if applicable) +# SMTP_HOST=smtp.gmail.com +# SMTP_PORT=587 +# SMTP_USER=your_email@gmail.com +# SMTP_PASS=your_password + +# Security +# JWT_SECRET=your_jwt_secret_here +# SESSION_SECRET=your_session_secret_here diff --git a/packages/core/src/templates/common/CONTRIBUTING.md.tpl b/packages/core/src/templates/common/CONTRIBUTING.md.tpl new file mode 100644 index 00000000..d0e6c6c4 --- /dev/null +++ b/packages/core/src/templates/common/CONTRIBUTING.md.tpl @@ -0,0 +1,49 @@ +# Contributing to {{projectName}} + +We love your input! We want to make contributing to {{projectName}} as easy and transparent as possible, whether it's: + +- Reporting a bug +- Discussing the current state of the code +- Submitting a fix +- Proposing new features +- Becoming a maintainer + +## Development Process + +We use GitHub to host code, to track issues and feature requests, as well as accept pull requests. + +### Pull Requests + +1. Fork the repo and create your branch from `main`. +2. If you've added code that should be tested, add tests. +3. If you've changed APIs, update the documentation. +4. Ensure the test suite passes. +5. Make sure your code lints. +6. Issue that pull request! + +### Coding Standards + +- Use meaningful variable and function names +- Write comments for complex logic +- Follow the existing code style +- Run `npm run lint` before committing + +### Commit Messages + +We use [Conventional Commits](https://conventionalcommits.org/) for commit messages: + +- `feat:` for new features +- `fix:` for bug fixes +- `docs:` for documentation changes +- `style:` for formatting changes +- `refactor:` for code refactoring +- `test:` for adding tests +- `chore:` for maintenance tasks + +## Code of Conduct + +This project and everyone participating in it is governed by our Code of Conduct. By participating, you are expected to uphold this code. + +## Questions? + +Feel free to contact the maintainers if you have any questions. diff --git a/packages/core/src/templates/gitignore/node-js.tpl b/packages/core/src/templates/gitignore/node-js.tpl new file mode 100644 index 00000000..662d121b --- /dev/null +++ b/packages/core/src/templates/gitignore/node-js.tpl @@ -0,0 +1,116 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node_modules +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +.env.development +.env.production + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +public + +# Vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* diff --git a/packages/core/src/templates/go/go.mod.tpl b/packages/core/src/templates/go/go.mod.tpl new file mode 100644 index 00000000..363d7c88 --- /dev/null +++ b/packages/core/src/templates/go/go.mod.tpl @@ -0,0 +1,35 @@ +module {{projectName}} + +go 1.21 + +require ( + github.com/gin-gonic/gin v1.9.1 + github.com/joho/godotenv v1.4.0 +) + +require ( + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/packages/core/src/templates/go/main.go.tpl b/packages/core/src/templates/go/main.go.tpl new file mode 100644 index 00000000..cfef28f0 --- /dev/null +++ b/packages/core/src/templates/go/main.go.tpl @@ -0,0 +1,78 @@ +package main + +import ( + "log" + "net/http" + "os" + + "github.com/gin-gonic/gin" + "github.com/joho/godotenv" +) + +// HealthResponse represents the health check response +type HealthResponse struct { + Status string `json:"status"` + Service string `json:"service"` + Version string `json:"version"` +} + +// WelcomeResponse represents the welcome message response +type WelcomeResponse struct { + Message string `json:"message"` + Status string `json:"status"` + Version string `json:"version"` +} + +func main() { + // Load environment variables + if err := godotenv.Load(); err != nil { + log.Println("No .env file found") + } + + // Set Gin mode + if os.Getenv("GIN_MODE") == "" { + gin.SetMode(gin.DebugMode) + } + + // Create Gin router + r := gin.Default() + + // Add middleware + r.Use(gin.Logger()) + r.Use(gin.Recovery()) + + // Routes + r.GET("/", handleWelcome) + r.GET("/health", handleHealth) + + // Get port from environment or use default + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + + log.Printf("Starting {{projectName}} server on port %s", port) + if err := r.Run(":" + port); err != nil { + log.Fatal("Failed to start server:", err) + } +} + +// handleWelcome handles the root endpoint +func handleWelcome(c *gin.Context) { + response := WelcomeResponse{ + Message: "Welcome to {{projectName}}!", + Status: "running", + Version: "1.0.0", + } + c.JSON(http.StatusOK, response) +} + +// handleHealth handles the health check endpoint +func handleHealth(c *gin.Context) { + response := HealthResponse{ + Status: "healthy", + Service: "{{projectName}}", + Version: "1.0.0", + } + c.JSON(http.StatusOK, response) +} diff --git a/packages/core/src/templates/java/pom.xml.tpl b/packages/core/src/templates/java/pom.xml.tpl new file mode 100644 index 00000000..b7f07766 --- /dev/null +++ b/packages/core/src/templates/java/pom.xml.tpl @@ -0,0 +1,58 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.1.5 + + + + com.example + {{projectName}} + 1.0.0 + {{projectName}} + {{description}} + + + 17 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/packages/core/src/templates/java/src/main/java/com/example/app/Application.java.tpl b/packages/core/src/templates/java/src/main/java/com/example/app/Application.java.tpl new file mode 100644 index 00000000..069c5cf4 --- /dev/null +++ b/packages/core/src/templates/java/src/main/java/com/example/app/Application.java.tpl @@ -0,0 +1,17 @@ +package com.example.app; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * {{projectName}} - {{description}} + * + * A Spring Boot application generated by StackCode. + */ +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/packages/core/src/templates/java/src/main/java/com/example/app/controller/MainController.java.tpl b/packages/core/src/templates/java/src/main/java/com/example/app/controller/MainController.java.tpl new file mode 100644 index 00000000..b5f09bb4 --- /dev/null +++ b/packages/core/src/templates/java/src/main/java/com/example/app/controller/MainController.java.tpl @@ -0,0 +1,31 @@ +package com.example.app.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import java.util.Map; +import java.util.HashMap; + +/** + * Main controller for {{projectName}} + */ +@RestController +public class MainController { + + @GetMapping("/") + public Map welcome() { + Map response = new HashMap<>(); + response.put("message", "Welcome to {{projectName}}!"); + response.put("status", "running"); + response.put("version", "1.0.0"); + return response; + } + + @GetMapping("/health") + public Map health() { + Map response = new HashMap<>(); + response.put("status", "healthy"); + response.put("service", "{{projectName}}"); + response.put("version", "1.0.0"); + return response; + } +} diff --git a/packages/core/src/templates/node-js/.env.example.tpl b/packages/core/src/templates/node-js/.env.example.tpl new file mode 100644 index 00000000..7266d971 --- /dev/null +++ b/packages/core/src/templates/node-js/.env.example.tpl @@ -0,0 +1,15 @@ +NODE_ENV=development +PORT=3000 + +# Database (when you add one) +# DB_HOST=localhost +# DB_PORT=5432 +# DB_NAME={{projectName}}_db +# DB_USER=postgres +# DB_PASSWORD=password + +# JWT Secret (when you add authentication) +# JWT_SECRET=your-super-secret-jwt-key + +# API Keys (when you integrate external services) +# API_KEY=your-api-key diff --git a/packages/core/src/templates/node-js/.eslintrc.cjs.tpl b/packages/core/src/templates/node-js/.eslintrc.cjs.tpl new file mode 100644 index 00000000..8aa99dd4 --- /dev/null +++ b/packages/core/src/templates/node-js/.eslintrc.cjs.tpl @@ -0,0 +1,21 @@ +module.exports = { + env: { + es2022: true, + node: true, + jest: true + }, + extends: [ + 'standard' + ], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module' + }, + rules: { + 'semi': ['error', 'always'], + 'quotes': ['error', 'single'], + 'no-unused-vars': ['error', { 'argsIgnorePattern': '^_' }], + 'no-console': 'warn', + 'prefer-const': 'error' + } +}; diff --git a/packages/core/src/templates/node-js/README.md.tpl b/packages/core/src/templates/node-js/README.md.tpl new file mode 100644 index 00000000..34e15682 --- /dev/null +++ b/packages/core/src/templates/node-js/README.md.tpl @@ -0,0 +1,96 @@ +# {{projectName}} + +{{description}} + +## 🚀 Getting Started + +### Prerequisites +- Node.js 18+ +- npm 8+ + +### Installation + +1. Clone the repository: +```bash +git clone +cd {{projectName}} +``` + +2. Install dependencies: +```bash +npm install +``` + +3. Create environment file: +```bash +cp .env.example .env +``` + +4. Start the development server: +```bash +npm run dev +``` + +The server will start at `http://localhost:3000` + +## 📜 Available Scripts + +- `npm start` - Start production server +- `npm run dev` - Start development server with auto-reload +- `npm test` - Run tests +- `npm run test:watch` - Run tests in watch mode +- `npm run lint` - Check code style +- `npm run lint:fix` - Fix code style issues + +## 🛠️ API Endpoints + +### Health Check +- `GET /health` - Basic health check +- `GET /health/detailed` - Detailed health information + +### API Routes +- `GET /api/welcome` - API welcome message +- `GET /api/users` - Get all users +- `GET /api/users/:id` - Get user by ID +- `POST /api/users` - Create new user +- `PUT /api/users/:id` - Update user +- `DELETE /api/users/:id` - Delete user + +## 📁 Project Structure + +``` +src/ +├── index.js # Main application file +├── controllers/ # Request handlers +│ └── userController.js +├── routes/ # Route definitions +│ ├── api.js +│ └── health.js +├── middleware/ # Custom middleware +│ └── errorHandler.js +└── utils/ # Utility functions + └── logger.js +``` + +## 🧪 Testing + +Run tests with: +```bash +npm test +``` + +## 🔧 Environment Variables + +Create a `.env` file with: +``` +NODE_ENV=development +PORT=3000 +``` + +## 👤 Author + +Created by {{authorName}} + +## 📄 License + +This project is licensed under the MIT License. diff --git a/packages/core/src/templates/node-js/jest.config.js.tpl b/packages/core/src/templates/node-js/jest.config.js.tpl new file mode 100644 index 00000000..9b109795 --- /dev/null +++ b/packages/core/src/templates/node-js/jest.config.js.tpl @@ -0,0 +1,13 @@ +export default { + testEnvironment: 'node', + testMatch: ['**/test/**/*.test.js'], + collectCoverageFrom: [ + 'src/**/*.js', + '!src/index.js' + ], + coverageDirectory: 'coverage', + coverageReporters: ['text', 'lcov', 'html'], + verbose: true, + forceExit: true, + clearMocks: true +}; diff --git a/packages/core/src/templates/node-js/package.json.tpl b/packages/core/src/templates/node-js/package.json.tpl new file mode 100644 index 00000000..a51dc4b3 --- /dev/null +++ b/packages/core/src/templates/node-js/package.json.tpl @@ -0,0 +1,39 @@ +{ + "name": "{{projectName}}", + "version": "1.0.0", + "description": "{{description}}", + "main": "src/index.js", + "type": "module", + "scripts": { + "start": "node src/index.js", + "dev": "nodemon src/index.js", + "test": "jest", + "test:watch": "jest --watch", + "lint": "eslint src/**/*.js", + "lint:fix": "eslint src/**/*.js --fix" + }, + "keywords": ["node", "javascript", "express", "api"], + "author": "{{authorName}}", + "license": "MIT", + "dependencies": { + "express": "^4.18.2", + "cors": "^2.8.5", + "helmet": "^7.0.0", + "morgan": "^1.10.0", + "dotenv": "^16.3.1" + }, + "devDependencies": { + "nodemon": "^3.0.1", + "jest": "^29.6.2", + "supertest": "^6.3.3", + "eslint": "^8.45.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^16.0.1", + "eslint-plugin-promise": "^6.1.1" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + } +} diff --git a/packages/core/src/templates/node-js/src/controllers/userController.js.tpl b/packages/core/src/templates/node-js/src/controllers/userController.js.tpl new file mode 100644 index 00000000..06d8b78e --- /dev/null +++ b/packages/core/src/templates/node-js/src/controllers/userController.js.tpl @@ -0,0 +1,157 @@ +import { logger } from '../utils/logger.js'; + +// Mock database - In a real app, you'd use a proper database +let users = [ + { id: 1, name: 'John Doe', email: 'john@example.com', createdAt: new Date().toISOString() }, + { id: 2, name: 'Jane Smith', email: 'jane@example.com', createdAt: new Date().toISOString() } +]; + +let nextId = 3; + +export const userController = { + // Get all users + getAll: (req, res) => { + try { + logger.info('Getting all users'); + res.json({ + success: true, + data: users, + count: users.length + }); + } catch (error) { + logger.error('Error getting users:', error); + res.status(500).json({ + success: false, + error: 'Internal server error' + }); + } + }, + + // Get user by ID + getById: (req, res) => { + try { + const id = parseInt(req.params.id); + const user = users.find(u => u.id === id); + + if (!user) { + return res.status(404).json({ + success: false, + error: 'User not found' + }); + } + + logger.info(`Getting user ${id}`); + res.json({ + success: true, + data: user + }); + } catch (error) { + logger.error('Error getting user:', error); + res.status(500).json({ + success: false, + error: 'Internal server error' + }); + } + }, + + // Create new user + create: (req, res) => { + try { + const { name, email } = req.body; + + if (!name || !email) { + return res.status(400).json({ + success: false, + error: 'Name and email are required' + }); + } + + const newUser = { + id: nextId++, + name, + email, + createdAt: new Date().toISOString() + }; + + users.push(newUser); + logger.info(`Created user ${newUser.id}`); + + res.status(201).json({ + success: true, + data: newUser, + message: 'User created successfully' + }); + } catch (error) { + logger.error('Error creating user:', error); + res.status(500).json({ + success: false, + error: 'Internal server error' + }); + } + }, + + // Update user + update: (req, res) => { + try { + const id = parseInt(req.params.id); + const userIndex = users.findIndex(u => u.id === id); + + if (userIndex === -1) { + return res.status(404).json({ + success: false, + error: 'User not found' + }); + } + + const { name, email } = req.body; + users[userIndex] = { + ...users[userIndex], + ...(name && { name }), + ...(email && { email }), + updatedAt: new Date().toISOString() + }; + + logger.info(`Updated user ${id}`); + res.json({ + success: true, + data: users[userIndex], + message: 'User updated successfully' + }); + } catch (error) { + logger.error('Error updating user:', error); + res.status(500).json({ + success: false, + error: 'Internal server error' + }); + } + }, + + // Delete user + delete: (req, res) => { + try { + const id = parseInt(req.params.id); + const userIndex = users.findIndex(u => u.id === id); + + if (userIndex === -1) { + return res.status(404).json({ + success: false, + error: 'User not found' + }); + } + + users.splice(userIndex, 1); + logger.info(`Deleted user ${id}`); + + res.json({ + success: true, + message: 'User deleted successfully' + }); + } catch (error) { + logger.error('Error deleting user:', error); + res.status(500).json({ + success: false, + error: 'Internal server error' + }); + } + } +}; diff --git a/packages/core/src/templates/node-js/src/index.js.tpl b/packages/core/src/templates/node-js/src/index.js.tpl new file mode 100644 index 00000000..f1156ee7 --- /dev/null +++ b/packages/core/src/templates/node-js/src/index.js.tpl @@ -0,0 +1,61 @@ +import express from 'express'; +import cors from 'cors'; +import helmet from 'helmet'; +import morgan from 'morgan'; +import dotenv from 'dotenv'; +import { router as healthRouter } from './routes/health.js'; +import { router as apiRouter } from './routes/api.js'; +import { errorHandler } from './middleware/errorHandler.js'; +import { logger } from './utils/logger.js'; + +// Load environment variables +dotenv.config(); + +const app = express(); +const PORT = process.env.PORT || 3000; + +// Middleware +app.use(helmet()); +app.use(cors()); +app.use(morgan('combined')); +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); + +// Routes +app.use('/health', healthRouter); +app.use('/api', apiRouter); + +// Root endpoint +app.get('/', (req, res) => { + res.json({ + message: 'Welcome to {{projectName}}', + description: '{{description}}', + version: '1.0.0', + author: '{{authorName}}', + endpoints: { + health: '/health', + api: '/api' + } + }); +}); + +// Error handling middleware +app.use(errorHandler); + +// 404 handler +app.use('*', (req, res) => { + res.status(404).json({ + error: 'Not Found', + message: `Route ${req.originalUrl} not found`, + statusCode: 404 + }); +}); + +// Start server +app.listen(PORT, () => { + logger.info(`🚀 Server running on port ${PORT}`); + logger.info(`📱 Environment: ${process.env.NODE_ENV || 'development'}`); + logger.info(`🔗 URL: http://localhost:${PORT}`); +}); + +export default app; diff --git a/packages/core/src/templates/node-js/src/middleware/errorHandler.js.tpl b/packages/core/src/templates/node-js/src/middleware/errorHandler.js.tpl new file mode 100644 index 00000000..b98929e6 --- /dev/null +++ b/packages/core/src/templates/node-js/src/middleware/errorHandler.js.tpl @@ -0,0 +1,50 @@ +import { logger } from '../utils/logger.js'; + +export const errorHandler = (err, req, res, next) => { + logger.error('Error occurred:', err); + + // Default error response + let error = { + success: false, + message: err.message || 'Internal Server Error', + statusCode: err.statusCode || 500 + }; + + // Mongoose validation error + if (err.name === 'ValidationError') { + const message = Object.values(err.errors).map(val => val.message); + error = { + ...error, + message: 'Validation Error', + details: message, + statusCode: 400 + }; + } + + // Mongoose duplicate key error + if (err.code === 11000) { + const message = 'Duplicate field value entered'; + error = { + ...error, + message, + statusCode: 400 + }; + } + + // Mongoose cast error + if (err.name === 'CastError') { + const message = 'Resource not found'; + error = { + ...error, + message, + statusCode: 404 + }; + } + + // Add stack trace in development + if (process.env.NODE_ENV === 'development') { + error.stack = err.stack; + } + + res.status(error.statusCode).json(error); +}; diff --git a/packages/core/src/templates/node-js/src/routes/api.js.tpl b/packages/core/src/templates/node-js/src/routes/api.js.tpl new file mode 100644 index 00000000..2f96ed05 --- /dev/null +++ b/packages/core/src/templates/node-js/src/routes/api.js.tpl @@ -0,0 +1,28 @@ +import express from 'express'; +import { userController } from '../controllers/userController.js'; + +const router = express.Router(); + +// API Routes +router.get('/welcome', (req, res) => { + res.json({ + message: 'Welcome to {{projectName}} API', + description: '{{description}}', + version: '1.0.0', + endpoints: [ + 'GET /api/welcome - This endpoint', + 'GET /api/users - Get all users', + 'GET /api/users/:id - Get user by ID', + 'POST /api/users - Create new user' + ] + }); +}); + +// User routes +router.get('/users', userController.getAll); +router.get('/users/:id', userController.getById); +router.post('/users', userController.create); +router.put('/users/:id', userController.update); +router.delete('/users/:id', userController.delete); + +export { router }; diff --git a/packages/core/src/templates/node-js/src/routes/health.js.tpl b/packages/core/src/templates/node-js/src/routes/health.js.tpl new file mode 100644 index 00000000..54e0857d --- /dev/null +++ b/packages/core/src/templates/node-js/src/routes/health.js.tpl @@ -0,0 +1,37 @@ +import express from 'express'; + +const router = express.Router(); + +// Health check endpoint +router.get('/', (req, res) => { + res.json({ + status: 'OK', + message: 'Service is healthy', + timestamp: new Date().toISOString(), + uptime: process.uptime(), + memory: process.memoryUsage(), + version: '1.0.0' + }); +}); + +// Detailed health check +router.get('/detailed', (req, res) => { + res.json({ + status: 'OK', + checks: { + database: 'OK', // Add actual database check here + cache: 'OK', // Add actual cache check here + external_api: 'OK' // Add external API checks here + }, + system: { + platform: process.platform, + nodeVersion: process.version, + pid: process.pid, + uptime: process.uptime(), + memory: process.memoryUsage() + }, + timestamp: new Date().toISOString() + }); +}); + +export { router }; diff --git a/packages/core/src/templates/node-js/src/utils/logger.js.tpl b/packages/core/src/templates/node-js/src/utils/logger.js.tpl new file mode 100644 index 00000000..d140176a --- /dev/null +++ b/packages/core/src/templates/node-js/src/utils/logger.js.tpl @@ -0,0 +1,42 @@ +// Simple logger utility +class Logger { + constructor() { + this.colors = { + info: '\x1b[36m', // Cyan + warn: '\x1b[33m', // Yellow + error: '\x1b[31m', // Red + success: '\x1b[32m', // Green + reset: '\x1b[0m' // Reset + }; + } + + formatMessage(level, message, ...args) { + const timestamp = new Date().toISOString(); + const color = this.colors[level] || this.colors.reset; + const levelStr = level.toUpperCase().padEnd(7); + + console.log( + `${color}[${timestamp}] ${levelStr}${this.colors.reset}`, + message, + ...args + ); + } + + info(message, ...args) { + this.formatMessage('info', message, ...args); + } + + warn(message, ...args) { + this.formatMessage('warn', message, ...args); + } + + error(message, ...args) { + this.formatMessage('error', message, ...args); + } + + success(message, ...args) { + this.formatMessage('success', message, ...args); + } +} + +export const logger = new Logger(); diff --git a/packages/core/src/templates/node-js/test/app.test.js.tpl b/packages/core/src/templates/node-js/test/app.test.js.tpl new file mode 100644 index 00000000..b77a5e21 --- /dev/null +++ b/packages/core/src/templates/node-js/test/app.test.js.tpl @@ -0,0 +1,93 @@ +import request from 'supertest'; +import app from '../src/index.js'; + +describe('Health Endpoints', () => { + test('GET /health should return OK status', async () => { + const response = await request(app) + .get('/health') + .expect(200); + + expect(response.body.status).toBe('OK'); + expect(response.body.message).toBe('Service is healthy'); + expect(response.body.timestamp).toBeDefined(); + }); + + test('GET /health/detailed should return detailed information', async () => { + const response = await request(app) + .get('/health/detailed') + .expect(200); + + expect(response.body.status).toBe('OK'); + expect(response.body.checks).toBeDefined(); + expect(response.body.system).toBeDefined(); + }); +}); + +describe('API Endpoints', () => { + test('GET / should return welcome message', async () => { + const response = await request(app) + .get('/') + .expect(200); + + expect(response.body.message).toContain('Welcome to'); + expect(response.body.version).toBe('1.0.0'); + }); + + test('GET /api/welcome should return API welcome', async () => { + const response = await request(app) + .get('/api/welcome') + .expect(200); + + expect(response.body.message).toContain('Welcome to'); + expect(response.body.endpoints).toBeDefined(); + }); +}); + +describe('User Endpoints', () => { + test('GET /api/users should return users list', async () => { + const response = await request(app) + .get('/api/users') + .expect(200); + + expect(response.body.success).toBe(true); + expect(Array.isArray(response.body.data)).toBe(true); + }); + + test('POST /api/users should create new user', async () => { + const newUser = { + name: 'Test User', + email: 'test@example.com' + }; + + const response = await request(app) + .post('/api/users') + .send(newUser) + .expect(201); + + expect(response.body.success).toBe(true); + expect(response.body.data.name).toBe(newUser.name); + expect(response.body.data.email).toBe(newUser.email); + expect(response.body.data.id).toBeDefined(); + }); + + test('POST /api/users should fail without required fields', async () => { + const response = await request(app) + .post('/api/users') + .send({}) + .expect(400); + + expect(response.body.success).toBe(false); + expect(response.body.error).toContain('required'); + }); +}); + +describe('Error Handling', () => { + test('GET /nonexistent should return 404', async () => { + const response = await request(app) + .get('/nonexistent') + .expect(404); + + expect(response.body.error).toBe('Not Found'); + expect(response.body.statusCode).toBe(404); + }); +}); diff --git a/packages/core/src/templates/node-ts/package.json.tpl b/packages/core/src/templates/node-ts/package.json.tpl index bf1c6e2a..090a680c 100644 --- a/packages/core/src/templates/node-ts/package.json.tpl +++ b/packages/core/src/templates/node-ts/package.json.tpl @@ -2,20 +2,32 @@ "name": "{{projectName}}", "version": "1.0.0", "description": "{{description}}", + "type": "module", "main": "dist/index.js", "scripts": { "clean": "rm -rf dist", "build": "tsc", "start": "node dist/index.js", "dev": "ts-node-dev --respawn --transpile-only src/index.ts", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "jest", + "test:watch": "jest --watch", + "lint": "eslint src/**/*.ts", + "lint:fix": "eslint src/**/*.ts --fix" }, - "keywords": [], + "keywords": ["nodejs", "typescript"], "author": "{{authorName}}", - "license": "ISC", - "dependencies": {}, + "license": "MIT", + "dependencies": { + "dotenv": "^16.3.1" + }, "devDependencies": { "@types/node": "^20.14.9", + "@types/jest": "^29.5.5", + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "eslint": "^8.49.0", + "jest": "^29.7.0", + "ts-jest": "^29.1.1", "ts-node-dev": "^2.0.0", "typescript": "^5.5.2" } diff --git a/packages/core/src/templates/node-ts/src/controllers/example.controller.ts.tpl b/packages/core/src/templates/node-ts/src/controllers/example.controller.ts.tpl new file mode 100644 index 00000000..3ff4fc5d --- /dev/null +++ b/packages/core/src/templates/node-ts/src/controllers/example.controller.ts.tpl @@ -0,0 +1,20 @@ +/** + * Example controller for handling basic routes + */ +export class ExampleController { + static getWelcome() { + return { + message: 'Welcome to {{projectName}}!', + status: 'running', + version: '1.0.0' + }; + } + + static getHealth() { + return { + status: 'healthy', + timestamp: new Date().toISOString(), + service: '{{projectName}}' + }; + } +} diff --git a/packages/core/src/templates/node-ts/src/index.ts.tpl b/packages/core/src/templates/node-ts/src/index.ts.tpl index 427cc75c..4206f6e2 100644 --- a/packages/core/src/templates/node-ts/src/index.ts.tpl +++ b/packages/core/src/templates/node-ts/src/index.ts.tpl @@ -1 +1,24 @@ -console.log('Hello, {{projectName}}!'); \ No newline at end of file +import { ExampleController } from './controllers/example.controller.js'; +import { Logger } from './utils/logger.js'; + +/** + * {{projectName}} - {{description}} + * + * A Node.js + TypeScript application generated by StackCode. + */ + +function main() { + Logger.info('Starting {{projectName}}...'); + + // Example usage of controller + const welcome = ExampleController.getWelcome(); + const health = ExampleController.getHealth(); + + Logger.info('Application initialized', { welcome, health }); + + // Your application logic goes here + Logger.info('{{projectName}} is running successfully!'); +} + +// Run the application +main(); \ No newline at end of file diff --git a/packages/core/src/templates/node-ts/src/utils/logger.ts.tpl b/packages/core/src/templates/node-ts/src/utils/logger.ts.tpl new file mode 100644 index 00000000..73f889b2 --- /dev/null +++ b/packages/core/src/templates/node-ts/src/utils/logger.ts.tpl @@ -0,0 +1,16 @@ +/** + * Simple logger utility + */ +export class Logger { + static info(message: string, data?: any) { + console.log(`[INFO] ${new Date().toISOString()}: ${message}`, data || ''); + } + + static error(message: string, error?: any) { + console.error(`[ERROR] ${new Date().toISOString()}: ${message}`, error || ''); + } + + static warn(message: string, data?: any) { + console.warn(`[WARN] ${new Date().toISOString()}: ${message}`, data || ''); + } +} diff --git a/packages/core/src/templates/node-ts/tests/example.test.ts.tpl b/packages/core/src/templates/node-ts/tests/example.test.ts.tpl new file mode 100644 index 00000000..b9e001cb --- /dev/null +++ b/packages/core/src/templates/node-ts/tests/example.test.ts.tpl @@ -0,0 +1,22 @@ +import { ExampleController } from '../src/controllers/example.controller.js'; + +/** + * Basic tests for ExampleController + */ +describe('ExampleController', () => { + test('getWelcome should return welcome message', () => { + const result = ExampleController.getWelcome(); + + expect(result).toHaveProperty('message'); + expect(result).toHaveProperty('status', 'running'); + expect(result).toHaveProperty('version', '1.0.0'); + }); + + test('getHealth should return health status', () => { + const result = ExampleController.getHealth(); + + expect(result).toHaveProperty('status', 'healthy'); + expect(result).toHaveProperty('timestamp'); + expect(result).toHaveProperty('service'); + }); +}); diff --git a/packages/core/src/templates/php/.env.example.tpl b/packages/core/src/templates/php/.env.example.tpl new file mode 100644 index 00000000..977b9531 --- /dev/null +++ b/packages/core/src/templates/php/.env.example.tpl @@ -0,0 +1,58 @@ +APP_NAME={{projectName}} +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_URL=http://localhost + +LOG_CHANNEL=stack +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE={{projectName}}_database +DB_USERNAME=root +DB_PASSWORD= + +BROADCAST_DRIVER=log +CACHE_DRIVER=file +FILESYSTEM_DISK=local +QUEUE_CONNECTION=sync +SESSION_DRIVER=file +SESSION_LIFETIME=120 + +MEMCACHED_HOST=127.0.0.1 + +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=smtp +MAIL_HOST=mailpit +MAIL_PORT=1025 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false + +PUSHER_APP_ID= +PUSHER_APP_KEY= +PUSHER_APP_SECRET= +PUSHER_HOST= +PUSHER_PORT=443 +PUSHER_SCHEME=https +PUSHER_APP_CLUSTER=mt1 + +VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" +VITE_PUSHER_HOST="${PUSHER_HOST}" +VITE_PUSHER_PORT="${PUSHER_PORT}" +VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" +VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" diff --git a/packages/core/src/templates/php/app/Http/Controllers/HomeController.php.tpl b/packages/core/src/templates/php/app/Http/Controllers/HomeController.php.tpl new file mode 100644 index 00000000..3e1f6e5c --- /dev/null +++ b/packages/core/src/templates/php/app/Http/Controllers/HomeController.php.tpl @@ -0,0 +1,46 @@ + '{{projectName}}', + 'description' => '{{description}}' + ]); + } + + /** + * API health check endpoint + */ + public function health(): JsonResponse + { + return response()->json([ + 'status' => 'ok', + 'message' => 'Application is running', + 'project' => '{{projectName}}', + 'timestamp' => now()->toISOString() + ]); + } + + /** + * API welcome endpoint + */ + public function welcome(): JsonResponse + { + return response()->json([ + 'message' => 'Welcome to {{projectName}}', + 'description' => '{{description}}', + 'version' => '1.0.0', + 'author' => '{{authorName}}' + ]); + } +} diff --git a/packages/core/src/templates/php/bootstrap/app.php.tpl b/packages/core/src/templates/php/bootstrap/app.php.tpl new file mode 100644 index 00000000..d6542762 --- /dev/null +++ b/packages/core/src/templates/php/bootstrap/app.php.tpl @@ -0,0 +1,19 @@ +withRouting( + web: __DIR__.'/../routes/web.php', + api: __DIR__.'/../routes/api.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware) { + // + }) + ->withExceptions(function (Exceptions $exceptions) { + // + })->create(); diff --git a/packages/core/src/templates/php/composer.json.tpl b/packages/core/src/templates/php/composer.json.tpl new file mode 100644 index 00000000..9d5965ec --- /dev/null +++ b/packages/core/src/templates/php/composer.json.tpl @@ -0,0 +1,63 @@ +{ + "name": "{{projectName}}", + "description": "{{description}}", + "type": "project", + "require": { + "php": "^8.1", + "laravel/framework": "^10.10", + "laravel/sanctum": "^3.2", + "laravel/tinker": "^2.8" + }, + "require-dev": { + "fakerphp/faker": "^1.9.1", + "laravel/pint": "^1.0", + "laravel/sail": "^1.18", + "mockery/mockery": "^1.4.4", + "nunomaduro/collision": "^7.0", + "phpunit/phpunit": "^10.1", + "spatie/laravel-ignition": "^2.0" + }, + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Factories\\": "database/factories/", + "Database\\Seeders\\": "database/seeders/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "scripts": { + "post-autoload-dump": [ + "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", + "@php artisan package:discover --ansi" + ], + "post-update-cmd": [ + "@php artisan vendor:publish --tag=laravel-assets --ansi --force" + ], + "post-root-package-install": [ + "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" + ], + "post-create-project-cmd": [ + "@php artisan key:generate --ansi" + ] + }, + "extra": { + "laravel": { + "dont-discover": [] + } + }, + "config": { + "optimize-autoloader": true, + "preferred-install": "dist", + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true, + "php-http/discovery": true + } + }, + "minimum-stability": "stable", + "prefer-stable": true +} diff --git a/packages/core/src/templates/php/resources/views/welcome.blade.php.tpl b/packages/core/src/templates/php/resources/views/welcome.blade.php.tpl new file mode 100644 index 00000000..be4134b1 --- /dev/null +++ b/packages/core/src/templates/php/resources/views/welcome.blade.php.tpl @@ -0,0 +1,68 @@ + + + + + + {{projectName}} + + + + + + + @vite(['resources/css/app.css', 'resources/js/app.js']) + + +
+
+
+

+ {{projectName}} +

+
+ +
+
+
+
+

+ Welcome to Laravel +

+ +

+ {{description}} +

+
+
+ +
+
+

+ API Endpoints +

+ +

+ Check out the API endpoints: +
+ /api/health - Health check +
+ /api/welcome - Welcome message +

+
+
+
+
+ +
+
+

Created by {{authorName}}

+
+ +
+ Laravel v{{ app()->version() }} (PHP v{{ PHP_VERSION }}) +
+
+
+
+ + diff --git a/packages/core/src/templates/php/routes/api.php.tpl b/packages/core/src/templates/php/routes/api.php.tpl new file mode 100644 index 00000000..cd2bad40 --- /dev/null +++ b/packages/core/src/templates/php/routes/api.php.tpl @@ -0,0 +1,23 @@ +get('/user', function (Request $request) { + return $request->user(); +}); + +Route::get('/health', [HomeController::class, 'health']); +Route::get('/welcome', [HomeController::class, 'welcome']); diff --git a/packages/core/src/templates/php/routes/web.php.tpl b/packages/core/src/templates/php/routes/web.php.tpl new file mode 100644 index 00000000..4de087ad --- /dev/null +++ b/packages/core/src/templates/php/routes/web.php.tpl @@ -0,0 +1,17 @@ +name('home'); diff --git a/packages/core/src/templates/python/pyproject.toml.tpl b/packages/core/src/templates/python/pyproject.toml.tpl new file mode 100644 index 00000000..31e72fe3 --- /dev/null +++ b/packages/core/src/templates/python/pyproject.toml.tpl @@ -0,0 +1,42 @@ +[project] +name = "{{projectName}}" +version = "1.0.0" +description = "{{description}}" +authors = [ + {name = "{{authorName}}", email = "user@example.com"} +] +dependencies = [ + "fastapi>=0.103.0", + "uvicorn[standard]>=0.23.0", + "pydantic>=2.3.0" +] +requires-python = ">=3.9" +readme = "README.md" +license = {text = "MIT"} + +[project.optional-dependencies] +dev = [ + "pytest>=7.4.0", + "pytest-asyncio>=0.21.0", + "black>=23.7.0", + "isort>=5.12.0", + "flake8>=6.0.0", + "mypy>=1.5.0" +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.black] +line-length = 88 +target-version = ['py39'] + +[tool.isort] +profile = "black" +line_length = 88 + +[tool.mypy] +python_version = "3.9" +warn_return_any = true +warn_unused_configs = true diff --git a/packages/core/src/templates/python/src/main.py.tpl b/packages/core/src/templates/python/src/main.py.tpl new file mode 100644 index 00000000..e09804d3 --- /dev/null +++ b/packages/core/src/templates/python/src/main.py.tpl @@ -0,0 +1,35 @@ +""" +{{projectName}} - {{description}} + +A Python application generated by StackCode. +""" + +from fastapi import FastAPI +from fastapi.responses import JSONResponse + +app = FastAPI( + title="{{projectName}}", + description="{{description}}", + version="1.0.0" +) + +@app.get("/") +async def root(): + """Root endpoint returning a welcome message.""" + return JSONResponse({ + "message": "Welcome to {{projectName}}!", + "status": "running", + "version": "1.0.0" + }) + +@app.get("/health") +async def health_check(): + """Health check endpoint.""" + return JSONResponse({ + "status": "healthy", + "service": "{{projectName}}" + }) + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/packages/core/src/templates/react/index.html.tpl b/packages/core/src/templates/react/index.html.tpl new file mode 100644 index 00000000..622f5384 --- /dev/null +++ b/packages/core/src/templates/react/index.html.tpl @@ -0,0 +1,13 @@ + + + + + + + {{projectName}} + + +
+ + + diff --git a/packages/core/src/templates/react/package.json.tpl b/packages/core/src/templates/react/package.json.tpl new file mode 100644 index 00000000..dadb6c97 --- /dev/null +++ b/packages/core/src/templates/react/package.json.tpl @@ -0,0 +1,39 @@ +{ + "name": "{{projectName}}", + "version": "1.0.0", + "description": "{{description}}", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "test": "vitest", + "test:ui": "vitest --ui", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "lint:fix": "eslint . --ext ts,tsx --fix" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.15.0" + }, + "devDependencies": { + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "@vitejs/plugin-react": "^4.0.3", + "autoprefixer": "^10.4.14", + "eslint": "^8.45.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.3", + "postcss": "^8.4.27", + "tailwindcss": "^3.3.3", + "typescript": "^5.0.2", + "vite": "^4.4.5", + "vitest": "^0.34.0" + }, + "keywords": ["react", "typescript", "vite"], + "author": "{{authorName}}", + "license": "MIT" +} diff --git a/packages/core/src/templates/react/postcss.config.js.tpl b/packages/core/src/templates/react/postcss.config.js.tpl new file mode 100644 index 00000000..2e7af2b7 --- /dev/null +++ b/packages/core/src/templates/react/postcss.config.js.tpl @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/packages/core/src/templates/react/src/App.tsx.tpl b/packages/core/src/templates/react/src/App.tsx.tpl new file mode 100644 index 00000000..d949bf2b --- /dev/null +++ b/packages/core/src/templates/react/src/App.tsx.tpl @@ -0,0 +1,20 @@ +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import { HomePage } from './components/pages/HomePage'; +import { AboutPage } from './components/pages/AboutPage'; +import { Layout } from './components/common/Layout'; +import './styles/globals.css'; + +function App() { + return ( + + + + } /> + } /> + + + + ); +} + +export default App; diff --git a/packages/core/src/templates/react/src/components/common/Layout.tsx.tpl b/packages/core/src/templates/react/src/components/common/Layout.tsx.tpl new file mode 100644 index 00000000..9b13c6a6 --- /dev/null +++ b/packages/core/src/templates/react/src/components/common/Layout.tsx.tpl @@ -0,0 +1,32 @@ +import { ReactNode } from 'react'; + +interface LayoutProps { + children: ReactNode; +} + +export const Layout = ({ children }: LayoutProps) => { + return ( +
+
+
+
+

+ {{projectName}} +

+ +
+
+
+
+ {children} +
+
+ ); +}; diff --git a/packages/core/src/templates/react/src/components/pages/AboutPage.tsx.tpl b/packages/core/src/templates/react/src/components/pages/AboutPage.tsx.tpl new file mode 100644 index 00000000..677b7650 --- /dev/null +++ b/packages/core/src/templates/react/src/components/pages/AboutPage.tsx.tpl @@ -0,0 +1,25 @@ +export const AboutPage = () => { + return ( +
+

About {{projectName}}

+
+

+ This is a React application generated by StackCode. It comes with a modern + development setup including: +

+
    +
  • React 18 with TypeScript
  • +
  • Vite for fast development and building
  • +
  • React Router for navigation
  • +
  • ESLint for code quality
  • +
  • Vitest for testing
  • +
  • Modern CSS with utility classes
  • +
+

+ Start building your application by editing the components in the + src/components directory. +

+
+
+ ); +}; diff --git a/packages/core/src/templates/react/src/components/pages/HomePage.tsx.tpl b/packages/core/src/templates/react/src/components/pages/HomePage.tsx.tpl new file mode 100644 index 00000000..14f05542 --- /dev/null +++ b/packages/core/src/templates/react/src/components/pages/HomePage.tsx.tpl @@ -0,0 +1,20 @@ +export const HomePage = () => { + return ( +
+

+ Welcome to {{projectName}}! +

+

+ {{description}} +

+
+ + +
+
+ ); +}; diff --git a/packages/core/src/templates/react/src/main.tsx.tpl b/packages/core/src/templates/react/src/main.tsx.tpl new file mode 100644 index 00000000..c2355a69 --- /dev/null +++ b/packages/core/src/templates/react/src/main.tsx.tpl @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' +import './styles/globals.css' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/packages/core/src/templates/react/src/styles/globals.css.tpl b/packages/core/src/templates/react/src/styles/globals.css.tpl new file mode 100644 index 00000000..ad94ef85 --- /dev/null +++ b/packages/core/src/templates/react/src/styles/globals.css.tpl @@ -0,0 +1,73 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/packages/core/src/templates/react/tailwind.config.js.tpl b/packages/core/src/templates/react/tailwind.config.js.tpl new file mode 100644 index 00000000..dca8ba02 --- /dev/null +++ b/packages/core/src/templates/react/tailwind.config.js.tpl @@ -0,0 +1,11 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +} diff --git a/packages/core/src/templates/react/tsconfig.json.tpl b/packages/core/src/templates/react/tsconfig.json.tpl new file mode 100644 index 00000000..a7fc6fbf --- /dev/null +++ b/packages/core/src/templates/react/tsconfig.json.tpl @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/packages/core/src/templates/react/tsconfig.node.json.tpl b/packages/core/src/templates/react/tsconfig.node.json.tpl new file mode 100644 index 00000000..42872c59 --- /dev/null +++ b/packages/core/src/templates/react/tsconfig.node.json.tpl @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/packages/core/src/templates/react/vite.config.ts.tpl b/packages/core/src/templates/react/vite.config.ts.tpl new file mode 100644 index 00000000..3b373a9d --- /dev/null +++ b/packages/core/src/templates/react/vite.config.ts.tpl @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], + server: { + port: 3000, + open: true + }, + build: { + outDir: 'dist', + sourcemap: true + } +}) diff --git a/packages/core/src/templates/vue/index.html.tpl b/packages/core/src/templates/vue/index.html.tpl new file mode 100644 index 00000000..0adc4418 --- /dev/null +++ b/packages/core/src/templates/vue/index.html.tpl @@ -0,0 +1,13 @@ + + + + + + + {{projectName}} + + +
+ + + diff --git a/packages/core/src/templates/vue/package.json.tpl b/packages/core/src/templates/vue/package.json.tpl new file mode 100644 index 00000000..73dc5512 --- /dev/null +++ b/packages/core/src/templates/vue/package.json.tpl @@ -0,0 +1,33 @@ +{ + "name": "{{projectName}}", + "version": "1.0.0", + "description": "{{description}}", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc && vite build", + "preview": "vite preview", + "test": "vitest", + "lint": "eslint . --ext .vue,.js,.ts --fix" + }, + "dependencies": { + "vue": "^3.4.0", + "vue-router": "^4.2.5" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.0.0", + "@vue/eslint-config-typescript": "^12.0.0", + "autoprefixer": "^10.4.16", + "eslint": "^8.56.0", + "eslint-plugin-vue": "^9.19.2", + "postcss": "^8.4.32", + "tailwindcss": "^3.4.0", + "typescript": "^5.3.0", + "vite": "^5.0.0", + "vitest": "^1.0.0", + "vue-tsc": "^1.8.27" + }, + "keywords": ["vue", "typescript", "vite"], + "author": "{{authorName}}", + "license": "MIT" +} diff --git a/packages/core/src/templates/vue/postcss.config.js.tpl b/packages/core/src/templates/vue/postcss.config.js.tpl new file mode 100644 index 00000000..2e7af2b7 --- /dev/null +++ b/packages/core/src/templates/vue/postcss.config.js.tpl @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/packages/core/src/templates/vue/src/App.vue.tpl b/packages/core/src/templates/vue/src/App.vue.tpl new file mode 100644 index 00000000..5ccbe51b --- /dev/null +++ b/packages/core/src/templates/vue/src/App.vue.tpl @@ -0,0 +1,15 @@ + + + diff --git a/packages/core/src/templates/vue/src/components/Footer.vue.tpl b/packages/core/src/templates/vue/src/components/Footer.vue.tpl new file mode 100644 index 00000000..5ad18d31 --- /dev/null +++ b/packages/core/src/templates/vue/src/components/Footer.vue.tpl @@ -0,0 +1,11 @@ + + + diff --git a/packages/core/src/templates/vue/src/components/Header.vue.tpl b/packages/core/src/templates/vue/src/components/Header.vue.tpl new file mode 100644 index 00000000..7aeb400f --- /dev/null +++ b/packages/core/src/templates/vue/src/components/Header.vue.tpl @@ -0,0 +1,21 @@ + + + + + diff --git a/packages/core/src/templates/vue/src/main.ts.tpl b/packages/core/src/templates/vue/src/main.ts.tpl new file mode 100644 index 00000000..fb613e2e --- /dev/null +++ b/packages/core/src/templates/vue/src/main.ts.tpl @@ -0,0 +1,19 @@ +import { createApp } from 'vue' +import { createRouter, createWebHistory } from 'vue-router' +import App from './App.vue' +import Home from './views/Home.vue' +import About from './views/About.vue' + +const routes = [ + { path: '/', component: Home }, + { path: '/about', component: About } +] + +const router = createRouter({ + history: createWebHistory(), + routes +}) + +const app = createApp(App) +app.use(router) +app.mount('#app') diff --git a/packages/core/src/templates/vue/src/styles/globals.css.tpl b/packages/core/src/templates/vue/src/styles/globals.css.tpl new file mode 100644 index 00000000..e1d26d02 --- /dev/null +++ b/packages/core/src/templates/vue/src/styles/globals.css.tpl @@ -0,0 +1,26 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; +} + +body { + margin: 0; + min-height: 100vh; + background-color: #f8fafc; + color: #1e293b; +} + +#app { + min-height: 100vh; + display: flex; + flex-direction: column; +} + +main { + flex: 1; +} diff --git a/packages/core/src/templates/vue/src/views/About.vue.tpl b/packages/core/src/templates/vue/src/views/About.vue.tpl new file mode 100644 index 00000000..49d5813e --- /dev/null +++ b/packages/core/src/templates/vue/src/views/About.vue.tpl @@ -0,0 +1,28 @@ + + + diff --git a/packages/core/src/templates/vue/src/views/Home.vue.tpl b/packages/core/src/templates/vue/src/views/Home.vue.tpl new file mode 100644 index 00000000..3b5f32c5 --- /dev/null +++ b/packages/core/src/templates/vue/src/views/Home.vue.tpl @@ -0,0 +1,21 @@ + + + diff --git a/packages/core/src/templates/vue/tailwind.config.js.tpl b/packages/core/src/templates/vue/tailwind.config.js.tpl new file mode 100644 index 00000000..bd3eb14e --- /dev/null +++ b/packages/core/src/templates/vue/tailwind.config.js.tpl @@ -0,0 +1,11 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{vue,js,ts,jsx,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +} diff --git a/packages/core/src/templates/vue/tsconfig.json.tpl b/packages/core/src/templates/vue/tsconfig.json.tpl new file mode 100644 index 00000000..f82888f3 --- /dev/null +++ b/packages/core/src/templates/vue/tsconfig.json.tpl @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/packages/core/src/templates/vue/tsconfig.node.json.tpl b/packages/core/src/templates/vue/tsconfig.node.json.tpl new file mode 100644 index 00000000..42872c59 --- /dev/null +++ b/packages/core/src/templates/vue/tsconfig.node.json.tpl @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/packages/core/src/templates/vue/vite.config.ts.tpl b/packages/core/src/templates/vue/vite.config.ts.tpl new file mode 100644 index 00000000..10ef1860 --- /dev/null +++ b/packages/core/src/templates/vue/vite.config.ts.tpl @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +export default defineConfig({ + plugins: [vue()], + server: { + port: 3000, + open: true + }, + build: { + outDir: 'dist', + sourcemap: true + } +}) From 0706ac27e81ce875359dcf55df3a9fe5f2f4d77c Mon Sep 17 00:00:00 2001 From: Yago Azevedo Borba <140000816+YagoBorba@users.noreply.github.com> Date: Fri, 22 Aug 2025 00:56:44 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8E=A8=20:art:=20Fix=20code=20formatt?= =?UTF-8?q?ing=20with=20Prettier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Apply consistent formatting to CONTRIBUTING.md - Format docs/STACKS.md for better readability - Fix TypeScript type formatting in ui.ts and scaffold.ts - Ensure all files follow project code style guidelines --- CONTRIBUTING.md | 32 +++++++++++++++++++++++++++++--- docs/STACKS.md | 30 +++++++++++++++++++++++++++--- packages/cli/src/commands/ui.ts | 10 +++++++++- packages/core/src/scaffold.ts | 10 +++++++++- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 324340b0..2bde7f78 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -101,11 +101,13 @@ packages/core/src/templates/your-stack-name/ ``` **Important**: Use these replacement variables in your templates: + - `{{projectName}}` - The project name - `{{description}}` - Project description - `{{authorName}}` - Author name **Example package.json.tpl:** + ```json { "name": "{{projectName}}", @@ -137,22 +139,42 @@ dist/ Add your new stack to the type definitions: **In `packages/core/src/scaffold.ts`:** + ```typescript export interface ProjectOptions { projectPath: string; - stack: "node-js" | "node-ts" | "react" | "vue" | "python" | "java" | "go" | "php" | "your-stack-name"; + stack: + | "node-js" + | "node-ts" + | "react" + | "vue" + | "python" + | "java" + | "go" + | "php" + | "your-stack-name"; features: ("docker" | "husky")[]; replacements: Record; } ``` **In `packages/cli/src/commands/ui.ts`:** + ```typescript export interface InitAnswers { projectName: string; description: string; authorName: string; - stack: "node-js" | "node-ts" | "react" | "vue" | "python" | "java" | "go" | "php" | "your-stack-name"; + stack: + | "node-js" + | "node-ts" + | "react" + | "vue" + | "python" + | "java" + | "go" + | "php" + | "your-stack-name"; features: ("docker" | "husky")[]; commitValidation?: boolean; } @@ -176,7 +198,7 @@ Update the stack choices in `packages/cli/src/commands/ui.ts`: { name: "Java + Spring", value: "java" }, { name: "Go + Gin", value: "go" }, { name: "PHP + Laravel", value: "php" }, - { name: "Your Stack + Framework", value: "your-stack-name" }, + { name: "Your Stack + Framework", value: "your-stack-name" }, ], } ``` @@ -206,6 +228,7 @@ if (answers.stack === "python") { ### 3. Best Practices for New Stacks #### Template Structure Guidelines: + - **Follow conventions**: Use the technology's standard project structure - **Include essentials**: Configuration files, build tools, testing setup - **Add documentation**: Include basic README template @@ -215,6 +238,7 @@ if (answers.stack === "python") { #### Example Folder Structures: **Frontend Stack (SPA):** + ``` src/ ├── components/ @@ -226,6 +250,7 @@ src/ ``` **Backend Stack (API):** + ``` src/ ├── controllers/ @@ -237,6 +262,7 @@ src/ ``` **Full-Stack Framework:** + ``` src/ ├── components/ diff --git a/docs/STACKS.md b/docs/STACKS.md index af66fd65..182b3b83 100644 --- a/docs/STACKS.md +++ b/docs/STACKS.md @@ -7,6 +7,7 @@ StackCode supports multiple technology stacks, each designed with best practices ### Frontend Stacks #### React + TypeScript + - **Framework**: React 18 with TypeScript - **Build Tool**: Vite - **Styling**: TailwindCSS @@ -15,6 +16,7 @@ StackCode supports multiple technology stacks, each designed with best practices - **Features**: Modern JSX Transform, ESLint configuration, component structure **Generated Structure:** + ``` ├── src/ │ ├── components/ @@ -30,6 +32,7 @@ StackCode supports multiple technology stacks, each designed with best practices ``` #### Vue.js + TypeScript + - **Framework**: Vue 3 with Composition API and TypeScript - **Build Tool**: Vite - **Styling**: TailwindCSS @@ -38,6 +41,7 @@ StackCode supports multiple technology stacks, each designed with best practices - **Features**: SFC (Single File Components), modern Vue patterns **Generated Structure:** + ``` ├── src/ │ ├── components/ # Reusable components @@ -54,11 +58,13 @@ StackCode supports multiple technology stacks, each designed with best practices ### Backend Stacks #### Node.js + JavaScript + - **Runtime**: Node.js with ES6+ - **Testing**: Jest - **Features**: Express.js structure, middleware, controllers, routes **Generated Structure:** + ``` ├── src/ │ ├── controllers/ # Request handlers @@ -72,11 +78,13 @@ StackCode supports multiple technology stacks, each designed with best practices ``` #### Node.js + TypeScript + - **Runtime**: Node.js with TypeScript - **Testing**: Vitest - **Features**: Type-safe development, modern TypeScript configuration **Generated Structure:** + ``` ├── src/ │ ├── controllers/ # Type-safe controllers @@ -88,11 +96,13 @@ StackCode supports multiple technology stacks, each designed with best practices ``` #### Python + FastAPI + - **Framework**: FastAPI - **Package Management**: pip with pyproject.toml - **Features**: Modern Python async API development **Generated Structure:** + ``` ├── src/ │ └── main.py @@ -100,11 +110,13 @@ StackCode supports multiple technology stacks, each designed with best practices ``` #### Java + Spring + - **Framework**: Spring Boot - **Build Tool**: Maven - **Features**: Enterprise Java development structure **Generated Structure:** + ``` ├── src/main/java/com/example/app/ │ ├── Application.java @@ -114,22 +126,26 @@ StackCode supports multiple technology stacks, each designed with best practices ``` #### Go + Gin + - **Framework**: Gin web framework - **Package Management**: Go modules - **Features**: High-performance Go web development **Generated Structure:** + ``` ├── main.go └── go.mod ``` #### PHP + Laravel + - **Framework**: Laravel - **Package Management**: Composer - **Features**: Modern PHP development with MVC structure **Generated Structure:** + ``` ├── app/Http/Controllers/ ├── bootstrap/ @@ -141,7 +157,9 @@ StackCode supports multiple technology stacks, each designed with best practices ## 🔧 Stack Features ### Automatic Configuration + Each stack includes: + - ✅ **Optimized package.json** (or equivalent) with relevant dependencies - ✅ **TypeScript configuration** (where applicable) - ✅ **Build tool setup** (Vite, Maven, etc.) @@ -150,18 +168,23 @@ Each stack includes: - ✅ **Best practice folder structure** ### Smart Package Management + StackCode automatically uses the appropriate package manager: + - **npm** for Node.js-based stacks (React, Vue, Node.js) - **pip** for Python projects -- **maven** for Java projects +- **maven** for Java projects - **go mod** for Go projects - **composer** for PHP projects ### Docker Support + All stacks can include Docker configuration when the Docker feature is selected during project initialization. ### Git Integration + Every generated project includes: + - ✅ **Stack-specific .gitignore** files - ✅ **Git repository initialization** - ✅ **Conventional commit setup** (with Husky) @@ -181,12 +204,13 @@ Then select your preferred technology stack from the interactive menu. Interested in adding support for a new technology stack? Check out our comprehensive guide in [CONTRIBUTING.md](../CONTRIBUTING.md#adding-new-technology-stacks). The process involves: + 1. Creating template files -2. Updating type definitions +2. Updating type definitions 3. Adding CLI options 4. Configuring package management 5. Testing thoroughly --- -*For more information about StackCode, visit our [main documentation](../README.md).* +_For more information about StackCode, visit our [main documentation](../README.md)._ diff --git a/packages/cli/src/commands/ui.ts b/packages/cli/src/commands/ui.ts index a22fd0da..cf6b97e3 100644 --- a/packages/cli/src/commands/ui.ts +++ b/packages/cli/src/commands/ui.ts @@ -194,7 +194,15 @@ export interface InitAnswers { projectName: string; description: string; authorName: string; - stack: "node-js" | "node-ts" | "react" | "vue" | "python" | "java" | "go" | "php"; + stack: + | "node-js" + | "node-ts" + | "react" + | "vue" + | "python" + | "java" + | "go" + | "php"; features: ("docker" | "husky")[]; commitValidation?: boolean; } diff --git a/packages/core/src/scaffold.ts b/packages/core/src/scaffold.ts index 17cac670..b8b74a5f 100644 --- a/packages/core/src/scaffold.ts +++ b/packages/core/src/scaffold.ts @@ -39,7 +39,15 @@ async function copyTemplateFiles( export interface ProjectOptions { projectPath: string; - stack: "node-js" | "node-ts" | "react" | "vue" | "python" | "java" | "go" | "php"; + stack: + | "node-js" + | "node-ts" + | "react" + | "vue" + | "python" + | "java" + | "go" + | "php"; features: ("docker" | "husky")[]; replacements: Record; }