@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
1,051 lines (902 loc) • 25.5 kB
JavaScript
"use strict";
/**
* Swift Backend Template Base Generator
* Shared functionality for all Swift web frameworks
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.SwiftBackendGenerator = void 0;
const backend_template_generator_1 = require("../shared/backend-template-generator");
const fs_1 = require("fs");
const path = __importStar(require("path"));
class SwiftBackendGenerator extends backend_template_generator_1.BackendTemplateGenerator {
constructor(framework) {
const config = {
language: 'Swift',
framework,
packageManager: 'swift-package-manager',
testFramework: 'XCTest',
features: [
'Async/Await support',
'Type-safe routing',
'Middleware pipeline',
'JSON encoding/decoding',
'WebSocket support',
'Database integration',
'Authentication & Authorization',
'Structured logging',
'Environment configuration',
'Docker support'
],
dependencies: {},
devDependencies: {},
scripts: {
'build': 'swift build',
'run': 'swift run',
'test': 'swift test',
'release': 'swift build -c release',
'clean': 'swift package clean',
'update': 'swift package update',
'generate-xcodeproj': 'swift package generate-xcodeproj'
},
dockerConfig: {
baseImage: 'swift:5.9-slim',
workDir: '/app',
exposedPorts: [8080],
buildSteps: [
'COPY . .',
'RUN swift build -c release'
],
runCommand: '.build/release/App',
multistage: true
},
envVars: {
'PORT': '8080',
'ENVIRONMENT': 'development',
'LOG_LEVEL': 'info',
'DATABASE_URL': 'postgresql://user:password@localhost:5432/dbname',
'JWT_SECRET': 'your-secret-key',
'REDIS_URL': 'redis://localhost:6379'
}
};
super(config);
}
async generateLanguageFiles(projectPath, options) {
// Generate Package.swift
await this.generatePackageSwift(projectPath, options);
// Generate .swiftlint.yml
await this.generateSwiftLint(projectPath);
// Generate .swift-version
await fs_1.promises.writeFile(path.join(projectPath, '.swift-version'), '5.9');
}
async generatePackageSwift(projectPath, options) {
const packageContent = `// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "${options.name}",
platforms: [
.macOS(.v13)
],
products: [
.executable(name: "App", targets: ["App"]),
],
dependencies: [
${this.getFrameworkDependencies().join(',\\n ')}
],
targets: [
.executableTarget(
name: "App",
dependencies: ${this.getTargetDependencies()},
path: "Sources/App"
),
.testTarget(
name: "AppTests",
dependencies: [
.target(name: "App"),
${this.getTestDependencies()}
],
path: "Tests/AppTests"
),
]
)
`;
await fs_1.promises.writeFile(path.join(projectPath, 'Package.swift'), packageContent);
}
async generateSwiftLint(projectPath) {
const config = `disabled_rules:
- trailing_whitespace
- line_length
opt_in_rules:
- empty_count
- closure_spacing
- collection_alignment
- contains_over_first_not_nil
- empty_string
- first_where
- force_unwrapping
- implicitly_unwrapped_optional
- last_where
- literal_expression_end_indentation
- multiline_arguments
- multiline_function_chains
- multiline_parameters
- operator_usage_whitespace
- prefer_self_type_over_type_of_self
- redundant_nil_coalescing
- sorted_first_last
- trailing_closure
- unneeded_parentheses_in_closure_argument
- vertical_parameter_alignment_on_call
- yoda_condition
excluded:
- .build
- .swiftpm
- Package.swift
line_length: 120
type_body_length:
warning: 300
error: 400
file_length:
warning: 500
error: 1200
function_body_length:
warning: 40
error: 100
cyclomatic_complexity:
warning: 10
error: 20
nesting:
type_level:
warning: 2
function_level:
warning: 3
`;
await fs_1.promises.writeFile(path.join(projectPath, '.swiftlint.yml'), config);
}
async generateTestStructure(projectPath, options) {
// Create test directories
const testDirs = [
'Tests/AppTests',
'Tests/AppTests/Controllers',
'Tests/AppTests/Services',
'Tests/AppTests/Models',
'Tests/AppTests/Utils'
];
for (const dir of testDirs) {
await fs_1.promises.mkdir(path.join(projectPath, dir), { recursive: true });
}
// Generate base test file
const baseTest = `import XCTest
@testable import App
class AppTestCase: XCTestCase {
var app: Application!
override func setUp() async throws {
try await super.setUp()
app = try await Application.testable()
}
override func tearDown() async throws {
try await app.shutdown()
try await super.tearDown()
}
}
extension Application {
static func testable() async throws -> Application {
let app = Application()
try await configure(app)
return app
}
}
`;
await fs_1.promises.writeFile(path.join(projectPath, 'Tests/AppTests/AppTestCase.swift'), baseTest);
// Generate example test
const exampleTest = `import XCTest
@testable import App
final class HealthCheckTests: AppTestCase {
func testHealthCheck() async throws {
try await app.test(.GET, "/health") { response in
XCTAssertEqual(response.status, .ok)
struct HealthResponse: Codable {
let status: String
let timestamp: Date
let version: String
}
let health = try response.content.decode(HealthResponse.self)
XCTAssertEqual(health.status, "healthy")
}
}
func testReadiness() async throws {
try await app.test(.GET, "/ready") { response in
XCTAssertEqual(response.status, .ok)
}
}
}
`;
await fs_1.promises.writeFile(path.join(projectPath, 'Tests/AppTests/Controllers/HealthCheckTests.swift'), exampleTest);
}
async generateHealthCheck(projectPath) {
const healthController = `import Foundation
struct HealthController {
struct HealthResponse: Codable {
let status: String
let timestamp: Date
let version: String
let uptime: TimeInterval
let environment: String
let checks: [String: Bool]
}
static func health() async throws -> HealthResponse {
let startTime = ProcessInfo.processInfo.systemUptime
// Perform health checks
let checks = [
"database": await checkDatabase(),
"redis": await checkRedis(),
"filesystem": checkFilesystem()
]
return HealthResponse(
status: checks.values.allSatisfy { $0 } ? "healthy" : "degraded",
timestamp: Date(),
version: getVersion(),
uptime: ProcessInfo.processInfo.systemUptime - startTime,
environment: Environment.current.rawValue,
checks: checks
)
}
static func readiness() async throws -> [String: Any] {
return [
"ready": true,
"timestamp": Date().timeIntervalSince1970
]
}
private static func checkDatabase() async -> Bool {
// Implement database connectivity check
return true
}
private static func checkRedis() async -> Bool {
// Implement Redis connectivity check
return true
}
private static func checkFilesystem() -> Bool {
// Check if we can write to temp directory
let tempFile = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
do {
try "test".write(to: tempFile, atomically: true, encoding: .utf8)
try FileManager.default.removeItem(at: tempFile)
return true
} catch {
return false
}
}
private static func getVersion() -> String {
return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0.0"
}
}
`;
await fs_1.promises.writeFile(path.join(projectPath, 'Sources/App/Controllers/HealthController.swift'), healthController);
}
async generateAPIDocs(projectPath) {
// Generate OpenAPI specification
const openAPISpec = `openapi: 3.0.0
info:
title: ${this.config.framework} API
description: API documentation for ${this.config.framework} microservice
version: 1.0.0
contact:
name: API Support
email: support@example.com
license:
name: MIT
url: https://opensource.org/licenses/MIT
servers:
- url: http://localhost:8080
description: Development server
- url: https://api.example.com
description: Production server
tags:
- name: Health
description: Health check endpoints
- name: Auth
description: Authentication endpoints
- name: Users
description: User management
paths:
/health:
get:
tags:
- Health
summary: Health check
description: Returns the health status of the service
responses:
'200':
description: Service is healthy
content:
application/json:
schema:
$ref: '#/components/schemas/HealthResponse'
/ready:
get:
tags:
- Health
summary: Readiness check
description: Returns whether the service is ready to accept requests
responses:
'200':
description: Service is ready
content:
application/json:
schema:
type: object
properties:
ready:
type: boolean
timestamp:
type: number
/auth/login:
post:
tags:
- Auth
summary: User login
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LoginRequest'
responses:
'200':
description: Login successful
content:
application/json:
schema:
$ref: '#/components/schemas/LoginResponse'
'401':
description: Invalid credentials
/auth/register:
post:
tags:
- Auth
summary: User registration
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RegisterRequest'
responses:
'201':
description: Registration successful
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
description: Invalid registration data
/users/me:
get:
tags:
- Users
summary: Get current user
security:
- bearerAuth: []
responses:
'200':
description: Current user information
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'401':
description: Unauthorized
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
HealthResponse:
type: object
properties:
status:
type: string
enum: [healthy, degraded, unhealthy]
timestamp:
type: string
format: date-time
version:
type: string
uptime:
type: number
environment:
type: string
checks:
type: object
additionalProperties:
type: boolean
LoginRequest:
type: object
required:
- email
- password
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
LoginResponse:
type: object
properties:
token:
type: string
refreshToken:
type: string
expiresIn:
type: integer
user:
$ref: '#/components/schemas/User'
RegisterRequest:
type: object
required:
- email
- password
- name
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
name:
type: string
minLength: 2
User:
type: object
properties:
id:
type: string
format: uuid
email:
type: string
format: email
name:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
`;
await fs_1.promises.writeFile(path.join(projectPath, 'docs/openapi.yaml'), openAPISpec);
}
async generateDockerFiles(projectPath, options) {
// Multi-stage Dockerfile
const dockerfile = `# ================================
# Build Stage
# ================================
FROM swift:5.9-slim as builder
# Install system dependencies
RUN apt-get update && apt-get install -y \\
libssl-dev \\
libsqlite3-dev \\
libpq-dev \\
libmysqlclient-dev \\
curl \\
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /app
# Copy package files
COPY Package.* ./
# Resolve dependencies
RUN swift package resolve
# Copy source code
COPY . .
# Build for release
RUN swift build -c release --static-swift-stdlib
# ================================
# Runtime Stage
# ================================
FROM ubuntu:22.04
# Install runtime dependencies
RUN apt-get update && apt-get install -y \\
libssl-dev \\
libsqlite3-dev \\
libpq-dev \\
libmysqlclient-dev \\
ca-certificates \\
tzdata \\
&& rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN useradd -m -u 1001 -s /bin/bash vapor
# Set working directory
WORKDIR /app
# Copy built executable
COPY --from=builder /app/.build/release/App /app/App
# Copy resources if needed
COPY --from=builder /app/Public ./Public
COPY --from=builder /app/Resources ./Resources
# Set ownership
RUN chown -R vapor:vapor /app
# Switch to non-root user
USER vapor
# Expose port
EXPOSE ${options.port || 8080}
# Set environment
ENV ENVIRONMENT=production
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
CMD curl -f http://localhost:${options.port || 8080}/health || exit 1
# Run the application
CMD ["./App"]
`;
await fs_1.promises.writeFile(path.join(projectPath, 'Dockerfile'), dockerfile);
// Docker compose for local development
const dockerCompose = `version: '3.8'
services:
app:
build: .
ports:
- "\${PORT:-8080}:8080"
environment:
- ENVIRONMENT=development
- DATABASE_URL=postgresql://postgres:postgres@db:5432/${options.name}
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
volumes:
- .:/app
- /app/.build
command: swift run
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=${options.name}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
`;
await fs_1.promises.writeFile(path.join(projectPath, 'docker-compose.yml'), dockerCompose);
// .dockerignore
const dockerignore = `.build/
.swiftpm/
*.xcodeproj
.git/
.gitignore
.dockerignore
Dockerfile
docker-compose.yml
README.md
.env
.env.*
Tests/
docs/
`;
await fs_1.promises.writeFile(path.join(projectPath, '.dockerignore'), dockerignore);
}
async generateDocumentation(projectPath, options) {
// API documentation guide
const apiGuide = `# API Documentation
## Overview
This ${this.config.framework} API provides a robust foundation for building microservices with Swift.
## Authentication
The API uses JWT (JSON Web Tokens) for authentication. Include the token in the Authorization header:
\`\`\`
Authorization: Bearer <your-jwt-token>
\`\`\`
## Rate Limiting
API endpoints are rate-limited to prevent abuse:
- Anonymous requests: 100 requests per hour
- Authenticated requests: 1000 requests per hour
## Error Handling
The API returns consistent error responses:
\`\`\`json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid input data",
"details": {
"field": "email",
"reason": "Invalid email format"
}
}
}
\`\`\`
## Common HTTP Status Codes
- \`200 OK\`: Request successful
- \`201 Created\`: Resource created successfully
- \`400 Bad Request\`: Invalid request data
- \`401 Unauthorized\`: Authentication required
- \`403 Forbidden\`: Access denied
- \`404 Not Found\`: Resource not found
- \`429 Too Many Requests\`: Rate limit exceeded
- \`500 Internal Server Error\`: Server error
## Pagination
List endpoints support pagination:
\`\`\`
GET /api/users?page=1&limit=20
\`\`\`
Response includes pagination metadata:
\`\`\`json
{
"data": [...],
"pagination": {
"page": 1,
"limit": 20,
"total": 100,
"pages": 5
}
}
\`\`\`
## Filtering and Sorting
Most list endpoints support filtering and sorting:
\`\`\`
GET /api/users?filter[name]=john&sort=-created_at
\`\`\`
## WebSocket Support
WebSocket connections are available at \`ws://localhost:8080/ws\`
### Events
- \`connection\`: Client connected
- \`message\`: New message received
- \`disconnect\`: Client disconnected
## Development
### Running Tests
\`\`\`bash
swift test
\`\`\`
### Code Style
This project uses SwiftLint for code style enforcement:
\`\`\`bash
swiftlint
\`\`\`
### Database Migrations
Run migrations before starting the application:
\`\`\`bash
swift run App migrate
\`\`\`
## Deployment
### Environment Variables
- \`PORT\`: Server port (default: 8080)
- \`ENVIRONMENT\`: Environment mode (development, staging, production)
- \`DATABASE_URL\`: PostgreSQL connection string
- \`REDIS_URL\`: Redis connection string
- \`JWT_SECRET\`: Secret key for JWT signing
- \`LOG_LEVEL\`: Logging level (debug, info, warning, error)
### Health Checks
- \`GET /health\`: Comprehensive health check
- \`GET /ready\`: Simple readiness check
## Security
### Best Practices
1. Always use HTTPS in production
2. Keep dependencies updated
3. Use environment variables for secrets
4. Enable CORS only for trusted origins
5. Implement proper input validation
6. Use prepared statements for database queries
7. Enable security headers
### Security Headers
The following security headers are enabled by default:
- \`X-Content-Type-Options: nosniff\`
- \`X-Frame-Options: DENY\`
- \`X-XSS-Protection: 1; mode=block\`
- \`Strict-Transport-Security: max-age=31536000; includeSubDomains\`
- \`Content-Security-Policy: default-src 'self'\`
`;
await fs_1.promises.writeFile(path.join(projectPath, 'docs/API.md'), apiGuide);
// Development guide
const devGuide = `# Development Guide
## Prerequisites
- Swift 5.9+
- Docker & Docker Compose
- PostgreSQL 15+ (or use Docker)
- Redis 7+ (or use Docker)
## Setup
1. Clone the repository:
\`\`\`bash
git clone <repository-url>
cd ${options.name}
\`\`\`
2. Install dependencies:
\`\`\`bash
swift package resolve
\`\`\`
3. Setup environment:
\`\`\`bash
cp .env.example .env
# Edit .env with your configuration
\`\`\`
4. Start dependencies:
\`\`\`bash
docker-compose up -d db redis
\`\`\`
5. Run migrations:
\`\`\`bash
swift run App migrate
\`\`\`
6. Start the application:
\`\`\`bash
swift run
\`\`\`
## Project Structure
\`\`\`
Sources/
├── App/
│ ├── Controllers/ # HTTP request handlers
│ ├── Models/ # Data models and DTOs
│ ├── Services/ # Business logic
│ ├── Middleware/ # Custom middleware
│ ├── Config/ # Configuration
│ ├── Utils/ # Utilities
│ └── main.swift # Application entry point
\`\`\`
## Coding Standards
### Naming Conventions
- Use PascalCase for types and protocols
- Use camelCase for functions, variables, and properties
- Use UPPER_SNAKE_CASE for constants
- Prefix protocols with their purpose (e.g., \`UserServiceProtocol\`)
### File Organization
- One type per file
- File name matches the primary type name
- Group related files in subdirectories
### Comments and Documentation
- Use \`///\` for public API documentation
- Use \`//\` for implementation comments
- Document complex algorithms and business logic
## Testing
### Unit Tests
\`\`\`bash
swift test --filter AppTests.UserServiceTests
\`\`\`
### Integration Tests
\`\`\`bash
swift test --filter AppTests.IntegrationTests
\`\`\`
### Test Coverage
\`\`\`bash
swift test --enable-code-coverage
\`\`\`
## Debugging
### Xcode
Generate Xcode project:
\`\`\`bash
swift package generate-xcodeproj
open *.xcodeproj
\`\`\`
### LLDB
\`\`\`bash
lldb .build/debug/App
(lldb) run
\`\`\`
### Logging
Configure log level in environment:
\`\`\`bash
LOG_LEVEL=debug swift run
\`\`\`
## Performance
### Profiling
Use Instruments for performance profiling:
\`\`\`bash
instruments -t "Time Profiler" .build/release/App
\`\`\`
### Benchmarking
Run benchmarks:
\`\`\`bash
swift test --filter AppTests.BenchmarkTests
\`\`\`
## Troubleshooting
### Common Issues
1. **Port already in use**
\`\`\`bash
lsof -i :8080
kill -9 <PID>
\`\`\`
2. **Database connection failed**
- Check DATABASE_URL format
- Ensure PostgreSQL is running
- Verify credentials
3. **Swift package resolution failed**
\`\`\`bash
swift package clean
rm -rf .build
swift package resolve
\`\`\`
`;
await fs_1.promises.writeFile(path.join(projectPath, 'docs/DEVELOPMENT.md'), devGuide);
}
// Utility methods
getLanguageSpecificIgnorePatterns() {
return [
'.build/',
'.swiftpm/',
'*.xcodeproj',
'*.xcworkspace',
'*.playground',
'DerivedData/',
'*.moved-aside',
'*.pbxuser',
'!default.pbxuser',
'*.mode1v3',
'!default.mode1v3',
'*.mode2v3',
'!default.mode2v3',
'*.perspectivev3',
'!default.perspectivev3'
];
}
getLanguagePrerequisites() {
return 'Swift 5.9+ (install via https://swift.org/download/)';
}
getInstallCommand() {
return 'swift package resolve';
}
getDevCommand() {
return 'swift run';
}
getProdCommand() {
return 'swift build -c release && .build/release/App';
}
getTestCommand() {
return 'swift test';
}
getCoverageCommand() {
return 'swift test --enable-code-coverage';
}
getLintCommand() {
return 'swiftlint';
}
getBuildCommand() {
return 'swift build -c release';
}
getSetupAction() {
return 'swift-actions/setup-swift@v1';
}
}
exports.SwiftBackendGenerator = SwiftBackendGenerator;