@aicgen/aicgen 1.0.0-beta.2 → 1.0.1
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/.agent/rules/api-design.md +649 -0
- package/.agent/rules/architecture.md +2507 -0
- package/.agent/rules/best-practices.md +622 -0
- package/.agent/rules/code-style.md +308 -0
- package/.agent/rules/design-patterns.md +577 -0
- package/.agent/rules/devops.md +230 -0
- package/.agent/rules/error-handling.md +417 -0
- package/.agent/rules/instructions.md +28 -0
- package/.agent/rules/language.md +786 -0
- package/.agent/rules/performance.md +710 -0
- package/.agent/rules/security.md +587 -0
- package/.agent/rules/testing.md +572 -0
- package/.agent/workflows/add-documentation.md +10 -0
- package/.agent/workflows/generate-integration-tests.md +10 -0
- package/.agent/workflows/generate-unit-tests.md +11 -0
- package/.agent/workflows/performance-audit.md +11 -0
- package/.agent/workflows/refactor-extract-module.md +12 -0
- package/.agent/workflows/security-audit.md +12 -0
- package/.gemini/instructions.md +4843 -0
- package/AGENTS.md +9 -11
- package/bun.lock +755 -4
- package/claude.md +2 -2
- package/config.example.yml +129 -0
- package/config.yml +38 -0
- package/data/guideline-mappings.yml +128 -0
- package/data/language/dart/async.md +289 -0
- package/data/language/dart/basics.md +280 -0
- package/data/language/dart/error-handling.md +355 -0
- package/data/language/dart/index.md +10 -0
- package/data/language/dart/testing.md +352 -0
- package/data/language/swift/basics.md +477 -0
- package/data/language/swift/concurrency.md +654 -0
- package/data/language/swift/error-handling.md +679 -0
- package/data/language/swift/swiftui-mvvm.md +795 -0
- package/data/language/swift/testing.md +708 -0
- package/data/version.json +10 -8
- package/dist/index.js +50295 -29101
- package/jest.config.js +46 -0
- package/package.json +13 -2
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
# Swift Language Fundamentals
|
|
2
|
+
|
|
3
|
+
## Naming Conventions
|
|
4
|
+
|
|
5
|
+
Follow Swift's standard naming conventions for clarity and consistency:
|
|
6
|
+
|
|
7
|
+
```swift
|
|
8
|
+
// ✅ Types and protocols: UpperCamelCase
|
|
9
|
+
class UserManager { }
|
|
10
|
+
struct UserProfile { }
|
|
11
|
+
protocol Drawable { }
|
|
12
|
+
enum NetworkError { }
|
|
13
|
+
|
|
14
|
+
// ✅ Functions, variables, constants: lowerCamelCase
|
|
15
|
+
func calculateTotal(items: [Item]) -> Double { }
|
|
16
|
+
let userName = "Alice"
|
|
17
|
+
var isLoggedIn = false
|
|
18
|
+
private let maxRetries = 3
|
|
19
|
+
|
|
20
|
+
// ✅ Enums: singular, UpperCamelCase
|
|
21
|
+
enum Result {
|
|
22
|
+
case success
|
|
23
|
+
case failure(Error)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ❌ Bad: Incorrect casing
|
|
27
|
+
class user_manager { } // Wrong
|
|
28
|
+
func Calculate_Total() { } // Wrong
|
|
29
|
+
let MAX_RETRIES = 3 // Use camelCase for constants
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Type Safety and Type Inference
|
|
33
|
+
|
|
34
|
+
Leverage Swift's powerful type system while maintaining code clarity:
|
|
35
|
+
|
|
36
|
+
```swift
|
|
37
|
+
// ✅ Type inference for obvious types
|
|
38
|
+
let name = "Alice" // Clearly a String
|
|
39
|
+
let count = 5 // Clearly an Int
|
|
40
|
+
let items = [1, 2, 3] // Clearly [Int]
|
|
41
|
+
|
|
42
|
+
// ✅ Explicit types when beneficial
|
|
43
|
+
let apiKey: String? = configuration.apiKey
|
|
44
|
+
let timeout: TimeInterval = 30.0
|
|
45
|
+
let callback: (Result<Data, Error>) -> Void
|
|
46
|
+
|
|
47
|
+
// ✅ Always specify return types for functions
|
|
48
|
+
func fetchUser(id: String) -> User? {
|
|
49
|
+
// Implementation
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ❌ Avoid unnecessary type annotations
|
|
53
|
+
let message: String = "Hello" // Type is obvious
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Value Types vs Reference Types
|
|
57
|
+
|
|
58
|
+
Prefer structs (value types) over classes (reference types) when possible:
|
|
59
|
+
|
|
60
|
+
```swift
|
|
61
|
+
// ✅ Use structs for simple data models
|
|
62
|
+
struct User {
|
|
63
|
+
let id: String
|
|
64
|
+
var name: String
|
|
65
|
+
var email: String
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ✅ Use classes when you need:
|
|
69
|
+
// - Inheritance
|
|
70
|
+
// - Reference semantics
|
|
71
|
+
// - Deinitializers
|
|
72
|
+
class NetworkManager {
|
|
73
|
+
private var session: URLSession
|
|
74
|
+
|
|
75
|
+
init(configuration: URLSessionConfiguration) {
|
|
76
|
+
self.session = URLSession(configuration: configuration)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
deinit {
|
|
80
|
+
session.invalidateAndCancel()
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ✅ Structs are copied, classes are referenced
|
|
85
|
+
var user1 = User(id: "1", name: "Alice", email: "alice@example.com")
|
|
86
|
+
var user2 = user1
|
|
87
|
+
user2.name = "Bob"
|
|
88
|
+
// user1.name is still "Alice" (different instance)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Properties and Computed Properties
|
|
92
|
+
|
|
93
|
+
Use appropriate property types based on your needs:
|
|
94
|
+
|
|
95
|
+
```swift
|
|
96
|
+
struct Rectangle {
|
|
97
|
+
// ✅ Stored properties
|
|
98
|
+
var width: Double
|
|
99
|
+
var height: Double
|
|
100
|
+
|
|
101
|
+
// ✅ Computed property for derived values
|
|
102
|
+
var area: Double {
|
|
103
|
+
return width * height
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ✅ Computed property with setter
|
|
107
|
+
var perimeter: Double {
|
|
108
|
+
get {
|
|
109
|
+
return 2 * (width + height)
|
|
110
|
+
}
|
|
111
|
+
set {
|
|
112
|
+
// Distribute new perimeter equally
|
|
113
|
+
let side = newValue / 4
|
|
114
|
+
width = side
|
|
115
|
+
height = side
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ✅ Property observers
|
|
120
|
+
var description: String = "" {
|
|
121
|
+
willSet {
|
|
122
|
+
print("About to set description to: \(newValue)")
|
|
123
|
+
}
|
|
124
|
+
didSet {
|
|
125
|
+
print("Description changed from: \(oldValue)")
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ❌ Avoid storing values that can be computed
|
|
131
|
+
struct Circle {
|
|
132
|
+
var radius: Double
|
|
133
|
+
var diameter: Double // ❌ Should be computed
|
|
134
|
+
var area: Double // ❌ Should be computed
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ✅ Better approach
|
|
138
|
+
struct Circle {
|
|
139
|
+
var radius: Double
|
|
140
|
+
|
|
141
|
+
var diameter: Double {
|
|
142
|
+
return radius * 2
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
var area: Double {
|
|
146
|
+
return .pi * radius * radius
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Access Control
|
|
152
|
+
|
|
153
|
+
Use appropriate access levels to maintain encapsulation:
|
|
154
|
+
|
|
155
|
+
```swift
|
|
156
|
+
// ✅ Public: Available to all modules
|
|
157
|
+
public class APIClient {
|
|
158
|
+
// ✅ Internal (default): Available within module
|
|
159
|
+
func fetchData() -> Data? {
|
|
160
|
+
return nil
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ✅ Private: Only visible within this type
|
|
164
|
+
private var apiKey: String = ""
|
|
165
|
+
|
|
166
|
+
// ✅ Fileprivate: Visible within this file
|
|
167
|
+
fileprivate func log(_ message: String) {
|
|
168
|
+
print(message)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ✅ Keep implementation details private
|
|
173
|
+
public struct User {
|
|
174
|
+
public let id: String
|
|
175
|
+
public var name: String
|
|
176
|
+
|
|
177
|
+
// ❌ Don't expose internal state unnecessarily
|
|
178
|
+
// public var internalCache: [String: Any] = [:]
|
|
179
|
+
|
|
180
|
+
// ✅ Keep internal state private
|
|
181
|
+
private var cache: [String: Any] = [:]
|
|
182
|
+
|
|
183
|
+
public init(id: String, name: String) {
|
|
184
|
+
self.id = id
|
|
185
|
+
self.name = name
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Extensions for Organization
|
|
191
|
+
|
|
192
|
+
Use extensions to organize code and add functionality:
|
|
193
|
+
|
|
194
|
+
```swift
|
|
195
|
+
// ✅ Protocol conformance in extensions
|
|
196
|
+
struct User {
|
|
197
|
+
let id: String
|
|
198
|
+
var name: String
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
extension User: Codable { }
|
|
202
|
+
|
|
203
|
+
extension User: Equatable {
|
|
204
|
+
static func == (lhs: User, rhs: User) -> Bool {
|
|
205
|
+
return lhs.id == rhs.id
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ✅ Computed properties in extensions
|
|
210
|
+
extension User {
|
|
211
|
+
var displayName: String {
|
|
212
|
+
return name.isEmpty ? "Unknown User" : name
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ✅ Methods in extensions
|
|
217
|
+
extension User {
|
|
218
|
+
func isValid() -> Bool {
|
|
219
|
+
return !id.isEmpty && !name.isEmpty
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ✅ Extend types you don't own
|
|
224
|
+
extension String {
|
|
225
|
+
var isValidEmail: Bool {
|
|
226
|
+
return self.contains("@") && self.contains(".")
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Guard Statements for Early Returns
|
|
232
|
+
|
|
233
|
+
Use `guard` for early returns and validation:
|
|
234
|
+
|
|
235
|
+
```swift
|
|
236
|
+
// ✅ Use guard for preconditions
|
|
237
|
+
func processUser(_ user: User?) {
|
|
238
|
+
guard let user = user else {
|
|
239
|
+
print("No user provided")
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
guard user.isValid() else {
|
|
244
|
+
print("Invalid user")
|
|
245
|
+
return
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
guard user.age >= 18 else {
|
|
249
|
+
print("User must be 18 or older")
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Happy path at the lowest indentation level
|
|
254
|
+
print("Processing user: \(user.name)")
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ❌ Avoid deep nesting with if-let
|
|
258
|
+
func processUser(_ user: User?) {
|
|
259
|
+
if let user = user {
|
|
260
|
+
if user.isValid() {
|
|
261
|
+
if user.age >= 18 {
|
|
262
|
+
print("Processing user: \(user.name)")
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Modern Swift Types
|
|
270
|
+
|
|
271
|
+
Use Swift's modern collection types and standard library:
|
|
272
|
+
|
|
273
|
+
```swift
|
|
274
|
+
// ✅ Use Swift types, not Objective-C types
|
|
275
|
+
let names: [String] = ["Alice", "Bob"] // Not NSArray
|
|
276
|
+
let scores: [String: Int] = ["Alice": 95] // Not NSDictionary
|
|
277
|
+
let uniqueIds: Set<String> = ["id1", "id2"] // Not NSSet
|
|
278
|
+
|
|
279
|
+
// ✅ Use Swift's String, not NSString
|
|
280
|
+
let message: String = "Hello, World!"
|
|
281
|
+
let uppercased = message.uppercased() // Not message.uppercaseString
|
|
282
|
+
|
|
283
|
+
// ✅ Leverage collection methods
|
|
284
|
+
let numbers = [1, 2, 3, 4, 5]
|
|
285
|
+
let doubled = numbers.map { $0 * 2 }
|
|
286
|
+
let evens = numbers.filter { $0 % 2 == 0 }
|
|
287
|
+
let sum = numbers.reduce(0, +)
|
|
288
|
+
|
|
289
|
+
// ✅ Use compactMap to filter and transform
|
|
290
|
+
let strings = ["1", "2", "foo", "3"]
|
|
291
|
+
let validNumbers = strings.compactMap { Int($0) }
|
|
292
|
+
// Result: [1, 2, 3]
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Immutability with let
|
|
296
|
+
|
|
297
|
+
Prefer `let` over `var` for immutable values:
|
|
298
|
+
|
|
299
|
+
```swift
|
|
300
|
+
// ✅ Use let whenever possible
|
|
301
|
+
let maxRetries = 3
|
|
302
|
+
let timeout: TimeInterval = 30.0
|
|
303
|
+
let apiEndpoint = "https://api.example.com"
|
|
304
|
+
|
|
305
|
+
// ✅ Only use var when value will change
|
|
306
|
+
var currentAttempt = 0
|
|
307
|
+
var isLoading = false
|
|
308
|
+
|
|
309
|
+
// ✅ Immutable collections are safer
|
|
310
|
+
let users: [User] = fetchUsers()
|
|
311
|
+
// users.append(newUser) // Compile error - safer!
|
|
312
|
+
|
|
313
|
+
// ❌ Avoid var for values that don't change
|
|
314
|
+
var serverURL = "https://api.example.com" // Should be let
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Trailing Closures
|
|
318
|
+
|
|
319
|
+
Use trailing closure syntax for better readability:
|
|
320
|
+
|
|
321
|
+
```swift
|
|
322
|
+
// ✅ Trailing closure for single closure parameter
|
|
323
|
+
UIView.animate(withDuration: 0.3) {
|
|
324
|
+
view.alpha = 0
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ✅ Multiple trailing closures (Swift 5.3+)
|
|
328
|
+
UIView.animate(withDuration: 0.3) {
|
|
329
|
+
view.alpha = 0
|
|
330
|
+
} completion: { _ in
|
|
331
|
+
view.removeFromSuperview()
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ❌ Avoid when it reduces clarity
|
|
335
|
+
array.map({ $0 * 2 }) // OK - simple and clear
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Avoid Force Unwrapping
|
|
339
|
+
|
|
340
|
+
Never use force unwrapping (`!`) unless absolutely necessary:
|
|
341
|
+
|
|
342
|
+
```swift
|
|
343
|
+
// ❌ Force unwrapping can crash
|
|
344
|
+
let user = optionalUser!
|
|
345
|
+
let name = user.name!
|
|
346
|
+
|
|
347
|
+
// ✅ Optional binding
|
|
348
|
+
if let user = optionalUser {
|
|
349
|
+
print(user.name)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ✅ Guard for early exit
|
|
353
|
+
guard let user = optionalUser else {
|
|
354
|
+
return
|
|
355
|
+
}
|
|
356
|
+
print(user.name)
|
|
357
|
+
|
|
358
|
+
// ✅ Nil coalescing for defaults
|
|
359
|
+
let name = optionalName ?? "Unknown"
|
|
360
|
+
|
|
361
|
+
// ✅ Optional chaining
|
|
362
|
+
let firstUserEmail = users.first?.email
|
|
363
|
+
|
|
364
|
+
// ⚠️ Force unwrap only when guaranteed non-nil
|
|
365
|
+
// (e.g., outlets in view controllers after viewDidLoad)
|
|
366
|
+
@IBOutlet private weak var titleLabel: UILabel!
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Type Aliases for Clarity
|
|
370
|
+
|
|
371
|
+
Use type aliases to make complex types more readable:
|
|
372
|
+
|
|
373
|
+
```swift
|
|
374
|
+
// ✅ Clarify complex types
|
|
375
|
+
typealias CompletionHandler = (Result<Data, Error>) -> Void
|
|
376
|
+
typealias UserID = String
|
|
377
|
+
typealias Coordinate = (latitude: Double, longitude: Double)
|
|
378
|
+
|
|
379
|
+
// Usage
|
|
380
|
+
func fetchUser(id: UserID, completion: CompletionHandler) {
|
|
381
|
+
// Implementation
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// ✅ Document units and intent
|
|
385
|
+
typealias Seconds = Double
|
|
386
|
+
typealias Meters = Double
|
|
387
|
+
|
|
388
|
+
let timeout: Seconds = 30.0
|
|
389
|
+
let distance: Meters = 100.0
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Enums for Type Safety
|
|
393
|
+
|
|
394
|
+
Use enums to represent a fixed set of related values:
|
|
395
|
+
|
|
396
|
+
```swift
|
|
397
|
+
// ✅ Simple enum
|
|
398
|
+
enum NetworkError: Error {
|
|
399
|
+
case noConnection
|
|
400
|
+
case timeout
|
|
401
|
+
case invalidResponse
|
|
402
|
+
case unauthorized
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// ✅ Enum with associated values
|
|
406
|
+
enum Result<Success, Failure: Error> {
|
|
407
|
+
case success(Success)
|
|
408
|
+
case failure(Failure)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// ✅ Enum with raw values
|
|
412
|
+
enum HTTPMethod: String {
|
|
413
|
+
case get = "GET"
|
|
414
|
+
case post = "POST"
|
|
415
|
+
case put = "PUT"
|
|
416
|
+
case delete = "DELETE"
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// ✅ Exhaustive switch statements
|
|
420
|
+
func handle(error: NetworkError) {
|
|
421
|
+
switch error {
|
|
422
|
+
case .noConnection:
|
|
423
|
+
print("No internet connection")
|
|
424
|
+
case .timeout:
|
|
425
|
+
print("Request timed out")
|
|
426
|
+
case .invalidResponse:
|
|
427
|
+
print("Invalid response from server")
|
|
428
|
+
case .unauthorized:
|
|
429
|
+
print("Unauthorized access")
|
|
430
|
+
}
|
|
431
|
+
// No default needed - all cases covered
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## Documentation Comments
|
|
436
|
+
|
|
437
|
+
Write clear documentation using Swift's markdown format:
|
|
438
|
+
|
|
439
|
+
```swift
|
|
440
|
+
/// Fetches user data from the API.
|
|
441
|
+
///
|
|
442
|
+
/// - Parameters:
|
|
443
|
+
/// - id: The unique identifier for the user
|
|
444
|
+
/// - completion: Closure called when the request completes
|
|
445
|
+
/// - Returns: A cancellable task
|
|
446
|
+
/// - Throws: `NetworkError` if the request fails
|
|
447
|
+
func fetchUser(
|
|
448
|
+
id: String,
|
|
449
|
+
completion: @escaping (Result<User, NetworkError>) -> Void
|
|
450
|
+
) -> URLSessionTask {
|
|
451
|
+
// Implementation
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/// Represents a user in the system.
|
|
455
|
+
///
|
|
456
|
+
/// Use this type to store user information retrieved from the API.
|
|
457
|
+
///
|
|
458
|
+
/// Example:
|
|
459
|
+
/// ```swift
|
|
460
|
+
/// let user = User(id: "123", name: "Alice")
|
|
461
|
+
/// print(user.displayName)
|
|
462
|
+
/// ```
|
|
463
|
+
struct User {
|
|
464
|
+
/// The unique identifier for this user
|
|
465
|
+
let id: String
|
|
466
|
+
|
|
467
|
+
/// The user's display name
|
|
468
|
+
var name: String
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
**Sources:**
|
|
475
|
+
- [Swift API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/)
|
|
476
|
+
- [Google Swift Style Guide](https://google.github.io/swift/)
|
|
477
|
+
- [Kodeco Swift Style Guide](https://github.com/kodecocodes/swift-style-guide)
|