Skip to main content
Ora Browser maintains strict code quality standards through automated formatting and linting. All code must adhere to these standards before being merged.

Formatting & Linting Tools

Code quality is enforced through git hooks that automatically run on every commit:

SwiftFormat

Handles code formatting and style consistency

SwiftLint

Enforces coding standards and best practices

Running Tools Manually

You can run these tools manually at any time:
swiftformat . --quiet
swiftlint --quiet
The setup script (./scripts/setup.sh) automatically installs git hooks that run these tools on every commit.

SwiftFormat Configuration

The project uses SwiftFormat with specific rules defined in .swiftformat:
.swiftformat
--swiftversion 5.9
--indent 4
--maxwidth 120
--allman false
--semicolons never
--stripunusedargs closure-only
--wraparguments before-first
--wrapcollections before-first
--commas inline
--closingparen balanced
--self remove
--trimwhitespace always
--ranges spaced

Key Formatting Rules

1

Indentation

Use 4 spaces for indentation (no tabs)
func example() {
    let value = 42
    if value > 0 {
        print(value)
    }
}
2

Line Length

Maximum line width is 120 characters
// Good - within 120 character limit
func processUserData(userId: UUID, name: String, email: String) { }

// Bad - exceeds limit, should be wrapped
func processUserDataWithVeryLongParameterNamesAndMultipleArgumentsThatMakeTheLineTooLongToRead(userId: UUID, userName: String) { }
3

Semicolons

Never use semicolons (they’re optional in Swift)
// Good
let x = 10
let y = 20

// Bad
let x = 10;
let y = 20;
4

Self References

Remove explicit self unless required for disambiguation
class Example {
    var name: String
    
    // Good - self removed where not needed
    func updateName(_ newName: String) {
        name = newName
    }
    
    // Good - self required in closure
    func delayedUpdate(_ newName: String) {
        DispatchQueue.main.async {
            self.name = newName
        }
    }
}

SwiftLint Configuration

SwiftLint enforces coding standards through .swiftlint.yml:

Enabled Rules

The project enables additional opt-in rules for stricter code quality:
opt_in_rules:
  - force_unwrapping          # Warn on force unwraps (!)
  - implicitly_unwrapped_optional  # Warn on implicitly unwrapped optionals
These rules help prevent runtime crashes:
// Warning - force unwrapping
let value = optionalValue!

// Preferred - safe unwrapping
guard let value = optionalValue else { return }

// Warning - implicitly unwrapped optional
var unsafeValue: String!

// Preferred - explicit optional handling
var safeValue: String?

Code Metrics

SwiftLint enforces limits on code complexity:
line_length:
  warning: 120

file_length:
  warning: 500
  error: 800

function_body_length:
  warning: 50
  error: 100

type_body_length:
  warning: 300
  error: 500

cyclomatic_complexity:
  warning: 10
  error: 20

nesting:
  type_level:
    warning: 2
    error: 3
  function_level:
    warning: 2
    error: 3
Functions exceeding 50 lines or cyclomatic complexity over 10 should be refactored into smaller, more maintainable units.

Custom Rules

The project defines custom rules for specific requirements:
custom_rules:
  no_print_statements:
    name: "No Print Statements"
    regex: "print\\("
    message: "Use logger instead of print statements"
    severity: warning
Example from Tab.swift:224:
// Bad - using print
print("Tab title changed: \(title)")

// Good - structured logging
delegate.onTitleChange = { [weak self] title in
    DispatchQueue.main.async {
        if let title, !title.isEmpty {
            self?.title = title
        }
    }
}

Coding Conventions

SwiftUI/AppKit Patterns

Follow established patterns in the codebase for consistency:
Organize SwiftUI views with clear separation:
OraRoot.swift
struct OraRoot: View {
    // MARK: - State Objects
    @StateObject private var appState = AppState()
    @StateObject private var tabManager: TabManager
    @StateObject private var historyManager: HistoryManager
    
    // MARK: - Injection Support
    @ObserveInjection var inject
    
    // MARK: - Properties
    let tabContext: ModelContext
    @State private var window: NSWindow?
    
    // MARK: - Body
    var body: some View {
        BrowserView()
            .environmentObject(appState)
            .enableInjection()
    }
}

Modern Swift APIs

Prefer modern Swift and SwiftUI APIs when possible:
// Good - modern async/await
Task { @MainActor in
    await downloadManager.startDownload(url: url)
}

// Avoid - older completion handler style (when async alternative exists)
downloadManager.startDownload(url: url) { result in
    DispatchQueue.main.async {
        // handle result
    }
}

// Good - SwiftUI state management
@Published var isLoading: Bool = false

// Good - modern collection operations
let activeTabs = tabs.filter { $0.type == .normal }

Compatibility Requirements

Ora Browser targets macOS 15.0+ with Swift 5.9.

OS Version Handling

When using newer APIs, always check availability:
if #available(macOS 15.0, *) {
    // Use macOS 15+ features
    window.backgroundColor = .systemBackground
} else {
    // Fallback for older versions
    window.backgroundColor = .windowBackgroundColor
}

// Or for declarations
@available(macOS 15.0, *)
func useNewFeature() {
    // Implementation using macOS 15+ APIs
}
Before raising minimum version: Open an issue to discuss the trade-offs. Backward compatibility should be preserved unless there’s a compelling reason to require a newer OS version.

File Organization

Maintain the established directory structure:
ora/
├── Common/           # Shared utilities and extensions
│   ├── Constants/   # App-wide constants
│   ├── Extensions/  # Swift/SwiftUI extensions
│   └── Utils/       # Helper utilities
├── Models/          # SwiftData models
├── Services/        # Business logic and managers
├── Modules/         # Feature-specific views
│   ├── Browser/
│   ├── Settings/
│   └── Sidebar/
└── UI/              # Reusable UI components
    ├── Buttons/
    ├── Dialog/
    └── Icons/
See Project Structure for detailed organization.

Code Review Checklist

Before submitting a pull request:
1

Formatting & Linting

  • SwiftFormat passes without changes
  • SwiftLint shows no warnings or errors
  • Git hooks ran successfully on commit
2

Code Quality

  • No force unwraps or implicitly unwrapped optionals
  • Functions are under 50 lines
  • Complexity is reasonable (< 10)
  • No print statements (use proper logging)
3

Conventions

  • Follows existing patterns in codebase
  • Uses modern Swift/SwiftUI APIs
  • Proper file organization
  • Availability checks for new APIs
4

Testing

  • Code builds without warnings
  • All tests pass
  • New functionality includes tests

Project Structure

Learn about the codebase organization

Contributing Guide

Complete guide to contributing

Setup Guide

Get your development environment ready

Testing

Writing and running tests

Build docs developers (and LLMs) love