diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 0b5e5e7..606b746 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -20,7 +20,7 @@ jobs: uses: sersoft-gmbh/oss-common-actions/.github/workflows/swift-generate-and-publish-docs.yml@main with: os: ubuntu - swift-version: '5.9' + swift-version: '5.10' organisation: ${{ github.repository_owner }} repository: ${{ github.event.repository.name }} pages-branch: gh-pages diff --git a/.github/workflows/swift-test.yml b/.github/workflows/swift-test.yml index ff8f66f..f6d4d3b 100644 --- a/.github/workflows/swift-test.yml +++ b/.github/workflows/swift-test.yml @@ -12,7 +12,7 @@ permissions: jobs: variables: outputs: - max-supported-swift-version: '5.9' + max-supported-swift-version: '5.10' xcode-scheme: route-docs xcode-platform-version: latest fail-if-codecov-fails: true @@ -25,7 +25,7 @@ jobs: strategy: matrix: os: [ macOS, ubuntu ] - swift-version-offset: [ 0 ] + swift-version-offset: [ 0, 1 ] uses: sersoft-gmbh/oss-common-actions/.github/workflows/swift-test-spm.yml@main with: os: ${{ matrix.os }} @@ -45,7 +45,8 @@ jobs: # - iPadOS # - tvOS # - watchOS - swift-version-offset: [ 0 ] + # - visionOS + swift-version-offset: [ 0, 1 ] uses: sersoft-gmbh/oss-common-actions/.github/workflows/swift-test-xcode.yml@main with: xcode-scheme: ${{ needs.variables.outputs.xcode-scheme }} diff --git a/Package.swift b/Package.swift index 78d5865..929112b 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.9 +// swift-tools-version:5.10 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -8,9 +8,12 @@ let swiftSettings: Array = [ .enableUpcomingFeature("ExistentialAny"), .enableUpcomingFeature("BareSlashRegexLiterals"), .enableUpcomingFeature("DisableOutwardActorInference"), + .enableUpcomingFeature("IsolatedDefaultValues"), + .enableUpcomingFeature("DeprecateApplicationMain"), + .enableExperimentalFeature("StrictConcurrency"), + .enableExperimentalFeature("GlobalConcurrency"), // .enableExperimentalFeature("AccessLevelOnImport"), // .enableExperimentalFeature("VariadicGenerics"), -// .unsafeFlags(["-warn-concurrency"], .when(configuration: .debug)), ] let package = Package( @@ -27,8 +30,8 @@ let package = Package( dependencies: [ // Dependencies declare other packages that this package depends on. .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), - .package(url: "https://github.com/apple/swift-nio", from: "2.59.0"), - .package(url: "https://github.com/vapor/vapor", from: "4.84.0"), + .package(url: "https://github.com/apple/swift-nio", from: "2.64.0"), + .package(url: "https://github.com/vapor/vapor", from: "4.92.0"), .package(url: "https://github.com/vapor/leaf-kit", from: "1.10.0"), .package(url: "https://github.com/vapor/leaf", from: "4.2.0"), ], diff --git a/Package@swift-5.9.swift b/Package@swift-5.9.swift new file mode 100644 index 0000000..4ef2b81 --- /dev/null +++ b/Package@swift-5.9.swift @@ -0,0 +1,55 @@ +// swift-tools-version:5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let swiftSettings: Array = [ + .enableUpcomingFeature("ConciseMagicFile"), + .enableUpcomingFeature("ExistentialAny"), + .enableUpcomingFeature("BareSlashRegexLiterals"), + .enableUpcomingFeature("DisableOutwardActorInference"), + .enableExperimentalFeature("StrictConcurrency"), +// .enableExperimentalFeature("AccessLevelOnImport"), +// .enableExperimentalFeature("VariadicGenerics"), +] + +let package = Package( + name: "route-docs", + platforms: [ + .macOS(.v10_15), + ], + products: [ + // Products define the executables and libraries produced by a package, and make them visible to other packages. + .library( + name: "RouteDocs", + targets: ["RouteDocs"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), + .package(url: "https://github.com/apple/swift-nio", from: "2.59.0"), + .package(url: "https://github.com/vapor/vapor", from: "4.84.0"), + .package(url: "https://github.com/vapor/leaf-kit", from: "1.10.0"), + .package(url: "https://github.com/vapor/leaf", from: "4.2.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define 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: "RouteDocs", + dependencies: [ + .product(name: "NIOConcurrencyHelpers", package: "swift-nio"), + .product(name: "Vapor", package: "vapor"), + .product(name: "LeafKit", package: "leaf-kit"), + .product(name: "Leaf", package: "leaf"), + ], + resources: [ + .copy("DefaultDocsView"), + ], + swiftSettings: swiftSettings), + .testTarget( + name: "RouteDocsTests", + dependencies: ["RouteDocs"], + swiftSettings: swiftSettings), + ] +) diff --git a/Sources/RouteDocs/DocumentationDecoder.swift b/Sources/RouteDocs/DocumentationDecoder.swift index 60bdc44..5b2a9d6 100644 --- a/Sources/RouteDocs/DocumentationDecoder.swift +++ b/Sources/RouteDocs/DocumentationDecoder.swift @@ -59,6 +59,10 @@ public struct DocumentationObject: Sendable, Hashable, CustomStringConvertible { } } + public static func clearTypeCaches() { + DocumentationDecoder.Cache.clear() + } + public let type: Any.Type public fileprivate(set) var body: Body @@ -166,7 +170,7 @@ fileprivate struct DocumentationDecoder: Decoder { self.init(storage: .init(type: type), codingPath: .init(), userInfo: userInfo) } - func push(key: some CodingKey) -> DocumentationDecoder { + func pushKey(_ key: some CodingKey) -> DocumentationDecoder { .init(storage: storage, codingPath: codingPath + CollectionOfOne(key), userInfo: userInfo) } @@ -201,7 +205,7 @@ fileprivate struct DocumentationDecoder: Decoder { return result } try setType(type, for: key) - let result = try T(from: push(key: key)) + let result = try T(from: pushKey(key)) try cache(result) return result } @@ -283,7 +287,7 @@ extension DocumentationDecoder { } fileprivate enum Cache { - struct Entry { + struct Entry: @unchecked Sendable { let object: any Decodable let documentation: DocumentationObject } @@ -298,6 +302,10 @@ extension DocumentationDecoder { // We must use the doc's type here, otherwise we mix up optionals vs. non-optionals. storage.withLockedValue { $0[ObjectIdentifier(entry.documentation.type)] = entry } } + + static func clear() { + storage.withLockedValue { $0.removeAll() } + } } fileprivate final class TypeBuilder { @@ -445,15 +453,15 @@ extension DocumentationDecoder { func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer where NestedKey: CodingKey { - KeyedDecodingContainer(KeyedContainer(decoder: decoder.push(key: key))) + KeyedDecodingContainer(KeyedContainer(decoder: decoder.pushKey(key))) } func nestedUnkeyedContainer(forKey key: Key) throws -> any UnkeyedDecodingContainer { - UnkeyedContainer(decoder: decoder.push(key: key)) + UnkeyedContainer(decoder: decoder.pushKey(key)) } func superDecoder() throws -> any Decoder { decoder } - func superDecoder(forKey key: Key) throws -> any Decoder { decoder.push(key: key) } + func superDecoder(forKey key: Key) throws -> any Decoder { decoder.pushKey(key) } } fileprivate struct UnkeyedContainer: UnkeyedDecodingContainer { @@ -595,12 +603,12 @@ extension DocumentationDecoder { where NestedKey: CodingKey { defer { currentIndex += 1 } - return KeyedDecodingContainer(KeyedContainer(decoder: decoder.push(key: IndexKey(index: currentIndex)))) + return KeyedDecodingContainer(KeyedContainer(decoder: decoder.pushKey(IndexKey(index: currentIndex)))) } mutating func nestedUnkeyedContainer() throws -> any UnkeyedDecodingContainer { defer { currentIndex += 1 } - return UnkeyedContainer(decoder: decoder.push(key: IndexKey(index: currentIndex))) + return UnkeyedContainer(decoder: decoder.pushKey(IndexKey(index: currentIndex))) } mutating func superDecoder() throws -> any Decoder { decoder }