swift-code-reviewer-skill 1.1.1 → 1.2.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +44 -162
  2. package/README.md +91 -21
  3. package/SKILL.md +107 -725
  4. package/bin/install.js +87 -22
  5. package/package.json +16 -2
  6. package/references/companion-skills.md +70 -0
  7. package/skills/README.md +43 -0
  8. package/skills/swift-concurrency/NOTICE.md +18 -0
  9. package/skills/swift-concurrency/SKILL.md +235 -0
  10. package/skills/swift-concurrency/references/actors.md +640 -0
  11. package/skills/swift-concurrency/references/async-await-basics.md +249 -0
  12. package/skills/swift-concurrency/references/async-sequences.md +635 -0
  13. package/skills/swift-concurrency/references/core-data.md +533 -0
  14. package/skills/swift-concurrency/references/glossary.md +96 -0
  15. package/skills/swift-concurrency/references/linting.md +38 -0
  16. package/skills/swift-concurrency/references/memory-management.md +542 -0
  17. package/skills/swift-concurrency/references/migration.md +721 -0
  18. package/skills/swift-concurrency/references/performance.md +574 -0
  19. package/skills/swift-concurrency/references/sendable.md +578 -0
  20. package/skills/swift-concurrency/references/tasks.md +604 -0
  21. package/skills/swift-concurrency/references/testing.md +565 -0
  22. package/skills/swift-concurrency/references/threading.md +452 -0
  23. package/skills/swift-expert/NOTICE.md +18 -0
  24. package/skills/swift-expert/SKILL.md +226 -0
  25. package/skills/swift-expert/references/async-concurrency.md +363 -0
  26. package/skills/swift-expert/references/memory-performance.md +380 -0
  27. package/skills/swift-expert/references/protocol-oriented.md +357 -0
  28. package/skills/swift-expert/references/swiftui-patterns.md +294 -0
  29. package/skills/swift-expert/references/testing-patterns.md +402 -0
  30. package/skills/swift-testing/NOTICE.md +18 -0
  31. package/skills/swift-testing/SKILL.md +295 -0
  32. package/skills/swift-testing/references/async-testing.md +245 -0
  33. package/skills/swift-testing/references/dump-snapshot-testing.md +265 -0
  34. package/skills/swift-testing/references/fixtures.md +193 -0
  35. package/skills/swift-testing/references/integration-testing.md +189 -0
  36. package/skills/swift-testing/references/migration-xctest.md +301 -0
  37. package/skills/swift-testing/references/parameterized-tests.md +171 -0
  38. package/skills/swift-testing/references/snapshot-testing.md +201 -0
  39. package/skills/swift-testing/references/test-doubles.md +243 -0
  40. package/skills/swift-testing/references/test-organization.md +231 -0
  41. package/skills/swiftui-expert-skill/NOTICE.md +18 -0
  42. package/skills/swiftui-expert-skill/SKILL.md +281 -0
  43. package/skills/swiftui-expert-skill/references/accessibility-patterns.md +151 -0
  44. package/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
  45. package/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
  46. package/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
  47. package/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
  48. package/skills/swiftui-expert-skill/references/charts.md +602 -0
  49. package/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
  50. package/skills/swiftui-expert-skill/references/latest-apis.md +464 -0
  51. package/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
  52. package/skills/swiftui-expert-skill/references/liquid-glass.md +414 -0
  53. package/skills/swiftui-expert-skill/references/list-patterns.md +394 -0
  54. package/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
  55. package/skills/swiftui-expert-skill/references/macos-views.md +357 -0
  56. package/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
  57. package/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
  58. package/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
  59. package/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
  60. package/skills/swiftui-expert-skill/references/state-management.md +417 -0
  61. package/skills/swiftui-expert-skill/references/view-structure.md +389 -0
  62. package/skills/swiftui-ui-patterns/NOTICE.md +18 -0
  63. package/skills/swiftui-ui-patterns/SKILL.md +95 -0
  64. package/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
  65. package/skills/swiftui-ui-patterns/references/async-state.md +96 -0
  66. package/skills/swiftui-ui-patterns/references/components-index.md +50 -0
  67. package/skills/swiftui-ui-patterns/references/controls.md +57 -0
  68. package/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
  69. package/skills/swiftui-ui-patterns/references/focus.md +90 -0
  70. package/skills/swiftui-ui-patterns/references/form.md +97 -0
  71. package/skills/swiftui-ui-patterns/references/grids.md +71 -0
  72. package/skills/swiftui-ui-patterns/references/haptics.md +71 -0
  73. package/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  74. package/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  75. package/skills/swiftui-ui-patterns/references/list.md +86 -0
  76. package/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  77. package/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
  78. package/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  79. package/skills/swiftui-ui-patterns/references/media.md +73 -0
  80. package/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
  81. package/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
  82. package/skills/swiftui-ui-patterns/references/overlay.md +45 -0
  83. package/skills/swiftui-ui-patterns/references/performance.md +62 -0
  84. package/skills/swiftui-ui-patterns/references/previews.md +48 -0
  85. package/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  86. package/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
  87. package/skills/swiftui-ui-patterns/references/searchable.md +71 -0
  88. package/skills/swiftui-ui-patterns/references/sheets.md +155 -0
  89. package/skills/swiftui-ui-patterns/references/split-views.md +72 -0
  90. package/skills/swiftui-ui-patterns/references/tabview.md +114 -0
  91. package/skills/swiftui-ui-patterns/references/theming.md +71 -0
  92. package/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
  93. package/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
  94. package/templates/agents/swift-code-reviewer.md +78 -0
  95. package/templates/commands/review.md +56 -0
@@ -0,0 +1,243 @@
1
+ # Test Doubles
2
+
3
+ Test doubles help isolate the system under test (SUT) from side effects. Terminology from [Martin Fowler's "Mocks Aren't Stubs"](https://martinfowler.com/articles/mocksArentStubs.html).
4
+
5
+ ## State vs Behavior Verification
6
+
7
+ | Approach | Description | Test Doubles Used |
8
+ |----------|-------------|-------------------|
9
+ | **State Verification** | Assert on final state after action | Stubs, Fakes, Spies |
10
+ | **Behavior Verification** | Verify correct calls to collaborators | Mocks |
11
+
12
+ **Prefer state verification** - simpler, less brittle tests.
13
+
14
+ ## Dummy
15
+
16
+ A dummy doesn't do anything - just a placeholder:
17
+
18
+ ```swift
19
+ struct UserServiceDummy: UserServiceProtocol {
20
+ func login(_ user: User, completion: (Result<Void, Error>) -> Void) {
21
+ // Does nothing
22
+ }
23
+ }
24
+ ```
25
+
26
+ ## Fake
27
+
28
+ Working implementation with shortcuts (e.g., in-memory database):
29
+
30
+ ```swift
31
+ final class FavoritesManagerFake: FavoritesManagerProtocol {
32
+ var favorites: [Movie] = []
33
+
34
+ func add(_ movie: Movie) throws {
35
+ guard !favorites.contains(where: { $0.id == movie.id }) else {
36
+ throw FavoritesError.alreadyExists
37
+ }
38
+ favorites.append(movie)
39
+ }
40
+
41
+ func remove(_ movie: Movie) throws {
42
+ guard let index = favorites.firstIndex(where: { $0.id == movie.id }) else {
43
+ throw FavoritesError.notFound
44
+ }
45
+ favorites.remove(at: index)
46
+ }
47
+ }
48
+ ```
49
+
50
+ ## Stub
51
+
52
+ Returns pre-configured values:
53
+
54
+ ```swift
55
+ final class PostsServiceStub: PostsServiceProtocol {
56
+ var fetchAllResultToBeReturned: Result<[Post], Error> = .success([])
57
+
58
+ func fetchAll() async throws -> [Post] {
59
+ try fetchAllResultToBeReturned.get()
60
+ }
61
+ }
62
+
63
+ // Naming: [methodName]ToBeReturned
64
+ ```
65
+
66
+ ## Spy
67
+
68
+ Records calls for verification:
69
+
70
+ ```swift
71
+ final class SafeStorageSpy: SafeStorageProtocol, @unchecked Sendable {
72
+ private(set) var storeUserDataCalled = false
73
+ private(set) var userPassed: User?
74
+ private(set) var storeUserDataCount = 0
75
+
76
+ func storeUserData(_ user: User) {
77
+ storeUserDataCalled = true
78
+ storeUserDataCount += 1
79
+ userPassed = user
80
+ }
81
+ }
82
+
83
+ // Naming conventions:
84
+ // - Method called: [name]Called (Bool)
85
+ // - Parameter captured: [name]Passed
86
+ // - Call count: [name]Count (Int)
87
+ // - All should be private(set)
88
+ ```
89
+
90
+ ## SpyingStub (Most Common)
91
+
92
+ Combines Stub + Spy - this is what Swift developers usually call "Mock":
93
+
94
+ ```swift
95
+ final class PersonalRecordsRepositorySpyingStub: PersonalRecordsRepositoryProtocol, @unchecked Sendable {
96
+ // Spy: Captured calls
97
+ private(set) var savedRecords: [PersonalRecord] = []
98
+ private(set) var deletedIds: [UUID] = []
99
+ private(set) var getAllCalled = false
100
+
101
+ // Stub: Configurable responses
102
+ var recordsToReturn: [PersonalRecord] = []
103
+ var errorToThrow: Error?
104
+
105
+ func getAll() async throws -> [PersonalRecord] {
106
+ getAllCalled = true
107
+ if let error = errorToThrow { throw error }
108
+ return recordsToReturn
109
+ }
110
+
111
+ func save(_ record: PersonalRecord) async throws {
112
+ if let error = errorToThrow { throw error }
113
+ savedRecords.append(record)
114
+ }
115
+
116
+ func delete(id: UUID) async throws {
117
+ if let error = errorToThrow { throw error }
118
+ deletedIds.append(id)
119
+ }
120
+ }
121
+
122
+ // Naming: [ProtocolName]SpyingStub
123
+ ```
124
+
125
+ ## True Mock (Fowler Definition)
126
+
127
+ Pre-programmed with expectations, self-verifies:
128
+
129
+ ```swift
130
+ final class UserServiceMock: UserServiceProtocol {
131
+ struct Expectation: Equatable {
132
+ let method: String
133
+ let userId: String?
134
+ }
135
+
136
+ private var expectations: [Expectation] = []
137
+ private var actualCalls: [Expectation] = []
138
+ private var returnValues: [String: User] = [:]
139
+
140
+ // Setup (before test)
141
+ func expectGetUser(id: String, returning user: User) {
142
+ expectations.append(Expectation(method: "getUser", userId: id))
143
+ returnValues[id] = user
144
+ }
145
+
146
+ // Protocol implementation
147
+ func getUser(id: String) async throws -> User {
148
+ let call = Expectation(method: "getUser", userId: id)
149
+ actualCalls.append(call)
150
+
151
+ guard expectations.contains(call) else {
152
+ fatalError("Unexpected call: getUser(id: \(id))")
153
+ }
154
+
155
+ guard let user = returnValues[id] else {
156
+ throw UserError.notFound
157
+ }
158
+ return user
159
+ }
160
+
161
+ // Verification (after test)
162
+ func verify() {
163
+ assert(expectations == actualCalls)
164
+ }
165
+ }
166
+
167
+ // Usage
168
+ @Test("fetches user with expected ID")
169
+ func fetchesExpectedUser() async throws {
170
+ let mock = UserServiceMock()
171
+ mock.expectGetUser(id: "123", returning: User.fixture())
172
+
173
+ await sut.loadProfile(userId: "123")
174
+
175
+ mock.verify() // Self-verifies
176
+ }
177
+ ```
178
+
179
+ **Use true mocks when**:
180
+ - Testing interaction protocols (delegates)
181
+ - Verifying exact call sequences
182
+ - Testing that calls are NOT made
183
+
184
+ ## Failings (Unimplemented)
185
+
186
+ Fail if unexpectedly called:
187
+
188
+ ```swift
189
+ import XCTestDynamicOverlay
190
+
191
+ struct FailingNetworkService: NetworkServiceProtocol {
192
+ func fetchData(from url: URL) async throws -> Data {
193
+ XCTFail("fetchData(from:) was not expected to be called!")
194
+ fatalError()
195
+ }
196
+ }
197
+ ```
198
+
199
+ With swift-dependencies:
200
+
201
+ ```swift
202
+ extension PersonalRecordsRepository: TestDependencyKey {
203
+ static let testValue = PersonalRecordsRepository(
204
+ getAll: unimplemented("\(Self.self).getAll"),
205
+ save: unimplemented("\(Self.self).save")
206
+ )
207
+ }
208
+ ```
209
+
210
+ ## Choosing the Right Double
211
+
212
+ | Need | Use |
213
+ |------|-----|
214
+ | Fill a parameter | Dummy |
215
+ | Working lightweight implementation | Fake |
216
+ | Control return values | Stub |
217
+ | Verify calls were made | Spy |
218
+ | Both control and verify | SpyingStub |
219
+ | Verify exact interactions | Mock |
220
+ | Catch unexpected usage | Failing |
221
+
222
+ ## Placement
223
+
224
+ Place test doubles **close to the interface**, not in test targets:
225
+
226
+ ```swift
227
+ // In ModuleName-Interface/Sources/...
228
+
229
+ public protocol MyServiceProtocol: Sendable {
230
+ func doSomething() async throws
231
+ }
232
+
233
+ #if DEBUG
234
+ public final class MyServiceSpyingStub: MyServiceProtocol {
235
+ // Implementation
236
+ }
237
+ #endif
238
+ ```
239
+
240
+ Benefits:
241
+ - Available to all test targets
242
+ - Lives with the contract it implements
243
+ - Zero production overhead with `#if DEBUG`
@@ -0,0 +1,231 @@
1
+ # Test Organization
2
+
3
+ Organizing tests with suites, tags, and traits in Swift Testing.
4
+
5
+ ## Test Suites
6
+
7
+ Group related tests:
8
+
9
+ ```swift
10
+ @Suite("User Management")
11
+ struct UserTests {
12
+ @Test func createUser() { }
13
+ @Test func deleteUser() { }
14
+ }
15
+
16
+ @Suite("Authentication")
17
+ struct AuthTests {
18
+ @Test func login() { }
19
+ @Test func logout() { }
20
+ }
21
+ ```
22
+
23
+ ### Nested Suites
24
+
25
+ ```swift
26
+ @Suite("Shopping Cart")
27
+ struct CartTests {
28
+ @Suite("Adding Items")
29
+ struct AddTests {
30
+ @Test func addSingleItem() { }
31
+ @Test func addMultipleItems() { }
32
+ }
33
+
34
+ @Suite("Removing Items")
35
+ struct RemoveTests {
36
+ @Test func removeSingleItem() { }
37
+ @Test func clearCart() { }
38
+ }
39
+ }
40
+ ```
41
+
42
+ ## Tags
43
+
44
+ Categorize tests for selective running:
45
+
46
+ ```swift
47
+ extension Tag {
48
+ @Tag static var integration: Self
49
+ @Tag static var slow: Self
50
+ @Tag static var network: Self
51
+ }
52
+
53
+ @Test(.tags(.integration))
54
+ func databaseIntegration() { }
55
+
56
+ @Test(.tags(.slow, .network))
57
+ func networkRequest() { }
58
+ ```
59
+
60
+ ### Running Tagged Tests
61
+
62
+ ```bash
63
+ # Run only integration tests
64
+ swift test --filter .tags:integration
65
+
66
+ # Exclude slow tests
67
+ swift test --skip .tags:slow
68
+ ```
69
+
70
+ ## Traits
71
+
72
+ ### Disabled Tests
73
+
74
+ ```swift
75
+ @Test(.disabled("Waiting for API fix"))
76
+ func brokenTest() { }
77
+
78
+ @Test(.disabled(if: isCI, "Flaky on CI"))
79
+ func sometimesFlaky() { }
80
+ ```
81
+
82
+ ### Time Limits
83
+
84
+ ```swift
85
+ @Test(.timeLimit(.minutes(1)))
86
+ func slowTest() async { }
87
+ ```
88
+
89
+ ### Bug References
90
+
91
+ ```swift
92
+ @Test(.bug("https://github.com/org/repo/issues/123"))
93
+ func testWithKnownBug() { }
94
+ ```
95
+
96
+ ### Custom Traits
97
+
98
+ ```swift
99
+ @Test(.enabled(if: ProcessInfo.processInfo.environment["RUN_SLOW_TESTS"] != nil))
100
+ func conditionalTest() { }
101
+ ```
102
+
103
+ ## Setup and Teardown
104
+
105
+ ### Per-Test Setup
106
+
107
+ ```swift
108
+ @Suite struct DatabaseTests {
109
+ var database: Database
110
+
111
+ init() throws {
112
+ // Runs before each test
113
+ database = try Database.inMemory()
114
+ }
115
+
116
+ @Test func insertRecord() {
117
+ // database is fresh for each test
118
+ }
119
+ }
120
+ ```
121
+
122
+ ### Suite-Level Setup
123
+
124
+ ```swift
125
+ @Suite struct ServerTests {
126
+ static var server: TestServer!
127
+
128
+ init() async throws {
129
+ // Per-test setup
130
+ }
131
+
132
+ @Test func request() async { }
133
+ }
134
+ ```
135
+
136
+ ## Test Organization Best Practices
137
+
138
+ ### File Structure
139
+
140
+ ```
141
+ Tests/
142
+ ├── UnitTests/
143
+ │ ├── Models/
144
+ │ │ ├── UserTests.swift
145
+ │ │ └── ProductTests.swift
146
+ │ ├── Services/
147
+ │ │ ├── AuthServiceTests.swift
148
+ │ │ └── CartServiceTests.swift
149
+ │ └── Utilities/
150
+ │ └── FormatterTests.swift
151
+ ├── IntegrationTests/
152
+ │ ├── DatabaseTests.swift
153
+ │ └── APITests.swift
154
+ └── TestHelpers/
155
+ ├── Fixtures.swift
156
+ └── Mocks.swift
157
+ ```
158
+
159
+ ### Naming Files
160
+
161
+ - Name test files after the type they test: `UserTests.swift` for `User`
162
+ - Use `Tests` suffix for test files
163
+
164
+ ### Organizing Within Files
165
+
166
+ ```swift
167
+ @Suite("User")
168
+ struct UserTests {
169
+ // MARK: - Initialization
170
+
171
+ @Test func initWithValidData() { }
172
+ @Test func initWithInvalidData() { }
173
+
174
+ // MARK: - Properties
175
+
176
+ @Test func fullName() { }
177
+ @Test func age() { }
178
+
179
+ // MARK: - Methods
180
+
181
+ @Test func update() { }
182
+ @Test func delete() { }
183
+ }
184
+ ```
185
+
186
+ ## Test Discovery
187
+
188
+ Swift Testing automatically discovers:
189
+ - Functions marked with `@Test`
190
+ - Types marked with `@Suite`
191
+ - Nested suites and tests
192
+
193
+ No need to:
194
+ - Inherit from XCTestCase
195
+ - Prefix with "test"
196
+ - Register tests manually
197
+
198
+ ## Parallel Execution
199
+
200
+ Tests run in parallel by default:
201
+
202
+ ```swift
203
+ @Suite(.serialized) // Run tests in this suite serially
204
+ struct SerialTests {
205
+ @Test func first() { }
206
+ @Test func second() { }
207
+ }
208
+ ```
209
+
210
+ ## FIRST Principles
211
+
212
+ Structure tests to be:
213
+
214
+ - **Fast**: Run quickly
215
+ - **Isolated**: No dependencies between tests
216
+ - **Repeatable**: Same result every time
217
+ - **Self-validating**: Clear pass/fail
218
+ - **Timely**: Written with or before code
219
+
220
+ ```swift
221
+ @Test func fastAndIsolated() {
222
+ // Uses in-memory database, not real one
223
+ let db = Database.inMemory()
224
+
225
+ // Self-contained data
226
+ let user = User.fixture()
227
+
228
+ // Clear assertion
229
+ #expect(db.save(user))
230
+ }
231
+ ```
@@ -0,0 +1,18 @@
1
+ # swiftui-expert-skill — Attribution Notice
2
+
3
+ Bundled into `swift-code-reviewer-skill` on 2026-04-21 from
4
+ `~/.agents/skills/swiftui-expert-skill`.
5
+
6
+ Primary author (best-effort attribution): **Thomas Ricouard ([@Dimillian](https://github.com/Dimillian))**
7
+ Also credited: [@AvdLee](https://github.com/AvdLee), [@bocato](https://github.com/bocato)
8
+
9
+ These three authors' public Swift/SwiftUI content — including IceCubesApp, SwiftLee,
10
+ and their various open-source contributions — informed the skills bundled here.
11
+
12
+ License: the upstream folder did not contain a LICENSE file at the time of vendoring.
13
+ Content is reproduced here in good faith for reference alongside this MIT-licensed
14
+ project. If you are an upstream author and want the attribution corrected, the license
15
+ clarified, or the content removed, please open an issue at:
16
+ https://github.com/Viniciuscarvalho/swift-code-reviewer-skill/issues
17
+
18
+ Changes from upstream: none (verbatim copy; `.DS_Store` files excluded).