From 4d211af56316b310bee243af574b66a96d741727 Mon Sep 17 00:00:00 2001 From: filip-sakel <51793967+filip-sakel@users.noreply.github.com> Date: Mon, 8 Mar 2021 20:49:05 +0200 Subject: [PATCH] Add '_spi(TokamakCore)' to ideally internal public members. (#386) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `_spi(TokamakCore)` to the modules: 1. TokamakCore 2. TokamakDOM 3. TokamakGTK 4. TokamakStaticHTML The attribute is applied to: 1. All `View` bodies in TokamakCore — either primitive or regular like `Color` 2. `ViewDeferredToRenderer` bodies 4. `ParentView` `children` members 5. `View` modifiers (such as `_onMount(perform:)`) 6. Other members of types (like `Color._withScheme`, and `_AnyApp._launch`) The attribute semantics (from my brief testing) 1. It can only be applied to `public` declarations 2. It ensures that every SPI declaration is exposed only by other SPI declarations (i.e. `@_spi(Module) public enum A {}; public var a: A` is illegal) 3. Regularly importing a library prohibits clients from accessing SPI declarations that are not protocol witnesses (with an error). 4. Regularly importing a library "discourages" clients from accessing SPI protocol witnesses by hiding them from the autocompletion suggestions (i.e. users can still access `body` of `Text`, but autocompletion hides it). 5. For a declaration marked with `@_spi(Module)`, a client has to write `@_spi(Module) import Library` in order to normally access such SPI declarations. * Add '_spi(TokamakCore)' to ideally internal public members. * Remove `_spi` attribute on '_ConditionalContent'. * Remove spi from 'Path._PathBox', 'Font._Font', and '_TupleScene.body'. * Remove spi from types. * Remove trailing whitespace. * Apply spi to 'View' modifiers. * Add _spi imports. * Introduce 'PrimitiveView'. * Remove 'PrimitiveView' conformances outside of TokamakCore. * Fix `PrimitiveView` default implementation. * Remove "BubbleCore" references. --- Sources/TokamakCore/App/AppStorage.swift | 1 + Sources/TokamakCore/App/Scenes/WindowGroup.swift | 1 + .../TokamakCore/App/Scenes/_SceneModifier.swift | 1 + Sources/TokamakCore/App/_AnyApp.swift | 6 ++++++ Sources/TokamakCore/App/_AnyScene.swift | 1 + .../Modifiers/LifecycleModifier.swift | 2 ++ .../TokamakCore/Preferences/PreferenceKey.swift | 6 ------ Sources/TokamakCore/Shapes/Shape.swift | 6 +----- Sources/TokamakCore/State/TargetRef.swift | 1 + Sources/TokamakCore/Styles/ButtonStyle.swift | 5 +---- .../TokamakCore/Styles/NavigationLinkStyle.swift | 1 + Sources/TokamakCore/Tokens/Color.swift | 2 ++ Sources/TokamakCore/Views/AnyView.swift | 7 ++----- Sources/TokamakCore/Views/Buttons/Button.swift | 8 +++----- Sources/TokamakCore/Views/Buttons/Link.swift | 6 +----- .../Views/Containers/DisclosureGroup.swift | 6 +----- .../TokamakCore/Views/Containers/ForEach.swift | 8 +++----- Sources/TokamakCore/Views/Containers/Group.swift | 7 ++----- Sources/TokamakCore/Views/Containers/List.swift | 1 + .../Views/Containers/OutlineGroup.swift | 2 ++ .../TokamakCore/Views/Containers/Section.swift | 1 + .../TokamakCore/Views/Containers/TupleView.swift | 6 +----- Sources/TokamakCore/Views/Image.swift | 6 +----- .../Views/Layout/GeometryReader.swift | 6 +----- Sources/TokamakCore/Views/Layout/HStack.swift | 7 ++----- Sources/TokamakCore/Views/Layout/LazyHGrid.swift | 6 +----- Sources/TokamakCore/Views/Layout/LazyVGrid.swift | 6 +----- .../TokamakCore/Views/Layout/ScrollView.swift | 7 ++----- Sources/TokamakCore/Views/Layout/VStack.swift | 7 ++----- Sources/TokamakCore/Views/Layout/ZStack.swift | 7 ++----- .../Views/Navigation/NavigationLink.swift | 8 +++----- .../Views/Navigation/NavigationView.swift | 6 +----- Sources/TokamakCore/Views/Selectors/Picker.swift | 16 ++++++---------- Sources/TokamakCore/Views/Selectors/Slider.swift | 7 ++----- Sources/TokamakCore/Views/Selectors/Toggle.swift | 2 ++ Sources/TokamakCore/Views/Spacers/Divider.swift | 6 ++---- Sources/TokamakCore/Views/Spacers/Spacer.swift | 6 +----- Sources/TokamakCore/Views/Text/SecureField.swift | 7 ++----- Sources/TokamakCore/Views/Text/Text.swift | 6 +----- Sources/TokamakCore/Views/Text/TextEditor.swift | 6 +----- Sources/TokamakCore/Views/Text/TextField.swift | 7 ++----- Sources/TokamakCore/Views/View.swift | 15 +++++++++++++-- Sources/TokamakCore/Views/ViewBuilder.swift | 12 ++---------- Sources/TokamakDOM/DOMRef.swift | 2 +- Sources/TokamakDOM/DOMRenderer.swift | 2 +- Sources/TokamakDOM/Styles/ButtonStyle.swift | 1 + Sources/TokamakDOM/Views/Buttons/Button.swift | 1 + .../Views/Containers/DisclosureGroup.swift | 1 + Sources/TokamakDOM/Views/DynamicHTML.swift | 2 ++ .../TokamakDOM/Views/Layout/GeometryReader.swift | 3 ++- .../Views/Navigation/NavigationLink.swift | 1 + Sources/TokamakDOM/Views/Selectors/Picker.swift | 2 ++ Sources/TokamakDOM/Views/Selectors/Slider.swift | 1 + Sources/TokamakDOM/Views/Text/SecureField.swift | 1 + Sources/TokamakDOM/Views/Text/TextEditor.swift | 1 + Sources/TokamakDOM/Views/Text/TextField.swift | 1 + .../TokamakGTK/Modifiers/WidgetModifier.swift | 1 + Sources/TokamakGTK/Shapes/Shape.swift | 1 + Sources/TokamakGTK/Tokens/BuiltinColors.swift | 2 +- Sources/TokamakGTK/Views/List.swift | 1 + Sources/TokamakGTK/Views/NavigationView.swift | 2 ++ Sources/TokamakGTK/Views/ScrollView.swift | 1 + Sources/TokamakGTK/Views/Stack.swift | 2 ++ Sources/TokamakGTK/Views/TextField.swift | 2 ++ .../Modifiers/ModifiedContent.swift | 1 + Sources/TokamakStaticHTML/Shapes/Path.swift | 1 + .../TokamakStaticHTML/Shapes/_ShapeView.swift | 1 + .../TokamakStaticHTML/Tokens/BuiltinColors.swift | 2 +- .../TokamakStaticHTML/Views/Buttons/Link.swift | 1 + .../Views/Containers/List.swift | 2 +- Sources/TokamakStaticHTML/Views/HTML.swift | 2 ++ .../TokamakStaticHTML/Views/Images/Image.swift | 1 + .../TokamakStaticHTML/Views/Layout/HStack.swift | 1 + .../Views/Layout/LazyHGrid.swift | 1 + .../Views/Layout/LazyVGrid.swift | 1 + .../Views/Layout/ScrollView.swift | 1 + .../TokamakStaticHTML/Views/Layout/VStack.swift | 1 + .../TokamakStaticHTML/Views/Layout/ZStack.swift | 1 + .../Views/Navigation/NavigationView.swift | 1 + .../Views/Spacers/Divider.swift | 2 +- .../TokamakStaticHTML/Views/Spacers/Spacer.swift | 1 + Tests/TokamakTests/ReconcilerTests.swift | 2 +- 82 files changed, 131 insertions(+), 164 deletions(-) diff --git a/Sources/TokamakCore/App/AppStorage.swift b/Sources/TokamakCore/App/AppStorage.swift index eb3b0dfa4..04ded2519 100644 --- a/Sources/TokamakCore/App/AppStorage.swift +++ b/Sources/TokamakCore/App/AppStorage.swift @@ -173,6 +173,7 @@ struct DefaultAppStorageEnvironmentKey: EnvironmentKey { } public extension EnvironmentValues { + @_spi(TokamakCore) var _defaultAppStorage: _StorageProvider? { get { self[DefaultAppStorageEnvironmentKey.self] diff --git a/Sources/TokamakCore/App/Scenes/WindowGroup.swift b/Sources/TokamakCore/App/Scenes/WindowGroup.swift index f3e4192bd..cd2d5c12a 100644 --- a/Sources/TokamakCore/App/Scenes/WindowGroup.swift +++ b/Sources/TokamakCore/App/Scenes/WindowGroup.swift @@ -63,6 +63,7 @@ public struct WindowGroup: Scene, TitledScene where Content: View { self.content = content() } + @_spi(TokamakCore) public var body: Never { neverScene("WindowGroup") } diff --git a/Sources/TokamakCore/App/Scenes/_SceneModifier.swift b/Sources/TokamakCore/App/Scenes/_SceneModifier.swift index b9030669e..555c3598a 100644 --- a/Sources/TokamakCore/App/Scenes/_SceneModifier.swift +++ b/Sources/TokamakCore/App/Scenes/_SceneModifier.swift @@ -25,6 +25,7 @@ public struct _SceneModifier_Content: Scene where Modifier: _SceneModi public let modifier: Modifier public let scene: _AnyScene + @_spi(TokamakCore) public var body: Never { neverScene("_SceneModifier_Content") } diff --git a/Sources/TokamakCore/App/_AnyApp.swift b/Sources/TokamakCore/App/_AnyApp.swift index 488cf2f2a..94fef4112 100644 --- a/Sources/TokamakCore/App/_AnyApp.swift +++ b/Sources/TokamakCore/App/_AnyApp.swift @@ -31,26 +31,32 @@ public struct _AnyApp: App { bodyType = A.Body.self } + @_spi(TokamakCore) public var body: Never { neverScene("_AnyApp") } + @_spi(TokamakCore) public init() { fatalError("`_AnyApp` cannot be initialized without an underlying `App` type.") } + @_spi(TokamakCore) public static func _launch(_ app: Self, _ rootEnvironment: EnvironmentValues) { fatalError("`_AnyApp` cannot be launched. Access underlying `app` value.") } + @_spi(TokamakCore) public static func _setTitle(_ title: String) { fatalError("`title` cannot be set for `AnyApp`. Access underlying `app` value.") } + @_spi(TokamakCore) public var _phasePublisher: AnyPublisher { fatalError("`_AnyApp` cannot monitor scenePhase. Access underlying `app` value.") } + @_spi(TokamakCore) public var _colorSchemePublisher: AnyPublisher { fatalError("`_AnyApp` cannot monitor colorScheme. Access underlying `app` value.") } diff --git a/Sources/TokamakCore/App/_AnyScene.swift b/Sources/TokamakCore/App/_AnyScene.swift index 59156bdbb..0a48557ff 100644 --- a/Sources/TokamakCore/App/_AnyScene.swift +++ b/Sources/TokamakCore/App/_AnyScene.swift @@ -66,6 +66,7 @@ public struct _AnyScene: Scene { } } + @_spi(TokamakCore) public var body: Never { neverScene("_AnyScene") } diff --git a/Sources/TokamakCore/Modifiers/LifecycleModifier.swift b/Sources/TokamakCore/Modifiers/LifecycleModifier.swift index aeda09b2b..5653a550a 100644 --- a/Sources/TokamakCore/Modifiers/LifecycleModifier.swift +++ b/Sources/TokamakCore/Modifiers/LifecycleModifier.swift @@ -14,10 +14,12 @@ // FIXME: these should have standalone implementations public extension View { + @_spi(TokamakCore) func _onMount(perform action: (() -> ())? = nil) -> some View { modifier(_AppearanceActionModifier(appear: action)) } + @_spi(TokamakCore) func _onUnmount(perform action: (() -> ())? = nil) -> some View { modifier(_AppearanceActionModifier(disappear: action)) } diff --git a/Sources/TokamakCore/Preferences/PreferenceKey.swift b/Sources/TokamakCore/Preferences/PreferenceKey.swift index 55962a2fb..d67845218 100644 --- a/Sources/TokamakCore/Preferences/PreferenceKey.swift +++ b/Sources/TokamakCore/Preferences/PreferenceKey.swift @@ -96,12 +96,6 @@ public protocol _PreferenceWritingModifierProtocol: ViewModifier func body(_ content: Self.Content, with preferenceStore: inout _PreferenceStore) -> AnyView } -public extension _PreferenceWritingViewProtocol where Self: View { - var body: Never { - neverBody(String(describing: Self.self)) - } -} - public extension _PreferenceWritingModifierProtocol { func body(content: Content) -> AnyView { content.view diff --git a/Sources/TokamakCore/Shapes/Shape.swift b/Sources/TokamakCore/Shapes/Shape.swift index 3f72340d0..214efdf51 100644 --- a/Sources/TokamakCore/Shapes/Shape.swift +++ b/Sources/TokamakCore/Shapes/Shape.swift @@ -46,7 +46,7 @@ public struct FillStyle: Equatable, ShapeStyle { } } -public struct _ShapeView: View where Content: Shape, Style: ShapeStyle { +public struct _ShapeView: PrimitiveView where Content: Shape, Style: ShapeStyle { @Environment(\.self) public var environment @Environment(\.foregroundColor) public var foregroundColor public var shape: Content @@ -58,10 +58,6 @@ public struct _ShapeView: View where Content: Shape, Style: Shap self.style = style self.fillStyle = fillStyle } - - public var body: Never { - neverBody("_ShapeView") - } } public extension Shape { diff --git a/Sources/TokamakCore/State/TargetRef.swift b/Sources/TokamakCore/State/TargetRef.swift index 9b124a867..f333b1139 100644 --- a/Sources/TokamakCore/State/TargetRef.swift +++ b/Sources/TokamakCore/State/TargetRef.swift @@ -33,6 +33,7 @@ public struct _TargetRef: View, TargetRefType { public extension View { /** Allows capturing target instance of aclosest descendant host view. The resulting instance is written to a given `binding`. */ + @_spi(TokamakCore) func _targetRef(_ binding: Binding) -> _TargetRef { .init(binding: binding, view: self) } diff --git a/Sources/TokamakCore/Styles/ButtonStyle.swift b/Sources/TokamakCore/Styles/ButtonStyle.swift index feab28f70..d3826e9d8 100644 --- a/Sources/TokamakCore/Styles/ButtonStyle.swift +++ b/Sources/TokamakCore/Styles/ButtonStyle.swift @@ -15,11 +15,8 @@ // Created by Gene Z. Ragan on 07/22/2020. public struct ButtonStyleConfiguration { - public struct Label: View { + public struct Label: PrimitiveView { let content: AnyView - public var body: Never { - neverBody("ButtonStyleConfiguration.Label") - } } public let label: Label diff --git a/Sources/TokamakCore/Styles/NavigationLinkStyle.swift b/Sources/TokamakCore/Styles/NavigationLinkStyle.swift index aef322fdb..f26bac3b0 100644 --- a/Sources/TokamakCore/Styles/NavigationLinkStyle.swift +++ b/Sources/TokamakCore/Styles/NavigationLinkStyle.swift @@ -68,6 +68,7 @@ extension EnvironmentValues { } public extension View { + @_spi(TokamakCore) func _navigationLinkStyle(_ style: S) -> some View { environment(\._navigationLinkStyle, _AnyNavigationLinkStyle(style)) } diff --git a/Sources/TokamakCore/Tokens/Color.swift b/Sources/TokamakCore/Tokens/Color.swift index f0e942c02..f36dd689c 100644 --- a/Sources/TokamakCore/Tokens/Color.swift +++ b/Sources/TokamakCore/Tokens/Color.swift @@ -241,6 +241,7 @@ public struct Color: Hashable, Equatable { } /// Create a `Color` dependent on the current `ColorScheme`. + @_spi(TokamakCore) public static func _withScheme(_ resolver: @escaping (ColorScheme) -> Self) -> Self { .init(_EnvironmentDependentColorBox { resolver($0.colorScheme) @@ -344,6 +345,7 @@ public extension Color { extension Color: ShapeStyle {} extension Color: View { + @_spi(TokamakCore) public var body: some View { _ShapeView(shape: Rectangle(), style: self) } diff --git a/Sources/TokamakCore/Views/AnyView.swift b/Sources/TokamakCore/Views/AnyView.swift index 13e5a9606..3d0cb6db3 100644 --- a/Sources/TokamakCore/Views/AnyView.swift +++ b/Sources/TokamakCore/Views/AnyView.swift @@ -16,7 +16,7 @@ // /// A type-erased view. -public struct AnyView: View { +public struct AnyView: PrimitiveView { /// The type of the underlying `view`. let type: Any.Type @@ -67,10 +67,6 @@ public struct AnyView: View { } } } - - public var body: Never { - neverBody("AnyView") - } } public func mapAnyView(_ anyView: AnyView, transform: (V) -> T) -> T? { @@ -80,6 +76,7 @@ public func mapAnyView(_ anyView: AnyView, transform: (V) -> T) -> T? { } extension AnyView: ParentView { + @_spi(TokamakCore) public var children: [AnyView] { (view as? ParentView)?.children ?? [] } diff --git a/Sources/TokamakCore/Views/Buttons/Button.swift b/Sources/TokamakCore/Views/Buttons/Button.swift index eaf5136e8..f5800731a 100644 --- a/Sources/TokamakCore/Views/Buttons/Button.swift +++ b/Sources/TokamakCore/Views/Buttons/Button.swift @@ -42,12 +42,13 @@ public struct Button