> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tablepro.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Code Style

> Swift conventions, tooling, naming, and file organization rules

# Code Style

## Tools

`.swiftlint.yml` and `.swiftformat` are the source of truth. When in doubt, check those files.

```bash theme={null}
# Check for issues
swiftlint lint

# Auto-fix
swiftlint --fix

# Format all code
swiftformat .

# Check formatting without applying
swiftformat --lint .
```

SwiftLint also runs during Xcode builds automatically.

## Formatting

| Rule            | Value                                             |
| --------------- | ------------------------------------------------- |
| Indentation     | 4 spaces (never tabs)                             |
| Line length     | 120 chars (SwiftLint warns at 180, errors at 300) |
| Braces          | K\&R (opening brace on same line)                 |
| Line endings    | LF                                                |
| Semicolons      | None                                              |
| Trailing commas | None                                              |

## Naming

| Element                            | Convention        | Example                                            |
| ---------------------------------- | ----------------- | -------------------------------------------------- |
| Classes, Structs, Enums, Protocols | UpperCamelCase    | `DatabaseConnection`                               |
| Enum cases                         | lowerCamelCase    | `.postgresql`                                      |
| Functions, Variables, Constants    | lowerCamelCase    | `executeQuery()`, `maxRetryAttempts`               |
| Booleans                           | is/has/can prefix | `isConnected`, `hasValidCredentials`               |
| Factory methods                    | make prefix       | `makeConnection()`                                 |
| Acronyms                           | Treat as words    | `JsonEncoder` not `JSONEncoder` (except SDK types) |

## Access Control

Always explicit. Prefer the most restrictive level that works.

```swift theme={null}
// Specify on the extension, not individual members
public extension NSEvent {
    var semanticKeyCode: KeyCode? { ... }
}
```

## Imports

System frameworks first (alphabetical), then third-party, then local. Blank line after imports.

```swift theme={null}
import AppKit
import Foundation
import os

import CodeEditSourceEditor

import TableProPluginKit
```

## Safety

No force unwrapping (`!`) or force casting (`as!`). Use `guard let`, `if let`, `as?`.

```swift theme={null}
// Good
guard let connection = activeConnection else { return }

// Bad
let connection = activeConnection!
```

## Logging

OSLog only. Never `print()`.

```swift theme={null}
import os

private static let logger = Logger(subsystem: "com.TablePro", category: "DatabaseManager")
```

## Localization

* `String(localized:)` for user-facing strings in computed properties, AppKit code, alerts, error descriptions
* SwiftUI view literals (`Text("Save")`, `Button("Cancel")`) auto-localize
* Do not localize technical terms: font names, database types, SQL keywords, encoding names
* Never use `String(localized:)` with string interpolation. Use `String(format: String(localized: "Preview %@"), name)` instead.

## SwiftUI Patterns

* `@State` for local view state
* `@Observable` for viewmodels (Swift 5.9+)
* Property wrapper order: Environment, State, Binding, regular properties
* Extract large views into subviews

## Limits

| Metric                | Warning    | Error      |
| --------------------- | ---------- | ---------- |
| File length           | 1200 lines | 1800 lines |
| Type body             | 1100 lines | 1500 lines |
| Function body         | 160 lines  | 250 lines  |
| Cyclomatic complexity | 40         | 60         |

When approaching these limits, extract into extension files:

<Tree>
  <Tree.File name="MainContentCoordinator.swift" />

  <Tree.Folder name="Extensions" defaultOpen>
    <Tree.File name="MainContentCoordinator+RowOperations.swift" />

    <Tree.File name="MainContentCoordinator+Pagination.swift" />

    <Tree.File name="MainContentCoordinator+Filtering.swift" />
  </Tree.Folder>
</Tree>

Group by domain logic, not arbitrary line counts.
