archforge-x 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archforge-x",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Enterprise Architecture Engine for scaffolding, analyzing, and visualizing software architecture.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -42,16 +42,16 @@
42
42
  "@types/node": "^25.0.3",
43
43
  "@types/prompts": "^2.4.9",
44
44
  "@types/viz.js": "^2.1.5",
45
- "ts-node": "^10.9.2",
46
- "typescript": "^5.9.3"
45
+ "ts-node": "^10.9.2"
47
46
  },
48
47
  "dependencies": {
49
48
  "chalk": "^5.6.2",
50
49
  "commander": "^14.0.2",
51
50
  "fs-extra": "^11.3.3",
52
51
  "prompts": "^2.4.2",
52
+ "typescript": "^5.9.3",
53
53
  "viz.js": "^2.1.2",
54
54
  "yaml": "^2.8.2",
55
55
  "zod": "^4.2.1"
56
56
  }
57
- }
57
+ }
@@ -1,509 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.professionalGenerator = professionalGenerator;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- const chalk_1 = __importDefault(require("chalk"));
10
- // --- HELPER FUNCTIONS ---
11
- const writeFile = (root, filePath, content) => {
12
- const fullPath = path_1.default.join(root, filePath);
13
- fs_1.default.mkdirSync(path_1.default.dirname(fullPath), { recursive: true });
14
- fs_1.default.writeFileSync(fullPath, content.trim());
15
- };
16
- const getPackageJson = (name, fw, arch, modules) => {
17
- const deps = {
18
- "dotenv": "^16.0.3",
19
- };
20
- const devDeps = {
21
- "typescript": "^5.0.0",
22
- "@types/node": "^20.0.0",
23
- "jest": "^29.5.0",
24
- "ts-jest": "^29.1.0",
25
- "@types/jest": "^29.5.0",
26
- "eslint": "^8.0.0",
27
- "prettier": "^3.0.0"
28
- };
29
- if (fw === "nestjs") {
30
- Object.assign(deps, {
31
- "@nestjs/common": "^10.0.0",
32
- "@nestjs/core": "^10.0.0",
33
- "@nestjs/platform-express": "^10.0.0",
34
- "reflect-metadata": "^0.1.13",
35
- "rxjs": "^7.8.0"
36
- });
37
- Object.assign(devDeps, {
38
- "@nestjs/cli": "^10.0.0",
39
- "@nestjs/schematics": "^10.0.0",
40
- "@nestjs/testing": "^10.0.0"
41
- });
42
- }
43
- else if (fw === "express") {
44
- Object.assign(deps, { "express": "^4.18.2", "cors": "^2.8.5" });
45
- Object.assign(devDeps, { "@types/express": "^4.17.17", "ts-node-dev": "^2.0.0" });
46
- }
47
- if (modules.includes("auth"))
48
- deps["jsonwebtoken"] = "^9.0.0";
49
- if (modules.includes("auth") && fw === "nestjs")
50
- deps["@nestjs/jwt"] = "^10.0.0";
51
- if (modules.includes("db"))
52
- deps["typeorm"] = "^0.3.17"; // Defaulting to TypeORM for boilerplate
53
- if (modules.includes("cache"))
54
- deps["ioredis"] = "^5.3.0";
55
- return JSON.stringify({
56
- name,
57
- version: "0.0.1",
58
- scripts: {
59
- "start:dev": fw === "nestjs" ? "nest start --watch" : "ts-node-dev src/main.ts",
60
- "build": "tsc",
61
- "test": "jest"
62
- },
63
- dependencies: deps,
64
- devDependencies: devDeps
65
- }, null, 2);
66
- };
67
- const getGoMod = (name, fw) => {
68
- return `module ${name}
69
-
70
- go 1.21
71
-
72
- require (
73
- ${fw === "gin" ? 'github.com/gin-gonic/gin v1.9.1' : ''}
74
- github.com/joho/godotenv v1.5.1
75
- )`;
76
- };
77
- const getRequirementsTxt = (fw, modules) => {
78
- const reqs = ["python-dotenv"];
79
- if (fw === "django")
80
- reqs.push("Django>=4.2");
81
- if (fw === "flask")
82
- reqs.push("Flask>=2.3");
83
- if (modules.includes("db"))
84
- reqs.push("psycopg2-binary", "sqlalchemy");
85
- if (modules.includes("auth"))
86
- reqs.push("PyJWT");
87
- return reqs.join("\n");
88
- };
89
- // --- CONTENT GENERATORS (Architecture Specific) ---
90
- const generateTsCleanArch = (root, options) => {
91
- // 1. Core / Domain (Enterprise Business Rules)
92
- writeFile(root, "src/domain/entities/user.entity.ts", `
93
- export class User {
94
- constructor(
95
- public readonly id: string,
96
- public readonly name: string,
97
- public readonly email: string,
98
- public readonly passwordHash: string
99
- ) {}
100
- }
101
- `);
102
- writeFile(root, "src/domain/repositories/user.repository.interface.ts", `
103
- import { User } from "../entities/user.entity";
104
-
105
- export interface IUserRepository {
106
- save(user: User): Promise<User>;
107
- findByEmail(email: string): Promise<User | null>;
108
- findById(id: string): Promise<User | null>;
109
- }
110
- `);
111
- // 2. Application (Application Business Rules / Use Cases)
112
- writeFile(root, "src/application/use-cases/create-user.use-case.ts", `
113
- import { User } from "../../domain/entities/user.entity";
114
- import { IUserRepository } from "../../domain/repositories/user.repository.interface";
115
-
116
- export class CreateUserUseCase {
117
- constructor(private userRepository: IUserRepository) {}
118
-
119
- async execute(name: string, email: string, passwordHash: string): Promise<User> {
120
- const existing = await this.userRepository.findByEmail(email);
121
- if (existing) throw new Error("User already exists");
122
-
123
- const user = new User(Date.now().toString(), name, email, passwordHash);
124
- return await this.userRepository.save(user);
125
- }
126
- }
127
- `);
128
- // 3. Interface Adapters (Controllers, Presenters)
129
- if (options.framework === "express") {
130
- writeFile(root, "src/interface-adapters/controllers/user.controller.ts", `
131
- import { Request, Response } from "express";
132
- import { CreateUserUseCase } from "../../application/use-cases/create-user.use-case";
133
-
134
- export class UserController {
135
- constructor(private createUserUseCase: CreateUserUseCase) {}
136
-
137
- async create(req: Request, res: Response) {
138
- try {
139
- const { name, email, password } = req.body;
140
- const user = await this.createUserUseCase.execute(name, email, password);
141
- res.status(201).json(user);
142
- } catch (e: any) {
143
- res.status(400).json({ error: e.message });
144
- }
145
- }
146
- }
147
- `);
148
- }
149
- // 4. Infrastructure (Frameworks, Drivers)
150
- writeFile(root, "src/infrastructure/repositories/in-memory-user.repository.ts", `
151
- import { User } from "../../domain/entities/user.entity";
152
- import { IUserRepository } from "../../domain/repositories/user.repository.interface";
153
-
154
- export class InMemoryUserRepository implements IUserRepository {
155
- private users: User[] = [];
156
- async save(user: User): Promise<User> {
157
- this.users.push(user);
158
- return user;
159
- }
160
- async findByEmail(email: string): Promise<User | null> {
161
- return this.users.find(u => u.email === email) || null;
162
- }
163
- async findById(id: string): Promise<User | null> {
164
- return this.users.find(u => u.id === id) || null;
165
- }
166
- }
167
- `);
168
- // Main Entry
169
- if (options.framework === "express") {
170
- writeFile(root, "src/main.ts", `
171
- import express from "express";
172
- import { UserController } from "./interface-adapters/controllers/user.controller";
173
- import { CreateUserUseCase } from "./application/use-cases/create-user.use-case";
174
- import { InMemoryUserRepository } from "./infrastructure/repositories/in-memory-user.repository";
175
-
176
- const app = express();
177
- app.use(express.json());
178
-
179
- // Dependency Injection Composition Root
180
- const userRepo = new InMemoryUserRepository();
181
- const createUserUseCase = new CreateUserUseCase(userRepo);
182
- const userController = new UserController(createUserUseCase);
183
-
184
- app.post("/users", (req, res) => userController.create(req, res));
185
-
186
- app.listen(3000, () => console.log("šŸš€ Server running on PORT 3000 (Clean Architecture)"));
187
- `);
188
- }
189
- else if (options.framework === "nestjs") {
190
- // NestJS needs modules
191
- writeFile(root, "src/app.module.ts", `
192
- import { Module } from '@nestjs/common';
193
- import { UserController } from './interface-adapters/controllers/user.controller';
194
- import { UserService } from './application/services/user.service'; // NestJS prefers Services over generic UseCases usually, but we stick to clean
195
- import { InMemoryUserRepository } from './infrastructure/repositories/in-memory-user.repository';
196
-
197
- @Module({
198
- controllers: [UserController],
199
- providers: [
200
- { provide: 'IUserRepository', useClass: InMemoryUserRepository },
201
- UserService
202
- ],
203
- })
204
- export class AppModule {}
205
- `);
206
- writeFile(root, "src/main.ts", `
207
- import { NestFactory } from '@nestjs/core';
208
- import { AppModule } from './app.module';
209
-
210
- async function bootstrap() {
211
- const app = await NestFactory.create(AppModule);
212
- await app.listen(3000);
213
- console.log("šŸš€ NestJS Server with Clean Architecture running on 3000");
214
- }
215
- bootstrap();
216
- `);
217
- }
218
- };
219
- const generateGoStandard = (root, options) => {
220
- // Standard Go Layout (Internal/Pkg)
221
- // Domain
222
- writeFile(root, "internal/core/domain/user.go", `
223
- package domain
224
-
225
- type User struct {
226
- ID string \`json:"id"\`
227
- Name string \`json:"name"\`
228
- Email string \`json:"email"\`
229
- }
230
-
231
- type UserRepository interface {
232
- Save(user *User) error
233
- GetByEmail(email string) (*User, error)
234
- }
235
- `);
236
- // Port/Service
237
- writeFile(root, "internal/core/services/user_service.go", `
238
- package services
239
- import (
240
- "errors"
241
- "${options.projectName}/internal/core/domain"
242
- "time"
243
- "fmt"
244
- )
245
-
246
- type UserService struct {
247
- repo domain.UserRepository
248
- }
249
-
250
- func NewUserService(repo domain.UserRepository) *UserService {
251
- return &UserService{repo: repo}
252
- }
253
-
254
- func (s *UserService) Create(name, email string) (*domain.User, error) {
255
- existing, _ := s.repo.GetByEmail(email)
256
- if existing != nil {
257
- return nil, errors.New("user already exists")
258
- }
259
- user := &domain.User{
260
- ID: fmt.Sprintf("%d", time.Now().Unix()),
261
- Name: name,
262
- Email: email,
263
- }
264
- return user, s.repo.Save(user)
265
- }
266
- `);
267
- // Adapter
268
- writeFile(root, "internal/adapters/repository/memory_repo.go", `
269
- package repository
270
- import "${options.projectName}/internal/core/domain"
271
-
272
- type MemoryRepo struct {
273
- users []*domain.User
274
- }
275
-
276
- func NewMemoryRepo() *MemoryRepo {
277
- return &MemoryRepo{users: []*domain.User{}}
278
- }
279
-
280
- func (m *MemoryRepo) Save(user *domain.User) error {
281
- m.users = append(m.users, user)
282
- return nil
283
- }
284
-
285
- func (m *MemoryRepo) GetByEmail(email string) (*domain.User, error) {
286
- for _, u := range m.users {
287
- if u.Email == email { return u, nil }
288
- }
289
- return nil, nil
290
- }
291
- `);
292
- // Main
293
- if (options.framework === "gin") {
294
- writeFile(root, "cmd/server/main.go", `
295
- package main
296
- import (
297
- "github.com/gin-gonic/gin"
298
- "${options.projectName}/internal/adapters/repository"
299
- "${options.projectName}/internal/core/services"
300
- "${options.projectName}/internal/core/domain"
301
- "net/http"
302
- )
303
-
304
- func main() {
305
- repo := repository.NewMemoryRepo()
306
- svc := services.NewUserService(repo)
307
-
308
- r := gin.Default()
309
- r.POST("/users", func(c *gin.Context) {
310
- var req domain.User
311
- if err := c.ShouldBindJSON(&req); err != nil {
312
- c.JSON(400, gin.H{"error": err.Error()})
313
- return
314
- }
315
- user, err := svc.Create(req.Name, req.Email)
316
- if err != nil {
317
- c.JSON(400, gin.H{"error": err.Error()})
318
- return
319
- }
320
- c.JSON(201, user)
321
- })
322
- r.Run(":8080")
323
- }
324
- `);
325
- }
326
- };
327
- const generatePythonStructure = (root, options) => {
328
- // Python tends to be slightly flatter, but we can do Clean
329
- const init = "";
330
- if (options.framework === "django") {
331
- writeFile(root, "manage.py", "# Django boilerplate management script");
332
- writeFile(root, `${options.projectName}/settings.py`, "# Django Settings");
333
- writeFile(root, `${options.projectName}/urls.py`, "# Main URLs");
334
- // Use DDD-like apps
335
- const appPath = "apps/users";
336
- writeFile(root, `${appPath}/__init__.py`, init);
337
- writeFile(root, `${appPath}/models.py`, `
338
- from django.db import models
339
-
340
- class User(models.Model):
341
- name = models.CharField(max_length=255)
342
- email = models.EmailField(unique=True)
343
- `);
344
- writeFile(root, `${appPath}/services.py`, `
345
- from .models import User
346
-
347
- class UserService:
348
- @staticmethod
349
- def create_user(name: str, email: str) -> User:
350
- if User.objects.filter(email=email).exists():
351
- raise ValueError("User exists")
352
- return User.objects.create(name=name, email=email)
353
- `);
354
- writeFile(root, `${appPath}/views.py`, `
355
- from rest_framework.views import APIView
356
- from rest_framework.response import Response
357
- from .services import UserService
358
-
359
- class UserView(APIView):
360
- def post(self, request):
361
- try:
362
- user = UserService.create_user(request.data['name'], request.data['email'])
363
- return Response({"id": user.id, "email": user.email})
364
- except Exception as e:
365
- return Response({"error": str(e)}, status=400)
366
- `);
367
- }
368
- else {
369
- // Flask Hexagonal
370
- writeFile(root, "app/__init__.py", init);
371
- // Domain
372
- writeFile(root, "app/core/domain/user.py", `
373
- from dataclasses import dataclass
374
- @dataclass
375
- class User:
376
- id: str
377
- name: str
378
- email: str
379
- `);
380
- // Ports
381
- writeFile(root, "app/core/ports/user_repository.py", `
382
- from abc import ABC, abstractmethod
383
- from ..domain.user import User
384
-
385
- class UserRepository(ABC):
386
- @abstractmethod
387
- def save(self, user: User): pass
388
- `);
389
- // Adapter
390
- writeFile(root, "app/adapters/db/in_memory_repo.py", `
391
- from app.core.ports.user_repository import UserRepository
392
- class InMemoryUserRepo(UserRepository):
393
- def __init__(self): self.users = []
394
- def save(self, user): self.users.append(user)
395
- `);
396
- // Entry
397
- writeFile(root, "run.py", `
398
- from flask import Flask, request, jsonify
399
- from app.adapters.db.in_memory_repo import InMemoryUserRepo
400
- from app.core.domain.user import User
401
- import uuid
402
-
403
- app = Flask(__name__)
404
- repo = InMemoryUserRepo()
405
-
406
- @app.route('/users', methods=['POST'])
407
- def create_user():
408
- data = request.json
409
- user = User(id=str(uuid.uuid4()), name=data['name'], email=data['email'])
410
- repo.save(user)
411
- return jsonify(user.__dict__), 201
412
-
413
- if __name__ == "__main__":
414
- app.run(debug=True, port=5000)
415
- `);
416
- }
417
- };
418
- // --- MAIN GENERATOR FUNCTION ---
419
- async function professionalGenerator(_arch, options) {
420
- const root = path_1.default.resolve(options.projectName);
421
- // 1. Scaffold Directories
422
- if (!fs_1.default.existsSync(root))
423
- fs_1.default.mkdirSync(root);
424
- console.log(chalk_1.default.green(`\nšŸ“‚ Creating project infrastructure at ${root}...`));
425
- // 2. Generate Configuration Files (The Backbone)
426
- if (options.language === "ts" || options.language === "js") {
427
- writeFile(root, "package.json", getPackageJson(options.projectName, options.framework, options.architecture, options.modules));
428
- writeFile(root, "tsconfig.json", JSON.stringify({
429
- compilerOptions: { target: "ES2020", module: "commonjs", outDir: "./dist", rootDir: "./src", strict: true, experimentalDecorators: true, emitDecoratorMetadata: true },
430
- exclude: ["node_modules", "dist"]
431
- }, null, 2));
432
- }
433
- else if (options.language === "go") {
434
- writeFile(root, "go.mod", getGoMod(options.projectName, options.framework));
435
- }
436
- else if (options.language === "py") {
437
- writeFile(root, "requirements.txt", getRequirementsTxt(options.framework, options.modules));
438
- }
439
- writeFile(root, ".env.example", "PORT=3000\nDB_HOST=localhost\nJWT_SECRET=supersecret");
440
- writeFile(root, ".gitignore", "node_modules/\ndist/\n.env\n__pycache__/\n*.exe\nvendor/");
441
- writeFile(root, "README.md", `# ${options.projectName}\nGenerated by ArchForge X\nArchitecture: ${options.architecture}`);
442
- // 3. Generate Architecture Logic
443
- console.log(chalk_1.default.blue("šŸ—ļø Constructing Architecture layers..."));
444
- if (options.language === "ts" || options.language === "js") {
445
- generateTsCleanArch(root, options);
446
- }
447
- else if (options.language === "go") {
448
- generateGoStandard(root, options);
449
- }
450
- else if (options.language === "py") {
451
- generatePythonStructure(root, options);
452
- }
453
- // 4. Inject Optional Modules (Advanced Integration)
454
- if (options.modules.includes("docker")) {
455
- console.log(chalk_1.default.cyan("🐳 Containerizing application..."));
456
- const dockerfileContent = options.language === "go"
457
- ? `FROM golang:1.21-alpine\nWORKDIR /app\nCOPY . .\nRUN go build -o main cmd/server/main.go\nCMD ["./main"]`
458
- : options.language === "py"
459
- ? `FROM python:3.9-slim\nWORKDIR /app\nCOPY requirements.txt .\nRUN pip install -r requirements.txt\nCOPY . .\nCMD ["python", "run.py"]`
460
- : `FROM node:18-alpine\nWORKDIR /app\nCOPY package*.json .\nRUN npm install\nCOPY . .\nRUN npm run build\nCMD ["npm", "start"]`;
461
- writeFile(root, "Dockerfile", dockerfileContent);
462
- writeFile(root, "docker-compose.yml", `
463
- version: '3.8'
464
- services:
465
- app:
466
- build: .
467
- ports:
468
- - "${options.language === 'py' ? '5000:5000' : '3000:3000'}"
469
- env_file: .env
470
- ${options.modules.includes("db") ? ` db:
471
- image: postgres:15
472
- environment:
473
- POSTGRES_PASSWORD: root
474
- ports:
475
- - "5432:5432"` : ''}
476
- `);
477
- }
478
- if (options.modules.includes("ci")) {
479
- writeFile(root, ".github/workflows/ci.yml", `
480
- name: CI
481
- on: [push]
482
- jobs:
483
- build:
484
- runs-on: ubuntu-latest
485
- steps:
486
- - uses: actions/checkout@v3
487
- - name: Test
488
- run: echo "Running tests..."
489
- `);
490
- }
491
- if (options.modules.includes("auth")) {
492
- // Add a specialized Auth service file depending on lang
493
- const authPath = options.language === "go" ? "internal/core/services/auth_service.go"
494
- : options.language === "py" ? "app/core/services/auth.py"
495
- : "src/application/services/auth.service.ts";
496
- writeFile(root, authPath, `
497
- // JWT Authentication Service Boilerplate
498
- // TODO: Implement actual signing and validation logic here
499
- export class AuthService {
500
- login(u: any) { return "jwt_token_example"; }
501
- }
502
- `.replace("export class", options.language === "go" ? "package services\ntype AuthService struct{}" : "class"));
503
- }
504
- console.log(chalk_1.default.green.bold(`\nāœ… Project ${options.projectName} successfully generated!`));
505
- console.log(chalk_1.default.gray(` Architecture: ${options.architecture.toUpperCase()}`));
506
- console.log(chalk_1.default.gray(` Language: ${options.language.toUpperCase()}`));
507
- if (options.modules.length > 0)
508
- console.log(chalk_1.default.gray(` Modules: ${options.modules.join(", ")}`));
509
- }
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateBaseFile = generateBaseFile;
4
- function generateBaseFile(layerName) {
5
- return `/**
6
- * Base file for ${layerName} layer
7
- * Generated by ArchForge X
8
- */
9
- `;
10
- }
@@ -1,8 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.something = void 0;
4
- /**
5
- * Base file for application layer
6
- * Generated by ArchForge X
7
- */
8
- exports.something = "something";
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,8 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.something = void 0;
4
- /**
5
- * Base file for infrastructure layer
6
- * Generated by ArchForge X
7
- */
8
- exports.something = "something";