rapidkit 1.0.0-beta.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/LICENSE +21 -0
- package/README.md +410 -0
- package/dist/create.d.ts +8 -0
- package/dist/create.d.ts.map +1 -0
- package/dist/create.js +505 -0
- package/dist/create.js.map +1 -0
- package/dist/demo-kit.d.ts +10 -0
- package/dist/demo-kit.d.ts.map +1 -0
- package/dist/demo-kit.js +124 -0
- package/dist/demo-kit.js.map +1 -0
- package/dist/generator.d.ts +12 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +877 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
- package/templates/kits/fastapi-standard/README.md.j2 +30 -0
- package/templates/kits/fastapi-standard/kit.yaml +120 -0
- package/templates/kits/fastapi-standard/pyproject.toml.j2 +41 -0
- package/templates/kits/fastapi-standard/src/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-standard/src/cli.py.j2 +333 -0
- package/templates/kits/fastapi-standard/src/main.py.j2 +41 -0
- package/templates/kits/fastapi-standard/src/modules/__init__.py.j2 +3 -0
- package/templates/kits/fastapi-standard/src/routing/__init__.py.j2 +13 -0
- package/templates/kits/fastapi-standard/src/routing/health.py.j2 +13 -0
- package/templates/kits/fastapi-standard/tests/__init__.py.j2 +1 -0
|
@@ -0,0 +1,877 @@
|
|
|
1
|
+
export function generateProjectFiles(config) {
|
|
2
|
+
const files = {};
|
|
3
|
+
const isFastAPI = config.framework.startsWith('fastapi');
|
|
4
|
+
files['README.md'] = generateReadme(config);
|
|
5
|
+
files['.gitignore'] = generateGitignore();
|
|
6
|
+
files['.env.example'] = generateEnvExample(config);
|
|
7
|
+
if (isFastAPI) {
|
|
8
|
+
if (config.packageManager === 'poetry') {
|
|
9
|
+
files['pyproject.toml'] = generatePyProjectToml(config);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
files['requirements.txt'] = generateRequirementsTxt(config);
|
|
13
|
+
files['setup.py'] = generateSetupPy(config);
|
|
14
|
+
}
|
|
15
|
+
files['src/__init__.py'] = '';
|
|
16
|
+
files['src/main.py'] = generateMainPy(config);
|
|
17
|
+
files['src/config.py'] = generateConfigPy(config);
|
|
18
|
+
files['src/core/__init__.py'] = '';
|
|
19
|
+
files['src/core/database.py'] = generateDatabasePy(config);
|
|
20
|
+
files['src/core/dependencies.py'] = generateDependenciesPy(config);
|
|
21
|
+
files['src/api/__init__.py'] = '';
|
|
22
|
+
files['src/api/routes.py'] = generateRoutesPy(config);
|
|
23
|
+
config.selectedModules.forEach((moduleSlug) => {
|
|
24
|
+
const moduleFiles = generateModuleFiles(moduleSlug, config);
|
|
25
|
+
Object.entries(moduleFiles).forEach(([path, content]) => {
|
|
26
|
+
files[path] = content;
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
files['package.json'] = generatePackageJson(config);
|
|
32
|
+
files['tsconfig.json'] = generateTsConfig();
|
|
33
|
+
files['nest-cli.json'] = generateNestCliJson();
|
|
34
|
+
files['src/main.ts'] = generateMainTs(config);
|
|
35
|
+
files['src/app.module.ts'] = generateAppModule(config);
|
|
36
|
+
files['src/app.controller.ts'] = generateAppController();
|
|
37
|
+
files['src/app.service.ts'] = generateAppService();
|
|
38
|
+
}
|
|
39
|
+
if (config.includeDocker) {
|
|
40
|
+
files['Dockerfile'] = generateDockerfile(config);
|
|
41
|
+
files['docker-compose.yml'] = generateDockerCompose(config);
|
|
42
|
+
files['.dockerignore'] = generateDockerignore();
|
|
43
|
+
}
|
|
44
|
+
if (config.includeTesting) {
|
|
45
|
+
if (isFastAPI) {
|
|
46
|
+
files['tests/__init__.py'] = '';
|
|
47
|
+
files['tests/conftest.py'] = generateConftestPy(config);
|
|
48
|
+
files['tests/test_main.py'] = generateTestMainPy(config);
|
|
49
|
+
files['pytest.ini'] = generatePytestIni();
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
files['test/app.e2e-spec.ts'] = generateE2ETest();
|
|
53
|
+
files['test/jest-e2e.json'] = generateJestE2EConfig();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (config.includeCI) {
|
|
57
|
+
files['.github/workflows/ci.yml'] = generateGitHubActions(config);
|
|
58
|
+
}
|
|
59
|
+
return files;
|
|
60
|
+
}
|
|
61
|
+
function generateReadme(config) {
|
|
62
|
+
return `# ${config.projectName}
|
|
63
|
+
|
|
64
|
+
Generated by [RapidKit](https://rapidkit.dev)
|
|
65
|
+
|
|
66
|
+
## Description
|
|
67
|
+
|
|
68
|
+
A production-ready ${config.framework} project with Clean Architecture patterns.
|
|
69
|
+
|
|
70
|
+
## Features
|
|
71
|
+
|
|
72
|
+
${config.selectedModules.map((m) => `- ${m}`).join('\n')}
|
|
73
|
+
|
|
74
|
+
## Prerequisites
|
|
75
|
+
|
|
76
|
+
${config.framework.startsWith('fastapi')
|
|
77
|
+
? `- Python ${config.pythonVersion}+
|
|
78
|
+
- ${config.packageManager === 'poetry' ? 'Poetry' : 'pip'}`
|
|
79
|
+
: '- Node.js 18+\n- npm or yarn'}
|
|
80
|
+
|
|
81
|
+
## Installation
|
|
82
|
+
|
|
83
|
+
\`\`\`bash
|
|
84
|
+
${config.framework.startsWith('fastapi')
|
|
85
|
+
? config.packageManager === 'poetry'
|
|
86
|
+
? 'poetry install'
|
|
87
|
+
: 'pip install -r requirements.txt'
|
|
88
|
+
: 'npm install'}
|
|
89
|
+
\`\`\`
|
|
90
|
+
|
|
91
|
+
## Configuration
|
|
92
|
+
|
|
93
|
+
Copy \`.env.example\` to \`.env\` and update the values:
|
|
94
|
+
|
|
95
|
+
\`\`\`bash
|
|
96
|
+
cp .env.example .env
|
|
97
|
+
\`\`\`
|
|
98
|
+
|
|
99
|
+
## Running the Application
|
|
100
|
+
|
|
101
|
+
### Development Mode
|
|
102
|
+
|
|
103
|
+
\`\`\`bash
|
|
104
|
+
${config.framework.startsWith('fastapi')
|
|
105
|
+
? config.packageManager === 'poetry'
|
|
106
|
+
? 'poetry run uvicorn src.main:app --reload'
|
|
107
|
+
: 'uvicorn src.main:app --reload'
|
|
108
|
+
: 'npm run start:dev'}
|
|
109
|
+
\`\`\`
|
|
110
|
+
|
|
111
|
+
${config.includeDocker
|
|
112
|
+
? `### Using Docker
|
|
113
|
+
|
|
114
|
+
\`\`\`bash
|
|
115
|
+
docker-compose up
|
|
116
|
+
\`\`\`
|
|
117
|
+
`
|
|
118
|
+
: ''}
|
|
119
|
+
|
|
120
|
+
## API Documentation
|
|
121
|
+
|
|
122
|
+
Once running, visit:
|
|
123
|
+
- Swagger UI: http://localhost:8000/docs
|
|
124
|
+
- ReDoc: http://localhost:8000/redoc
|
|
125
|
+
|
|
126
|
+
## Testing
|
|
127
|
+
|
|
128
|
+
\`\`\`bash
|
|
129
|
+
${config.framework.startsWith('fastapi')
|
|
130
|
+
? config.packageManager === 'poetry'
|
|
131
|
+
? 'poetry run pytest'
|
|
132
|
+
: 'pytest'
|
|
133
|
+
: 'npm run test'}
|
|
134
|
+
\`\`\`
|
|
135
|
+
|
|
136
|
+
## Project Structure
|
|
137
|
+
|
|
138
|
+
\`\`\`
|
|
139
|
+
${config.projectName}/
|
|
140
|
+
├── src/
|
|
141
|
+
│ ├── main.${config.framework.startsWith('fastapi') ? 'py' : 'ts'}
|
|
142
|
+
│ ├── api/
|
|
143
|
+
│ ├── core/
|
|
144
|
+
${config.selectedModules.map((m) => `│ ├── ${m}/`).join('\n')}
|
|
145
|
+
│ └── ...
|
|
146
|
+
${config.includeTesting ? '├── tests/\n' : ''}${config.includeDocker ? '├── Dockerfile\n├── docker-compose.yml\n' : ''}└── README.md
|
|
147
|
+
\`\`\`
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
MIT
|
|
152
|
+
|
|
153
|
+
## Support
|
|
154
|
+
|
|
155
|
+
For issues and questions, visit [RapidKit GitHub](https://github.com/getrapidkit/community)
|
|
156
|
+
`;
|
|
157
|
+
}
|
|
158
|
+
function generateGitignore() {
|
|
159
|
+
return `# Python
|
|
160
|
+
__pycache__/
|
|
161
|
+
*.py[cod]
|
|
162
|
+
*$py.class
|
|
163
|
+
*.so
|
|
164
|
+
.Python
|
|
165
|
+
build/
|
|
166
|
+
develop-eggs/
|
|
167
|
+
dist/
|
|
168
|
+
downloads/
|
|
169
|
+
eggs/
|
|
170
|
+
.eggs/
|
|
171
|
+
lib/
|
|
172
|
+
lib64/
|
|
173
|
+
parts/
|
|
174
|
+
sdist/
|
|
175
|
+
var/
|
|
176
|
+
wheels/
|
|
177
|
+
*.egg-info/
|
|
178
|
+
.installed.cfg
|
|
179
|
+
*.egg
|
|
180
|
+
|
|
181
|
+
# Virtual environments
|
|
182
|
+
venv/
|
|
183
|
+
ENV/
|
|
184
|
+
env/
|
|
185
|
+
.venv
|
|
186
|
+
|
|
187
|
+
# IDEs
|
|
188
|
+
.vscode/
|
|
189
|
+
.idea/
|
|
190
|
+
*.swp
|
|
191
|
+
*.swo
|
|
192
|
+
*~
|
|
193
|
+
|
|
194
|
+
# Environment variables
|
|
195
|
+
.env
|
|
196
|
+
.env.local
|
|
197
|
+
.env.*.local
|
|
198
|
+
|
|
199
|
+
# Testing
|
|
200
|
+
.coverage
|
|
201
|
+
.pytest_cache/
|
|
202
|
+
htmlcov/
|
|
203
|
+
.tox/
|
|
204
|
+
|
|
205
|
+
# Node
|
|
206
|
+
node_modules/
|
|
207
|
+
npm-debug.log*
|
|
208
|
+
yarn-debug.log*
|
|
209
|
+
yarn-error.log*
|
|
210
|
+
|
|
211
|
+
# OS
|
|
212
|
+
.DS_Store
|
|
213
|
+
Thumbs.db
|
|
214
|
+
|
|
215
|
+
# Logs
|
|
216
|
+
*.log
|
|
217
|
+
logs/
|
|
218
|
+
`;
|
|
219
|
+
}
|
|
220
|
+
function generateEnvExample(config) {
|
|
221
|
+
return `# Application
|
|
222
|
+
APP_NAME="${config.projectName}"
|
|
223
|
+
APP_ENV=development
|
|
224
|
+
DEBUG=True
|
|
225
|
+
${config.framework.startsWith('fastapi') ? 'HOST=0.0.0.0\nPORT=8000' : 'PORT=3000'}
|
|
226
|
+
|
|
227
|
+
# Database${config.selectedModules.includes('database') ||
|
|
228
|
+
config.selectedModules.includes('database-orm-pro')
|
|
229
|
+
? `
|
|
230
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/${config.projectName}
|
|
231
|
+
# or for SQLite:
|
|
232
|
+
# DATABASE_URL=sqlite:///./database.db`
|
|
233
|
+
: `
|
|
234
|
+
# DATABASE_URL=postgresql://user:password@localhost:5432/${config.projectName}`}
|
|
235
|
+
|
|
236
|
+
# Authentication${config.selectedModules.includes('auth')
|
|
237
|
+
? `
|
|
238
|
+
JWT_SECRET=your-secret-key-here-change-in-production
|
|
239
|
+
JWT_ALGORITHM=HS256
|
|
240
|
+
JWT_EXPIRATION=3600`
|
|
241
|
+
: `
|
|
242
|
+
# JWT_SECRET=your-secret-key-here`}
|
|
243
|
+
|
|
244
|
+
# Redis${config.selectedModules.includes('cache')
|
|
245
|
+
? `
|
|
246
|
+
REDIS_URL=redis://localhost:6379/0`
|
|
247
|
+
: `
|
|
248
|
+
# REDIS_URL=redis://localhost:6379/0`}
|
|
249
|
+
|
|
250
|
+
# Email${config.selectedModules.includes('email')
|
|
251
|
+
? `
|
|
252
|
+
SMTP_HOST=smtp.gmail.com
|
|
253
|
+
SMTP_PORT=587
|
|
254
|
+
SMTP_USER=your-email@gmail.com
|
|
255
|
+
SMTP_PASSWORD=your-app-password
|
|
256
|
+
EMAIL_FROM=noreply@${config.projectName}.com`
|
|
257
|
+
: `
|
|
258
|
+
# SMTP_HOST=smtp.gmail.com
|
|
259
|
+
# SMTP_PORT=587`}
|
|
260
|
+
|
|
261
|
+
# AWS S3${config.selectedModules.includes('storage')
|
|
262
|
+
? `
|
|
263
|
+
AWS_ACCESS_KEY_ID=your-access-key
|
|
264
|
+
AWS_SECRET_ACCESS_KEY=your-secret-key
|
|
265
|
+
AWS_REGION=us-east-1
|
|
266
|
+
S3_BUCKET_NAME=your-bucket-name`
|
|
267
|
+
: `
|
|
268
|
+
# AWS_ACCESS_KEY_ID=your-access-key
|
|
269
|
+
# AWS_SECRET_ACCESS_KEY=your-secret-key`}
|
|
270
|
+
`;
|
|
271
|
+
}
|
|
272
|
+
function generatePyProjectToml(config) {
|
|
273
|
+
const dependencies = [
|
|
274
|
+
'fastapi = "^0.115.0"',
|
|
275
|
+
'uvicorn = { extras = ["standard"], version = "^0.32.0" }',
|
|
276
|
+
'pydantic = "^2.9.0"',
|
|
277
|
+
'pydantic-settings = "^2.5.0"',
|
|
278
|
+
];
|
|
279
|
+
if (config.selectedModules.includes('database') ||
|
|
280
|
+
config.selectedModules.includes('database-orm-pro')) {
|
|
281
|
+
dependencies.push('sqlalchemy = "^2.0.0"', 'alembic = "^1.13.0"');
|
|
282
|
+
}
|
|
283
|
+
if (config.selectedModules.includes('auth')) {
|
|
284
|
+
dependencies.push('python-jose = { extras = ["cryptography"], version = "^3.3.0" }', 'passlib = { extras = ["bcrypt"], version = "^1.7.4" }');
|
|
285
|
+
}
|
|
286
|
+
if (config.selectedModules.includes('cache')) {
|
|
287
|
+
dependencies.push('redis = "^5.0.0"');
|
|
288
|
+
}
|
|
289
|
+
return `[tool.poetry]
|
|
290
|
+
name = "${config.projectName}"
|
|
291
|
+
version = "0.1.0"
|
|
292
|
+
description = "Generated by RapidKit"
|
|
293
|
+
authors = ["Your Name <you@example.com>"]
|
|
294
|
+
readme = "README.md"
|
|
295
|
+
|
|
296
|
+
[tool.poetry.dependencies]
|
|
297
|
+
python = "^${config.pythonVersion}"
|
|
298
|
+
${dependencies.join('\n')}
|
|
299
|
+
|
|
300
|
+
[tool.poetry.group.dev.dependencies]
|
|
301
|
+
pytest = "^8.3.0"
|
|
302
|
+
pytest-asyncio = "^0.24.0"
|
|
303
|
+
httpx = "^0.27.0"
|
|
304
|
+
black = "^24.8.0"
|
|
305
|
+
flake8 = "^7.1.0"
|
|
306
|
+
mypy = "^1.11.0"
|
|
307
|
+
|
|
308
|
+
[build-system]
|
|
309
|
+
requires = ["poetry-core"]
|
|
310
|
+
build-backend = "poetry.core.masonry.api"
|
|
311
|
+
|
|
312
|
+
[tool.black]
|
|
313
|
+
line-length = 100
|
|
314
|
+
target-version = ["py${config.pythonVersion.replace('.', '')}"]
|
|
315
|
+
|
|
316
|
+
[tool.mypy]
|
|
317
|
+
python_version = "${config.pythonVersion}"
|
|
318
|
+
warn_return_any = true
|
|
319
|
+
warn_unused_configs = true
|
|
320
|
+
disallow_untyped_defs = true
|
|
321
|
+
`;
|
|
322
|
+
}
|
|
323
|
+
function generateRequirementsTxt(config) {
|
|
324
|
+
const deps = [
|
|
325
|
+
'fastapi>=0.115.0',
|
|
326
|
+
'uvicorn[standard]>=0.32.0',
|
|
327
|
+
'pydantic>=2.9.0',
|
|
328
|
+
'pydantic-settings>=2.5.0',
|
|
329
|
+
];
|
|
330
|
+
if (config.selectedModules.includes('database') ||
|
|
331
|
+
config.selectedModules.includes('database-orm-pro')) {
|
|
332
|
+
deps.push('sqlalchemy>=2.0.0', 'alembic>=1.13.0');
|
|
333
|
+
}
|
|
334
|
+
if (config.selectedModules.includes('auth')) {
|
|
335
|
+
deps.push('python-jose[cryptography]>=3.3.0', 'passlib[bcrypt]>=1.7.4');
|
|
336
|
+
}
|
|
337
|
+
if (config.selectedModules.includes('cache')) {
|
|
338
|
+
deps.push('redis>=5.0.0');
|
|
339
|
+
}
|
|
340
|
+
return deps.join('\n') + '\n';
|
|
341
|
+
}
|
|
342
|
+
function generateSetupPy(config) {
|
|
343
|
+
return `from setuptools import setup, find_packages
|
|
344
|
+
|
|
345
|
+
setup(
|
|
346
|
+
name="${config.projectName}",
|
|
347
|
+
version="0.1.0",
|
|
348
|
+
description="Generated by RapidKit",
|
|
349
|
+
packages=find_packages(),
|
|
350
|
+
python_requires=">=${config.pythonVersion}",
|
|
351
|
+
)
|
|
352
|
+
`;
|
|
353
|
+
}
|
|
354
|
+
function generateMainPy(config) {
|
|
355
|
+
return `from fastapi import FastAPI
|
|
356
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
357
|
+
from src.config import settings
|
|
358
|
+
from src.api.routes import api_router
|
|
359
|
+
|
|
360
|
+
app = FastAPI(
|
|
361
|
+
title=settings.APP_NAME,
|
|
362
|
+
description="Generated by RapidKit",
|
|
363
|
+
version="0.1.0",
|
|
364
|
+
docs_url="/docs",
|
|
365
|
+
redoc_url="/redoc",
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
# CORS middleware
|
|
369
|
+
app.add_middleware(
|
|
370
|
+
CORSMiddleware,
|
|
371
|
+
allow_origins=["*"], # Update in production
|
|
372
|
+
allow_credentials=True,
|
|
373
|
+
allow_methods=["*"],
|
|
374
|
+
allow_headers=["*"],
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
# Include routers
|
|
378
|
+
app.include_router(api_router, prefix="/api")
|
|
379
|
+
|
|
380
|
+
@app.get("/")
|
|
381
|
+
async def root():
|
|
382
|
+
return {
|
|
383
|
+
"message": "Welcome to ${config.projectName}",
|
|
384
|
+
"status": "running",
|
|
385
|
+
"docs": "/docs",
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
@app.get("/health")
|
|
389
|
+
async def health_check():
|
|
390
|
+
return {"status": "healthy"}
|
|
391
|
+
|
|
392
|
+
if __name__ == "__main__":
|
|
393
|
+
import uvicorn
|
|
394
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
395
|
+
`;
|
|
396
|
+
}
|
|
397
|
+
function generateConfigPy(config) {
|
|
398
|
+
return `from pydantic_settings import BaseSettings
|
|
399
|
+
|
|
400
|
+
class Settings(BaseSettings):
|
|
401
|
+
APP_NAME: str = "${config.projectName}"
|
|
402
|
+
APP_ENV: str = "development"
|
|
403
|
+
DEBUG: bool = True
|
|
404
|
+
HOST: str = "0.0.0.0"
|
|
405
|
+
PORT: int = 8000
|
|
406
|
+
|
|
407
|
+
${config.selectedModules.includes('database') ||
|
|
408
|
+
config.selectedModules.includes('database-orm-pro')
|
|
409
|
+
? 'DATABASE_URL: str = "sqlite:///./database.db"'
|
|
410
|
+
: '# DATABASE_URL: str = ""'}
|
|
411
|
+
|
|
412
|
+
${config.selectedModules.includes('auth')
|
|
413
|
+
? `JWT_SECRET: str = "your-secret-key"
|
|
414
|
+
JWT_ALGORITHM: str = "HS256"
|
|
415
|
+
JWT_EXPIRATION: int = 3600`
|
|
416
|
+
: '# JWT_SECRET: str = ""'}
|
|
417
|
+
|
|
418
|
+
class Config:
|
|
419
|
+
env_file = ".env"
|
|
420
|
+
case_sensitive = True
|
|
421
|
+
|
|
422
|
+
settings = Settings()
|
|
423
|
+
`;
|
|
424
|
+
}
|
|
425
|
+
function generateDatabasePy(config) {
|
|
426
|
+
if (!config.selectedModules.includes('database') &&
|
|
427
|
+
!config.selectedModules.includes('database-orm-pro')) {
|
|
428
|
+
return '# Database configuration will be added when database module is included\n';
|
|
429
|
+
}
|
|
430
|
+
return `from sqlalchemy import create_engine
|
|
431
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
432
|
+
from sqlalchemy.orm import sessionmaker
|
|
433
|
+
from src.config import settings
|
|
434
|
+
|
|
435
|
+
engine = create_engine(
|
|
436
|
+
settings.DATABASE_URL,
|
|
437
|
+
connect_args={"check_same_thread": False} if "sqlite" in settings.DATABASE_URL else {},
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
441
|
+
|
|
442
|
+
Base = declarative_base()
|
|
443
|
+
|
|
444
|
+
def get_db():
|
|
445
|
+
db = SessionLocal()
|
|
446
|
+
try:
|
|
447
|
+
yield db
|
|
448
|
+
finally:
|
|
449
|
+
db.close()
|
|
450
|
+
`;
|
|
451
|
+
}
|
|
452
|
+
function generateDependenciesPy(config) {
|
|
453
|
+
return `from typing import Generator
|
|
454
|
+
from fastapi import Depends, HTTPException, status
|
|
455
|
+
${config.selectedModules.includes('database') || config.selectedModules.includes('database-orm-pro')
|
|
456
|
+
? 'from sqlalchemy.orm import Session\nfrom src.core.database import get_db'
|
|
457
|
+
: ''}
|
|
458
|
+
|
|
459
|
+
# Add your dependencies here
|
|
460
|
+
`;
|
|
461
|
+
}
|
|
462
|
+
function generateRoutesPy(config) {
|
|
463
|
+
return `from fastapi import APIRouter
|
|
464
|
+
|
|
465
|
+
api_router = APIRouter()
|
|
466
|
+
|
|
467
|
+
@api_router.get("/status")
|
|
468
|
+
async def status():
|
|
469
|
+
return {"status": "ok", "message": "API is running"}
|
|
470
|
+
|
|
471
|
+
# Import and include module routers here
|
|
472
|
+
${config.selectedModules.map((m) => `# from src.${m}.routes import router as ${m}_router\n# api_router.include_router(${m}_router, prefix="/${m}", tags=["${m}"])`).join('\n')}
|
|
473
|
+
`;
|
|
474
|
+
}
|
|
475
|
+
function generateModuleFiles(moduleSlug, _config) {
|
|
476
|
+
const files = {};
|
|
477
|
+
const moduleName = moduleSlug.replace(/-/g, '_');
|
|
478
|
+
files[`src/${moduleName}/__init__.py`] = '';
|
|
479
|
+
files[`src/${moduleName}/models.py`] = `# ${moduleSlug} models\n`;
|
|
480
|
+
files[`src/${moduleName}/schemas.py`] =
|
|
481
|
+
`# ${moduleSlug} schemas\nfrom pydantic import BaseModel\n`;
|
|
482
|
+
files[`src/${moduleName}/routes.py`] =
|
|
483
|
+
`# ${moduleSlug} routes\nfrom fastapi import APIRouter\n\nrouter = APIRouter()\n`;
|
|
484
|
+
files[`src/${moduleName}/services.py`] = `# ${moduleSlug} services\n`;
|
|
485
|
+
return files;
|
|
486
|
+
}
|
|
487
|
+
function generatePackageJson(config) {
|
|
488
|
+
return `{
|
|
489
|
+
"name": "${config.projectName}",
|
|
490
|
+
"version": "0.1.0",
|
|
491
|
+
"description": "Generated by RapidKit",
|
|
492
|
+
"author": "",
|
|
493
|
+
"private": true,
|
|
494
|
+
"license": "MIT",
|
|
495
|
+
"scripts": {
|
|
496
|
+
"build": "nest build",
|
|
497
|
+
"format": "prettier --write \\"src/**/*.ts\\"",
|
|
498
|
+
"start": "nest start",
|
|
499
|
+
"start:dev": "nest start --watch",
|
|
500
|
+
"start:debug": "nest start --debug --watch",
|
|
501
|
+
"start:prod": "node dist/main",
|
|
502
|
+
"lint": "eslint \\"{src,apps,libs,test}/**/*.ts\\" --fix",
|
|
503
|
+
"test": "jest",
|
|
504
|
+
"test:watch": "jest --watch",
|
|
505
|
+
"test:cov": "jest --coverage",
|
|
506
|
+
"test:e2e": "jest --config ./test/jest-e2e.json"
|
|
507
|
+
},
|
|
508
|
+
"dependencies": {
|
|
509
|
+
"@nestjs/common": "^10.0.0",
|
|
510
|
+
"@nestjs/core": "^10.0.0",
|
|
511
|
+
"@nestjs/platform-express": "^10.0.0",
|
|
512
|
+
"reflect-metadata": "^0.2.0",
|
|
513
|
+
"rxjs": "^7.8.1"
|
|
514
|
+
},
|
|
515
|
+
"devDependencies": {
|
|
516
|
+
"@nestjs/cli": "^10.0.0",
|
|
517
|
+
"@nestjs/schematics": "^10.0.0",
|
|
518
|
+
"@nestjs/testing": "^10.0.0",
|
|
519
|
+
"@types/express": "^4.17.17",
|
|
520
|
+
"@types/jest": "^29.5.2",
|
|
521
|
+
"@types/node": "^20.3.1",
|
|
522
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
523
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
524
|
+
"eslint": "^8.42.0",
|
|
525
|
+
"jest": "^29.5.0",
|
|
526
|
+
"prettier": "^3.0.0",
|
|
527
|
+
"ts-jest": "^29.1.0",
|
|
528
|
+
"ts-loader": "^9.4.3",
|
|
529
|
+
"ts-node": "^10.9.1",
|
|
530
|
+
"tsconfig-paths": "^4.2.0",
|
|
531
|
+
"typescript": "^5.1.3"
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
`;
|
|
535
|
+
}
|
|
536
|
+
function generateTsConfig() {
|
|
537
|
+
return `{
|
|
538
|
+
"compilerOptions": {
|
|
539
|
+
"module": "commonjs",
|
|
540
|
+
"declaration": true,
|
|
541
|
+
"removeComments": true,
|
|
542
|
+
"emitDecoratorMetadata": true,
|
|
543
|
+
"experimentalDecorators": true,
|
|
544
|
+
"allowSyntheticDefaultImports": true,
|
|
545
|
+
"target": "ES2021",
|
|
546
|
+
"sourceMap": true,
|
|
547
|
+
"outDir": "./dist",
|
|
548
|
+
"baseUrl": "./",
|
|
549
|
+
"incremental": true,
|
|
550
|
+
"skipLibCheck": true,
|
|
551
|
+
"strictNullChecks": false,
|
|
552
|
+
"noImplicitAny": false,
|
|
553
|
+
"strictBindCallApply": false,
|
|
554
|
+
"forceConsistentCasingInFileNames": false,
|
|
555
|
+
"noFallthroughCasesInSwitch": false
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
`;
|
|
559
|
+
}
|
|
560
|
+
function generateNestCliJson() {
|
|
561
|
+
return `{
|
|
562
|
+
"$schema": "https://json.schemastore.org/nest-cli",
|
|
563
|
+
"collection": "@nestjs/schematics",
|
|
564
|
+
"sourceRoot": "src",
|
|
565
|
+
"compilerOptions": {
|
|
566
|
+
"deleteOutDir": true
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
`;
|
|
570
|
+
}
|
|
571
|
+
function generateMainTs(_config) {
|
|
572
|
+
return `import { NestFactory } from '@nestjs/core';
|
|
573
|
+
import { AppModule } from './app.module';
|
|
574
|
+
|
|
575
|
+
async function bootstrap() {
|
|
576
|
+
const app = await NestFactory.create(AppModule);
|
|
577
|
+
app.enableCors();
|
|
578
|
+
await app.listen(3000);
|
|
579
|
+
console.log(\`Application is running on: \${await app.getUrl()}\`);
|
|
580
|
+
}
|
|
581
|
+
bootstrap();
|
|
582
|
+
`;
|
|
583
|
+
}
|
|
584
|
+
function generateAppModule(_config) {
|
|
585
|
+
return `import { Module } from '@nestjs/common';
|
|
586
|
+
import { AppController } from './app.controller';
|
|
587
|
+
import { AppService } from './app.service';
|
|
588
|
+
|
|
589
|
+
@Module({
|
|
590
|
+
imports: [],
|
|
591
|
+
controllers: [AppController],
|
|
592
|
+
providers: [AppService],
|
|
593
|
+
})
|
|
594
|
+
export class AppModule {}
|
|
595
|
+
`;
|
|
596
|
+
}
|
|
597
|
+
function generateAppController() {
|
|
598
|
+
return `import { Controller, Get } from '@nestjs/common';
|
|
599
|
+
import { AppService } from './app.service';
|
|
600
|
+
|
|
601
|
+
@Controller()
|
|
602
|
+
export class AppController {
|
|
603
|
+
constructor(private readonly appService: AppService) {}
|
|
604
|
+
|
|
605
|
+
@Get()
|
|
606
|
+
getHello(): string {
|
|
607
|
+
return this.appService.getHello();
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
@Get('health')
|
|
611
|
+
healthCheck() {
|
|
612
|
+
return { status: 'healthy' };
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
`;
|
|
616
|
+
}
|
|
617
|
+
function generateAppService() {
|
|
618
|
+
return `import { Injectable } from '@nestjs/common';
|
|
619
|
+
|
|
620
|
+
@Injectable()
|
|
621
|
+
export class AppService {
|
|
622
|
+
getHello(): string {
|
|
623
|
+
return 'Welcome to your NestJS application!';
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
`;
|
|
627
|
+
}
|
|
628
|
+
function generateDockerfile(config) {
|
|
629
|
+
if (config.framework.startsWith('fastapi')) {
|
|
630
|
+
return `FROM python:${config.pythonVersion}-slim
|
|
631
|
+
|
|
632
|
+
WORKDIR /app
|
|
633
|
+
|
|
634
|
+
# Install dependencies
|
|
635
|
+
${config.packageManager === 'poetry'
|
|
636
|
+
? `RUN pip install poetry
|
|
637
|
+
COPY pyproject.toml poetry.lock* ./
|
|
638
|
+
RUN poetry config virtualenvs.create false && poetry install --no-dev --no-interaction --no-ansi`
|
|
639
|
+
: `COPY requirements.txt .
|
|
640
|
+
RUN pip install --no-cache-dir -r requirements.txt`}
|
|
641
|
+
|
|
642
|
+
# Copy application
|
|
643
|
+
COPY . .
|
|
644
|
+
|
|
645
|
+
EXPOSE 8000
|
|
646
|
+
|
|
647
|
+
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
|
648
|
+
`;
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
return `FROM node:18-alpine
|
|
652
|
+
|
|
653
|
+
WORKDIR /app
|
|
654
|
+
|
|
655
|
+
COPY package*.json ./
|
|
656
|
+
RUN npm ci --only=production
|
|
657
|
+
|
|
658
|
+
COPY . .
|
|
659
|
+
RUN npm run build
|
|
660
|
+
|
|
661
|
+
EXPOSE 3000
|
|
662
|
+
|
|
663
|
+
CMD ["node", "dist/main"]
|
|
664
|
+
`;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
function generateDockerCompose(config) {
|
|
668
|
+
const hasDatabase = config.selectedModules.includes('database') ||
|
|
669
|
+
config.selectedModules.includes('database-orm-pro');
|
|
670
|
+
const hasCache = config.selectedModules.includes('cache');
|
|
671
|
+
return `version: '3.8'
|
|
672
|
+
|
|
673
|
+
services:
|
|
674
|
+
app:
|
|
675
|
+
build: .
|
|
676
|
+
ports:
|
|
677
|
+
- "${config.framework.startsWith('fastapi') ? '8000:8000' : '3000:3000'}"
|
|
678
|
+
environment:
|
|
679
|
+
- APP_ENV=production
|
|
680
|
+
${hasDatabase ? ` - DATABASE_URL=postgresql://postgres:postgres@db:5432/${config.projectName}` : ''}
|
|
681
|
+
${hasCache ? ' - REDIS_URL=redis://redis:6379/0' : ''}
|
|
682
|
+
depends_on:
|
|
683
|
+
${hasDatabase ? ' - db' : ''}
|
|
684
|
+
${hasCache ? ' - redis' : ''}
|
|
685
|
+
volumes:
|
|
686
|
+
- .:/app
|
|
687
|
+
${hasDatabase
|
|
688
|
+
? `
|
|
689
|
+
db:
|
|
690
|
+
image: postgres:15-alpine
|
|
691
|
+
environment:
|
|
692
|
+
- POSTGRES_USER=postgres
|
|
693
|
+
- POSTGRES_PASSWORD=postgres
|
|
694
|
+
- POSTGRES_DB=${config.projectName}
|
|
695
|
+
ports:
|
|
696
|
+
- "5432:5432"
|
|
697
|
+
volumes:
|
|
698
|
+
- postgres_data:/var/lib/postgresql/data`
|
|
699
|
+
: ''}
|
|
700
|
+
${hasCache
|
|
701
|
+
? `
|
|
702
|
+
redis:
|
|
703
|
+
image: redis:7-alpine
|
|
704
|
+
ports:
|
|
705
|
+
- "6379:6379"`
|
|
706
|
+
: ''}
|
|
707
|
+
|
|
708
|
+
${hasDatabase || hasCache
|
|
709
|
+
? `volumes:${hasDatabase ? '\n postgres_data:' : ''}${hasCache ? '\n redis_data:' : ''}`
|
|
710
|
+
: ''}
|
|
711
|
+
`;
|
|
712
|
+
}
|
|
713
|
+
function generateDockerignore() {
|
|
714
|
+
return `__pycache__
|
|
715
|
+
*.pyc
|
|
716
|
+
*.pyo
|
|
717
|
+
*.pyd
|
|
718
|
+
.Python
|
|
719
|
+
env
|
|
720
|
+
venv
|
|
721
|
+
.venv
|
|
722
|
+
node_modules
|
|
723
|
+
.git
|
|
724
|
+
.gitignore
|
|
725
|
+
.dockerignore
|
|
726
|
+
.env
|
|
727
|
+
.env.local
|
|
728
|
+
*.log
|
|
729
|
+
.pytest_cache
|
|
730
|
+
.coverage
|
|
731
|
+
htmlcov
|
|
732
|
+
dist
|
|
733
|
+
build
|
|
734
|
+
*.egg-info
|
|
735
|
+
`;
|
|
736
|
+
}
|
|
737
|
+
function generateConftestPy(_config) {
|
|
738
|
+
return `import pytest
|
|
739
|
+
from fastapi.testclient import TestClient
|
|
740
|
+
from src.main import app
|
|
741
|
+
|
|
742
|
+
@pytest.fixture
|
|
743
|
+
def client():
|
|
744
|
+
with TestClient(app) as c:
|
|
745
|
+
yield c
|
|
746
|
+
`;
|
|
747
|
+
}
|
|
748
|
+
function generateTestMainPy(_config) {
|
|
749
|
+
return `def test_root(client):
|
|
750
|
+
response = client.get("/")
|
|
751
|
+
assert response.status_code == 200
|
|
752
|
+
assert "message" in response.json()
|
|
753
|
+
|
|
754
|
+
def test_health_check(client):
|
|
755
|
+
response = client.get("/health")
|
|
756
|
+
assert response.status_code == 200
|
|
757
|
+
assert response.json() == {"status": "healthy"}
|
|
758
|
+
`;
|
|
759
|
+
}
|
|
760
|
+
function generatePytestIni() {
|
|
761
|
+
return `[pytest]
|
|
762
|
+
testpaths = tests
|
|
763
|
+
python_files = test_*.py
|
|
764
|
+
python_classes = Test*
|
|
765
|
+
python_functions = test_*
|
|
766
|
+
addopts = -v --tb=short
|
|
767
|
+
`;
|
|
768
|
+
}
|
|
769
|
+
function generateE2ETest() {
|
|
770
|
+
return `import { Test, TestingModule } from '@nestjs/testing';
|
|
771
|
+
import { INestApplication } from '@nestjs/common';
|
|
772
|
+
import * as request from 'supertest';
|
|
773
|
+
import { AppModule } from './../src/app.module';
|
|
774
|
+
|
|
775
|
+
describe('AppController (e2e)', () => {
|
|
776
|
+
let app: INestApplication;
|
|
777
|
+
|
|
778
|
+
beforeEach(async () => {
|
|
779
|
+
const moduleFixture: TestingModule = await Test.createTestingModule({
|
|
780
|
+
imports: [AppModule],
|
|
781
|
+
}).compile();
|
|
782
|
+
|
|
783
|
+
app = moduleFixture.createNestApplication();
|
|
784
|
+
await app.init();
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
it('/ (GET)', () => {
|
|
788
|
+
return request(app.getHttpServer())
|
|
789
|
+
.get('/')
|
|
790
|
+
.expect(200)
|
|
791
|
+
.expect('Welcome to your NestJS application!');
|
|
792
|
+
});
|
|
793
|
+
});
|
|
794
|
+
`;
|
|
795
|
+
}
|
|
796
|
+
function generateJestE2EConfig() {
|
|
797
|
+
return `{
|
|
798
|
+
"moduleFileExtensions": ["js", "json", "ts"],
|
|
799
|
+
"rootDir": ".",
|
|
800
|
+
"testEnvironment": "node",
|
|
801
|
+
"testRegex": ".e2e-spec.ts$",
|
|
802
|
+
"transform": {
|
|
803
|
+
"^.+\\\\.(t|j)s$": "ts-jest"
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
`;
|
|
807
|
+
}
|
|
808
|
+
function generateGitHubActions(config) {
|
|
809
|
+
if (config.framework.startsWith('fastapi')) {
|
|
810
|
+
return `name: CI
|
|
811
|
+
|
|
812
|
+
on:
|
|
813
|
+
push:
|
|
814
|
+
branches: [ main, develop ]
|
|
815
|
+
pull_request:
|
|
816
|
+
branches: [ main, develop ]
|
|
817
|
+
|
|
818
|
+
jobs:
|
|
819
|
+
test:
|
|
820
|
+
runs-on: ubuntu-latest
|
|
821
|
+
|
|
822
|
+
steps:
|
|
823
|
+
- uses: actions/checkout@v3
|
|
824
|
+
|
|
825
|
+
- name: Set up Python ${config.pythonVersion}
|
|
826
|
+
uses: actions/setup-python@v4
|
|
827
|
+
with:
|
|
828
|
+
python-version: ${config.pythonVersion}
|
|
829
|
+
|
|
830
|
+
- name: Install dependencies
|
|
831
|
+
run: |
|
|
832
|
+
${config.packageManager === 'poetry'
|
|
833
|
+
? 'pip install poetry\npoetry install'
|
|
834
|
+
: 'pip install -r requirements.txt'}
|
|
835
|
+
|
|
836
|
+
- name: Run tests
|
|
837
|
+
run: |
|
|
838
|
+
${config.packageManager === 'poetry' ? 'poetry run pytest' : 'pytest'}
|
|
839
|
+
|
|
840
|
+
- name: Lint with flake8
|
|
841
|
+
run: |
|
|
842
|
+
${config.packageManager === 'poetry' ? 'poetry run flake8 src' : 'flake8 src'}
|
|
843
|
+
`;
|
|
844
|
+
}
|
|
845
|
+
else {
|
|
846
|
+
return `name: CI
|
|
847
|
+
|
|
848
|
+
on:
|
|
849
|
+
push:
|
|
850
|
+
branches: [ main, develop ]
|
|
851
|
+
pull_request:
|
|
852
|
+
branches: [ main, develop ]
|
|
853
|
+
|
|
854
|
+
jobs:
|
|
855
|
+
test:
|
|
856
|
+
runs-on: ubuntu-latest
|
|
857
|
+
|
|
858
|
+
steps:
|
|
859
|
+
- uses: actions/checkout@v3
|
|
860
|
+
|
|
861
|
+
- name: Set up Node.js
|
|
862
|
+
uses: actions/setup-node@v3
|
|
863
|
+
with:
|
|
864
|
+
node-version: '18'
|
|
865
|
+
|
|
866
|
+
- name: Install dependencies
|
|
867
|
+
run: npm ci
|
|
868
|
+
|
|
869
|
+
- name: Run tests
|
|
870
|
+
run: npm test
|
|
871
|
+
|
|
872
|
+
- name: Build
|
|
873
|
+
run: npm run build
|
|
874
|
+
`;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
//# sourceMappingURL=generator.js.map
|