Skip to content

dadbodgeoff/SwiftUIAudit

Repository files navigation

SwiftUI Audit

A design system compliance auditor for SwiftUI projects. Catches hard-coded values, accessibility issues, and performance anti-patterns before they ship.

Why?

SwiftLint has 2 accessibility rules. That's it. No tool exists for:

  • Typography token compliance
  • Color token compliance
  • Spacing token compliance
  • Touch target validation
  • Loading/error state patterns
  • Performance anti-patterns in SwiftUI

SwiftUI Audit fills this gap.

Real-World Example

We ran this on a production iOS app (111 files, ~50k LOC). Results:

❌ Audit FAILED
  Files reviewed: 111
  Overall score: 21/100
  Total violations: 485
    Critical: 345 (accessibility, hard-coded values)
    High: 138 (typography, performance)

Top issues found:

  • 258 accessibility violations (missing labels, small touch targets)
  • 112 hard-coded spacing values (not using design tokens)
  • 47 typography issues (hard-coded font sizes)
  • 24 hard-coded colors (breaks dark mode)
  • 5 performance anti-patterns (non-lazy lists)

See EXAMPLE_OUTPUT.md for detailed before/after examples.

Installation

Swift Package Manager

Add to your Package.swift:

dependencies: [
    .package(url: "https://github.com/yourusername/SwiftUIAudit.git", from: "1.0.0")
]

Homebrew (coming soon)

brew install swiftui-audit

Manual

git clone https://github.com/yourusername/SwiftUIAudit.git
cd SwiftUIAudit
swift build -c release
cp .build/release/swiftui-audit /usr/local/bin/

Quick Start

# Audit current directory
swiftui-audit

# Audit specific path
swiftui-audit /path/to/project

# Generate config file
swiftui-audit init

# List available rules
swiftui-audit rules

Configuration

Create .swiftui-audit.yml in your project root:

# Design System Token Names
tokens:
  typography:
    prefix: "AppTypography"  # Your typography namespace
    body: "bodyMedium"
    headline: "headlineMedium"
    title: "titleLarge"

  colors:
    prefix: "AppColors"      # Your color namespace
    primary: "brandPrimary"
    error: "errorRed"
    background: "surfaceBackground"
  
  spacing:
    prefix: "Spacing"        # Your spacing namespace
    sm: "small"
    md: "medium"
    lg: "large"

# Files to exclude
excludedPatterns:
  - Tests
  - Preview
  - Generated
  - Pods

# Token definition files (won't be flagged)
tokenDefinitionPatterns:
  - Tokens
  - Theme.swift
  - DesignSystem

# Rules to disable
disabledRules: []

# Minimum severity: low, medium, high, critical
minimumSeverity: low

# Output format: markdown, json, console
outputFormat: console

Rules

Typography (TYPO)

  • TYPO-001: Hard-coded font sizes → Use typography tokens
  • TYPO-002: Missing typography modifier → Apply consistent text styling

Colors (COLOR)

  • COLOR-001: Hard-coded colors → Use color tokens

Spacing (SPACE)

  • SPACE-001: Hard-coded padding/margins → Use spacing tokens

Accessibility (A11Y)

  • A11Y-001: Missing accessibility labels on interactive elements
  • A11Y-002: Touch targets below 44pt minimum

Architecture (ARCH)

  • ARCH-001: State management patterns

Performance (PERF)

  • PERF-001: Non-lazy lists, uncancelled tasks, expensive body operations

Code Organization (ORG)

  • ORG-001: Naming conventions, MARK comments, documentation

Output Formats

Console (default)

✅ Audit PASSED
==================================================

📊 Summary
  Files reviewed: 42
  Overall score: 94/100
  Total violations: 3
    Critical: 0
    High: 1
    Medium: 2

Markdown

swiftui-audit --format markdown --output audit-report.md

JSON

swiftui-audit --format json --output audit-report.json

CI Integration

GitHub Actions

- name: SwiftUI Audit
  run: |
    swift build -c release
    .build/release/swiftui-audit --format markdown --output audit.md
    
- name: Comment PR
  uses: actions/github-script@v6
  with:
    script: |
      const fs = require('fs');
      const report = fs.readFileSync('audit.md', 'utf8');
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: report
      });

Library Usage

import SwiftUIAudit

// Load config
let config = AuditConfiguration.findAndLoad(in: projectPath)

// Run audit
let runner = AuditRunner(configuration: config)
let result = runner.runAudit(on: projectPath)

// Check results
if result.passed {
    print("✅ All checks passed!")
} else {
    print("❌ Found \(result.report?.totalViolations ?? 0) violations")
}

// Generate report
if let markdown = runner.generateMarkdownReport(from: result) {
    print(markdown)
}

Custom Rules

struct MyCustomRule: AuditRule {
    let id = "CUSTOM-001"
    let name = "My Custom Rule"
    let category = AuditCategory.architecture
    let severity = ViolationSeverity.medium
    
    var ruleDescription: String {
        "Checks for my custom pattern"
    }
    
    func check(file: SwiftFile, configuration: AuditConfiguration) -> [Violation] {
        // Your rule logic here
        return []
    }
}

// Add to runner
let runner = AuditRunner()
runner.addRule(MyCustomRule())

License

MIT License - see LICENSE

Contributing

PRs welcome! Please:

  1. Add tests for new rules
  2. Update documentation
  3. Follow existing code style

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages