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.
- package/README.md +156 -56
- package/dist/cli/commands/sync.js +22 -0
- package/dist/cli/interactive.js +41 -3
- package/dist/core/architecture/schema.js +23 -2
- package/dist/core/architecture/validator.js +112 -0
- package/dist/generators/base.js +166 -0
- package/dist/generators/generator.js +35 -332
- package/dist/generators/go/gin.js +327 -0
- package/dist/generators/node/express.js +920 -0
- package/dist/generators/node/nestjs.js +770 -0
- package/dist/generators/node/nextjs.js +252 -0
- package/dist/generators/python/django.js +327 -0
- package/dist/generators/python/fastapi.js +309 -0
- package/dist/generators/registry.js +25 -0
- package/dist/index.js +29 -15
- package/package.json +3 -1
- package/dist/cli/init.js +0 -74
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FastAPIGenerator = void 0;
|
|
4
|
+
const base_1 = require("../base");
|
|
5
|
+
class FastAPIGenerator extends base_1.BaseGenerator {
|
|
6
|
+
getGeneratorName() {
|
|
7
|
+
return "FastAPI";
|
|
8
|
+
}
|
|
9
|
+
async generateProjectStructure(root, arch, options) {
|
|
10
|
+
this.generateCommonFiles(root, options);
|
|
11
|
+
this.generateAppStructure(root, options);
|
|
12
|
+
}
|
|
13
|
+
generateCommonFiles(root, options) {
|
|
14
|
+
const projectName = options.projectName || "fastapi-app";
|
|
15
|
+
this.writeFile(root, "requirements.txt", `
|
|
16
|
+
fastapi>=0.100.0
|
|
17
|
+
uvicorn>=0.23.0
|
|
18
|
+
pydantic>=2.0.0
|
|
19
|
+
python-dotenv>=1.0.0
|
|
20
|
+
import-linter>=1.10.0
|
|
21
|
+
structlog>=23.1.0
|
|
22
|
+
asgi-correlation-id>=4.2.0
|
|
23
|
+
${options.orm === 'sqlalchemy' ? 'sqlalchemy>=2.0.0' : ''}
|
|
24
|
+
${options.orm === 'sqlalchemy' && options.database === 'postgresql' ? 'psycopg2-binary>=2.9.0' : ''}
|
|
25
|
+
${options.orm === 'sqlalchemy' && options.database === 'mysql' ? 'mysqlclient>=2.2.0' : ''}
|
|
26
|
+
`.trim());
|
|
27
|
+
if (options.orm === 'sqlalchemy') {
|
|
28
|
+
this.generateSQLAlchemySetup(root, options);
|
|
29
|
+
}
|
|
30
|
+
this.writeFile(root, ".env", "PORT=8000\nENV=development");
|
|
31
|
+
this.writeFile(root, ".gitignore", "__pycache__/\n.env\nvenv/\n");
|
|
32
|
+
this.writeFile(root, "README.md", `# ${projectName}\n\nGenerated by ArchForge X`);
|
|
33
|
+
// .import-linter (Architecture Guardrails)
|
|
34
|
+
this.writeFile(root, ".import-linter", `
|
|
35
|
+
[importlinter]
|
|
36
|
+
root_package = app
|
|
37
|
+
|
|
38
|
+
[importlinter:contract:1]
|
|
39
|
+
name = API Layer Boundaries
|
|
40
|
+
type = layers
|
|
41
|
+
layers =
|
|
42
|
+
api
|
|
43
|
+
schemas
|
|
44
|
+
models
|
|
45
|
+
containers = app
|
|
46
|
+
`.trim());
|
|
47
|
+
}
|
|
48
|
+
generateAppStructure(root, options) {
|
|
49
|
+
// Main entry point
|
|
50
|
+
this.writeFile(root, "main.py", `
|
|
51
|
+
import uvicorn
|
|
52
|
+
import structlog
|
|
53
|
+
from fastapi import FastAPI, Request
|
|
54
|
+
from asgi_correlation_id import CorrelationIdMiddleware
|
|
55
|
+
from app.api.v1.endpoints import users
|
|
56
|
+
|
|
57
|
+
# Configure Structlog
|
|
58
|
+
structlog.configure(
|
|
59
|
+
processors=[
|
|
60
|
+
structlog.contextvars.merge_contextvars,
|
|
61
|
+
structlog.processors.add_log_level,
|
|
62
|
+
structlog.processors.TimeStamper(fmt="iso"),
|
|
63
|
+
structlog.processors.JSONRenderer()
|
|
64
|
+
],
|
|
65
|
+
logger_factory=structlog.PrintLoggerFactory(),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
logger = structlog.get_logger()
|
|
69
|
+
|
|
70
|
+
app = FastAPI(title="FastAPI App")
|
|
71
|
+
|
|
72
|
+
# Middleware
|
|
73
|
+
app.add_middleware(CorrelationIdMiddleware)
|
|
74
|
+
|
|
75
|
+
@app.middleware("http")
|
|
76
|
+
async def log_requests(request: Request, call_next):
|
|
77
|
+
logger.info("Incoming request", method=request.method, url=str(request.url))
|
|
78
|
+
response = await call_next(request)
|
|
79
|
+
logger.info("Request completed", status_code=response.status_code)
|
|
80
|
+
return response
|
|
81
|
+
|
|
82
|
+
app.include_router(users.router, prefix="/api/v1/users", tags=["users"])
|
|
83
|
+
|
|
84
|
+
@app.get("/")
|
|
85
|
+
def read_root():
|
|
86
|
+
return {"message": "Welcome to FastAPI generated by ArchForge X"}
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
|
|
90
|
+
`);
|
|
91
|
+
// App package
|
|
92
|
+
this.createDir(root, "app");
|
|
93
|
+
this.writeFile(root, "app/__init__.py", "");
|
|
94
|
+
// Models
|
|
95
|
+
this.writeFile(root, "app/models/__init__.py", "");
|
|
96
|
+
if (options.orm === 'sqlalchemy') {
|
|
97
|
+
this.writeFile(root, "app/models/user.py", `
|
|
98
|
+
from sqlalchemy import Column, String
|
|
99
|
+
from app.infrastructure.database import Base
|
|
100
|
+
|
|
101
|
+
class User(Base):
|
|
102
|
+
__tablename__ = "users"
|
|
103
|
+
|
|
104
|
+
id = Column(String, primary_key=True, index=True)
|
|
105
|
+
name = Column(String)
|
|
106
|
+
email = Column(String, unique=True, index=True)
|
|
107
|
+
`);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.writeFile(root, "app/models/user.py", `
|
|
111
|
+
from pydantic import BaseModel
|
|
112
|
+
|
|
113
|
+
class User(BaseModel):
|
|
114
|
+
id: str
|
|
115
|
+
name: str
|
|
116
|
+
email: str
|
|
117
|
+
`);
|
|
118
|
+
}
|
|
119
|
+
// Schemas
|
|
120
|
+
this.writeFile(root, "app/schemas/__init__.py", "");
|
|
121
|
+
this.writeFile(root, "app/schemas/user.py", `
|
|
122
|
+
from pydantic import BaseModel
|
|
123
|
+
|
|
124
|
+
class UserCreate(BaseModel):
|
|
125
|
+
name: str
|
|
126
|
+
email: str
|
|
127
|
+
|
|
128
|
+
class UserResponse(BaseModel):
|
|
129
|
+
id: str
|
|
130
|
+
name: str
|
|
131
|
+
email: str
|
|
132
|
+
|
|
133
|
+
class Config:
|
|
134
|
+
from_attributes = True
|
|
135
|
+
`);
|
|
136
|
+
// API
|
|
137
|
+
this.createDir(root, "app/api");
|
|
138
|
+
this.writeFile(root, "app/api/__init__.py", "");
|
|
139
|
+
this.createDir(root, "app/api/v1");
|
|
140
|
+
this.writeFile(root, "app/api/v1/__init__.py", "");
|
|
141
|
+
this.createDir(root, "app/api/v1/endpoints");
|
|
142
|
+
this.writeFile(root, "app/api/v1/endpoints/__init__.py", "");
|
|
143
|
+
if (options.orm === 'sqlalchemy') {
|
|
144
|
+
this.writeFile(root, "app/api/v1/endpoints/users.py", `
|
|
145
|
+
from fastapi import APIRouter, HTTPException, Depends
|
|
146
|
+
from sqlalchemy.orm import Session
|
|
147
|
+
from app.schemas.user import UserCreate, UserResponse
|
|
148
|
+
from app.models.user import User
|
|
149
|
+
from app.infrastructure.database import get_db
|
|
150
|
+
import uuid
|
|
151
|
+
|
|
152
|
+
router = APIRouter()
|
|
153
|
+
|
|
154
|
+
@router.post("/", response_model=UserResponse)
|
|
155
|
+
def create_user(user_in: UserCreate, db: Session = Depends(get_db)):
|
|
156
|
+
user = User(id=str(uuid.uuid4()), name=user_in.name, email=user_in.email)
|
|
157
|
+
db.add(user)
|
|
158
|
+
db.commit()
|
|
159
|
+
db.refresh(user)
|
|
160
|
+
return user
|
|
161
|
+
|
|
162
|
+
@router.get("/", response_model=list[UserResponse])
|
|
163
|
+
def read_users(db: Session = Depends(get_db)):
|
|
164
|
+
return db.query(User).all()
|
|
165
|
+
`);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
this.writeFile(root, "app/api/v1/endpoints/users.py", `
|
|
169
|
+
from fastapi import APIRouter, HTTPException
|
|
170
|
+
from app.schemas.user import UserCreate, UserResponse
|
|
171
|
+
from app.models.user import User
|
|
172
|
+
import uuid
|
|
173
|
+
|
|
174
|
+
router = APIRouter()
|
|
175
|
+
|
|
176
|
+
users_db = []
|
|
177
|
+
|
|
178
|
+
@router.post("/", response_model=UserResponse)
|
|
179
|
+
def create_user(user_in: UserCreate):
|
|
180
|
+
user = User(id=str(uuid.uuid4()), name=user_in.name, email=user_in.email)
|
|
181
|
+
users_db.append(user)
|
|
182
|
+
return user
|
|
183
|
+
|
|
184
|
+
@router.get("/", response_model=list[UserResponse])
|
|
185
|
+
def read_users():
|
|
186
|
+
return users_db
|
|
187
|
+
`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
generateDocker(root, options) {
|
|
191
|
+
const dbService = options.database === "postgresql" ? `
|
|
192
|
+
db:
|
|
193
|
+
image: postgres:15-alpine
|
|
194
|
+
environment:
|
|
195
|
+
- POSTGRES_USER=user
|
|
196
|
+
- POSTGRES_PASSWORD=password
|
|
197
|
+
- POSTGRES_DB=appdb
|
|
198
|
+
ports:
|
|
199
|
+
- "5432:5432"
|
|
200
|
+
` : options.database === "mysql" ? `
|
|
201
|
+
db:
|
|
202
|
+
image: mysql:8
|
|
203
|
+
environment:
|
|
204
|
+
- MYSQL_ROOT_PASSWORD=password
|
|
205
|
+
- MYSQL_DATABASE=appdb
|
|
206
|
+
ports:
|
|
207
|
+
- "3306:3306"
|
|
208
|
+
` : "";
|
|
209
|
+
const dbUrl = options.database === "postgresql" ? "postgresql://user:password@db:5432/appdb" :
|
|
210
|
+
options.database === "mysql" ? "mysql://root:password@db:3306/appdb" :
|
|
211
|
+
"sqlite:///./dev.db";
|
|
212
|
+
this.writeFile(root, "Dockerfile", `
|
|
213
|
+
FROM python:3.11-slim
|
|
214
|
+
|
|
215
|
+
WORKDIR /app
|
|
216
|
+
|
|
217
|
+
COPY requirements.txt .
|
|
218
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
219
|
+
|
|
220
|
+
COPY . .
|
|
221
|
+
|
|
222
|
+
EXPOSE 8000
|
|
223
|
+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
|
224
|
+
`);
|
|
225
|
+
this.writeFile(root, "docker-compose.yml", `
|
|
226
|
+
version: '3.8'
|
|
227
|
+
services:
|
|
228
|
+
app:
|
|
229
|
+
build: .
|
|
230
|
+
ports:
|
|
231
|
+
- "8000:8000"
|
|
232
|
+
environment:
|
|
233
|
+
- PORT=8000
|
|
234
|
+
- ENV=production
|
|
235
|
+
- DATABASE_URL=${dbUrl}
|
|
236
|
+
depends_on:
|
|
237
|
+
${dbService ? "- db" : ""}
|
|
238
|
+
restart: always
|
|
239
|
+
${dbService}
|
|
240
|
+
`);
|
|
241
|
+
}
|
|
242
|
+
generateCI(root, options) {
|
|
243
|
+
this.writeFile(root, ".github/workflows/ci.yml", `
|
|
244
|
+
name: CI
|
|
245
|
+
|
|
246
|
+
on:
|
|
247
|
+
push:
|
|
248
|
+
branches: [ main ]
|
|
249
|
+
pull_request:
|
|
250
|
+
branches: [ main ]
|
|
251
|
+
|
|
252
|
+
jobs:
|
|
253
|
+
test:
|
|
254
|
+
runs-on: ubuntu-latest
|
|
255
|
+
|
|
256
|
+
steps:
|
|
257
|
+
- uses: actions/checkout@v3
|
|
258
|
+
- name: Set up Python 3.11
|
|
259
|
+
uses: actions/setup-python@v4
|
|
260
|
+
with:
|
|
261
|
+
python-version: "3.11"
|
|
262
|
+
cache: 'pip'
|
|
263
|
+
- name: Install dependencies
|
|
264
|
+
run: |
|
|
265
|
+
python -m pip install --upgrade pip
|
|
266
|
+
pip install -r requirements.txt
|
|
267
|
+
pip install pytest flake8
|
|
268
|
+
- name: Lint with flake8
|
|
269
|
+
run: |
|
|
270
|
+
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
|
271
|
+
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
|
272
|
+
- name: Architecture Sync & Validation
|
|
273
|
+
run: |
|
|
274
|
+
pip install archforge-x # In a real scenario, this would be available
|
|
275
|
+
archforge sync
|
|
276
|
+
`);
|
|
277
|
+
}
|
|
278
|
+
generateSQLAlchemySetup(root, options) {
|
|
279
|
+
const dbUrl = options.database === "postgresql" ? "os.getenv('DATABASE_URL', 'postgresql://user:password@localhost:5432/appdb')" :
|
|
280
|
+
options.database === "mysql" ? "os.getenv('DATABASE_URL', 'mysql://root:password@localhost:3306/appdb')" :
|
|
281
|
+
"os.getenv('DATABASE_URL', 'sqlite:///./dev.db')";
|
|
282
|
+
this.writeFile(root, "app/infrastructure/database.py", `
|
|
283
|
+
import os
|
|
284
|
+
from sqlalchemy import create_all, create_engine
|
|
285
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
286
|
+
from sqlalchemy.orm import sessionmaker
|
|
287
|
+
|
|
288
|
+
SQLALCHEMY_DATABASE_URL = ${dbUrl}
|
|
289
|
+
|
|
290
|
+
engine = create_engine(
|
|
291
|
+
SQLALCHEMY_DATABASE_URL,
|
|
292
|
+
connect_args={"check_same_thread": False} if "sqlite" in SQLALCHEMY_DATABASE_URL else {}
|
|
293
|
+
)
|
|
294
|
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
295
|
+
|
|
296
|
+
Base = declarative_base()
|
|
297
|
+
|
|
298
|
+
def get_db():
|
|
299
|
+
db = SessionLocal()
|
|
300
|
+
try:
|
|
301
|
+
yield db
|
|
302
|
+
finally:
|
|
303
|
+
db.close()
|
|
304
|
+
`);
|
|
305
|
+
// Update main.py to create tables
|
|
306
|
+
this.writeFile(root, "app/infrastructure/__init__.py", "");
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
exports.FastAPIGenerator = FastAPIGenerator;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GeneratorRegistry = void 0;
|
|
4
|
+
class GeneratorRegistry {
|
|
5
|
+
static register(key, generator) {
|
|
6
|
+
this.generators.set(key, generator);
|
|
7
|
+
}
|
|
8
|
+
static getGenerator(language, framework) {
|
|
9
|
+
// Try exact match first
|
|
10
|
+
const key = `${language}:${framework}`;
|
|
11
|
+
if (this.generators.has(key)) {
|
|
12
|
+
return this.generators.get(key);
|
|
13
|
+
}
|
|
14
|
+
// Fallback to language only if framework specific one not found (or if framework is generic)
|
|
15
|
+
if (this.generators.has(language)) {
|
|
16
|
+
return this.generators.get(language);
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
static listGenerators() {
|
|
21
|
+
return Array.from(this.generators.keys());
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.GeneratorRegistry = GeneratorRegistry;
|
|
25
|
+
GeneratorRegistry.generators = new Map();
|
package/dist/index.js
CHANGED
|
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const commander_1 = require("commander");
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
const init_1 = require("./cli/init");
|
|
10
9
|
const interactive_1 = require("./cli/interactive");
|
|
10
|
+
const sync_1 = require("./cli/commands/sync");
|
|
11
11
|
const parser_1 = require("./core/architecture/parser");
|
|
12
12
|
const generator_1 = require("./generators/generator");
|
|
13
13
|
const dependency_1 = require("./analyzers/dependency");
|
|
@@ -26,10 +26,22 @@ const loadConfig = (configPath) => {
|
|
|
26
26
|
return (0, parser_1.loadArchitecture)(configPath);
|
|
27
27
|
};
|
|
28
28
|
// --- COMMANDS ---
|
|
29
|
-
program
|
|
29
|
+
program
|
|
30
|
+
.command("init")
|
|
31
|
+
.description("Initialize a new project with interactive wizard (Recommended)")
|
|
32
|
+
.action(async () => {
|
|
33
|
+
await (0, interactive_1.interactiveCLI)();
|
|
34
|
+
});
|
|
35
|
+
program
|
|
36
|
+
.command("sync")
|
|
37
|
+
.description("Synchronize architecture with archforge.yaml and validate structure")
|
|
38
|
+
.action(async () => {
|
|
39
|
+
await (0, sync_1.syncCommand)();
|
|
40
|
+
});
|
|
30
41
|
program
|
|
31
42
|
.command("generate")
|
|
32
|
-
.
|
|
43
|
+
.alias("create")
|
|
44
|
+
.description("Scaffold a project or module based on architecture definition")
|
|
33
45
|
.option("-c, --config <path>", "Path to yaml config", "archforge.yaml")
|
|
34
46
|
.option("-m, --mode <mode>", "Generation mode: 'standard' or 'professional'", "professional")
|
|
35
47
|
.action(async (options) => {
|
|
@@ -41,7 +53,9 @@ program
|
|
|
41
53
|
language: arch.metadata.language,
|
|
42
54
|
framework: arch.metadata.framework,
|
|
43
55
|
modules: arch.metadata.modules,
|
|
44
|
-
projectName: arch.project.name
|
|
56
|
+
projectName: arch.project.name,
|
|
57
|
+
orm: arch.metadata.orm,
|
|
58
|
+
database: arch.metadata.database
|
|
45
59
|
};
|
|
46
60
|
await (0, generator_1.generateProject)(arch, genOptions);
|
|
47
61
|
}
|
|
@@ -51,14 +65,15 @@ program
|
|
|
51
65
|
}
|
|
52
66
|
});
|
|
53
67
|
program
|
|
54
|
-
.command("
|
|
55
|
-
.
|
|
68
|
+
.command("validate")
|
|
69
|
+
.alias("check")
|
|
70
|
+
.description("Validate project structure and dependencies against rules")
|
|
56
71
|
.option("-c, --config <path>", "Path to yaml config", "archforge.yaml")
|
|
57
72
|
.option("--ignore-tests", "Exclude test files from analysis")
|
|
58
73
|
.option("-o, --output <file>", "Export report to JSON/Markdown")
|
|
59
74
|
.action((options) => {
|
|
60
75
|
try {
|
|
61
|
-
console.log(chalk_1.default.cyan("š
|
|
76
|
+
console.log(chalk_1.default.cyan("š Validating Architecture..."));
|
|
62
77
|
const arch = loadConfig(options.config);
|
|
63
78
|
const violations = (0, dependency_1.analyzeDependencies)(arch, {
|
|
64
79
|
ignoreTests: options.ignoreTests,
|
|
@@ -69,13 +84,13 @@ program
|
|
|
69
84
|
process.exit(1);
|
|
70
85
|
}
|
|
71
86
|
catch (err) {
|
|
72
|
-
console.error(chalk_1.default.red.bold("\nā
|
|
87
|
+
console.error(chalk_1.default.red.bold("\nā Validation Error:"), err.message);
|
|
73
88
|
process.exit(1);
|
|
74
89
|
}
|
|
75
90
|
});
|
|
76
91
|
program
|
|
77
92
|
.command("audit")
|
|
78
|
-
.description("
|
|
93
|
+
.description("Perform a deep architectural audit with auto-fix suggestions")
|
|
79
94
|
.option("-c, --config <path>", "Path to yaml config", "archforge.yaml")
|
|
80
95
|
.option("-o, --output <file>", "Export audit results")
|
|
81
96
|
.action((options) => {
|
|
@@ -91,8 +106,9 @@ program
|
|
|
91
106
|
}
|
|
92
107
|
});
|
|
93
108
|
program
|
|
94
|
-
.command("
|
|
95
|
-
.
|
|
109
|
+
.command("graph")
|
|
110
|
+
.alias("visualize")
|
|
111
|
+
.description("Generate a visual dependency graph (SVG)")
|
|
96
112
|
.option("-c, --config <path>", "Path to yaml config", "archforge.yaml")
|
|
97
113
|
.option("-o, --output <file>", "Output file path", "architecture-graph.svg")
|
|
98
114
|
.action(async (options) => {
|
|
@@ -106,10 +122,8 @@ program
|
|
|
106
122
|
console.error(chalk_1.default.red.bold("\nā Visualization Error:"), err.message);
|
|
107
123
|
}
|
|
108
124
|
});
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
.description("Interactive Wizard (Recommended)")
|
|
112
|
-
.action(async () => {
|
|
125
|
+
// Set default command to init
|
|
126
|
+
program.action(async () => {
|
|
113
127
|
await (0, interactive_1.interactiveCLI)();
|
|
114
128
|
});
|
|
115
129
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "archforge-x",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Enterprise Architecture Engine for scaffolding, analyzing, and visualizing software architecture.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"homepage": "https://github.com/henabakos/archforge-x#readme",
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/fs-extra": "^11.0.4",
|
|
42
|
+
"@types/js-yaml": "^4.0.9",
|
|
42
43
|
"@types/node": "^25.0.3",
|
|
43
44
|
"@types/prompts": "^2.4.9",
|
|
44
45
|
"@types/viz.js": "^2.1.5",
|
|
@@ -48,6 +49,7 @@
|
|
|
48
49
|
"chalk": "^5.6.2",
|
|
49
50
|
"commander": "^14.0.2",
|
|
50
51
|
"fs-extra": "^11.3.3",
|
|
52
|
+
"js-yaml": "^4.1.1",
|
|
51
53
|
"prompts": "^2.4.2",
|
|
52
54
|
"typescript": "^5.9.3",
|
|
53
55
|
"viz.js": "^2.1.2",
|
package/dist/cli/init.js
DELETED
|
@@ -1,74 +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.initCommand = void 0;
|
|
7
|
-
const commander_1 = require("commander");
|
|
8
|
-
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
exports.initCommand = new commander_1.Command("init")
|
|
12
|
-
.description("Initialize a new architecture configuration file (archforge.yaml)")
|
|
13
|
-
.action(() => {
|
|
14
|
-
const configPath = path_1.default.resolve(process.cwd(), "archforge.yaml");
|
|
15
|
-
// 1. Safety Check: Don't overwrite existing config
|
|
16
|
-
if (fs_1.default.existsSync(configPath)) {
|
|
17
|
-
console.log(chalk_1.default.yellow("ā ļø Configuration file 'archforge.yaml' already exists."));
|
|
18
|
-
console.log(chalk_1.default.gray(` Path: ${configPath}`));
|
|
19
|
-
console.log(chalk_1.default.blue(" Run 'archforge analyze' or 'archforge generate' to use it."));
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const template = `
|
|
23
|
-
version: "1.0"
|
|
24
|
-
name: "Enterprise Architecture Config"
|
|
25
|
-
project:
|
|
26
|
-
name: "my-awesome-project"
|
|
27
|
-
root: "."
|
|
28
|
-
|
|
29
|
-
metadata:
|
|
30
|
-
type: "clean" # Options: clean, ddd, hexagonal, layered
|
|
31
|
-
language: "ts" # Options: ts, js, py, go
|
|
32
|
-
framework: "nestjs" # Options: nestjs, express, django, flask, gin
|
|
33
|
-
version: "1.0.0"
|
|
34
|
-
modules: # Optional modules to scaffold
|
|
35
|
-
- "auth"
|
|
36
|
-
- "docker"
|
|
37
|
-
|
|
38
|
-
# Define your architecture layers and dependency rules here
|
|
39
|
-
layers:
|
|
40
|
-
- name: "domain"
|
|
41
|
-
path: "src/domain"
|
|
42
|
-
description: "Core business logic and entities (Enterprise Rules)"
|
|
43
|
-
strict: true
|
|
44
|
-
forbiddenImports: ["infrastructure", "interface", "application"]
|
|
45
|
-
|
|
46
|
-
- name: "application"
|
|
47
|
-
path: "src/application"
|
|
48
|
-
description: "Use cases and application logic"
|
|
49
|
-
allowedImports: ["domain"]
|
|
50
|
-
|
|
51
|
-
- name: "infrastructure"
|
|
52
|
-
path: "src/infrastructure"
|
|
53
|
-
description: "External tools, databases, and third-party services"
|
|
54
|
-
allowedImports: ["domain", "application"]
|
|
55
|
-
|
|
56
|
-
- name: "interface"
|
|
57
|
-
path: "src/interface"
|
|
58
|
-
description: "Controllers, API endpoints, and Presenters"
|
|
59
|
-
allowedImports: ["application"]
|
|
60
|
-
`.trim();
|
|
61
|
-
// 3. Write the file
|
|
62
|
-
try {
|
|
63
|
-
fs_1.default.writeFileSync(configPath, template, "utf-8");
|
|
64
|
-
console.log(chalk_1.default.green.bold("ā
Successfully initialized 'archforge.yaml'"));
|
|
65
|
-
console.log(chalk_1.default.white(" You can now customize the layers in the file."));
|
|
66
|
-
console.log(chalk_1.default.gray("\nNext steps:"));
|
|
67
|
-
console.log(chalk_1.default.cyan(" 1. archforge generate"));
|
|
68
|
-
console.log(chalk_1.default.cyan(" 2. archforge analyze"));
|
|
69
|
-
}
|
|
70
|
-
catch (err) {
|
|
71
|
-
console.error(chalk_1.default.red("ā Failed to create configuration file:"), err.message);
|
|
72
|
-
process.exit(1);
|
|
73
|
-
}
|
|
74
|
-
});
|