@el-j/magic-helix-plugins 4.0.0-beta.2 → 4.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/dist/architecture/codeowners.md +123 -0
- package/dist/architecture/monorepo.md +146 -0
- package/dist/architecture/nx.md +122 -0
- package/dist/architecture/turborepo.md +114 -0
- package/dist/ci/github-actions.md +268 -0
- package/dist/ci/gitlab-ci.md +330 -0
- package/dist/containers/docker-multistage.md +120 -0
- package/dist/containers/kubernetes-deploy.md +210 -0
- package/dist/cpp/index.cjs +79 -0
- package/dist/cpp/index.mjs +209 -0
- package/dist/csharp/index.cjs +2 -2
- package/dist/csharp/{index.js → index.mjs} +17 -11
- package/dist/csharp/templates/framework-aspnetcore.md +205 -0
- package/dist/csharp/templates/framework-blazor.md +271 -0
- package/dist/csharp/templates/lang-csharp.md +162 -0
- package/dist/devops/docker-compose.md +111 -0
- package/dist/devops/docker-dockerfile.md +94 -0
- package/dist/devops/github-actions.md +160 -0
- package/dist/devops/gitlab-ci.md +210 -0
- package/dist/generic/lang-typescript.md +57 -0
- package/dist/generic/state-redux.md +21 -0
- package/dist/generic/state-rxjs.md +6 -0
- package/dist/generic/style-mui.md +23 -0
- package/dist/generic/style-tailwind.md +76 -0
- package/dist/generic/test-cypress.md +21 -0
- package/dist/generic/test-jest.md +20 -0
- package/dist/generic/test-playwright.md +21 -0
- package/dist/generic/test-vitest.md +131 -0
- package/dist/go/index.cjs +3 -3
- package/dist/go/{index.js → index.mjs} +18 -15
- package/dist/go/templates/lang-go.md +571 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +24 -0
- package/dist/java/index.cjs +2 -2
- package/dist/java/{index.js → index.mjs} +25 -19
- package/dist/java/templates/build-gradle.md +102 -0
- package/dist/java/templates/build-maven.md +86 -0
- package/dist/java/templates/framework-spring-boot.md +179 -0
- package/dist/java/templates/lang-java.md +78 -0
- package/dist/java/templates/lang-kotlin.md +88 -0
- package/dist/meta/magic-helix-meta.md +213 -0
- package/dist/meta/meta-debug.md +459 -0
- package/dist/meta/meta-implement.md +450 -0
- package/dist/meta/meta-roadmap.md +265 -0
- package/dist/nodejs/templates/angular-core.md +19 -0
- package/dist/nodejs/templates/lang-typescript.md +57 -0
- package/dist/nodejs/templates/nestjs-core.md +7 -0
- package/dist/nodejs/templates/react-core.md +677 -0
- package/dist/nodejs/templates/react-zustand.md +7 -0
- package/dist/nodejs/templates/state-redux.md +21 -0
- package/dist/nodejs/templates/state-rxjs.md +6 -0
- package/dist/nodejs/templates/style-primevue.md +6 -0
- package/dist/nodejs/templates/style-quasar.md +22 -0
- package/dist/nodejs/templates/style-tailwind.md +76 -0
- package/dist/nodejs/templates/test-cypress.md +21 -0
- package/dist/nodejs/templates/test-jest.md +20 -0
- package/dist/nodejs/templates/test-playwright.md +21 -0
- package/dist/nodejs/templates/test-vitest.md +131 -0
- package/dist/nodejs/templates/vue-core.md +108 -0
- package/dist/nodejs/templates/vue-pinia.md +5 -0
- package/dist/patterns/architecture/clean-architecture.md +469 -0
- package/dist/patterns/architecture/dependency-injection.md +517 -0
- package/dist/patterns/architecture/domain-driven-design.md +621 -0
- package/dist/patterns/architecture/layered-architecture.md +382 -0
- package/dist/patterns/architecture/repository-pattern.md +408 -0
- package/dist/patterns/domain-expertise/nextjs-rules.md +115 -0
- package/dist/patterns/domain-expertise/react-patterns.md +181 -0
- package/dist/patterns/domain-expertise/server-components.md +212 -0
- package/dist/patterns/domain-expertise/shadcn-ui.md +52 -0
- package/dist/patterns/domain-expertise/tailwind-patterns.md +52 -0
- package/dist/patterns/environment/container-awareness.md +17 -0
- package/dist/patterns/environment/ide-features.md +17 -0
- package/dist/patterns/environment/os-commands.md +17 -0
- package/dist/patterns/organization/heading-hierarchy.md +103 -0
- package/dist/patterns/organization/sequential-workflows.md +102 -0
- package/dist/patterns/organization/xml-rule-groups.md +64 -0
- package/dist/patterns/reasoning/agent-loop.md +151 -0
- package/dist/patterns/reasoning/confirmation-gates.md +141 -0
- package/dist/patterns/reasoning/dependency-analysis.md +132 -0
- package/dist/patterns/reasoning/one-tool-per-iteration.md +152 -0
- package/dist/patterns/reasoning/preview-before-action.md +194 -0
- package/dist/patterns/reasoning/reflection-checkpoints.md +166 -0
- package/dist/patterns/reasoning/result-verification.md +157 -0
- package/dist/patterns/reasoning/subtask-breakdown.md +131 -0
- package/dist/patterns/reasoning/thinking-tags.md +100 -0
- package/dist/patterns/role-definition/capability-declarations.md +72 -0
- package/dist/patterns/role-definition/expert-identity.md +45 -0
- package/dist/patterns/role-definition/scope-boundaries.md +61 -0
- package/dist/patterns/safety/code-safety-rules.md +17 -0
- package/dist/patterns/safety/credential-handling.md +17 -0
- package/dist/patterns/safety/destructive-warnings.md +17 -0
- package/dist/patterns/safety/refusal-messages.md +17 -0
- package/dist/patterns/tone/adaptive-tone.md +17 -0
- package/dist/patterns/tone/concise-communication.md +17 -0
- package/dist/patterns/tone/forbidden-phrases.md +17 -0
- package/dist/patterns/tool-guidelines/function-schemas.md +143 -0
- package/dist/patterns/tool-guidelines/parameter-examples.md +137 -0
- package/dist/patterns/tool-guidelines/usage-policies.md +105 -0
- package/dist/php/index.cjs +2 -2
- package/dist/php/{index.js → index.mjs} +12 -6
- package/dist/php/templates/framework-laravel.md +112 -0
- package/dist/php/templates/lang-php.md +94 -0
- package/dist/python/index.cjs +4 -4
- package/dist/python/{index.js → index.mjs} +10 -7
- package/dist/python/templates/lang-python.md +508 -0
- package/dist/ruby/index.cjs +2 -2
- package/dist/ruby/{index.js → index.mjs} +16 -10
- package/dist/ruby/templates/framework-rails.md +309 -0
- package/dist/ruby/templates/framework-sinatra.md +227 -0
- package/dist/ruby/templates/lang-ruby.md +216 -0
- package/dist/rust/index.cjs +3 -3
- package/dist/rust/{index.js → index.mjs} +24 -18
- package/dist/rust/templates/lang-rust.md +89 -0
- package/dist/swift/index.cjs +32 -0
- package/dist/swift/index.mjs +112 -0
- package/dist/swift/templates/framework-vapor.md +352 -0
- package/dist/swift/templates/lang-swift.md +291 -0
- package/package.json +31 -21
- package/dist/index.js +0 -20
- /package/dist/nodejs/{index.js → index.mjs} +0 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
# Vapor Framework Instructions
|
|
2
|
+
|
|
3
|
+
## Server-Side Swift Web Framework
|
|
4
|
+
|
|
5
|
+
Vapor is a modern, high-performance web framework for Swift.
|
|
6
|
+
|
|
7
|
+
## Project Structure
|
|
8
|
+
```
|
|
9
|
+
Sources/
|
|
10
|
+
├── App/
|
|
11
|
+
│ ├── Controllers/
|
|
12
|
+
│ ├── Models/
|
|
13
|
+
│ ├── Migrations/
|
|
14
|
+
│ ├── configure.swift
|
|
15
|
+
│ └── routes.swift
|
|
16
|
+
└── Run/
|
|
17
|
+
└── main.swift
|
|
18
|
+
Tests/
|
|
19
|
+
└── AppTests/
|
|
20
|
+
Package.swift
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Basic Application
|
|
24
|
+
|
|
25
|
+
### configure.swift
|
|
26
|
+
```swift
|
|
27
|
+
import Vapor
|
|
28
|
+
import Fluent
|
|
29
|
+
import FluentPostgresDriver
|
|
30
|
+
|
|
31
|
+
public func configure(_ app: Application) async throws {
|
|
32
|
+
// Database
|
|
33
|
+
app.databases.use(
|
|
34
|
+
.postgres(
|
|
35
|
+
hostname: Environment.get("DATABASE_HOST") ?? "localhost",
|
|
36
|
+
port: Environment.get("DATABASE_PORT").flatMap(Int.init) ?? 5432,
|
|
37
|
+
username: Environment.get("DATABASE_USERNAME") ?? "postgres",
|
|
38
|
+
password: Environment.get("DATABASE_PASSWORD") ?? "",
|
|
39
|
+
database: Environment.get("DATABASE_NAME") ?? "vapor"
|
|
40
|
+
),
|
|
41
|
+
as: .psql
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
// Migrations
|
|
45
|
+
app.migrations.add(CreateUser())
|
|
46
|
+
|
|
47
|
+
try await app.autoMigrate()
|
|
48
|
+
|
|
49
|
+
// Routes
|
|
50
|
+
try routes(app)
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### routes.swift
|
|
55
|
+
```swift
|
|
56
|
+
import Vapor
|
|
57
|
+
|
|
58
|
+
func routes(_ app: Application) throws {
|
|
59
|
+
app.get { req in
|
|
60
|
+
"Welcome to Vapor!"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
app.get("hello", ":name") { req -> String in
|
|
64
|
+
let name = req.parameters.get("name")!
|
|
65
|
+
return "Hello, \(name)!"
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try app.register(collection: UserController())
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Models with Fluent ORM
|
|
73
|
+
|
|
74
|
+
```swift
|
|
75
|
+
import Fluent
|
|
76
|
+
import Vapor
|
|
77
|
+
|
|
78
|
+
final class User: Model, Content {
|
|
79
|
+
static let schema = "users"
|
|
80
|
+
|
|
81
|
+
@ID(key: .id)
|
|
82
|
+
var id: UUID?
|
|
83
|
+
|
|
84
|
+
@Field(key: "name")
|
|
85
|
+
var name: String
|
|
86
|
+
|
|
87
|
+
@Field(key: "email")
|
|
88
|
+
var email: String
|
|
89
|
+
|
|
90
|
+
@Children(for: \.$user)
|
|
91
|
+
var posts: [Post]
|
|
92
|
+
|
|
93
|
+
init() {}
|
|
94
|
+
|
|
95
|
+
init(id: UUID? = nil, name: String, email: String) {
|
|
96
|
+
self.id = id
|
|
97
|
+
self.name = name
|
|
98
|
+
self.email = email
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Migration
|
|
103
|
+
struct CreateUser: AsyncMigration {
|
|
104
|
+
func prepare(on database: Database) async throws {
|
|
105
|
+
try await database.schema("users")
|
|
106
|
+
.id()
|
|
107
|
+
.field("name", .string, .required)
|
|
108
|
+
.field("email", .string, .required)
|
|
109
|
+
.unique(on: "email")
|
|
110
|
+
.create()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
func revert(on database: Database) async throws {
|
|
114
|
+
try await database.schema("users").delete()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Controllers
|
|
120
|
+
|
|
121
|
+
```swift
|
|
122
|
+
import Vapor
|
|
123
|
+
|
|
124
|
+
struct UserController: RouteCollection {
|
|
125
|
+
func boot(routes: RoutesBuilder) throws {
|
|
126
|
+
let users = routes.grouped("api", "users")
|
|
127
|
+
users.get(use: index)
|
|
128
|
+
users.get(":id", use: show)
|
|
129
|
+
users.post(use: create)
|
|
130
|
+
users.put(":id", use: update)
|
|
131
|
+
users.delete(":id", use: delete)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
func index(req: Request) async throws -> [User] {
|
|
135
|
+
try await User.query(on: req.db).all()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
func show(req: Request) async throws -> User {
|
|
139
|
+
guard let user = try await User.find(req.parameters.get("id"), on: req.db) else {
|
|
140
|
+
throw Abort(.notFound)
|
|
141
|
+
}
|
|
142
|
+
return user
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
func create(req: Request) async throws -> User {
|
|
146
|
+
let user = try req.content.decode(User.self)
|
|
147
|
+
try await user.save(on: req.db)
|
|
148
|
+
return user
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
func update(req: Request) async throws -> User {
|
|
152
|
+
guard let user = try await User.find(req.parameters.get("id"), on: req.db) else {
|
|
153
|
+
throw Abort(.notFound)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let updateData = try req.content.decode(User.self)
|
|
157
|
+
user.name = updateData.name
|
|
158
|
+
user.email = updateData.email
|
|
159
|
+
try await user.save(on: req.db)
|
|
160
|
+
return user
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
func delete(req: Request) async throws -> HTTPStatus {
|
|
164
|
+
guard let user = try await User.find(req.parameters.get("id"), on: req.db) else {
|
|
165
|
+
throw Abort(.notFound)
|
|
166
|
+
}
|
|
167
|
+
try await user.delete(on: req.db)
|
|
168
|
+
return .noContent
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Middleware
|
|
174
|
+
|
|
175
|
+
```swift
|
|
176
|
+
import Vapor
|
|
177
|
+
|
|
178
|
+
struct LogMiddleware: AsyncMiddleware {
|
|
179
|
+
func respond(to request: Request, chainingTo next: AsyncResponder) async throws -> Response {
|
|
180
|
+
request.logger.info("\(request.method) \(request.url.path)")
|
|
181
|
+
let response = try await next.respond(to: request)
|
|
182
|
+
request.logger.info("Response: \(response.status.code)")
|
|
183
|
+
return response
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Register middleware
|
|
188
|
+
app.middleware.use(LogMiddleware())
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Authentication
|
|
192
|
+
|
|
193
|
+
```swift
|
|
194
|
+
import Vapor
|
|
195
|
+
import Fluent
|
|
196
|
+
|
|
197
|
+
final class User: Model, Content, Authenticatable {
|
|
198
|
+
// ... model definition
|
|
199
|
+
|
|
200
|
+
static func authenticator() -> Authenticator {
|
|
201
|
+
return BearerAuthenticator()
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Protected route
|
|
206
|
+
let protected = app.grouped(User.authenticator())
|
|
207
|
+
protected.get("protected") { req -> String in
|
|
208
|
+
let user = try req.auth.require(User.self)
|
|
209
|
+
return "Hello, \(user.name)!"
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Validation
|
|
214
|
+
|
|
215
|
+
```swift
|
|
216
|
+
import Vapor
|
|
217
|
+
|
|
218
|
+
struct CreateUserRequest: Content, Validatable {
|
|
219
|
+
var name: String
|
|
220
|
+
var email: String
|
|
221
|
+
|
|
222
|
+
static func validations(_ validations: inout Validations) {
|
|
223
|
+
validations.add("name", as: String.self, is: !.empty)
|
|
224
|
+
validations.add("email", as: String.self, is: .email)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
func create(req: Request) async throws -> User {
|
|
229
|
+
try CreateUserRequest.validate(content: req)
|
|
230
|
+
let userData = try req.content.decode(CreateUserRequest.self)
|
|
231
|
+
// ...
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Testing
|
|
236
|
+
|
|
237
|
+
```swift
|
|
238
|
+
import XCTVapor
|
|
239
|
+
@testable import App
|
|
240
|
+
|
|
241
|
+
final class UserTests: XCTestCase {
|
|
242
|
+
var app: Application!
|
|
243
|
+
|
|
244
|
+
override func setUp() async throws {
|
|
245
|
+
app = Application(.testing)
|
|
246
|
+
try await configure(app)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
override func tearDown() async throws {
|
|
250
|
+
app.shutdown()
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
func testGetUsers() async throws {
|
|
254
|
+
try await app.test(.GET, "api/users") { res in
|
|
255
|
+
XCTAssertEqual(res.status, .ok)
|
|
256
|
+
let users = try res.content.decode([User].self)
|
|
257
|
+
XCTAssertGreaterThan(users.count, 0)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
func testCreateUser() async throws {
|
|
262
|
+
let user = User(name: "John", email: "john@example.com")
|
|
263
|
+
|
|
264
|
+
try await app.test(.POST, "api/users", beforeRequest: { req in
|
|
265
|
+
try req.content.encode(user)
|
|
266
|
+
}, afterResponse: { res in
|
|
267
|
+
XCTAssertEqual(res.status, .ok)
|
|
268
|
+
let created = try res.content.decode(User.self)
|
|
269
|
+
XCTAssertEqual(created.name, "John")
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Docker Production Setup
|
|
276
|
+
|
|
277
|
+
```dockerfile
|
|
278
|
+
FROM swift:5.9-jammy AS build
|
|
279
|
+
WORKDIR /app
|
|
280
|
+
|
|
281
|
+
COPY Package.swift Package.resolved ./
|
|
282
|
+
RUN swift package resolve
|
|
283
|
+
|
|
284
|
+
COPY . .
|
|
285
|
+
RUN swift build -c release --static-swift-stdlib
|
|
286
|
+
|
|
287
|
+
FROM ubuntu:22.04
|
|
288
|
+
WORKDIR /app
|
|
289
|
+
|
|
290
|
+
RUN apt-get update && apt-get install -y \
|
|
291
|
+
libcurl4 \
|
|
292
|
+
libxml2 \
|
|
293
|
+
ca-certificates \
|
|
294
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
295
|
+
|
|
296
|
+
COPY --from=build /app/.build/release/Run ./Run
|
|
297
|
+
|
|
298
|
+
RUN useradd -m -u 1000 vapor
|
|
299
|
+
USER vapor
|
|
300
|
+
|
|
301
|
+
EXPOSE 8080
|
|
302
|
+
ENV VAPOR_ENV=production
|
|
303
|
+
|
|
304
|
+
ENTRYPOINT ["./Run"]
|
|
305
|
+
CMD ["serve", "--hostname", "0.0.0.0", "--port", "8080"]
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Environment Configuration
|
|
309
|
+
|
|
310
|
+
```swift
|
|
311
|
+
import Vapor
|
|
312
|
+
|
|
313
|
+
func configure(_ app: Application) async throws {
|
|
314
|
+
switch app.environment {
|
|
315
|
+
case .production:
|
|
316
|
+
app.logger.logLevel = .warning
|
|
317
|
+
case .development:
|
|
318
|
+
app.logger.logLevel = .debug
|
|
319
|
+
default:
|
|
320
|
+
break
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Database URL from environment
|
|
324
|
+
if let databaseURL = Environment.get("DATABASE_URL") {
|
|
325
|
+
try app.databases.use(.postgres(url: databaseURL), as: .psql)
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Performance Tips
|
|
331
|
+
|
|
332
|
+
- Use async/await throughout
|
|
333
|
+
- Leverage connection pooling
|
|
334
|
+
- Implement caching where appropriate
|
|
335
|
+
- Use database indexes
|
|
336
|
+
- Profile with Instruments
|
|
337
|
+
- Enable release optimizations
|
|
338
|
+
- Use EventLoopFuture batching for multiple operations
|
|
339
|
+
- Implement pagination for large datasets
|
|
340
|
+
|
|
341
|
+
## Best Practices
|
|
342
|
+
|
|
343
|
+
- Use proper error handling with `Abort`
|
|
344
|
+
- Validate user input
|
|
345
|
+
- Implement authentication/authorization
|
|
346
|
+
- Use migrations for database schema changes
|
|
347
|
+
- Write comprehensive tests
|
|
348
|
+
- Use environment variables for configuration
|
|
349
|
+
- Implement health check endpoints
|
|
350
|
+
- Log appropriately
|
|
351
|
+
- Use middlewares for cross-cutting concerns
|
|
352
|
+
- Keep controllers thin, logic in services
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# Swift Language Instructions
|
|
2
|
+
|
|
3
|
+
## Project Type
|
|
4
|
+
- Language: Swift
|
|
5
|
+
- Package Manager: Swift Package Manager (SPM)
|
|
6
|
+
- Platform: {iOS|macOS|Linux|Server}
|
|
7
|
+
|
|
8
|
+
## Build Commands
|
|
9
|
+
|
|
10
|
+
### Swift Package Manager
|
|
11
|
+
```bash
|
|
12
|
+
swift build # Build project
|
|
13
|
+
swift test # Run tests
|
|
14
|
+
swift run # Run executable
|
|
15
|
+
swift package update # Update dependencies
|
|
16
|
+
swift package clean # Clean build artifacts
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Xcode
|
|
20
|
+
```bash
|
|
21
|
+
xcodebuild -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'
|
|
22
|
+
xcodebuild test -scheme MyApp
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Code Conventions
|
|
26
|
+
|
|
27
|
+
### Swift Basics
|
|
28
|
+
```swift
|
|
29
|
+
// Variables and constants
|
|
30
|
+
var mutableValue = 42
|
|
31
|
+
let constantValue = 100
|
|
32
|
+
|
|
33
|
+
// Optionals
|
|
34
|
+
var name: String? = "John"
|
|
35
|
+
if let unwrappedName = name {
|
|
36
|
+
print(unwrappedName)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Nil coalescing
|
|
40
|
+
let displayName = name ?? "Anonymous"
|
|
41
|
+
|
|
42
|
+
// Optional chaining
|
|
43
|
+
let length = user?.name?.count
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Structs and Classes
|
|
47
|
+
```swift
|
|
48
|
+
struct User {
|
|
49
|
+
let id: UUID
|
|
50
|
+
var name: String
|
|
51
|
+
var email: String
|
|
52
|
+
|
|
53
|
+
func fullProfile() -> String {
|
|
54
|
+
"\(name) <\(email)>"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class UserRepository {
|
|
59
|
+
private var users: [User] = []
|
|
60
|
+
|
|
61
|
+
func add(_ user: User) {
|
|
62
|
+
users.append(user)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
func find(by id: UUID) -> User? {
|
|
66
|
+
users.first { $0.id == id }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Protocols and Extensions
|
|
72
|
+
```swift
|
|
73
|
+
protocol Identifiable {
|
|
74
|
+
var id: UUID { get }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
extension User: Identifiable {}
|
|
78
|
+
|
|
79
|
+
extension String {
|
|
80
|
+
func toSnakeCase() -> String {
|
|
81
|
+
// Implementation
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Async/Await (Concurrency)
|
|
87
|
+
```swift
|
|
88
|
+
func fetchUser(id: UUID) async throws -> User {
|
|
89
|
+
let (data, _) = try await URLSession.shared.data(from: url)
|
|
90
|
+
return try JSONDecoder().decode(User.self, from: data)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Usage
|
|
94
|
+
Task {
|
|
95
|
+
do {
|
|
96
|
+
let user = try await fetchUser(id: userId)
|
|
97
|
+
print(user.name)
|
|
98
|
+
} catch {
|
|
99
|
+
print("Error: \(error)")
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Error Handling
|
|
105
|
+
```swift
|
|
106
|
+
enum UserError: Error {
|
|
107
|
+
case notFound
|
|
108
|
+
case invalidEmail
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func getUser(id: UUID) throws -> User {
|
|
112
|
+
guard let user = findUser(id) else {
|
|
113
|
+
throw UserError.notFound
|
|
114
|
+
}
|
|
115
|
+
return user
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Usage
|
|
119
|
+
do {
|
|
120
|
+
let user = try getUser(id: userId)
|
|
121
|
+
} catch UserError.notFound {
|
|
122
|
+
print("User not found")
|
|
123
|
+
} catch {
|
|
124
|
+
print("Unknown error: \(error)")
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Testing with XCTest
|
|
129
|
+
|
|
130
|
+
```swift
|
|
131
|
+
import XCTest
|
|
132
|
+
@testable import MyApp
|
|
133
|
+
|
|
134
|
+
final class UserTests: XCTestCase {
|
|
135
|
+
func testUserFullProfile() {
|
|
136
|
+
let user = User(
|
|
137
|
+
id: UUID(),
|
|
138
|
+
name: "John",
|
|
139
|
+
email: "john@example.com"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
XCTAssertEqual(user.fullProfile(), "John <john@example.com>")
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
func testAsyncFunction() async throws {
|
|
146
|
+
let user = try await fetchUser(id: testUserId)
|
|
147
|
+
XCTAssertEqual(user.name, "John")
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Docker for Server-Side Swift
|
|
153
|
+
|
|
154
|
+
### Multi-stage Dockerfile
|
|
155
|
+
```dockerfile
|
|
156
|
+
# Build stage
|
|
157
|
+
FROM swift:5.9-jammy AS build
|
|
158
|
+
WORKDIR /app
|
|
159
|
+
|
|
160
|
+
COPY Package.swift Package.resolved ./
|
|
161
|
+
RUN swift package resolve
|
|
162
|
+
|
|
163
|
+
COPY . .
|
|
164
|
+
RUN swift build -c release --static-swift-stdlib
|
|
165
|
+
|
|
166
|
+
# Runtime stage
|
|
167
|
+
FROM ubuntu:22.04
|
|
168
|
+
WORKDIR /app
|
|
169
|
+
|
|
170
|
+
RUN apt-get update && apt-get install -y \
|
|
171
|
+
libcurl4 \
|
|
172
|
+
libxml2 \
|
|
173
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
174
|
+
|
|
175
|
+
COPY --from=build /app/.build/release/MyApp ./
|
|
176
|
+
|
|
177
|
+
RUN useradd -m -u 1000 swift
|
|
178
|
+
USER swift
|
|
179
|
+
|
|
180
|
+
EXPOSE 8080
|
|
181
|
+
CMD ["./MyApp"]
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Docker Compose
|
|
185
|
+
```yaml
|
|
186
|
+
services:
|
|
187
|
+
app:
|
|
188
|
+
build: .
|
|
189
|
+
ports:
|
|
190
|
+
- "8080:8080"
|
|
191
|
+
environment:
|
|
192
|
+
- DATABASE_URL=postgresql://postgres:password@db/myapp
|
|
193
|
+
depends_on:
|
|
194
|
+
- db
|
|
195
|
+
|
|
196
|
+
db:
|
|
197
|
+
image: postgres:15-alpine
|
|
198
|
+
environment:
|
|
199
|
+
POSTGRES_PASSWORD: password
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Package.swift Structure
|
|
203
|
+
|
|
204
|
+
```swift
|
|
205
|
+
// swift-tools-version: 5.9
|
|
206
|
+
import PackageDescription
|
|
207
|
+
|
|
208
|
+
let package = Package(
|
|
209
|
+
name: "MyApp",
|
|
210
|
+
platforms: [
|
|
211
|
+
.macOS(.v13),
|
|
212
|
+
.iOS(.v16),
|
|
213
|
+
.linux
|
|
214
|
+
],
|
|
215
|
+
products: [
|
|
216
|
+
.executable(name: "MyApp", targets: ["MyApp"]),
|
|
217
|
+
.library(name: "MyLibrary", targets: ["MyLibrary"])
|
|
218
|
+
],
|
|
219
|
+
dependencies: [
|
|
220
|
+
.package(url: "https://github.com/vapor/vapor.git", from: "4.89.0")
|
|
221
|
+
],
|
|
222
|
+
targets: [
|
|
223
|
+
.executableTarget(
|
|
224
|
+
name: "MyApp",
|
|
225
|
+
dependencies: [
|
|
226
|
+
.product(name: "Vapor", package: "vapor")
|
|
227
|
+
]
|
|
228
|
+
),
|
|
229
|
+
.testTarget(
|
|
230
|
+
name: "MyAppTests",
|
|
231
|
+
dependencies: ["MyApp"]
|
|
232
|
+
)
|
|
233
|
+
]
|
|
234
|
+
)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Memory Management
|
|
238
|
+
|
|
239
|
+
```swift
|
|
240
|
+
// ARC (Automatic Reference Counting)
|
|
241
|
+
class User {
|
|
242
|
+
var name: String
|
|
243
|
+
init(name: String) { self.name = name }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Weak references to avoid retain cycles
|
|
247
|
+
class ViewController {
|
|
248
|
+
weak var delegate: UserDelegate?
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Unowned for guaranteed non-nil references
|
|
252
|
+
class Order {
|
|
253
|
+
unowned let customer: Customer
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Performance Tips
|
|
258
|
+
|
|
259
|
+
- Use value types (structs) for immutable data
|
|
260
|
+
- Leverage copy-on-write for collections
|
|
261
|
+
- Use `lazy` for expensive computations
|
|
262
|
+
- Profile with Instruments
|
|
263
|
+
- Use `@inlinable` for small, frequently-called functions
|
|
264
|
+
- Prefer `async/await` over completion handlers
|
|
265
|
+
- Use actors for thread-safe state
|
|
266
|
+
|
|
267
|
+
## Common Frameworks
|
|
268
|
+
|
|
269
|
+
### iOS/macOS
|
|
270
|
+
- **SwiftUI**: Modern declarative UI
|
|
271
|
+
- **Combine**: Reactive programming
|
|
272
|
+
- **CoreData**: Persistence
|
|
273
|
+
- **URLSession**: Networking
|
|
274
|
+
|
|
275
|
+
### Server-Side
|
|
276
|
+
- **Vapor**: Web framework
|
|
277
|
+
- **Fluent**: ORM
|
|
278
|
+
- **PostgresNIO**: PostgreSQL driver
|
|
279
|
+
- **AsyncHTTPClient**: HTTP client
|
|
280
|
+
|
|
281
|
+
## Best Practices
|
|
282
|
+
|
|
283
|
+
- Use optionals appropriately
|
|
284
|
+
- Prefer value types over reference types
|
|
285
|
+
- Use guard statements for early returns
|
|
286
|
+
- Implement proper error handling
|
|
287
|
+
- Write unit tests
|
|
288
|
+
- Use protocols for abstraction
|
|
289
|
+
- Follow Swift naming conventions
|
|
290
|
+
- Use type inference wisely
|
|
291
|
+
- Leverage Swift's type safety
|