archforge-x 1.0.0

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.
@@ -0,0 +1,342 @@
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.generateProject = generateProject;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
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_extra_1.default.mkdirpSync(path_1.default.dirname(fullPath));
14
+ fs_extra_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";
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
+ const getArchForgeYaml = (name, arch, lang, fw, modules) => {
90
+ let layers = "";
91
+ if (arch === "clean") {
92
+ layers = `
93
+ layers:
94
+ - name: "domain"
95
+ path: "src/domain"
96
+ description: "Enterprise business rules and entities"
97
+ forbiddenImports: ["application", "infrastructure", "interface-adapters"]
98
+
99
+ - name: "application"
100
+ path: "src/application"
101
+ description: "Application business rules and use cases"
102
+ allowedImports: ["domain"]
103
+
104
+ - name: "interface-adapters"
105
+ path: "src/interface-adapters"
106
+ description: "Controllers, presenters, and gateways"
107
+ allowedImports: ["domain", "application"]
108
+
109
+ - name: "infrastructure"
110
+ path: "src/infrastructure"
111
+ description: "Frameworks, drivers, and external tools"
112
+ allowedImports: ["domain", "application", "interface-adapters"]
113
+ `;
114
+ }
115
+ else if (arch === "ddd") {
116
+ layers = `
117
+ layers:
118
+ - name: "domain"
119
+ path: "src/domain"
120
+ description: "Core domain logic and aggregates"
121
+ forbiddenImports: ["application", "infrastructure", "interfaces"]
122
+
123
+ - name: "application"
124
+ path: "src/application"
125
+ description: "Application services and orchestration"
126
+ allowedImports: ["domain"]
127
+
128
+ - name: "infrastructure"
129
+ path: "src/infrastructure"
130
+ description: "Persistence and external service implementations"
131
+ allowedImports: ["domain", "application"]
132
+
133
+ - name: "interfaces"
134
+ path: "src/interfaces"
135
+ description: "Web APIs and user interfaces"
136
+ allowedImports: ["domain", "application"]
137
+ `;
138
+ }
139
+ else {
140
+ // Default layered
141
+ layers = `
142
+ layers:
143
+ - name: "core"
144
+ path: "src/core"
145
+ description: "Core business logic"
146
+
147
+ - name: "services"
148
+ path: "src/services"
149
+ allowedImports: ["core"]
150
+
151
+ - name: "api"
152
+ path: "src/api"
153
+ allowedImports: ["core", "services"]
154
+ `;
155
+ }
156
+ return `
157
+ version: "1.0"
158
+ name: "${name} Architecture"
159
+ project:
160
+ name: "${name}"
161
+ root: "."
162
+
163
+ metadata:
164
+ type: "${arch}"
165
+ language: "${lang}"
166
+ framework: "${fw}"
167
+ modules: ${JSON.stringify(modules)}
168
+
169
+ ${layers.trim()}
170
+ `.trim();
171
+ };
172
+ // --- CONTENT GENERATORS ---
173
+ const generateTsCleanArch = (root, options) => {
174
+ const fw = options.framework;
175
+ writeFile(root, "src/domain/entities/user.entity.ts", `
176
+ export class User {
177
+ constructor(
178
+ public readonly id: string,
179
+ public readonly name: string,
180
+ public readonly email: string,
181
+ public readonly passwordHash: string
182
+ ) {}
183
+ }
184
+ `);
185
+ writeFile(root, "src/domain/repositories/user.repository.interface.ts", `
186
+ import { User } from "../entities/user.entity";
187
+
188
+ export interface IUserRepository {
189
+ save(user: User): Promise<User>;
190
+ findByEmail(email: string): Promise<User | null>;
191
+ findById(id: string): Promise<User | null>;
192
+ }
193
+ `);
194
+ writeFile(root, "src/application/use-cases/create-user.use-case.ts", `
195
+ import { User } from "../../domain/entities/user.entity";
196
+ import { IUserRepository } from "../../domain/repositories/user.repository.interface";
197
+
198
+ export class CreateUserUseCase {
199
+ constructor(private userRepository: IUserRepository) {}
200
+
201
+ async execute(name: string, email: string, passwordHash: string): Promise<User> {
202
+ const existing = await this.userRepository.findByEmail(email);
203
+ if (existing) throw new Error("User already exists");
204
+
205
+ const user = new User(Date.now().toString(), name, email, passwordHash);
206
+ return await this.userRepository.save(user);
207
+ }
208
+ }
209
+ `);
210
+ if (fw === "express") {
211
+ writeFile(root, "src/interface-adapters/controllers/user.controller.ts", `
212
+ import { Request, Response } from "express";
213
+ import { CreateUserUseCase } from "../../application/use-cases/create-user.use-case";
214
+
215
+ export class UserController {
216
+ constructor(private createUserUseCase: CreateUserUseCase) {}
217
+
218
+ async create(req: Request, res: Response) {
219
+ try {
220
+ const { name, email, password } = req.body;
221
+ const user = await this.createUserUseCase.execute(name, email, password);
222
+ res.status(201).json(user);
223
+ } catch (e: any) {
224
+ res.status(400).json({ error: e.message });
225
+ }
226
+ }
227
+ }
228
+ `);
229
+ writeFile(root, "src/main.ts", `
230
+ import express from "express";
231
+ import { UserController } from "./interface-adapters/controllers/user.controller";
232
+ import { CreateUserUseCase } from "./application/use-cases/create-user.use-case";
233
+ import { InMemoryUserRepository } from "./infrastructure/repositories/in-memory-user.repository";
234
+
235
+ const app = express();
236
+ app.use(express.json());
237
+
238
+ const userRepo = new InMemoryUserRepository();
239
+ const createUserUseCase = new CreateUserUseCase(userRepo);
240
+ const userController = new UserController(createUserUseCase);
241
+
242
+ app.post("/users", (req, res) => userController.create(req, res));
243
+
244
+ app.listen(3000, () => console.log("šŸš€ Server running on PORT 3000 (Clean Architecture)"));
245
+ `);
246
+ }
247
+ else if (fw === "nestjs") {
248
+ writeFile(root, "src/app.module.ts", `
249
+ import { Module } from '@nestjs/common';
250
+ import { UserController } from './interface-adapters/controllers/user.controller';
251
+ import { CreateUserUseCase } from './application/use-cases/create-user.use-case';
252
+ import { InMemoryUserRepository } from './infrastructure/repositories/in-memory-user.repository';
253
+
254
+ @Module({
255
+ controllers: [UserController],
256
+ providers: [
257
+ { provide: 'IUserRepository', useClass: InMemoryUserRepository },
258
+ CreateUserUseCase
259
+ ],
260
+ })
261
+ export class AppModule {}
262
+ `);
263
+ writeFile(root, "src/main.ts", `
264
+ import { NestFactory } from '@nestjs/core';
265
+ import { AppModule } from './app.module';
266
+
267
+ async function bootstrap() {
268
+ const app = await NestFactory.create(AppModule);
269
+ await app.listen(3000);
270
+ console.log("šŸš€ NestJS Server with Clean Architecture running on 3000");
271
+ }
272
+ bootstrap();
273
+ `);
274
+ }
275
+ writeFile(root, "src/infrastructure/repositories/in-memory-user.repository.ts", `
276
+ import { User } from "../../domain/entities/user.entity";
277
+ import { IUserRepository } from "../../domain/repositories/user.repository.interface";
278
+
279
+ export class InMemoryUserRepository implements IUserRepository {
280
+ private users: User[] = [];
281
+ async save(user: User): Promise<User> {
282
+ this.users.push(user);
283
+ return user;
284
+ }
285
+ async findByEmail(email: string): Promise<User | null> {
286
+ return this.users.find(u => u.email === email) || null;
287
+ }
288
+ async findById(id: string): Promise<User | null> {
289
+ return this.users.find(u => u.id === id) || null;
290
+ }
291
+ }
292
+ `);
293
+ };
294
+ // --- MAIN GENERATOR ---
295
+ async function generateProject(arch, options = {}) {
296
+ const mode = options.mode || 'standard';
297
+ const projectName = options.projectName || arch.project.name || "generated-project";
298
+ const root = path_1.default.resolve(projectName);
299
+ console.log(chalk_1.default.blueBright(`šŸš€ Starting project generation in ${mode} mode...`));
300
+ if (mode === 'professional') {
301
+ if (!fs_extra_1.default.existsSync(root))
302
+ fs_extra_1.default.mkdirpSync(root);
303
+ const lang = options.language || arch.metadata.language;
304
+ const fw = options.framework || arch.metadata.framework || "";
305
+ const modules = options.modules || arch.metadata.modules || [];
306
+ const archStyle = options.architecture || arch.metadata.type;
307
+ // Config Files
308
+ if (lang === "ts" || lang === "js") {
309
+ writeFile(root, "package.json", getPackageJson(projectName, fw, archStyle, modules));
310
+ writeFile(root, "tsconfig.json", JSON.stringify({
311
+ compilerOptions: { target: "ES2020", module: "commonjs", outDir: "./dist", rootDir: "./src", strict: true, experimentalDecorators: true, emitDecoratorMetadata: true },
312
+ exclude: ["node_modules", "dist"]
313
+ }, null, 2));
314
+ }
315
+ else if (lang === "go") {
316
+ writeFile(root, "go.mod", getGoMod(projectName, fw));
317
+ }
318
+ else if (lang === "py") {
319
+ writeFile(root, "requirements.txt", getRequirementsTxt(fw, modules));
320
+ }
321
+ writeFile(root, ".env.example", "PORT=3000\nDB_HOST=localhost\nJWT_SECRET=supersecret");
322
+ writeFile(root, ".gitignore", "node_modules/\ndist/\n.env\n__pycache__/\n*.exe\nvendor/");
323
+ writeFile(root, "README.md", `# ${projectName}\nGenerated by ArchForge X\nArchitecture: ${archStyle}`);
324
+ // Generate archforge.yaml Rules File
325
+ writeFile(root, "archforge.yaml", getArchForgeYaml(projectName, archStyle, lang, fw, modules));
326
+ if (lang === "ts" || lang === "js") {
327
+ generateTsCleanArch(root, options);
328
+ }
329
+ }
330
+ else {
331
+ // Standard Mode: Just layers and READMEs
332
+ for (const layer of arch.layers) {
333
+ const layerPath = path_1.default.resolve(root, layer.path);
334
+ fs_extra_1.default.mkdirpSync(layerPath);
335
+ const readmeContent = `# ${layer.name} Layer\n\nPath: ${layer.path}\n\nAllowed Imports: ${layer.allowedImports?.join(", ") || "Any"}\nForbidden Imports: ${layer.forbiddenImports?.join(", ") || "None"}\n`;
336
+ fs_extra_1.default.writeFileSync(path_1.default.join(layerPath, "README.md"), readmeContent);
337
+ const baseFileContent = `/**\n * Base file for ${layer.name} layer\n * Generated by ArchForge X\n */\n`;
338
+ fs_extra_1.default.writeFileSync(path_1.default.join(layerPath, `${layer.name}.ts`), baseFileContent);
339
+ }
340
+ }
341
+ console.log(chalk_1.default.green.bold(`\nāœ… Project ${projectName} successfully generated!`));
342
+ }