From 328134d7644b5ac2c71b1db273b6430071be63f9 Mon Sep 17 00:00:00 2001 From: Brett-Best Date: Wed, 29 May 2024 23:05:53 +1000 Subject: [PATCH 1/8] feat(spm): enabled upcoming and experimental feature swift settings for package --- Package.swift | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Package.swift b/Package.swift index f7f36a4..a6d0eb8 100644 --- a/Package.swift +++ b/Package.swift @@ -135,6 +135,37 @@ let package = Package( ] ) +// Use https://www.swift.org/swift-evolution/ to see details of the upcoming/experimental features +let upcomingFeatureSwiftSettings: [SwiftSetting] = [ + "ConciseMagicFile", // SE-0274 + "ForwardTrailingClosures", // SE-0286 + "ExistentialAny", // SE-0335 + "BareSlashRegexLiterals", // SE-0354 + "ImportObjcForwardDeclarations", // SE-0384 + "DeprecateApplicationMain", // SE-0383 + "DisableOutwardActorInference", // SE-0401 + "IsolatedDefaultValues", // SE-0411 + "GlobalConcurrency" // SE-0412 +].map { + .enableUpcomingFeature($0) +} + +let experimentalFeatureSwiftSettings: [SwiftSetting] = [ + "AccessLevelOnImport", // SE-0409 + "StrictConcurrency" // SE-0412 +].map { + .enableExperimentalFeature($0) +} + +package.targets.forEach { target in + guard target.name != "XCStringsToolPlugin" else { + return /// Plugins don't support setting `swiftSettings` + } + + let swiftSettings = target.swiftSettings ?? [] + target.swiftSettings = swiftSettings + upcomingFeatureSwiftSettings + experimentalFeatureSwiftSettings +} + // https://swiftpackageindex.com/swiftpackageindex/spimanifest/0.19.0/documentation/spimanifest/validation // On CI, we want to validate the manifest, but nobody else needs that. if ProcessInfo.processInfo.environment.keys.contains("VALIDATE_SPI_MANIFEST") { From 1a7ee6fb78dc90e2376b6d7785beee338c68b38f Mon Sep 17 00:00:00 2001 From: Brett-Best Date: Wed, 29 May 2024 23:06:35 +1000 Subject: [PATCH 2/8] feature(warnings): fixed a bunch of strict concurrency errors and use `#filePath` instead of `#file` --- Sources/StringCatalog/Types/StringExtractionState.swift | 2 +- Sources/StringCatalog/Types/StringLanguage.swift | 2 +- Sources/StringCatalog/Types/StringUnitState.swift | 2 +- Sources/StringCatalog/Types/StringVariations.swift | 4 ++-- Sources/StringExtractor/ExtractionError.swift | 2 +- Sources/xcstrings-tool/XCStringsTool.swift | 2 +- Tests/XCStringsToolTests/FixtureTestCase.swift | 2 +- Tests/XCStringsToolTests/GenerateTests.swift | 5 +++-- 8 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Sources/StringCatalog/Types/StringExtractionState.swift b/Sources/StringCatalog/Types/StringExtractionState.swift index a69840d..a4b0f60 100644 --- a/Sources/StringCatalog/Types/StringExtractionState.swift +++ b/Sources/StringCatalog/Types/StringExtractionState.swift @@ -1,6 +1,6 @@ import Foundation -public struct StringExtractionState: Codable, Hashable, RawRepresentable, ExpressibleByStringLiteral { +public struct StringExtractionState: Codable, Hashable, RawRepresentable, ExpressibleByStringLiteral, Sendable { public let rawValue: String public init(rawValue: String) { diff --git a/Sources/StringCatalog/Types/StringLanguage.swift b/Sources/StringCatalog/Types/StringLanguage.swift index 06b6f18..a00b0ef 100644 --- a/Sources/StringCatalog/Types/StringLanguage.swift +++ b/Sources/StringCatalog/Types/StringLanguage.swift @@ -1,6 +1,6 @@ import Foundation -public struct StringLanguage: Codable, Hashable, RawRepresentable, ExpressibleByStringLiteral, CodingKeyRepresentable { +public struct StringLanguage: Codable, Hashable, RawRepresentable, ExpressibleByStringLiteral, CodingKeyRepresentable, Sendable { public let rawValue: String public init(rawValue: String) { diff --git a/Sources/StringCatalog/Types/StringUnitState.swift b/Sources/StringCatalog/Types/StringUnitState.swift index decbf8d..931b8e8 100644 --- a/Sources/StringCatalog/Types/StringUnitState.swift +++ b/Sources/StringCatalog/Types/StringUnitState.swift @@ -1,6 +1,6 @@ import Foundation -public struct StringUnitState: Codable, Hashable, RawRepresentable, ExpressibleByStringLiteral { +public struct StringUnitState: Codable, Hashable, RawRepresentable, ExpressibleByStringLiteral, Sendable { public let rawValue: String public init(rawValue: String) { diff --git a/Sources/StringCatalog/Types/StringVariations.swift b/Sources/StringCatalog/Types/StringVariations.swift index a1c95b5..e3434d3 100644 --- a/Sources/StringCatalog/Types/StringVariations.swift +++ b/Sources/StringCatalog/Types/StringVariations.swift @@ -11,7 +11,7 @@ public struct StringVariations: Codable { } extension StringVariations { - public struct DeviceKey: Codable, Hashable, RawRepresentable, ExpressibleByStringLiteral, CodingKeyRepresentable { + public struct DeviceKey: Codable, Hashable, RawRepresentable, ExpressibleByStringLiteral, CodingKeyRepresentable, Sendable { public let rawValue: String public init(rawValue: String) { @@ -32,7 +32,7 @@ extension StringVariations { public static let other = Self(rawValue: "other") } - public struct PluralKey: Codable, Hashable, RawRepresentable, ExpressibleByStringLiteral, CodingKeyRepresentable { + public struct PluralKey: Codable, Hashable, RawRepresentable, ExpressibleByStringLiteral, CodingKeyRepresentable, Sendable { public let rawValue: String public init(rawValue: String) { diff --git a/Sources/StringExtractor/ExtractionError.swift b/Sources/StringExtractor/ExtractionError.swift index 0611851..d2f709f 100644 --- a/Sources/StringExtractor/ExtractionError.swift +++ b/Sources/StringExtractor/ExtractionError.swift @@ -1,7 +1,7 @@ import Foundation public enum ExtractionError: Error { - public struct Context { + public struct Context: Codable, Sendable { /// The key of the localization being parsed public let key: String diff --git a/Sources/xcstrings-tool/XCStringsTool.swift b/Sources/xcstrings-tool/XCStringsTool.swift index 2299f89..a89f16b 100644 --- a/Sources/xcstrings-tool/XCStringsTool.swift +++ b/Sources/xcstrings-tool/XCStringsTool.swift @@ -3,7 +3,7 @@ import XCStringsToolConstants @main struct XCStringsTool: ParsableCommand { - static var configuration = CommandConfiguration( + static let configuration = CommandConfiguration( commandName: "xcstrings-tool", abstract: "Generates Swift code from String Catalogs (.xcstrings files)", version: version, diff --git a/Tests/XCStringsToolTests/FixtureTestCase.swift b/Tests/XCStringsToolTests/FixtureTestCase.swift index 12a2cf6..e257af0 100644 --- a/Tests/XCStringsToolTests/FixtureTestCase.swift +++ b/Tests/XCStringsToolTests/FixtureTestCase.swift @@ -11,7 +11,7 @@ class FixtureTestCase: XCTestCase { fixtures = try XCTUnwrap(bundle.urls(forResourcesWithExtension: "xcstrings", subdirectory: "__Fixtures__")) } - func eachFixture(_ test: (URL) throws -> Void) throws { + @MainActor func eachFixture(_ test: (URL) throws -> Void) throws { for fileURL in fixtures { try XCTContext.runActivity(named: fileURL.lastPathComponent) { activity in do { diff --git a/Tests/XCStringsToolTests/GenerateTests.swift b/Tests/XCStringsToolTests/GenerateTests.swift index 35cce08..ea6bedd 100644 --- a/Tests/XCStringsToolTests/GenerateTests.swift +++ b/Tests/XCStringsToolTests/GenerateTests.swift @@ -4,7 +4,7 @@ import SnapshotTesting import XCTest final class GenerateTests: FixtureTestCase { - func testGenerate() throws { + @MainActor func testGenerate() throws { try eachFixture { inputURL in if !inputURL.lastPathComponent.hasPrefix("!") { try snapshot(for: inputURL) @@ -79,7 +79,7 @@ private extension GenerateTests { func assertError( for inputURL: URL, localizedDescription expected: String, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { XCTAssertThrowsError(try run(for: inputURL), file: file, line: line) { error in @@ -106,6 +106,7 @@ private extension GenerateTests { // Cleanup any temporary output addTeardownBlock { + let fileManager = FileManager.default /// Needed because `FileManager` is not `Sendable` if fileManager.fileExists(atPath: outputURL.path()) { try? fileManager.removeItem(at: outputURL) } From 27a36ecd9fde9d01122da67292616802a64c26a7 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Wed, 29 May 2024 23:35:36 +0200 Subject: [PATCH 3/8] Fix indentation (4 spaces) --- Sources/StringExtractor/ExtractionError.swift | 2 +- Tests/XCStringsToolTests/FixtureTestCase.swift | 2 +- Tests/XCStringsToolTests/GenerateTests.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/StringExtractor/ExtractionError.swift b/Sources/StringExtractor/ExtractionError.swift index d2f709f..086e945 100644 --- a/Sources/StringExtractor/ExtractionError.swift +++ b/Sources/StringExtractor/ExtractionError.swift @@ -1,7 +1,7 @@ import Foundation public enum ExtractionError: Error { - public struct Context: Codable, Sendable { + public struct Context: Codable, Sendable { /// The key of the localization being parsed public let key: String diff --git a/Tests/XCStringsToolTests/FixtureTestCase.swift b/Tests/XCStringsToolTests/FixtureTestCase.swift index e257af0..8ca5659 100644 --- a/Tests/XCStringsToolTests/FixtureTestCase.swift +++ b/Tests/XCStringsToolTests/FixtureTestCase.swift @@ -11,7 +11,7 @@ class FixtureTestCase: XCTestCase { fixtures = try XCTUnwrap(bundle.urls(forResourcesWithExtension: "xcstrings", subdirectory: "__Fixtures__")) } - @MainActor func eachFixture(_ test: (URL) throws -> Void) throws { + @MainActor func eachFixture(_ test: (URL) throws -> Void) throws { for fileURL in fixtures { try XCTContext.runActivity(named: fileURL.lastPathComponent) { activity in do { diff --git a/Tests/XCStringsToolTests/GenerateTests.swift b/Tests/XCStringsToolTests/GenerateTests.swift index ea6bedd..d1350de 100644 --- a/Tests/XCStringsToolTests/GenerateTests.swift +++ b/Tests/XCStringsToolTests/GenerateTests.swift @@ -4,7 +4,7 @@ import SnapshotTesting import XCTest final class GenerateTests: FixtureTestCase { - @MainActor func testGenerate() throws { + @MainActor func testGenerate() throws { try eachFixture { inputURL in if !inputURL.lastPathComponent.hasPrefix("!") { try snapshot(for: inputURL) From 979b07209a71ef66c7d4b6d27036586f4d11a8e4 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Wed, 29 May 2024 23:35:47 +0200 Subject: [PATCH 4/8] Comment formatting --- Package.swift | 2 +- Tests/XCStringsToolTests/GenerateTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index a6d0eb8..cefb79d 100644 --- a/Package.swift +++ b/Package.swift @@ -159,7 +159,7 @@ let experimentalFeatureSwiftSettings: [SwiftSetting] = [ package.targets.forEach { target in guard target.name != "XCStringsToolPlugin" else { - return /// Plugins don't support setting `swiftSettings` + return // Plugins don't support setting `swiftSettings` } let swiftSettings = target.swiftSettings ?? [] diff --git a/Tests/XCStringsToolTests/GenerateTests.swift b/Tests/XCStringsToolTests/GenerateTests.swift index d1350de..e23502e 100644 --- a/Tests/XCStringsToolTests/GenerateTests.swift +++ b/Tests/XCStringsToolTests/GenerateTests.swift @@ -106,7 +106,7 @@ private extension GenerateTests { // Cleanup any temporary output addTeardownBlock { - let fileManager = FileManager.default /// Needed because `FileManager` is not `Sendable` + let fileManager = FileManager.default // Needed because `FileManager` is not `Sendable` if fileManager.fileExists(atPath: outputURL.path()) { try? fileManager.removeItem(at: outputURL) } From 51d5c17360e8374090d2946c295a57ee11a1959e Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Wed, 29 May 2024 23:36:05 +0200 Subject: [PATCH 5/8] Remove redundant Codable conformance --- Sources/StringExtractor/ExtractionError.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/StringExtractor/ExtractionError.swift b/Sources/StringExtractor/ExtractionError.swift index 086e945..034b52c 100644 --- a/Sources/StringExtractor/ExtractionError.swift +++ b/Sources/StringExtractor/ExtractionError.swift @@ -1,7 +1,7 @@ import Foundation public enum ExtractionError: Error { - public struct Context: Codable, Sendable { + public struct Context: Sendable { /// The key of the localization being parsed public let key: String From a56ceb8b5564359f4d037f962ad700672a4c2908 Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Wed, 29 May 2024 23:47:13 +0200 Subject: [PATCH 6/8] Move @MainActor annotations to class in tests --- Tests/XCStringsToolTests/FixtureTestCase.swift | 3 ++- Tests/XCStringsToolTests/GenerateTests.swift | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Tests/XCStringsToolTests/FixtureTestCase.swift b/Tests/XCStringsToolTests/FixtureTestCase.swift index 8ca5659..29c77cd 100644 --- a/Tests/XCStringsToolTests/FixtureTestCase.swift +++ b/Tests/XCStringsToolTests/FixtureTestCase.swift @@ -1,6 +1,7 @@ import Foundation import XCTest +@MainActor class FixtureTestCase: XCTestCase { var fixtures: [URL]! @@ -11,7 +12,7 @@ class FixtureTestCase: XCTestCase { fixtures = try XCTUnwrap(bundle.urls(forResourcesWithExtension: "xcstrings", subdirectory: "__Fixtures__")) } - @MainActor func eachFixture(_ test: (URL) throws -> Void) throws { + func eachFixture(_ test: (URL) throws -> Void) throws { for fileURL in fixtures { try XCTContext.runActivity(named: fileURL.lastPathComponent) { activity in do { diff --git a/Tests/XCStringsToolTests/GenerateTests.swift b/Tests/XCStringsToolTests/GenerateTests.swift index e23502e..6625851 100644 --- a/Tests/XCStringsToolTests/GenerateTests.swift +++ b/Tests/XCStringsToolTests/GenerateTests.swift @@ -3,8 +3,9 @@ import SnapshotTesting @testable import xcstrings_tool import XCTest +@MainActor final class GenerateTests: FixtureTestCase { - @MainActor func testGenerate() throws { + func testGenerate() throws { try eachFixture { inputURL in if !inputURL.lastPathComponent.hasPrefix("!") { try snapshot(for: inputURL) From 63f37a0ac2c6351b6b46658f1fbc14ed1a90ee2f Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Thu, 30 May 2024 00:09:43 +0200 Subject: [PATCH 7/8] Make sourceCode property a static var --- Tests/XCStringsToolTests/GenerateTests.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/XCStringsToolTests/GenerateTests.swift b/Tests/XCStringsToolTests/GenerateTests.swift index 6625851..922e768 100644 --- a/Tests/XCStringsToolTests/GenerateTests.swift +++ b/Tests/XCStringsToolTests/GenerateTests.swift @@ -139,5 +139,7 @@ extension URL { extension Snapshotting where Value == String, Format == String { /// A snapshot strategy for comparing Swift Source Code based on equality. - public static let sourceCode = Snapshotting(pathExtension: "swift", diffing: .lines) + public static var sourceCode: Snapshotting { + Snapshotting(pathExtension: "swift", diffing: .lines) + } } From 09b5f50418adbd4a97c2db3f4e2ace68e32a137d Mon Sep 17 00:00:00 2001 From: Liam Nichols Date: Thu, 30 May 2024 00:09:52 +0200 Subject: [PATCH 8/8] Revert "Move @MainActor annotations to class in tests" This reverts commit a56ceb8b5564359f4d037f962ad700672a4c2908. --- Tests/XCStringsToolTests/FixtureTestCase.swift | 3 +-- Tests/XCStringsToolTests/GenerateTests.swift | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Tests/XCStringsToolTests/FixtureTestCase.swift b/Tests/XCStringsToolTests/FixtureTestCase.swift index 29c77cd..8ca5659 100644 --- a/Tests/XCStringsToolTests/FixtureTestCase.swift +++ b/Tests/XCStringsToolTests/FixtureTestCase.swift @@ -1,7 +1,6 @@ import Foundation import XCTest -@MainActor class FixtureTestCase: XCTestCase { var fixtures: [URL]! @@ -12,7 +11,7 @@ class FixtureTestCase: XCTestCase { fixtures = try XCTUnwrap(bundle.urls(forResourcesWithExtension: "xcstrings", subdirectory: "__Fixtures__")) } - func eachFixture(_ test: (URL) throws -> Void) throws { + @MainActor func eachFixture(_ test: (URL) throws -> Void) throws { for fileURL in fixtures { try XCTContext.runActivity(named: fileURL.lastPathComponent) { activity in do { diff --git a/Tests/XCStringsToolTests/GenerateTests.swift b/Tests/XCStringsToolTests/GenerateTests.swift index 922e768..70d7f4d 100644 --- a/Tests/XCStringsToolTests/GenerateTests.swift +++ b/Tests/XCStringsToolTests/GenerateTests.swift @@ -3,9 +3,8 @@ import SnapshotTesting @testable import xcstrings_tool import XCTest -@MainActor final class GenerateTests: FixtureTestCase { - func testGenerate() throws { + @MainActor func testGenerate() throws { try eachFixture { inputURL in if !inputURL.lastPathComponent.hasPrefix("!") { try snapshot(for: inputURL)