AXComponentKit 2.0: Swift 6, @AXScreen macro, dynamic component enhancements#4
AXComponentKit 2.0: Swift 6, @AXScreen macro, dynamic component enhancements#4Chris Stroud (Clstroud) wants to merge 8 commits into
Conversation
|
Copilot Please review |
There was a problem hiding this comment.
Pull request overview
This PR modernizes AXComponentKit for Swift 6 with stricter concurrency semantics, introduces an optional @AXScreen macro for auto-synthesized screen identifiers/conformance, and expands the dynamic component + navigator APIs to improve UI test ergonomics and reliability (along with significant documentation and sample app updates).
Changes:
- Added
@AXScreenmacro support (new macro targets + swift-syntax dependency) and migrated screen models towardSendable/@MainActorusage. - Simplified dynamic component APIs around
AXIdentifierConvertible, added optional/prefixed dynamic identifiers, and added prefix-based “first match” querying helpers. - Updated navigator/test support ergonomics (e.g.,
navigatorproperty,navigaterename, animation suppression helpers), plus refreshed sample app UI tests and DocC/README.
Reviewed changes
Copilot reviewed 80 out of 80 changed files in this pull request and generated 23 comments.
Show a summary per file
| File | Description |
|---|---|
| Sources/AXComponentKitTestSupport/XCTestCase+AsyncSetup.swift | Removed legacy async setUp(completion:) helper. |
| Sources/AXComponentKitTestSupport/Navigation/ScrollTransaction.swift | Adjusted scroll gesture coordinate ranges. |
| Sources/AXComponentKitTestSupport/Navigation/AXTabComponent.swift | Made tab component Sendable; exposed name. |
| Sources/AXComponentKitTestSupport/Navigation/AXTabBarNavigable.swift | Updated tab navigation to use renamed navigator API. |
| Sources/AXComponentKitTestSupport/Navigation/AXScreenNavigator+Scrolling.swift | Simplified dynamic scroll overloads; tweaked timing/velocity. |
| Sources/AXComponentKitTestSupport/Navigation/AXScreenNavigator.swift | Added AXScreen.navigator; renamed navigation API; added breadcrumb log. |
| Sources/AXComponentKitTestSupport/Launch/XCUIApplication+AutomationLaunch.swift | Added automation-configured app launch helpers. |
| Sources/AXComponentKitTestSupport/Existence/XCUIElement+Existence.swift | Improved existence waiting; routed failures through AXFailure.fail. |
| Sources/AXComponentKitTestSupport/Element Querying/AXScreenModel+Tap.swift | Added AXScreen.tap(...) convenience helpers. |
| Sources/AXComponentKitTestSupport/Element Querying/AXScreenModel+TabComponents.swift | Hardened tab item label predicate construction. |
| Sources/AXComponentKitTestSupport/Element Querying/AXScreenModel+FirstDynamicElement.swift | Added prefix-based “first dynamic element” query/tap helpers. |
| Sources/AXComponentKitTestSupport/Element Querying/AXScreenModel+DynamicElements.swift | Consolidated dynamic element querying around AXIdentifierConvertible. |
| Sources/AXComponentKitTestSupport/Element Querying/AXScreenModel+AssumedElements.swift | Consolidated assumed-element APIs around AXIdentifierConvertible. |
| Sources/AXComponentKitTestSupport/AXFailure.swift | Refactored failure reporting to central fail(...) helper. |
| Sources/AXComponentKitTestSupport/AXComponentKitTestSupport.docc/WritingYourFirstTest.md | Updated examples to async setUp and new APIs. |
| Sources/AXComponentKitTestSupport/AXComponentKitTestSupport.docc/NavigatorFundamentals.md | Updated docs for navigator and navigate rename. |
| Sources/AXComponentKitTestSupport/AXComponentKitTestSupport.docc/CustomNavigatorOperations.md | Updated docs for new navigator call patterns. |
| Sources/AXComponentKitMacroSupport/Exports.swift | Re-exported AXComponentKit from macro support product. |
| Sources/AXComponentKitMacroSupport/AXScreenMacroDeclaration.swift | Declared @AXScreen macros (default/custom identifier). |
| Sources/AXComponentKitMacros/Plugin.swift | Added Swift compiler plugin entry point. |
| Sources/AXComponentKitMacros/AXScreenMacro.swift | Implemented macro expansion + identifier derivation. |
| Sources/AXComponentKit/Screen Models/AXScreenModel+Components.swift | Simplified dynamic component resolution API surface. |
| Sources/AXComponentKit/Screen Models/AXScreen.swift | Made AXScreen Sendable. |
| Sources/AXComponentKit/Extensions/Temporal/Measurement+TimeInterval.swift | Removed explicit Measurement: Sendable conformance. |
| Sources/AXComponentKit/Extensions/App UI/View+ScreenIdentityModifier.swift | Adjusted accessibility wrapping to avoid VoiceOver interference. |
| Sources/AXComponentKit/Extensions/App UI/View+AXScrollView.swift | Adjusted accessibility wrapping for scroll views. |
| Sources/AXComponentKit/Extensions/App UI/View+AXDynamicComponent.swift | Added optional/prefixed dynamic identifier modifiers; unified constraints. |
| Sources/AXComponentKit/Extensions/App UI/View+AXComponent.swift | Removed optional component overload that emitted "undefined". |
| Sources/AXComponentKit/Extensions/App UI/View+AnimationSuppression.swift | Added .automationOptimized() view modifier. |
| Sources/AXComponentKit/Configuration/AXAutomation.swift | Added automation runner detection + animation suppression entry point. |
| Sources/AXComponentKit/Configuration/AnimationSuppressor.swift | Implemented UIKit/Core Animation suppression mechanics. |
| Sources/AXComponentKit/AXComponentKit.docc/ScreenModels.md | Documented @AXScreen macro + AXIdentifierConvertible guidance. |
| Sources/AXComponentKit/AXComponentKit.docc/Overview.md | Filled in framework overview and setup guidance. |
| Sources/AXComponentKit/AXComponentKit.docc/IntegratingWithViews.md | Documented optional/prefixed dynamics + animation suppression usage. |
| Sources/AXComponentKit/AX Components/Static Components/AXScrollView.swift | Marked AXScrollView as Sendable. |
| Sources/AXComponentKit/AX Components/Static Components/AXComponent.swift | Marked AXComponent as Sendable. |
| Sources/AXComponentKit/AX Components/Dynamic Components/AXIdentifierConvertible.swift | Added AXIdentifierConvertible + stdlib conformances. |
| Sources/AXComponentKit/AX Components/Dynamic Components/AXDynamicValue.swift | Made AXDynamicValue refine AXIdentifierConvertible. |
| Sources/AXComponentKit/AX Components/Dynamic Components/AXDynamicComponent.swift | Constrained dynamic values to AXIdentifierConvertible; made prefix public. |
| README.md | Replaced stub with full README + examples. |
| Package.swift | Bumped tools/platforms; added macro targets + swift-syntax dependency. |
| AXComponentKitSample/UITests/SettingsScreenTests.swift | Added Settings UI tests using new APIs. |
| AXComponentKitSample/UITests/SecondTabScreenTests.swift | Updated sample tests to async setUp + navigator APIs. |
| AXComponentKitSample/UITests/Screens+TestSupport/ShareScreen+TestSupport.swift | Added Share screen capability conformance. |
| AXComponentKitSample/UITests/Screens+TestSupport/SettingsScreen+TestSupport.swift | Added Settings screen capability conformance. |
| AXComponentKitSample/UITests/Screens+TestSupport/SettingsScreen+Navigator.swift | Added Settings→Profile navigator op. |
| AXComponentKitSample/UITests/Screens+TestSupport/SecondTabScreen+Navigator.swift | Updated navigator op to renamed navigate. |
| AXComponentKitSample/UITests/Screens+TestSupport/ProfileScreen+TestSupport.swift | Added dismissible conformance mapping. |
| AXComponentKitSample/UITests/Screens+TestSupport/ProfileScreen+Navigator.swift | Added profile save navigator op. |
| AXComponentKitSample/UITests/Screens+TestSupport/ItemDetailScreen+Navigator.swift | Added item detail → share navigator op. |
| AXComponentKitSample/UITests/Screens+TestSupport/FirstTabScreen+Navigator.swift | Updated First tab navigator to new tap/navigate API. |
| AXComponentKitSample/UITests/Screens+TestSupport/CategoryDetailScreen+Navigator.swift | Added category detail → item navigator op. |
| AXComponentKitSample/UITests/Screens+TestSupport/CatalogScreen+TestSupport.swift | Added Catalog screen tab capability conformance. |
| AXComponentKitSample/UITests/Screens+TestSupport/CatalogScreen+Navigator.swift | Added catalog → category navigator op. |
| AXComponentKitSample/UITests/FirstTabScreenTests.swift | Updated sample tests to async setUp + navigator APIs. |
| AXComponentKitSample/UITests/DeepNavigationTests.swift | Added deep navigation chain tests. |
| AXComponentKitSample/UITests/CatalogScreenTests.swift | Added catalog tests covering dynamic components. |
| AXComponentKitSample/UITests/Capabilities/RootTabBarNavigable.swift | Expanded sample tab capabilities (settings/catalog). |
| AXComponentKitSample/UITests/Capabilities/DismissibleScreen.swift | Added dismissible capability + navigator dismiss helper. |
| AXComponentKitSample/UITests/AXComponentKitSample.xctestplan | Added xctestplan for sample UI tests. |
| AXComponentKitSample/AXComponentKitSample/Views/Third Tab/SettingsView.swift | Added Settings SwiftUI view with automation identifiers. |
| AXComponentKitSample/AXComponentKitSample/Views/Third Tab/ProfileView.swift | Added Profile SwiftUI view with dynamic/static identifiers. |
| AXComponentKitSample/AXComponentKitSample/Views/Shared/ShareSheetView.swift | Added Share sheet view with automation identifiers. |
| AXComponentKitSample/AXComponentKitSample/Views/Fourth Tab/ItemDetailView.swift | Added Item detail view and identifiers. |
| AXComponentKitSample/AXComponentKitSample/Views/Fourth Tab/CategoryDetailView.swift | Added Category detail view with dynamic identifiers. |
| AXComponentKitSample/AXComponentKitSample/Views/Fourth Tab/CatalogView.swift | Added Catalog view with dynamic + scroll view identifiers. |
| AXComponentKitSample/AXComponentKitSample/Views/ContentView.swift | Expanded sample app to 4 tabs. |
| AXComponentKitSample/AXComponentKitSample/AXScreens/ShareScreen.swift | Added screen model using @AXScreen. |
| AXComponentKitSample/AXComponentKitSample/AXScreens/SettingsScreen.swift | Added screen model using @AXScreen. |
| AXComponentKitSample/AXComponentKitSample/AXScreens/SecondTabScreen.swift | Migrated screen model to @AXScreen. |
| AXComponentKitSample/AXComponentKitSample/AXScreens/ProfileScreen.swift | Added screen model using @AXScreen. |
| AXComponentKitSample/AXComponentKitSample/AXScreens/ItemDetailScreen.swift | Added screen model using @AXScreen. |
| AXComponentKitSample/AXComponentKitSample/AXScreens/FirstTabScreen.swift | Migrated screen model to @AXScreen. |
| AXComponentKitSample/AXComponentKitSample/AXScreens/DetailScreen.swift | Migrated screen model to @AXScreen. |
| AXComponentKitSample/AXComponentKitSample/AXScreens/CategoryDetailScreen.swift | Added screen model using @AXScreen. |
| AXComponentKitSample/AXComponentKitSample/AXScreens/Category.swift | Added sample dynamic value type (AXDynamicValue). |
| AXComponentKitSample/AXComponentKitSample/AXScreens/CatalogScreen.swift | Added screen model using @AXScreen. |
| AXComponentKitSample/AXComponentKitSample/AXComponentKitSampleApp.swift | Enabled .automationOptimized() at app root. |
| AXComponentKitSample/AXComponentKitSample.xcodeproj/xcshareddata/xcschemes/AXComponentKitSample.xcscheme | Updated scheme to use test plan. |
| AXComponentKitSample/AXComponentKitSample.xcodeproj/project.pbxproj | Updated project format + package/framework linkage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…component enhancements - Bump swift-tools-version to 6.0, minimum deployment to iOS 16 / macOS 13 - Full Swift 6 strict concurrency compliance (Sendable, @mainactor) - Add @AXScreen macro for automatic screenIdentifier synthesis - Introduce AXIdentifierConvertible protocol, collapsing 4× overload explosion - Refactor navigator: static .navigator property, rename performNavigation→navigate, add tap convenience - Add optional-value and prefixed automationComponent view modifiers for dynamic components - Add firstElement(anyOf:) and tapFirst(anyOf:) for prefix-based dynamic element queries - Make AXDynamicComponent.prefix public for downstream query use - Add navigator screen-appear logging via NSLog - Add animation suppression system for UIKit, Core Animation, and SwiftUI - Refactor AXFailure to avoid double failure output - Fix accessibility modifiers interfering with VoiceOver - Fix NSPredicate injection in tab query - Improve scroll gesture reliability - Remove deprecated XCTestCase async setUp bridge
- Add four-tab layout with catalog, profile, and settings screens - Add deep navigation test coverage (catalog → category → item detail) - Add capability protocols (DismissibleScreen, NavigationScreen) - Convert UI tests to xctestplan format - Demonstrate @AXScreen macro, animation suppression, and tab navigation
- Rewrite README with installation, quick start, animation suppression, and dynamic component sections - Document optional-value and prefixed automationComponent overloads in IntegratingWithViews - Document firstElement(anyOf:) and tapFirst(anyOf:) in WritingYourFirstTest - Update navigator documentation for static .navigator property and navigate() rename - Refresh Overview, ScreenModels, and CustomNavigatorOperations docc articles
…t interpolated macro identifiers - Add explicit `import Foundation` to AXScreenNavigator.swift instead of relying on transitive import from XCTest for NSLog availability - Add `segments.count == 1` guard in @AXScreen macro's extractIdentifier to fall back to auto-derived name instead of silently truncating interpolated string literals
8d2c9fd to
08a9be2
Compare
Review feedback responseThanks for the thorough review! Here's a breakdown of how we addressed each comment: Accepted (fixed in 08a9be2)
Not applicable — explained below
Also in this push
|
|
Reviewed top-to-bottom. The modernization is genuinely strong — net public surface is smaller and more coherent, the H1 —
|
…ards - Add firstElement(anyOf:prefix:) and tapFirst(anyOf:prefix:) overloads that mirror the writer-side automationComponent(_:value:prefix:) API, so prefixed identifiers are not silently missed by BEGINSWITH queries - Guard ExtensionMacro against emitting redundant AXScreen conformance when the type already conforms (check protocols.isEmpty) - Guard MemberMacro against emitting duplicate screenIdentifier when the struct already declares one manually
|
Joel Garrett (@Nitewriter) Thanks for the thorough review — both HIGH findings were valid and are fixed in 7328ff7. Inline replies on the specific files above. Procedural — sample-app validation: Agreed, will run the sample app build + UI tests and check those boxes before tagging. |
…case conversion - 7 tests for pascalCaseToKebabCase: simple, acronyms (UIKit, URLSession, AXScreen), single word, all-uppercase, already-lowercase - 6 tests for macro expansion: basic generation, custom identifier, interpolated string fallback, existing screenIdentifier skip, existing conformance skip, error on class - Dedicated Xcode scheme for running macro tests on macOS
…clear background Accidentally dropped during the AXIdentifierConvertible refactor. Without it, the screen identifier element relies on an undocumented SwiftUI heuristic to stay out of the VoiceOver tree.
Summary
Major modernization of AXComponentKit, bringing it to Swift 6.0 with full strict concurrency compliance, a new
@AXScreenmacro, enhanced dynamic component APIs, and comprehensive documentation.Changes
Core Library
swift-tools-versionto 6.0, minimum deployment to iOS 16 / macOS 13. Full strict concurrency (Sendable,@MainActor) compliance throughout.@AXScreenmacro: Auto-generatesscreenIdentifierfrom PascalCase struct names. Optional — manualAXScreenconformance still works.AXIdentifierConvertibleprotocol: Collapsed 4× generic overload explosion into a single protocol-based API.AXScreen.navigatorstatic property,performNavigation→navigaterename,tap()convenience methods..automationOptimized()view modifier andAXAutomation.suppressAnimationsIfNeeded()for UIKit — no-op in production.AXFailurerefactor: Avoids double failure output on assertion failures.XCTestCaseasync setUp bridge removed: Deprecated in favor of nativesetUp() async throws.Dynamic Component Enhancements (new in this PR)
automationComponent: When value isnil, no identifier is applied — useful for loading/placeholder states.automationComponent: Adds a custom prefix to distinguish elements sharing a component definition (e.g."featured-catalog-category_electronics").firstElement(anyOf:)/tapFirst(anyOf:): Query/tap the first element matching a dynamic component's prefix when the exact value is unknown at test time.AXDynamicComponent.prefixmade public: Enables downstream prefix-based queries.NSLogbreadcrumb on screen transitions for debugging.Sample App
DismissibleScreen,NavigationScreen).xctestplanformat.Documentation
Test plan
AXComponentKittarget builds for iOS SimulatorAXComponentKitTestSupporttarget builds for iOS Simulator