diff --git a/Package.swift b/Package.swift index ffaf733c7..2ea9dc3ac 100644 --- a/Package.swift +++ b/Package.swift @@ -62,17 +62,14 @@ let package = Package( // a module or a test suite. // Targets can depend on other targets in this package, and on products // in packages which this package depends on. - .target( - name: "CombineShim", - dependencies: [.product( - name: "OpenCombine", - package: "OpenCombine", - condition: .when(platforms: [.wasi, .linux]) - )] - ), .target( name: "TokamakCore", - dependencies: ["CombineShim"] + dependencies: [ + .product( + name: "OpenCombineShim", + package: "OpenCombine" + ), + ] ), .target( name: "TokamakShim", @@ -105,7 +102,13 @@ let package = Package( ), .target( name: "TokamakGTK", - dependencies: ["TokamakCore", "CGTK", "CGDK", "TokamakGTKCHelpers", "CombineShim"] + dependencies: [ + "TokamakCore", "CGTK", "CGDK", "TokamakGTKCHelpers", + .product( + name: "OpenCombineShim", + package: "OpenCombine" + ), + ] ), .target( name: "TokamakGTKDemo", @@ -135,15 +138,18 @@ let package = Package( .target( name: "TokamakDOM", dependencies: [ - "CombineShim", - "OpenCombineJS", "TokamakCore", "TokamakStaticHTML", + .product( + name: "OpenCombineShim", + package: "OpenCombine" + ), .product( name: "JavaScriptKit", package: "JavaScriptKit", condition: .when(platforms: [.wasi]) ), + "OpenCombineJS", ] ), .target( diff --git a/Sources/TokamakCore/App/App.swift b/Sources/TokamakCore/App/App.swift index 6a7d39941..7f0104549 100644 --- a/Sources/TokamakCore/App/App.swift +++ b/Sources/TokamakCore/App/App.swift @@ -15,7 +15,7 @@ // Created by Carson Katri on 7/16/20. // -import CombineShim +import OpenCombineShim /// Provides the ability to set the title of the Scene. public protocol _TitledApp { diff --git a/Sources/TokamakCore/App/AppStorage.swift b/Sources/TokamakCore/App/AppStorage.swift index 04ded2519..a9afa3190 100644 --- a/Sources/TokamakCore/App/AppStorage.swift +++ b/Sources/TokamakCore/App/AppStorage.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ // Created by Carson Katri on 7/16/20. // -import CombineShim +import OpenCombineShim @propertyWrapper public struct AppStorage: DynamicProperty { let provider: _StorageProvider? diff --git a/Sources/TokamakCore/App/Scenes/SceneStorage.swift b/Sources/TokamakCore/App/Scenes/SceneStorage.swift index 00c28706c..960308905 100644 --- a/Sources/TokamakCore/App/Scenes/SceneStorage.swift +++ b/Sources/TokamakCore/App/Scenes/SceneStorage.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ // Created by Carson Katri on 7/17/20. // -import CombineShim +import OpenCombineShim /// The renderer must specify a default `_StorageProvider` before any `SceneStorage` /// values are accessed. diff --git a/Sources/TokamakCore/App/_AnyApp.swift b/Sources/TokamakCore/App/_AnyApp.swift index 94fef4112..650f4ceb8 100644 --- a/Sources/TokamakCore/App/_AnyApp.swift +++ b/Sources/TokamakCore/App/_AnyApp.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ // Created by Carson Katri on 7/19/20. // -import CombineShim +import OpenCombineShim public struct _AnyApp: App { var app: Any diff --git a/Sources/TokamakCore/App/_StorageProvider.swift b/Sources/TokamakCore/App/_StorageProvider.swift index ac12e706a..3a27a2444 100644 --- a/Sources/TokamakCore/App/_StorageProvider.swift +++ b/Sources/TokamakCore/App/_StorageProvider.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ // Created by Carson Katri on 7/22/20. // -import CombineShim +import OpenCombineShim public protocol _StorageProvider { func store(key: String, value: Bool?) diff --git a/Sources/TokamakCore/Environment/EnvironmentObject.swift b/Sources/TokamakCore/Environment/EnvironmentObject.swift index e02d8c43f..7c4986cd3 100644 --- a/Sources/TokamakCore/Environment/EnvironmentObject.swift +++ b/Sources/TokamakCore/Environment/EnvironmentObject.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ // Created by Carson Katri on 7/7/20. // -import CombineShim +import OpenCombineShim @propertyWrapper public struct EnvironmentObject: DynamicProperty where ObjectType: ObservableObject diff --git a/Sources/TokamakCore/Environment/EnvironmentValues.swift b/Sources/TokamakCore/Environment/EnvironmentValues.swift index b13adbda5..1291c2c5f 100644 --- a/Sources/TokamakCore/Environment/EnvironmentValues.swift +++ b/Sources/TokamakCore/Environment/EnvironmentValues.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import CombineShim +import OpenCombineShim public struct EnvironmentValues: CustomStringConvertible { public var description: String { diff --git a/Sources/TokamakCore/MountedViews/MountedApp.swift b/Sources/TokamakCore/MountedViews/MountedApp.swift index 73bb90a77..078c4d40f 100644 --- a/Sources/TokamakCore/MountedViews/MountedApp.swift +++ b/Sources/TokamakCore/MountedViews/MountedApp.swift @@ -15,7 +15,7 @@ // Created by Carson Katri on 7/19/20. // -import CombineShim +import OpenCombineShim // This is very similar to `MountedCompositeView`. However, the `mountedBody` // is the computed content of the specified `Scene`, instead of having child diff --git a/Sources/TokamakCore/MountedViews/MountedCompositeElement.swift b/Sources/TokamakCore/MountedViews/MountedCompositeElement.swift index 85f81fa69..3fbc0ec58 100644 --- a/Sources/TokamakCore/MountedViews/MountedCompositeElement.swift +++ b/Sources/TokamakCore/MountedViews/MountedCompositeElement.swift @@ -1,4 +1,4 @@ -// Copyright 2018-2020 Tokamak contributors +// Copyright 2018-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ // Created by Carson Katri on 7/19/20. // -import CombineShim +import OpenCombineShim class MountedCompositeElement: MountedElement { let parentTarget: R.TargetType diff --git a/Sources/TokamakCore/MountedViews/MountedCompositeView.swift b/Sources/TokamakCore/MountedViews/MountedCompositeView.swift index cac366fee..9b3293be3 100644 --- a/Sources/TokamakCore/MountedViews/MountedCompositeView.swift +++ b/Sources/TokamakCore/MountedViews/MountedCompositeView.swift @@ -15,7 +15,7 @@ // Created by Max Desiatov on 03/12/2018. // -import CombineShim +import OpenCombineShim final class MountedCompositeView: MountedCompositeElement { override func mount( diff --git a/Sources/TokamakCore/Reflection/Layouts/FieldDescriptor.swift b/Sources/TokamakCore/Reflection/Layouts/FieldDescriptor.swift index 74c9feff9..4f238261b 100644 --- a/Sources/TokamakCore/Reflection/Layouts/FieldDescriptor.swift +++ b/Sources/TokamakCore/Reflection/Layouts/FieldDescriptor.swift @@ -30,8 +30,7 @@ func _getTypeByMangledNameInContext( _ nameLength: UInt, _ genericContext: UnsafeRawPointer?, _ genericArguments: UnsafeRawPointer? -) - -> Any.Type? +) -> Any.Type? /// https://github.com/apple/swift/blob/f2c42509628bed66bf5b8ee02fae778a2ba747a1/include/swift/Reflection/Records.h#L160 struct FieldDescriptor { diff --git a/Sources/TokamakCore/StackReconciler.swift b/Sources/TokamakCore/StackReconciler.swift index b14310443..8b2339394 100644 --- a/Sources/TokamakCore/StackReconciler.swift +++ b/Sources/TokamakCore/StackReconciler.swift @@ -15,7 +15,7 @@ // Created by Max Desiatov on 28/11/2018. // -import CombineShim +import OpenCombineShim /** A class that reconciles a "raw" tree of element values (such as `App`, `Scene` and `View`, all coming from `body` or `renderedBody` properties) with a tree of mounted element instances diff --git a/Sources/TokamakCore/State/ObservedObject.swift b/Sources/TokamakCore/State/ObservedObject.swift index c1a56f2cb..5268552d5 100644 --- a/Sources/TokamakCore/State/ObservedObject.swift +++ b/Sources/TokamakCore/State/ObservedObject.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -import CombineShim +import OpenCombineShim -public typealias ObservableObject = CombineShim.ObservableObject -public typealias Published = CombineShim.Published +public typealias ObservableObject = OpenCombineShim.ObservableObject +public typealias Published = OpenCombineShim.Published protocol ObservedProperty: DynamicProperty { var objectWillChange: AnyPublisher<(), Never> { get } diff --git a/Sources/TokamakCore/State/StateObject.swift b/Sources/TokamakCore/State/StateObject.swift index 51aef0a46..5f2a87c8d 100644 --- a/Sources/TokamakCore/State/StateObject.swift +++ b/Sources/TokamakCore/State/StateObject.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import CombineShim +import OpenCombineShim @propertyWrapper public struct StateObject: DynamicProperty { diff --git a/Sources/TokamakCore/Views/Containers/List/List+Init.swift b/Sources/TokamakCore/Views/Containers/List/List+Init.swift index 2c3e043b7..25f6d2447 100644 --- a/Sources/TokamakCore/Views/Containers/List/List+Init.swift +++ b/Sources/TokamakCore/Views/Containers/List/List+Init.swift @@ -31,7 +31,6 @@ public extension List { init( _ data: Data, - id: KeyPath, selection: Binding>?, @ViewBuilder rowContent: @escaping (Data.Element) -> RowContent diff --git a/Sources/TokamakDOM/App/App.swift b/Sources/TokamakDOM/App/App.swift index 75fec0513..d679d6fba 100644 --- a/Sources/TokamakDOM/App/App.swift +++ b/Sources/TokamakDOM/App/App.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,8 +15,8 @@ // Created by Carson Katri on 7/16/20. // -import CombineShim import JavaScriptKit +import OpenCombineShim import TokamakCore import TokamakStaticHTML diff --git a/Sources/TokamakDOM/App/ColorSchemeObserver.swift b/Sources/TokamakDOM/App/ColorSchemeObserver.swift index 3e8b92f64..475acc469 100644 --- a/Sources/TokamakDOM/App/ColorSchemeObserver.swift +++ b/Sources/TokamakDOM/App/ColorSchemeObserver.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import CombineShim import JavaScriptKit +import OpenCombineShim enum ColorSchemeObserver { static var publisher = CurrentValueSubject( diff --git a/Sources/TokamakDOM/App/ScenePhaseObserver.swift b/Sources/TokamakDOM/App/ScenePhaseObserver.swift index 05a48fe93..53b3446f0 100644 --- a/Sources/TokamakDOM/App/ScenePhaseObserver.swift +++ b/Sources/TokamakDOM/App/ScenePhaseObserver.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import CombineShim import JavaScriptKit +import OpenCombineShim enum ScenePhaseObserver { static var publisher = CurrentValueSubject(.active) diff --git a/Sources/TokamakDOM/Storage/LocalStorage.swift b/Sources/TokamakDOM/Storage/LocalStorage.swift index 4816b93b1..6967e5b7b 100644 --- a/Sources/TokamakDOM/Storage/LocalStorage.swift +++ b/Sources/TokamakDOM/Storage/LocalStorage.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,8 +15,8 @@ // Created by Carson Katri on 7/20/20. // -import CombineShim import JavaScriptKit +import OpenCombineShim import TokamakCore private let rootPublisher = ObservableObjectPublisher() diff --git a/Sources/TokamakDOM/Storage/SessionStorage.swift b/Sources/TokamakDOM/Storage/SessionStorage.swift index 8719ad51b..52108bfa9 100644 --- a/Sources/TokamakDOM/Storage/SessionStorage.swift +++ b/Sources/TokamakDOM/Storage/SessionStorage.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,8 +15,8 @@ // Created by Carson Katri on 7/20/20. // -import CombineShim import JavaScriptKit +import OpenCombineShim import TokamakCore private let sessionStorage = JSObject.global.sessionStorage.object! diff --git a/Sources/TokamakDOM/Storage/WebStorage.swift b/Sources/TokamakDOM/Storage/WebStorage.swift index 9d959ae7b..2daecf53f 100644 --- a/Sources/TokamakDOM/Storage/WebStorage.swift +++ b/Sources/TokamakDOM/Storage/WebStorage.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,8 +15,8 @@ // Created by Carson Katri on 7/21/20. // -import CombineShim import JavaScriptKit +import OpenCombineShim import TokamakCore protocol WebStorage { diff --git a/Sources/TokamakDemo/ButtonStyleDemo.swift b/Sources/TokamakDemo/ButtonStyleDemo.swift index 3c469a353..006ee9b3d 100644 --- a/Sources/TokamakDemo/ButtonStyleDemo.swift +++ b/Sources/TokamakDemo/ButtonStyleDemo.swift @@ -62,9 +62,9 @@ public struct ButtonStyleDemo: View { Text("Label").padding(.leading, 5) } }) - .buttonStyle( - PressedButtonStyle(pressedColor: Color.red) - ) + .buttonStyle( + PressedButtonStyle(pressedColor: Color.red) + ) } } } diff --git a/Sources/TokamakGTK/App/App.swift b/Sources/TokamakGTK/App/App.swift index fa000b4e1..1dc13e6de 100644 --- a/Sources/TokamakGTK/App/App.swift +++ b/Sources/TokamakGTK/App/App.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,8 +16,8 @@ // import CGTK -import CombineShim import Dispatch +import OpenCombineShim import TokamakCore public extension App { diff --git a/Sources/TokamakStaticHTML/App.swift b/Sources/TokamakStaticHTML/App.swift index 1f89423af..22b509099 100644 --- a/Sources/TokamakStaticHTML/App.swift +++ b/Sources/TokamakStaticHTML/App.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2020-2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ // Created by Carson Katri on 7/31/20. // -import CombineShim +import OpenCombineShim import TokamakCore public extension App { diff --git a/Sources/TokamakTestRenderer/App.swift b/Sources/TokamakTestRenderer/App.swift new file mode 100644 index 000000000..42738bef4 --- /dev/null +++ b/Sources/TokamakTestRenderer/App.swift @@ -0,0 +1,26 @@ +// Copyright 2021 Tokamak contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import OpenCombineShim +import TokamakCore + +public extension App { + static func _setTitle(_ title: String) {} + + static func _launch(_ app: Self, _ rootEnvironment: EnvironmentValues) {} + + var _phasePublisher: AnyPublisher { Empty().eraseToAnyPublisher() } + + var _colorSchemePublisher: AnyPublisher { Empty().eraseToAnyPublisher() } +} diff --git a/Sources/TokamakTestRenderer/TestRenderer.swift b/Sources/TokamakTestRenderer/TestRenderer.swift index 73c0f17ee..6ba72b141 100644 --- a/Sources/TokamakTestRenderer/TestRenderer.swift +++ b/Sources/TokamakTestRenderer/TestRenderer.swift @@ -29,6 +29,16 @@ public final class TestRenderer: Renderer { reconciler!.rootTarget } + public init(_ app: A) { + reconciler = StackReconciler( + app: app, + target: TestView(EmptyView()), + environment: .init(), + renderer: self, + scheduler: testScheduler + ) + } + public init(_ view: V) { reconciler = StackReconciler( view: view, diff --git a/Sources/CombineShim/CombineShim.swift b/Sources/TokamakTestRenderer/WindowGroup.swift similarity index 76% rename from Sources/CombineShim/CombineShim.swift rename to Sources/TokamakTestRenderer/WindowGroup.swift index d82f71560..825369413 100644 --- a/Sources/CombineShim/CombineShim.swift +++ b/Sources/TokamakTestRenderer/WindowGroup.swift @@ -1,4 +1,4 @@ -// Copyright 2020 Tokamak contributors +// Copyright 2021 Tokamak contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,8 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if canImport(Combine) -@_exported import Combine -#else -@_exported import OpenCombine -#endif +import TokamakCore + +extension WindowGroup: SceneDeferredToRenderer { + public var deferredBody: AnyView { + AnyView(content) + } +} diff --git a/Tests/TokamakTests/ReconcilerStressTests.swift b/Tests/TokamakTests/ReconcilerStressTests.swift new file mode 100644 index 000000000..00d20dfd6 --- /dev/null +++ b/Tests/TokamakTests/ReconcilerStressTests.swift @@ -0,0 +1,59 @@ +// Copyright 2021 Tokamak contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import TokamakTestRenderer +import XCTest + +@testable import TokamakCore + +private struct SpookyHanger: App { + var body: some Scene { + WindowGroup("Spooky Hanger") { + NavigationView { + List { + ForEach(["Item 1"], id: \.self) { childRow in + NavigationLink( + destination: Text(childRow) + ) { + Text(childRow) + } + } + } + } + } + } +} + +final class ReconcilerStressTests: XCTestCase { + func testSpookyHanger() { + let renderer = TestRenderer(SpookyHanger()) + let root = renderer.rootTarget + + return + + let list = root.subviews[0].subviews[0] + + XCTAssertTrue( + root.view + .view is NavigationView>>> + ) + + guard let link = list.subviews[0].view.view as? NavigationLink else { + XCTAssert(false, "navigation has no link") + return + } + + _NavigationLinkProxy(link).activate() + } +}