Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .agents/skills/running-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,7 @@ mise install
./ide --no-open
./swiftformat --lint
./test --everything
# The native-macOS Ledger scheme has no simulator and runs in its own CI job:
mise exec -- tuist test Ledger-macOS-Tests --no-selective-testing -- \
-destination 'platform=macOS'
```
56 changes: 28 additions & 28 deletions .bumper/Sources/WhereProjectRules.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ let whereProjectRules = RuleSet {
Rules.constructionOwnership(
"WhereServices",
allowed: whereServicesConstructionScope,
id: "where.services_composition_ownership"
id: "where.services_composition_ownership",
)
Rules.constructionOwnership(
"CoreLocationSource",
allowed: .files(["Where/WhereUI/Sources/Launch/WhereLaunch.swift"]),
id: "where.live_location_source_ownership"
id: "where.live_location_source_ownership",
)
Rules.singleNominalSpelling(
suffix: "Log",
owner: whereLoggingScope,
id: "where.logging_type_ownership"
id: "where.logging_type_ownership",
)
productionStoreOpeningRule
checkedConcurrencyBoundaryRule
Expand Down Expand Up @@ -46,7 +46,7 @@ private let productionStoreOpeningPaths: Set<RelativeFilePath> = [
private let productionStoreOpeningRule = Rules.files(
"where.production_store_opening",
severity: .error,
summary: "Production SwiftData stores open only at the app and share-extension composition roots."
summary: "Production SwiftData stores open only at the app and share-extension composition roots.",
) { file in
functionCalls()
.filter { match in
Expand All @@ -59,8 +59,8 @@ private let productionStoreOpeningRule = Rules.files(
message: "SwiftDataStore.make is called outside a process composition root.",
evidence: ViolationEvidence(
observed: "SwiftDataStore.make in \(file.path.rawValue)",
expectation: "open the production store in WhereLaunch or ShareEvidenceModel"
)
expectation: "open the production store in WhereLaunch or ShareEvidenceModel",
),
)
}
}
Expand All @@ -76,7 +76,7 @@ private let documentedUnsafeConcurrencyPaths: Set<RelativeFilePath> = [
private let checkedConcurrencyBoundaryRule = Rules.files(
"where.checked_concurrency_boundaries",
severity: .error,
summary: "Unchecked concurrency escape hatches stay inside documented lifecycle boundaries."
summary: "Unchecked concurrency escape hatches stay inside documented lifecycle boundaries.",
) { file in
let preconcurrencyFailures = SyntaxQuery<AttributeSyntax>()
.filter { match in
Expand All @@ -88,8 +88,8 @@ private let checkedConcurrencyBoundaryRule = Rules.files(
message: "Production code uses an @preconcurrency escape hatch.",
evidence: ViolationEvidence(
observed: match.node.trimmedDescription,
expectation: "use checked Swift concurrency"
)
expectation: "use checked Swift concurrency",
),
)
}

Expand All @@ -105,8 +105,8 @@ private let checkedConcurrencyBoundaryRule = Rules.files(
message: "nonisolated(unsafe) is outside a documented lifecycle boundary.",
evidence: ViolationEvidence(
observed: match.node.trimmedDescription,
expectation: "checked isolation or a documented existing boundary"
)
expectation: "checked isolation or a documented existing boundary",
),
)
}

Expand All @@ -116,7 +116,7 @@ private let checkedConcurrencyBoundaryRule = Rules.files(
private let gregorianCalendarRule = Rules.files(
"where.gregorian_calendar",
severity: .error,
summary: "Where day and year calculations do not use the device's potentially non-Gregorian current calendar."
summary: "Where day and year calculations do not use the device's potentially non-Gregorian current calendar.",
) { file in
SyntaxQuery<MemberAccessExprSyntax>()
.filter { match in
Expand All @@ -129,8 +129,8 @@ private let gregorianCalendarRule = Rules.files(
message: "Where uses Calendar.current instead of an explicit Gregorian calendar.",
evidence: ViolationEvidence(
observed: match.node.trimmedDescription,
expectation: "an injected Gregorian calendar or Calendar.whereIntents"
)
expectation: "an injected Gregorian calendar or Calendar.whereIntents",
),
)
}
}
Expand All @@ -151,7 +151,7 @@ private let whereStoreMutatingMethods: Set<String> = [
private let storeTransactionBoundaryRule = Rules.files(
"where.store_transaction_boundary",
severity: .error,
summary: "WhereStore mutations occur inside the transaction owned by store.perform."
summary: "WhereStore mutations occur inside the transaction owned by store.perform.",
) { file in
functionCalls()
.filter { match in
Expand All @@ -170,8 +170,8 @@ private let storeTransactionBoundaryRule = Rules.files(
message: "WhereStore mutation occurs outside store.perform.",
evidence: ViolationEvidence(
observed: match.node.calledExpression.trimmedDescription,
expectation: "call the mutation from inside store.perform { ... }"
)
expectation: "call the mutation from inside store.perform { ... }",
),
)
}
}
Expand All @@ -195,7 +195,7 @@ private func isInsideStorePerform(_ node: FunctionCallExprSyntax) -> Bool {
private let appShortcutsProviderOwnershipRule = Rules.files(
"where.app_shortcuts_provider_ownership",
severity: .error,
summary: "AppShortcutsProvider conformances live in the Where app target."
summary: "AppShortcutsProvider conformances live in the Where app target.",
) { file in
guard file.component.rawValue != WhereComponent.app.rawValue else { return [] }
return SyntaxQuery<InheritedTypeSyntax>()
Expand All @@ -206,16 +206,16 @@ private let appShortcutsProviderOwnershipRule = Rules.files(
message: "AppShortcutsProvider conformance is outside the Where app target.",
evidence: ViolationEvidence(
observed: file.path.rawValue,
expectation: "a source owned by the Where app component"
)
expectation: "a source owned by the Where app component",
),
)
}
}

private let loggingFacadeRule = Rules.files(
"where.logging_facade",
severity: .error,
summary: "Where production logging goes through its typed Periscope facades."
summary: "Where production logging goes through its typed Periscope facades.",
) { file in
let rawLoggingImports = SyntaxQuery<ImportDeclSyntax>()
.filter { $0.node.path.trimmedDescription == "OSLog" }
Expand All @@ -225,8 +225,8 @@ private let loggingFacadeRule = Rules.files(
message: "Where production code imports OSLog directly.",
evidence: ViolationEvidence(
observed: "import OSLog",
expectation: "WhereLog or RegionLog"
)
expectation: "WhereLog or RegionLog",
),
)
}

Expand All @@ -238,8 +238,8 @@ private let loggingFacadeRule = Rules.files(
message: "Where production code prints directly.",
evidence: ViolationEvidence(
observed: "print",
expectation: "a typed WhereLog or RegionLog event"
)
expectation: "a typed WhereLog or RegionLog event",
),
)
}

Expand All @@ -254,7 +254,7 @@ private let previewCoverageRule = Rules.files(
"where.preview_coverage",
severity: .error,
summary: "Every WhereUI or widget source file declaring a previewable component includes a #Preview.",
scope: previewScope
scope: previewScope,
) { file in
let previewableDeclarations = SyntaxQuery<StructDeclSyntax>()
.filter { match in
Expand Down Expand Up @@ -283,8 +283,8 @@ private let previewCoverageRule = Rules.files(
message: "\(match.node.name.text) has no #Preview in its source file.",
evidence: ViolationEvidence(
observed: file.path.rawValue,
expectation: "at least one #Preview in the same file"
)
expectation: "at least one #Preview in the same file",
),
)
}
}
40 changes: 20 additions & 20 deletions .bumper/Tests/WhereArchitectureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ func `Where architecture accepts downward dependencies`() throws {
files: [
SourceInput(
path: "Where/WhereCore/Sources/Service.swift",
component: try ComponentID(WhereComponent.whereCore.rawValue),
source: "import RegionKit\nstruct Service {}"
component: ComponentID(WhereComponent.whereCore.rawValue),
source: "import RegionKit\nstruct Service {}",
),
SourceInput(
path: "Where/WhereUI/Sources/Screen.swift",
component: try ComponentID(WhereComponent.whereUI.rawValue),
source: "import WhereCore\nimport SwiftUI\nstruct Screen {}"
component: ComponentID(WhereComponent.whereUI.rawValue),
source: "import WhereCore\nimport SwiftUI\nstruct Screen {}",
),
]
)
],
),
)

#expect(report.violations.isEmpty)
Expand All @@ -32,11 +32,11 @@ func `RegionKit cannot depend upward on WhereCore`() throws {
files: [
SourceInput(
path: "Where/RegionKit/Sources/Region.swift",
component: try ComponentID(WhereComponent.regionKit.rawValue),
source: "import WhereCore\nstruct Region {}"
component: ComponentID(WhereComponent.regionKit.rawValue),
source: "import WhereCore\nstruct Region {}",
),
]
)
],
),
)

let violation = try #require(report.violations.first)
Expand All @@ -53,11 +53,11 @@ func `WhereUI cannot import persistence`() throws {
files: [
SourceInput(
path: "Where/WhereUI/Sources/Screen.swift",
component: try ComponentID(WhereComponent.whereUI.rawValue),
source: "import SwiftData\nstruct Screen {}"
component: ComponentID(WhereComponent.whereUI.rawValue),
source: "import SwiftData\nstruct Screen {}",
),
]
)
],
),
)

let violation = try #require(report.violations.first)
Expand All @@ -74,16 +74,16 @@ func `Where adapters cannot link Broadway directly`() throws {
files: [
SourceInput(
path: "Where/WhereWidgets/Sources/Widget.swift",
component: try ComponentID(WhereComponent.widgets.rawValue),
source: "import BroadwayUI\nstruct Widget {}"
component: ComponentID(WhereComponent.widgets.rawValue),
source: "import BroadwayUI\nstruct Widget {}",
),
SourceInput(
path: "Where/WhereIntents/Sources/Intent.swift",
component: try ComponentID(WhereComponent.whereIntents.rawValue),
source: "import BroadwayCore\nstruct Intent {}"
component: ComponentID(WhereComponent.whereIntents.rawValue),
source: "import BroadwayCore\nstruct Intent {}",
),
]
)
],
),
)

#expect(report.violations.count == 2)
Expand Down
Loading