A design system compliance auditor for SwiftUI projects. Catches hard-coded values, accessibility issues, and performance anti-patterns before they ship.
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.
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.
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/yourusername/SwiftUIAudit.git", from: "1.0.0")
]brew install swiftui-auditgit clone https://github.com/yourusername/SwiftUIAudit.git
cd SwiftUIAudit
swift build -c release
cp .build/release/swiftui-audit /usr/local/bin/# Audit current directory
swiftui-audit
# Audit specific path
swiftui-audit /path/to/project
# Generate config file
swiftui-audit init
# List available rules
swiftui-audit rulesCreate .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- TYPO-001: Hard-coded font sizes → Use typography tokens
- TYPO-002: Missing typography modifier → Apply consistent text styling
- COLOR-001: Hard-coded colors → Use color tokens
- SPACE-001: Hard-coded padding/margins → Use spacing tokens
- A11Y-001: Missing accessibility labels on interactive elements
- A11Y-002: Touch targets below 44pt minimum
- ARCH-001: State management patterns
- PERF-001: Non-lazy lists, uncancelled tasks, expensive body operations
- ORG-001: Naming conventions, MARK comments, documentation
✅ Audit PASSED
==================================================
📊 Summary
Files reviewed: 42
Overall score: 94/100
Total violations: 3
Critical: 0
High: 1
Medium: 2
swiftui-audit --format markdown --output audit-report.mdswiftui-audit --format json --output audit-report.json- 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
});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)
}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())MIT License - see LICENSE
PRs welcome! Please:
- Add tests for new rules
- Update documentation
- Follow existing code style