From 6792e9173518797123c18ac0306df92dbeacb2be Mon Sep 17 00:00:00 2001 From: Maksim Dimitrov Date: Tue, 17 Feb 2026 15:43:14 +0200 Subject: [PATCH] feat: add Swift language-specific rules Add 5 rule files for Swift following the established pattern used by TypeScript, Python, and Go rule sets. Covers Swift 6 strict concurrency, Swift Testing framework, protocol-oriented patterns, Keychain-based secret management, and SwiftFormat/SwiftLint hooks. --- rules/README.md | 5 ++- rules/swift/coding-style.md | 47 ++++++++++++++++++++++++++ rules/swift/hooks.md | 20 +++++++++++ rules/swift/patterns.md | 66 +++++++++++++++++++++++++++++++++++++ rules/swift/security.md | 33 +++++++++++++++++++ rules/swift/testing.md | 45 +++++++++++++++++++++++++ 6 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 rules/swift/coding-style.md create mode 100644 rules/swift/hooks.md create mode 100644 rules/swift/patterns.md create mode 100644 rules/swift/security.md create mode 100644 rules/swift/testing.md diff --git a/rules/README.md b/rules/README.md index 57de9d38..51dffbad 100644 --- a/rules/README.md +++ b/rules/README.md @@ -17,7 +17,8 @@ rules/ │ └── security.md ├── typescript/ # TypeScript/JavaScript specific ├── python/ # Python specific -└── golang/ # Go specific +├── golang/ # Go specific +└── swift/ # Swift specific ``` - **common/** contains universal principles — no language-specific code examples. @@ -32,6 +33,7 @@ rules/ ./install.sh typescript ./install.sh python ./install.sh golang +./install.sh swift # Install multiple languages at once ./install.sh typescript python @@ -53,6 +55,7 @@ cp -r rules/common ~/.claude/rules/common cp -r rules/typescript ~/.claude/rules/typescript cp -r rules/python ~/.claude/rules/python cp -r rules/golang ~/.claude/rules/golang +cp -r rules/swift ~/.claude/rules/swift # Attention ! ! ! Configure according to your actual project requirements; the configuration here is for reference only. ``` diff --git a/rules/swift/coding-style.md b/rules/swift/coding-style.md new file mode 100644 index 00000000..d9fc38d7 --- /dev/null +++ b/rules/swift/coding-style.md @@ -0,0 +1,47 @@ +--- +paths: + - "**/*.swift" + - "**/Package.swift" +--- +# Swift Coding Style + +> This file extends [common/coding-style.md](../common/coding-style.md) with Swift specific content. + +## Formatting + +- **SwiftFormat** for auto-formatting, **SwiftLint** for style enforcement +- `swift-format` is bundled with Xcode 16+ as an alternative + +## Immutability + +- Prefer `let` over `var` — define everything as `let` and only change to `var` if the compiler requires it +- Use `struct` with value semantics by default; use `class` only when identity or reference semantics are needed + +## Naming + +Follow [Apple API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/): + +- Clarity at the point of use — omit needless words +- Name methods and properties for their roles, not their types +- Use `static let` for constants over global constants + +## Error Handling + +Use typed throws (Swift 6+) and pattern matching: + +```swift +func load(id: String) throws(LoadError) -> Item { + guard let data = try? read(from: path) else { + throw .fileNotFound(id) + } + return try decode(data) +} +``` + +## Concurrency + +Enable Swift 6 strict concurrency checking. Prefer: + +- `Sendable` value types for data crossing isolation boundaries +- Actors for shared mutable state +- Structured concurrency (`async let`, `TaskGroup`) over unstructured `Task {}` diff --git a/rules/swift/hooks.md b/rules/swift/hooks.md new file mode 100644 index 00000000..0fbde366 --- /dev/null +++ b/rules/swift/hooks.md @@ -0,0 +1,20 @@ +--- +paths: + - "**/*.swift" + - "**/Package.swift" +--- +# Swift Hooks + +> This file extends [common/hooks.md](../common/hooks.md) with Swift specific content. + +## PostToolUse Hooks + +Configure in `~/.claude/settings.json`: + +- **SwiftFormat**: Auto-format `.swift` files after edit +- **SwiftLint**: Run lint checks after editing `.swift` files +- **swift build**: Type-check modified packages after edit + +## Warning + +Flag `print()` statements — use `os.Logger` or structured logging instead for production code. diff --git a/rules/swift/patterns.md b/rules/swift/patterns.md new file mode 100644 index 00000000..b03b0baf --- /dev/null +++ b/rules/swift/patterns.md @@ -0,0 +1,66 @@ +--- +paths: + - "**/*.swift" + - "**/Package.swift" +--- +# Swift Patterns + +> This file extends [common/patterns.md](../common/patterns.md) with Swift specific content. + +## Protocol-Oriented Design + +Define small, focused protocols. Use protocol extensions for shared defaults: + +```swift +protocol Repository: Sendable { + associatedtype Item: Identifiable & Sendable + func find(by id: Item.ID) async throws -> Item? + func save(_ item: Item) async throws +} +``` + +## Value Types + +- Use structs for data transfer objects and models +- Use enums with associated values to model distinct states: + +```swift +enum LoadState: Sendable { + case idle + case loading + case loaded(T) + case failed(Error) +} +``` + +## Actor Pattern + +Use actors for shared mutable state instead of locks or dispatch queues: + +```swift +actor Cache { + private var storage: [Key: Value] = [:] + + func get(_ key: Key) -> Value? { storage[key] } + func set(_ key: Key, value: Value) { storage[key] = value } +} +``` + +## Dependency Injection + +Inject protocols with default parameters — production uses defaults, tests inject mocks: + +```swift +struct UserService { + private let repository: any UserRepository + + init(repository: any UserRepository = DefaultUserRepository()) { + self.repository = repository + } +} +``` + +## References + +See skill: `swift-actor-persistence` for actor-based persistence patterns. +See skill: `swift-protocol-di-testing` for protocol-based DI and testing. diff --git a/rules/swift/security.md b/rules/swift/security.md new file mode 100644 index 00000000..878503ae --- /dev/null +++ b/rules/swift/security.md @@ -0,0 +1,33 @@ +--- +paths: + - "**/*.swift" + - "**/Package.swift" +--- +# Swift Security + +> This file extends [common/security.md](../common/security.md) with Swift specific content. + +## Secret Management + +- Use **Keychain Services** for sensitive data (tokens, passwords, keys) — never `UserDefaults` +- Use environment variables or `.xcconfig` files for build-time secrets +- Never hardcode secrets in source — decompilation tools extract them trivially + +```swift +let apiKey = ProcessInfo.processInfo.environment["API_KEY"] +guard let apiKey, !apiKey.isEmpty else { + fatalError("API_KEY not configured") +} +``` + +## Transport Security + +- App Transport Security (ATS) is enforced by default — do not disable it +- Use certificate pinning for critical endpoints +- Validate all server certificates + +## Input Validation + +- Sanitize all user input before display to prevent injection +- Use `URL(string:)` with validation rather than force-unwrapping +- Validate data from external sources (APIs, deep links, pasteboard) before processing diff --git a/rules/swift/testing.md b/rules/swift/testing.md new file mode 100644 index 00000000..9a1b0127 --- /dev/null +++ b/rules/swift/testing.md @@ -0,0 +1,45 @@ +--- +paths: + - "**/*.swift" + - "**/Package.swift" +--- +# Swift Testing + +> This file extends [common/testing.md](../common/testing.md) with Swift specific content. + +## Framework + +Use **Swift Testing** (`import Testing`) for new tests. Use `@Test` and `#expect`: + +```swift +@Test("User creation validates email") +func userCreationValidatesEmail() throws { + #expect(throws: ValidationError.invalidEmail) { + try User(email: "not-an-email") + } +} +``` + +## Test Isolation + +Each test gets a fresh instance — set up in `init`, tear down in `deinit`. No shared mutable state between tests. + +## Parameterized Tests + +```swift +@Test("Validates formats", arguments: ["json", "xml", "csv"]) +func validatesFormat(format: String) throws { + let parser = try Parser(format: format) + #expect(parser.isValid) +} +``` + +## Coverage + +```bash +swift test --enable-code-coverage +``` + +## Reference + +See skill: `swift-protocol-di-testing` for protocol-based dependency injection and mock patterns with Swift Testing.