archforge-x 1.0.2 → 1.0.4

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,252 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NextJSGenerator = void 0;
4
+ const base_1 = require("../base");
5
+ class NextJSGenerator extends base_1.BaseGenerator {
6
+ getGeneratorName() {
7
+ return "Next.js";
8
+ }
9
+ async generateProjectStructure(root, arch, options) {
10
+ // Next.js is opinionated, so we'll stick to its standard structure but organized well.
11
+ // We can support "clean" by adding a separate folder for domain logic if requested.
12
+ this.generateCommonFiles(root, options);
13
+ this.generateSourceFiles(root, options);
14
+ }
15
+ generateCommonFiles(root, options) {
16
+ const projectName = options.projectName || "nextjs-app";
17
+ this.writeFile(root, "package.json", JSON.stringify({
18
+ name: projectName,
19
+ version: "0.1.0",
20
+ private: true,
21
+ scripts: {
22
+ "dev": "next dev",
23
+ "build": "next build",
24
+ "start": "next start",
25
+ "lint": "next lint"
26
+ },
27
+ dependencies: {
28
+ "react": "^18",
29
+ "react-dom": "^18",
30
+ "next": "14.0.0",
31
+ "pino": "^8.14.0",
32
+ "uuid": "^9.0.0"
33
+ },
34
+ devDependencies: {
35
+ "typescript": "^5",
36
+ "@types/node": "^20",
37
+ "@types/react": "^18",
38
+ "@types/react-dom": "^18",
39
+ "@types/uuid": "^9.0.2",
40
+ "eslint": "^8",
41
+ "eslint-config-next": "14.0.0",
42
+ "eslint-plugin-import": "^2.27.5",
43
+ "pino-pretty": "^10.0.0"
44
+ }
45
+ }, null, 2));
46
+ this.writeFile(root, "tsconfig.json", JSON.stringify({
47
+ compilerOptions: {
48
+ target: "es5",
49
+ lib: ["dom", "dom.iterable", "esnext"],
50
+ allowJs: true,
51
+ skipLibCheck: true,
52
+ strict: true,
53
+ noEmit: true,
54
+ esModuleInterop: true,
55
+ module: "esnext",
56
+ moduleResolution: "bundler",
57
+ resolveJsonModule: true,
58
+ isolatedModules: true,
59
+ jsx: "preserve",
60
+ incremental: true,
61
+ plugins: [{ name: "next" }],
62
+ paths: { "@/*": ["./src/*"] }
63
+ },
64
+ include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
65
+ exclude: ["node_modules"]
66
+ }, null, 2));
67
+ // .eslintrc.json (Architecture Guardrails)
68
+ this.writeFile(root, ".eslintrc.json", JSON.stringify({
69
+ "extends": "next/core-web-vitals",
70
+ "plugins": ["import"],
71
+ "rules": {
72
+ "import/no-restricted-paths": ["error", {
73
+ "zones": [
74
+ {
75
+ "target": "./src/components",
76
+ "from": "./src/app",
77
+ "message": "Components cannot import from App (Pages)"
78
+ },
79
+ {
80
+ "target": "./src/lib",
81
+ "from": "./src/components",
82
+ "message": "Lib cannot import from Components"
83
+ },
84
+ {
85
+ "target": "./src/lib",
86
+ "from": "./src/app",
87
+ "message": "Lib cannot import from App (Pages)"
88
+ }
89
+ ]
90
+ }]
91
+ }
92
+ }, null, 2));
93
+ this.writeFile(root, "next.config.js", `/** @type {import('next').NextConfig} */
94
+ const nextConfig = {}
95
+ module.exports = nextConfig
96
+ `);
97
+ this.writeFile(root, ".gitignore", `node_modules/\n.next/\n.env\n`);
98
+ this.writeFile(root, "next-env.d.ts", `/// <reference types="next" />
99
+ /// <reference types="next/image-types/global" />
100
+
101
+ // NOTE: This file should not be edited
102
+ // see https://nextjs.org/docs/basic-features/typescript for more information.
103
+ `);
104
+ }
105
+ generateSourceFiles(root, options) {
106
+ // App Router structure
107
+ this.writeFile(root, "src/app/layout.tsx", `
108
+ import type { Metadata } from 'next'
109
+
110
+ export const metadata: Metadata = {
111
+ title: 'Create Next App',
112
+ description: 'Generated by create next app',
113
+ }
114
+
115
+ export default function RootLayout({
116
+ children,
117
+ }: {
118
+ children: React.ReactNode
119
+ }) {
120
+ return (
121
+ <html lang="en">
122
+ <body>{children}</body>
123
+ </html>
124
+ )
125
+ }
126
+ `);
127
+ this.writeFile(root, "src/app/page.tsx", `
128
+ export default function Home() {
129
+ return (
130
+ <main style={{ padding: '2rem', fontFamily: 'sans-serif' }}>
131
+ <h1>Welcome to Next.js</h1>
132
+ <p>Generated by ArchForge X</p>
133
+ </main>
134
+ )
135
+ }
136
+ `);
137
+ // API Route example
138
+ this.writeFile(root, "src/app/api/hello/route.ts", `
139
+ import { NextResponse } from 'next/server';
140
+ import logger from '@/lib/logger';
141
+
142
+ export async function GET() {
143
+ logger.info('Hello API called');
144
+ return NextResponse.json({ message: 'Hello from ArchForge X!' });
145
+ }
146
+ `);
147
+ // Logger Utility
148
+ this.writeFile(root, "src/lib/logger.ts", `
149
+ import pino from 'pino';
150
+
151
+ const logger = pino({
152
+ level: process.env.LOG_LEVEL || 'info',
153
+ transport: process.env.NODE_ENV !== 'production' ? { target: 'pino-pretty' } : undefined,
154
+ base: {
155
+ env: process.env.NODE_ENV,
156
+ },
157
+ });
158
+
159
+ export default logger;
160
+ `);
161
+ // Middleware for Correlation ID
162
+ this.writeFile(root, "src/middleware.ts", `
163
+ import { NextResponse } from 'next/server';
164
+ import type { NextRequest } from 'next/server';
165
+ import { v4 as uuidv4 } from 'uuid';
166
+
167
+ export function middleware(request: NextRequest) {
168
+ const requestHeaders = new Headers(request.headers);
169
+ const correlationId = requestHeaders.get('x-correlation-id') || uuidv4();
170
+ requestHeaders.set('x-correlation-id', correlationId);
171
+
172
+ const response = NextResponse.next({
173
+ request: {
174
+ headers: requestHeaders,
175
+ },
176
+ });
177
+
178
+ response.headers.set('x-correlation-id', correlationId);
179
+ return response;
180
+ }
181
+
182
+ export const config = {
183
+ matcher: '/:path*',
184
+ };
185
+ `);
186
+ }
187
+ generateDocker(root, options) {
188
+ this.writeFile(root, "Dockerfile", `
189
+ FROM node:18-alpine AS base
190
+
191
+ FROM base AS deps
192
+ WORKDIR /app
193
+ COPY package.json package-lock.json* ./
194
+ RUN npm ci
195
+
196
+ FROM base AS builder
197
+ WORKDIR /app
198
+ COPY --from=deps /app/node_modules ./node_modules
199
+ COPY . .
200
+ RUN npm run build
201
+
202
+ FROM base AS runner
203
+ WORKDIR /app
204
+ ENV NODE_ENV production
205
+ COPY --from=builder /app/public ./public
206
+ COPY --from=builder /app/.next/standalone ./
207
+ COPY --from=builder /app/.next/static ./.next/static
208
+
209
+ EXPOSE 3000
210
+ ENV PORT 3000
211
+ CMD ["node", "server.js"]
212
+ `);
213
+ this.writeFile(root, "docker-compose.yml", `
214
+ version: '3.8'
215
+ services:
216
+ app:
217
+ build: .
218
+ ports:
219
+ - "3000:3000"
220
+ environment:
221
+ - NODE_ENV=production
222
+ restart: always
223
+ `);
224
+ }
225
+ generateCI(root, options) {
226
+ this.writeFile(root, ".github/workflows/ci.yml", `
227
+ name: CI
228
+
229
+ on:
230
+ push:
231
+ branches: [ main ]
232
+ pull_request:
233
+ branches: [ main ]
234
+
235
+ jobs:
236
+ build:
237
+ runs-on: ubuntu-latest
238
+
239
+ steps:
240
+ - uses: actions/checkout@v3
241
+ - name: Use Node.js 18.x
242
+ uses: actions/setup-node@v3
243
+ with:
244
+ node-version: 18.x
245
+ cache: 'npm'
246
+ - run: npm ci
247
+ - run: npm run lint
248
+ - run: npm run build
249
+ `);
250
+ }
251
+ }
252
+ exports.NextJSGenerator = NextJSGenerator;
@@ -0,0 +1,327 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DjangoGenerator = void 0;
4
+ const base_1 = require("../base");
5
+ class DjangoGenerator extends base_1.BaseGenerator {
6
+ getGeneratorName() {
7
+ return "Django";
8
+ }
9
+ async generateProjectStructure(root, arch, options) {
10
+ // Django structure is complex to generate file-by-file without the CLI,
11
+ // but we will generate a standard working structure.
12
+ const projectName = options.projectName || "django_project";
13
+ const appName = "core"; // Default app name
14
+ this.generateRequirements(root, options);
15
+ this.generateManagePy(root, projectName, options);
16
+ this.generateProjectConfig(root, projectName, options);
17
+ this.generateApp(root, appName);
18
+ }
19
+ generateRequirements(root, options) {
20
+ this.writeFile(root, "requirements.txt", `
21
+ Django>=4.2.0
22
+ djangorestframework>=3.14.0
23
+ python-dotenv>=1.0.0
24
+ import-linter>=1.10.0
25
+ structlog>=23.1.0
26
+ django-structlog>=5.1.0
27
+ dj-database-url>=2.1.0
28
+ ${options.database === 'postgresql' ? 'psycopg2-binary>=2.9.0' : ''}
29
+ ${options.database === 'mysql' ? 'mysqlclient>=2.2.0' : ''}
30
+ `.trim());
31
+ // .import-linter (Architecture Guardrails)
32
+ this.writeFile(root, ".import-linter", `
33
+ [importlinter]
34
+ root_package = core
35
+
36
+ [importlinter:contract:1]
37
+ name = Django App Boundaries
38
+ type = layers
39
+ layers =
40
+ views
41
+ models
42
+ containers = core
43
+ `.trim());
44
+ }
45
+ generateManagePy(root, projectName, options) {
46
+ this.writeFile(root, "manage.py", `
47
+ #!/usr/bin/env python
48
+ """Django's command-line utility for administrative tasks."""
49
+ import os
50
+ import sys
51
+
52
+ def main():
53
+ """Run administrative tasks."""
54
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', '${projectName}.settings')
55
+ try:
56
+ from django.core.management import execute_from_command_line
57
+ except ImportError as exc:
58
+ raise ImportError(
59
+ "Couldn't import Django. Are you sure it's installed and "
60
+ "available on your PYTHONPATH environment variable? Did you "
61
+ "forget to activate a virtual environment?"
62
+ ) from exc
63
+ execute_from_command_line(sys.argv)
64
+
65
+ if __name__ == '__main__':
66
+ main()
67
+ `);
68
+ }
69
+ generateProjectConfig(root, projectName, options) {
70
+ const configDir = `${projectName}`; // Django project folder usually has same name as project
71
+ this.createDir(root, configDir);
72
+ this.writeFile(root, `${configDir}/__init__.py`, "");
73
+ this.writeFile(root, `${configDir}/settings.py`, `
74
+ from pathlib import Path
75
+
76
+ BASE_DIR = Path(__file__).resolve().parent.parent
77
+ SECRET_KEY = 'django-insecure-generated-key'
78
+ DEBUG = True
79
+ ALLOWED_HOSTS = []
80
+
81
+ INSTALLED_APPS = [
82
+ 'django.contrib.admin',
83
+ 'django.contrib.auth',
84
+ 'django.contrib.contenttypes',
85
+ 'django.contrib.sessions',
86
+ 'django.contrib.messages',
87
+ 'django.contrib.staticfiles',
88
+ 'rest_framework',
89
+ 'core',
90
+ ]
91
+
92
+ MIDDLEWARE = [
93
+ 'django.middleware.security.SecurityMiddleware',
94
+ 'django.contrib.sessions.middleware.SessionMiddleware',
95
+ 'django.middleware.common.CommonMiddleware',
96
+ 'django.middleware.csrf.CsrfViewMiddleware',
97
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
98
+ 'django.contrib.messages.middleware.MessageMiddleware',
99
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
100
+ ]
101
+
102
+ ROOT_URLCONF = '${projectName}.urls'
103
+
104
+ TEMPLATES = [
105
+ {
106
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
107
+ 'DIRS': [],
108
+ 'APP_DIRS': True,
109
+ 'OPTIONS': {
110
+ 'context_processors': [
111
+ 'django.template.context_processors.debug',
112
+ 'django.template.context_processors.request',
113
+ 'django.contrib.auth.context_processors.auth',
114
+ 'django.contrib.messages.context_processors.messages',
115
+ ],
116
+ },
117
+ },
118
+ ]
119
+
120
+ WSGI_APPLICATION = '${projectName}.wsgi.application'
121
+
122
+ import os
123
+ import dj_database_url
124
+
125
+ DATABASES = {
126
+ 'default': dj_database_url.config(
127
+ default=os.getenv('DATABASE_URL', 'sqlite:///' + str(BASE_DIR / 'db.sqlite3'))
128
+ )
129
+ }
130
+
131
+ AUTH_PASSWORD_VALIDATORS = []
132
+ LANGUAGE_CODE = 'en-us'
133
+ TIME_ZONE = 'UTC'
134
+ USE_I18N = True
135
+ USE_TZ = True
136
+ STATIC_URL = 'static/'
137
+ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
138
+
139
+ # Logging Configuration
140
+ import structlog
141
+
142
+ LOGGING = {
143
+ "version": 1,
144
+ "disable_existing_loggers": False,
145
+ "formatters": {
146
+ "json_formatter": {
147
+ "()": structlog.stdlib.ProcessorFormatter,
148
+ "processor": structlog.processors.JSONRenderer(),
149
+ },
150
+ },
151
+ "handlers": {
152
+ "console": {
153
+ "class": "logging.StreamHandler",
154
+ "formatter": "json_formatter",
155
+ },
156
+ },
157
+ "root": {
158
+ "handlers": ["console"],
159
+ "level": "INFO",
160
+ },
161
+ }
162
+
163
+ structlog.configure(
164
+ processors=[
165
+ structlog.contextvars.merge_contextvars,
166
+ structlog.stdlib.filter_by_level,
167
+ structlog.processors.TimeStamper(fmt="iso"),
168
+ structlog.stdlib.add_logger_name,
169
+ structlog.stdlib.add_log_level,
170
+ structlog.stdlib.PositionalArgumentsFormatter(),
171
+ structlog.processors.StackInfoRenderer(),
172
+ structlog.processors.format_exc_info,
173
+ structlog.stdlib.ProcessorFormatter.wrap_for_formatter,
174
+ ],
175
+ logger_factory=structlog.stdlib.LoggerFactory(),
176
+ cache_logger_on_first_use=True,
177
+ )
178
+
179
+ MIDDLEWARE.insert(0, 'django_structlog.middlewares.RequestMiddleware')
180
+ `);
181
+ this.writeFile(root, `${configDir}/urls.py`, `
182
+ from django.contrib import admin
183
+ from django.urls import path, include
184
+
185
+ urlpatterns = [
186
+ path('admin/', admin.site.urls),
187
+ path('api/', include('core.urls')),
188
+ ]
189
+ `);
190
+ this.writeFile(root, `${configDir}/wsgi.py`, `
191
+ import os
192
+ from django.core.wsgi import get_wsgi_application
193
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', '${projectName}.settings')
194
+ application = get_wsgi_application()
195
+ `);
196
+ this.writeFile(root, `${configDir}/asgi.py`, `
197
+ import os
198
+ from django.core.asgi import get_asgi_application
199
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', '${projectName}.settings')
200
+ application = get_asgi_application()
201
+ `);
202
+ }
203
+ generateApp(root, appName) {
204
+ this.createDir(root, appName);
205
+ this.writeFile(root, `${appName}/__init__.py`, "");
206
+ this.writeFile(root, `${appName}/admin.py`, "from django.contrib import admin\n# Register your models here.");
207
+ this.writeFile(root, `${appName}/apps.py`, `
208
+ from django.apps import AppConfig
209
+ class CoreConfig(AppConfig):
210
+ default_auto_field = 'django.db.models.BigAutoField'
211
+ name = '${appName}'
212
+ `);
213
+ this.writeFile(root, `${appName}/models.py`, "from django.db import models\n# Create your models here.");
214
+ this.writeFile(root, `${appName}/tests.py`, "from django.test import TestCase\n# Create your tests here.");
215
+ this.writeFile(root, `${appName}/views.py`, `
216
+ from rest_framework.decorators import api_view
217
+ from rest_framework.response import Response
218
+
219
+ @api_view(['GET'])
220
+ def hello_world(request):
221
+ return Response({"message": "Hello from Django generated by ArchForge X"})
222
+ `);
223
+ this.writeFile(root, `${appName}/urls.py`, `
224
+ from django.urls import path
225
+ from . import views
226
+
227
+ urlpatterns = [
228
+ path('hello/', views.hello_world),
229
+ ]
230
+ `);
231
+ }
232
+ generateDocker(root, options) {
233
+ const dbService = options.database === "postgresql" ? `
234
+ db:
235
+ image: postgres:15-alpine
236
+ environment:
237
+ - POSTGRES_USER=user
238
+ - POSTGRES_PASSWORD=password
239
+ - POSTGRES_DB=appdb
240
+ ports:
241
+ - "5432:5432"
242
+ ` : options.database === "mysql" ? `
243
+ db:
244
+ image: mysql:8
245
+ environment:
246
+ - MYSQL_ROOT_PASSWORD=password
247
+ - MYSQL_DATABASE=appdb
248
+ ports:
249
+ - "3306:3306"
250
+ ` : "";
251
+ const dbUrl = options.database === "postgresql" ? "postgres://user:password@db:5432/appdb" :
252
+ options.database === "mysql" ? "mysql://root:password@db:3306/appdb" :
253
+ "sqlite:///db.sqlite3";
254
+ this.writeFile(root, "Dockerfile", `
255
+ FROM python:3.11-slim
256
+
257
+ WORKDIR /app
258
+
259
+ COPY requirements.txt .
260
+ RUN pip install --no-cache-dir -r requirements.txt
261
+
262
+ COPY . .
263
+
264
+ EXPOSE 8000
265
+ CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
266
+ `);
267
+ this.writeFile(root, "docker-compose.yml", `
268
+ version: '3.8'
269
+ services:
270
+ app:
271
+ build: .
272
+ ports:
273
+ - "8000:8000"
274
+ environment:
275
+ - DEBUG=0
276
+ - SECRET_KEY=production-secret
277
+ - DATABASE_URL=${dbUrl}
278
+ depends_on:
279
+ ${dbService ? "- db" : ""}
280
+ restart: always
281
+ ${dbService}
282
+ `);
283
+ }
284
+ generateCI(root, options) {
285
+ this.writeFile(root, ".github/workflows/ci.yml", `
286
+ name: CI
287
+
288
+ on:
289
+ push:
290
+ branches: [ main ]
291
+ pull_request:
292
+ branches: [ main ]
293
+
294
+ jobs:
295
+ test:
296
+ runs-on: ubuntu-latest
297
+
298
+ steps:
299
+ - uses: actions/checkout@v3
300
+ - name: Set up Python 3.11
301
+ uses: actions/setup-python@v4
302
+ with:
303
+ python-version: "3.11"
304
+ cache: 'pip'
305
+ - name: Install dependencies
306
+ run: |
307
+ python -m pip install --upgrade pip
308
+ pip install -r requirements.txt
309
+ pip install flake8
310
+ - name: Lint with flake8
311
+ run: |
312
+ flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
313
+ flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
314
+ - name: Architecture Sync & Validation
315
+ run: |
316
+ # In a real scenario, archforge would be installed
317
+ echo "Running archforge sync..."
318
+ - name: Check Architecture Boundaries
319
+ run: |
320
+ lint-imports
321
+ - name: Run Tests
322
+ run: |
323
+ python manage.py test
324
+ `);
325
+ }
326
+ }
327
+ exports.DjangoGenerator = DjangoGenerator;