diff --git a/CMakeLists.txt b/CMakeLists.txt index ffb0ea1ab..1d4b40b47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,11 @@ set(_SwiftFoundation_FutureAvailability "macOS 10000, iOS 10000, tvOS 10000, wat # All versions to define for each availability name list(APPEND _SwiftFoundation_versions + "5.5" + "5.7" + "5.8" + "5.9" + "6.0" "6.0.2" "6.1" "6.2" @@ -107,10 +112,12 @@ list(APPEND _SwiftFoundation_versions # Each availability name to define list(APPEND _SwiftFoundation_availability_names "FoundationPreview" + "FoundationAttributedString" "FoundationSpan") # The aligned availability for each name (in the same order) list(APPEND _SwiftFoundation_availability_releases + ${_SwiftFoundation_BaseAvailability} ${_SwiftFoundation_BaseAvailability} ${_SwiftFoundation_macOS26Availability}) diff --git a/Package.swift b/Package.swift index cedb5599b..297f35c7d 100644 --- a/Package.swift +++ b/Package.swift @@ -8,9 +8,10 @@ import CompilerPluginSupport let availabilityTags: [_Availability] = [ _Availability("FoundationPreview"), // Default FoundationPreview availability + _Availability("FoundationAttributedString"), _Availability("FoundationSpan", availability: .macOS26), // Availability of Span types ] -let versionNumbers = ["6.0.2", "6.1", "6.2"] +let versionNumbers = ["5.5", "5.7", "5.8", "5.9", "6.0", "6.0.2", "6.1", "6.2"] // Availability Macro Utilities diff --git a/Sources/FoundationEssentials/AttributedString/AttributeContainer.swift b/Sources/FoundationEssentials/AttributedString/AttributeContainer.swift index 10c2dc35c..78c0350fe 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributeContainer.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributeContainer.swift @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// @dynamicMemberLookup -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public struct AttributeContainer : Sendable { internal var storage : AttributedString._AttributeStorage @@ -24,7 +24,7 @@ public struct AttributeContainer : Sendable { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeContainer { @preconcurrency public subscript(_: T.Type) -> T.Value? where T.Value : Sendable { @@ -87,26 +87,27 @@ extension AttributeContainer { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeContainer: Equatable {} -@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) +@available(FoundationAttributedString 5.7, *) extension AttributeContainer: Hashable {} -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeContainer: CustomStringConvertible { public var description: String { storage.description } } +@available(FoundationAttributedString 5.5, *) extension AttributeContainer { internal var _hasConstrainedAttributes: Bool { storage.hasConstrainedAttributes } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributeContainer { /// Returns a copy of the attribute container with only attributes that specify the provided inheritance behavior. /// - Parameter inheritedByAddedText: An `inheritedByAddedText` value to filter. Attributes matching this value are included in the returned container. diff --git a/Sources/FoundationEssentials/AttributedString/AttributeScope.swift b/Sources/FoundationEssentials/AttributedString/AttributeScope.swift index 2fac17426..a0901fa05 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributeScope.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributeScope.swift @@ -16,14 +16,14 @@ // var foregroundColor : ForegroundColor // } // An AttributeScope can contain other scopes as well. -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public protocol AttributeScope : DecodingConfigurationProviding, EncodingConfigurationProviding { static var decodingConfiguration: AttributeScopeCodableConfiguration { get } static var encodingConfiguration: AttributeScopeCodableConfiguration { get } } @frozen -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public enum AttributeScopes { } @available(macOS, unavailable, introduced: 12.0) @@ -171,7 +171,7 @@ internal func _loadDefaultAttributes() -> [String : any AttributedStringKey.Type } // TODO: Support AttributeScope key finding in FoundationPreview -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeScope { private static var scopeDescription: ScopeDescription { if let cached = _loadedScopeCache.withLock({ $0[Self.self] }) { @@ -207,7 +207,7 @@ extension AttributeScope { } /// A list of all attribute keys contained within this scope and any sub-scopes. - @available(FoundationPreview 6.2, *) + @available(FoundationAttributedString 6.2, *) public static var attributeKeys: some Sequence { Self.scopeDescription.attributes.values } diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+AttributeTransformation.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+AttributeTransformation.swift index acf2a878d..4bcbf1757 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+AttributeTransformation.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+AttributeTransformation.swift @@ -18,7 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { @preconcurrency public struct SingleAttributeTransformer : Sendable where T.Value : Sendable { @@ -45,7 +45,7 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { internal func applyRemovals( withOriginal orig: AttributedString.SingleAttributeTransformer, @@ -78,7 +78,7 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { @preconcurrency public func transformingAttributes( @@ -251,7 +251,7 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { @preconcurrency public func transformingAttributes( diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+CharacterView.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+CharacterView.swift index 12af67060..d6fce4b29 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+CharacterView.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+CharacterView.swift @@ -18,7 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { public struct CharacterView : Sendable { /// The guts of the base attributed string. @@ -80,13 +80,14 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.CharacterView { internal var _characters: BigSubstring { BigSubstring(_unchecked: _guts.string, in: _range) } } +@available(FoundationAttributedString 5.5, *) extension Slice { internal var _rebased: AttributedString.CharacterView { let bounds = Range(uncheckedBounds: (self.startIndex._value, self.endIndex._value)) @@ -100,7 +101,7 @@ extension Slice { // FIXME: AttributedString.CharacterView needs to publicly conform to Equatable & Hashable. -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.CharacterView: BidirectionalCollection { public typealias Element = Character public typealias Index = AttributedString.Index @@ -123,7 +124,7 @@ extension AttributedString.CharacterView: BidirectionalCollection { return _defaultCount } - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) @usableFromInline internal var _count: Int { _characters.count @@ -153,7 +154,7 @@ extension AttributedString.CharacterView: BidirectionalCollection { return _defaultIndex(i, offsetBy: distance) } - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) @usableFromInline internal func _index(_ i: AttributedString.Index, offsetBy distance: Int) -> AttributedString.Index { precondition(i >= startIndex && i <= endIndex, "AttributedString index out of bounds") @@ -176,7 +177,7 @@ extension AttributedString.CharacterView: BidirectionalCollection { return _defaultIndex(i, offsetBy: distance, limitedBy: limit) } - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) @usableFromInline internal func _index( _ i: AttributedString.Index, @@ -207,7 +208,7 @@ extension AttributedString.CharacterView: BidirectionalCollection { return _defaultDistance(from: start, to: end) } - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) @usableFromInline internal func _distance(from start: AttributedString.Index, to end: AttributedString.Index) -> Int { precondition(start >= startIndex && start <= endIndex, "AttributedString index out of bounds") @@ -245,7 +246,7 @@ extension AttributedString.CharacterView: BidirectionalCollection { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.CharacterView: RangeReplaceableCollection { internal mutating func _ensureUniqueReference() { if !isKnownUniquelyReferenced(&_guts) { diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+Guts.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+Guts.swift index 163215139..2a2e80dfa 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+Guts.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+Guts.swift @@ -18,6 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif +@available(FoundationAttributedString 5.5, *) extension AttributedString { internal final class Guts : @unchecked Sendable { typealias Index = AttributedString.Index @@ -54,6 +55,7 @@ extension AttributedString { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString.Guts { __consuming func copy() -> AttributedString.Guts { AttributedString.Guts(string: self.string, runs: self.runs) @@ -73,6 +75,7 @@ extension AttributedString.Guts { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString.Guts { internal static func characterwiseIsEqual( _ left: AttributedString.Guts, @@ -182,6 +185,7 @@ extension AttributedString.Guts { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString.Guts { internal func description(in range: Range) -> String { self.description(in: RangeSet(range)) @@ -199,6 +203,7 @@ extension AttributedString.Guts { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString.Guts { var stringBounds: Range { Range(uncheckedBounds: (string.startIndex, string.endIndex)) diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+IndexTracking.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+IndexTracking.swift index c4646fc6c..1c0977670 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+IndexTracking.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+IndexTracking.swift @@ -20,6 +20,7 @@ internal import _FoundationCollections // MARK: - Internal Index Updating +@available(FoundationAttributedString 5.5, *) extension AttributedString.Guts { func _prepareTrackedIndicesUpdate(mutationRange: Range) { // Move any range endpoints inside of the mutation range to outside of the mutation range since a range should never end up splitting a mutation @@ -75,7 +76,7 @@ extension AttributedString.Guts { // MARK: - Public API -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedString { // MARK: inout API diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+IndexValidity.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+IndexValidity.swift index 8b617aaab..98df21dde 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+IndexValidity.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+IndexValidity.swift @@ -14,6 +14,7 @@ internal import Synchronization #endif +@available(FoundationAttributedString 5.5, *) extension AttributedString.Guts { typealias Version = UInt @@ -43,7 +44,7 @@ extension AttributedString.Guts { // MARK: - Public API -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedString.Index { /// Indicates whether the index is valid for use with the provided attributed string. /// - Parameter text: An attributed string used to validate the index. @@ -63,7 +64,7 @@ extension AttributedString.Index { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension Range { /// Indicates whether the range is valid for use with the provided attributed string. /// - Parameter text: An attributed string used to validate the range. @@ -88,7 +89,7 @@ extension Range { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension RangeSet { /// Indicates whether the range set is valid for use with the provided attributed string. /// - Parameter text: An attributed string used to validate the range set. diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+Runs+AttributeSlices.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+Runs+AttributeSlices.swift index 943bbcb56..d84919989 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+Runs+AttributeSlices.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+Runs+AttributeSlices.swift @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs { @preconcurrency public struct AttributesSlice1 : BidirectionalCollection, Sendable @@ -142,7 +142,7 @@ extension AttributedString.Runs { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs { @preconcurrency public struct AttributesSlice2< @@ -298,7 +298,7 @@ extension AttributedString.Runs { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs { @preconcurrency public struct AttributesSlice3< @@ -466,7 +466,7 @@ extension AttributedString.Runs { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs { @preconcurrency public struct AttributesSlice4< @@ -648,7 +648,7 @@ extension AttributedString.Runs { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs { @preconcurrency public struct AttributesSlice5< @@ -846,7 +846,7 @@ extension AttributedString.Runs { #if FOUNDATION_FRAMEWORK -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs { @_spi(AttributedString) public struct NSAttributesSlice : BidirectionalCollection, Sendable { diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+Runs+Run.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+Runs+Run.swift index fce658af4..631cf2170 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+Runs+Run.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+Runs+Run.swift @@ -18,7 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs { @dynamicMemberLookup public struct Run: Sendable { @@ -42,7 +42,7 @@ extension AttributedString.Runs { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs.Run: Equatable { public static func == (lhs: Self, rhs: Self) -> Bool { lhs._range._utf8OffsetRange.count == rhs._range._utf8OffsetRange.count @@ -50,14 +50,14 @@ extension AttributedString.Runs.Run: Equatable { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs.Run: CustomStringConvertible { public var description: String { AttributedSubstring(_guts, in: _range).description } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs.Run { public var range: Range { let lower = AttributedString.Index(_range.lowerBound, version: _guts.version) @@ -78,7 +78,7 @@ extension AttributedString.Runs.Run { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs.Run { @preconcurrency @inlinable // Trivial implementation, allows callers to optimize away the keypath allocation diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+Runs.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+Runs.swift index f1c9c8abc..08afba4b1 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+Runs.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+Runs.swift @@ -18,7 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { public struct Runs: Sendable { internal typealias _InternalRun = AttributedString._InternalRun @@ -95,7 +95,7 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs: Equatable { public static func == (lhs: Self, rhs: Self) -> Bool { // Note: Unlike AttributedString itself, this is comparing run lengths without normalizing @@ -119,14 +119,14 @@ extension AttributedString.Runs: Equatable { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs: CustomStringConvertible { public var description: String { _guts.description(in: _strBounds) } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs { public struct Index: Sendable { /// The offset of this run from the start of the attributed string. @@ -185,7 +185,7 @@ extension AttributedString.Runs { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs.Index: Comparable { public static func == (lhs: Self, rhs: Self) -> Bool { lhs._runOffset == rhs._runOffset && lhs._stringIndex == rhs._stringIndex @@ -210,11 +210,11 @@ extension AttributedString.Runs.Index: Comparable { } #if !FOUNDATION_FRAMEWORK -@available(macOS, deprecated: 10000, introduced: 12, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") -@available(iOS, deprecated: 10000, introduced: 15, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") -@available(tvOS, deprecated: 10000, introduced: 15, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") -@available(watchOS, deprecated: 10000, introduced: 8, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") -@available(visionOS, deprecated: 10000, introduced: 1, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") +@available(macOS, deprecated: 10000, introduced: 26, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") +@available(iOS, deprecated: 10000, introduced: 26, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") +@available(tvOS, deprecated: 10000, introduced: 26, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") +@available(watchOS, deprecated: 10000, introduced: 26, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") +@available(visionOS, deprecated: 10000, introduced: 26, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") @available(*, deprecated, message: "AttributedString.Runs.Index should not be used as a Strideable and should instead be offset using the API provided by AttributedString.Runs") extension AttributedString.Runs.Index: Strideable { public func distance(to other: Self) -> Int { @@ -230,14 +230,14 @@ extension AttributedString.Runs.Index: Strideable { } #endif -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension Range { var _runOffsetRange: Range { Range(uncheckedBounds: (lowerBound._runOffset, upperBound._runOffset)) } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs: BidirectionalCollection { public typealias Element = Run @@ -339,7 +339,7 @@ extension AttributedString.Runs: BidirectionalCollection { } #endif - @available(FoundationPreview 6.2, *) + @available(FoundationAttributedString 6.2, *) @usableFromInline internal func _distance(from start: Index, to end: Index) -> Int { guard _isDiscontiguous else { @@ -366,7 +366,7 @@ extension AttributedString.Runs: BidirectionalCollection { #endif } - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) @usableFromInline internal func _index(_ index: Index, offsetBy distance: Int) -> Index { guard _isDiscontiguous else { @@ -433,7 +433,7 @@ extension AttributedString.Runs: BidirectionalCollection { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs { // FIXME: Make public, with a better name. (Probably no need to state "run" -- `index(containing:)`?) internal func indexOfRun(at position: AttributedString.Index) -> Index { @@ -488,7 +488,7 @@ extension AttributedString.Runs { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Runs { internal func _slicedRunBoundary( after i: AttributedString.Index, @@ -620,7 +620,7 @@ extension AttributedString.Runs { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension BigString { internal func _firstConstraintBreak( in range: Range, diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+UTF16View.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+UTF16View.swift index a9566bebd..355a266ba 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+UTF16View.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+UTF16View.swift @@ -18,7 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedString { /// A view of an attributed string’s contents as a collection of UTF-16 code units. public struct UTF16View: Sendable { @@ -42,7 +42,7 @@ extension AttributedString { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedSubstring { /// A view of the attributed substring's contents as a collection of UTF-16 code units. public var utf16: AttributedString.UTF16View { @@ -50,14 +50,14 @@ extension AttributedSubstring { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedString.UTF16View { var _utf16: BigSubstring.UTF16View { BigSubstring.UTF16View(_unchecked: _guts.string, in: _range) } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedString.UTF16View: BidirectionalCollection { public typealias Element = UTF16.CodeUnit public typealias Index = AttributedString.Index diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+UTF8View.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+UTF8View.swift index 7f68cf8b2..281adc001 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+UTF8View.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+UTF8View.swift @@ -18,7 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedString { /// A view of an attributed string’s contents as a collection of UTF-8 code units. public struct UTF8View: Sendable { @@ -42,7 +42,7 @@ extension AttributedString { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedSubstring { /// A view of the attributed substring's contents as a collection of UTF-8 code units. public var utf8: AttributedString.UTF8View { @@ -50,14 +50,14 @@ extension AttributedSubstring { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedString.UTF8View { var _utf8: BigSubstring.UTF8View { BigSubstring.UTF8View(_unchecked: _guts.string, in: _range) } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedString.UTF8View: BidirectionalCollection { public typealias Element = UTF8.CodeUnit public typealias Index = AttributedString.Index diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+UnicodeScalarView.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+UnicodeScalarView.swift index a0f8ed991..42c1d04c3 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+UnicodeScalarView.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+UnicodeScalarView.swift @@ -18,7 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { public struct UnicodeScalarView: Sendable { internal var _guts: Guts @@ -73,12 +73,14 @@ extension AttributedString { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString.UnicodeScalarView { var _unicodeScalars: BigSubstring.UnicodeScalarView { BigSubstring.UnicodeScalarView(_unchecked: _guts.string, in: _range) } } +@available(FoundationAttributedString 5.5, *) extension Slice { internal var _rebased: AttributedString.UnicodeScalarView { let bounds = Range(uncheckedBounds: (self.startIndex._value, self.endIndex._value)) @@ -90,6 +92,7 @@ extension Slice { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString.UnicodeScalarView { // FIXME: AttributedString.UnicodeScalarView needs to publicly conform to Hashable. internal func _isEqual(to other: Self) -> Bool { @@ -101,7 +104,7 @@ extension AttributedString.UnicodeScalarView { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.UnicodeScalarView: BidirectionalCollection { public typealias Element = UnicodeScalar public typealias Index = AttributedString.Index @@ -124,7 +127,7 @@ extension AttributedString.UnicodeScalarView: BidirectionalCollection { return _defaultCount } - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) @usableFromInline internal var _count: Int { _unicodeScalars.count @@ -165,7 +168,7 @@ extension AttributedString.UnicodeScalarView: BidirectionalCollection { return _defaultIndex(i, offsetBy: distance, limitedBy: limit) } - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) @usableFromInline internal func _index( _ i: AttributedString.Index, @@ -189,15 +192,19 @@ extension AttributedString.UnicodeScalarView: BidirectionalCollection { from start: AttributedString.Index, to end: AttributedString.Index ) -> Int { + #if FOUNDATION_FRAMEWORK if #available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) { return _distance(from: start, to: end) } precondition(start >= startIndex && start <= endIndex, "AttributedString index out of bounds") precondition(end >= startIndex && end <= endIndex, "AttributedString index out of bounds") return _defaultDistance(from: start, to: end) + #else + return _distance(from: start, to: end) + #endif } - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) @usableFromInline internal func _distance( from start: AttributedString.Index, @@ -226,7 +233,7 @@ extension AttributedString.UnicodeScalarView: BidirectionalCollection { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.UnicodeScalarView: RangeReplaceableCollection { internal mutating func _ensureUniqueReference() { if !isKnownUniquelyReferenced(&_guts) { diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRun.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRun.swift index ffd6fd179..f1d36098a 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRun.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRun.swift @@ -18,7 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { internal struct _InternalRun: Sendable { // UTF-8 Code Unit Length @@ -32,12 +32,14 @@ extension AttributedString { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRun: Equatable { internal static func == (left: Self, right: Self) -> Bool { left.length == right.length && left.attributes == right.attributes } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRun: Hashable { internal func hash(into hasher: inout Hasher) { hasher.combine(length) @@ -45,6 +47,7 @@ extension AttributedString._InternalRun: Hashable { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRun: RopeElement { typealias Index = Int @@ -72,12 +75,14 @@ extension AttributedString._InternalRun: RopeElement { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRun { internal func get(_ k: T.Type) -> T.Value? where T.Value : Sendable { attributes[k] } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRun { struct Summary: Sendable { var count: Int @@ -95,6 +100,7 @@ extension AttributedString._InternalRun { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRun.Summary: RopeSummary { @inline(__always) static var maxNodeSize: Int { 15 } diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRuns.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRuns.swift index 0c0e3c6fe..cb2cdedcb 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRuns.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRuns.swift @@ -18,6 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif +@available(FoundationAttributedString 5.5, *) extension AttributedString { /// An internal convenience wrapper around `Rope<_InternalRun>`, giving it functionality /// that's specific to attributed strings. @@ -41,6 +42,7 @@ extension AttributedString { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRuns { /// A metric that assigns each run a size of 1; i.e., the metric corresponding to run offsets. /// @@ -89,6 +91,7 @@ extension AttributedString._InternalRuns { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRuns { struct Index { /// The underlying index in the rope. @@ -108,17 +111,20 @@ extension AttributedString._InternalRuns { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRuns.Index: Equatable { static func ==(left: Self, right: Self) -> Bool { left.utf8Offset == right.utf8Offset } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRuns.Index: Comparable { static func <(left: Self, right: Self) -> Bool { left.utf8Offset < right.utf8Offset } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRuns: BidirectionalCollection { typealias Element = _InternalRun typealias SubSequence = Slice @@ -187,12 +193,14 @@ extension AttributedString._InternalRuns: BidirectionalCollection { } } +@available(FoundationAttributedString 5.5, *) extension Slice { var utf8Count: Int { self.base.distance(from: self.startIndex, to: self.endIndex) } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRuns { func index(atRunOffset runOffset: Int) -> Index { let r = _rope.find(at: runOffset, in: RunMetric(), preferEnd: false) @@ -221,6 +229,7 @@ extension AttributedString._InternalRuns { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRuns { var utf8Count: Int { _rope.count(in: UTF8Metric()) @@ -249,6 +258,7 @@ extension AttributedString._InternalRuns { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRuns { /// Update the run at `index` with the provided `run` and coalesce it with its /// neighbors if necessary. `index` is updated to a valid index addressing the diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRunsSlice.swift b/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRunsSlice.swift index 5386c8217..de5396832 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRunsSlice.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString+_InternalRunsSlice.swift @@ -18,6 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif +@available(FoundationAttributedString 5.5, *) extension AttributedString { /// A mutable rope of `_InternalRun` values, sliced on an arbitrary UTF-8 offset range. /// Boundary runs may be sliced into two parts; this collection transparently constructs @@ -49,6 +50,7 @@ extension AttributedString { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRunsSlice: BidirectionalCollection { // Note: This is a true bidirectional collection, only supporting step-by-step access. // (It would be possible to implement `index(_:offsetBy:)` in logarithmic time, but we have @@ -102,6 +104,7 @@ extension AttributedString._InternalRunsSlice: BidirectionalCollection { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString._InternalRunsSlice { func update( at index: inout _InternalRuns.Index, diff --git a/Sources/FoundationEssentials/AttributedString/AttributedString.swift b/Sources/FoundationEssentials/AttributedString/AttributedString.swift index 1f871c647..27e08fa54 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedString.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedString.swift @@ -19,7 +19,7 @@ internal import _FoundationCollections #endif @dynamicMemberLookup -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public struct AttributedString : Sendable { internal var _guts: Guts @@ -28,7 +28,7 @@ public struct AttributedString : Sendable { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { internal static let currentIdentity = LockedState(initialState: 0) internal static var _nextModifyIdentity : Int { @@ -40,7 +40,7 @@ extension AttributedString { } // MARK: Initialization -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { public init() { self._guts = Guts() @@ -126,7 +126,7 @@ extension AttributedString { #endif // FOUNDATION_FRAMEWORK } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { internal static func _bstring>(from elements: S) -> BigString { if let elements = _specializingCast(elements, to: String.self) { @@ -147,7 +147,7 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { // Equatable public static func == (lhs: Self, rhs: Self) -> Bool { AttributedString.Guts.characterwiseIsEqual(lhs._guts, to: rhs._guts) @@ -156,14 +156,14 @@ extension AttributedString { // Equatable // Note: The Hashable implementation is inherited from AttributedStringProtocol. -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString: ExpressibleByStringLiteral { public init(stringLiteral value: String) { self.init(value) } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { // AttributedStringAttributeMutation public mutating func setAttributes(_ attributes: AttributeContainer) { ensureUniqueReference() @@ -199,7 +199,7 @@ extension AttributedString { // AttributedStringAttributeMutation } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString: AttributedStringProtocol { public struct Index : Comparable, Sendable { internal var _value: BigString.Index @@ -273,7 +273,7 @@ extension AttributedString: AttributedStringProtocol { } // MARK: Mutating operations -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { internal mutating func ensureUniqueReference() { if !isKnownUniquelyReferenced(&_guts) { @@ -304,7 +304,7 @@ extension AttributedString { } // MARK: Concatenation operators -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { public static func +(lhs: AttributedString, rhs: some AttributedStringProtocol) -> AttributedString { var result = lhs @@ -328,7 +328,7 @@ extension AttributedString { } // MARK: Substring access -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { public subscript(bounds: some RangeExpression) -> AttributedSubstring { get { @@ -365,7 +365,7 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension Range where Bound == AttributedString.Index { internal var _bstringRange: Range { Range(uncheckedBounds: (lowerBound._value, upperBound._value)) @@ -376,12 +376,14 @@ extension Range where Bound == AttributedString.Index { } } +@available(FoundationAttributedString 5.5, *) extension RangeSet where Bound == AttributedString.Index { internal var _bstringIndices: RangeSet { RangeSet(self.ranges.map(\._bstringRange)) } } +@available(FoundationAttributedString 5.5, *) extension RangeSet where Bound == BigString.Index { internal func _attributedStringIndices(version: AttributedString.Guts.Version) -> RangeSet { RangeSet(self.ranges.lazy.map { @@ -390,7 +392,7 @@ extension RangeSet where Bound == BigString.Index { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension Range where Bound == BigString.Index { internal var _utf8OffsetRange: Range { Range(uncheckedBounds: (lowerBound.utf8Offset, upperBound.utf8Offset)) diff --git a/Sources/FoundationEssentials/AttributedString/AttributedStringAttribute.swift b/Sources/FoundationEssentials/AttributedString/AttributedStringAttribute.swift index ec6cc8487..95b74ede0 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedStringAttribute.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedStringAttribute.swift @@ -12,7 +12,7 @@ // MARK: AttributedStringKey API -@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) +@available(FoundationAttributedString 5.7, *) extension AttributedString { public enum AttributeRunBoundaries : Hashable, Sendable { case paragraph @@ -34,7 +34,7 @@ extension AttributedString { } } -@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) +@available(FoundationAttributedString 5.7, *) extension AttributedString.AttributeRunBoundaries { var _isScalarConstrained: Bool { if case .character = self { return true } @@ -49,7 +49,7 @@ extension AttributedString.AttributeRunBoundaries { } } -@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) +@available(FoundationAttributedString 5.7, *) extension AttributedString { public struct AttributeInvalidationCondition : Hashable, Sendable { private enum _Storage : Hashable { @@ -94,39 +94,39 @@ extension AttributedString { } // Developers define new attributes by implementing AttributeKey. -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public protocol AttributedStringKey { associatedtype Value : Hashable static var name : String { get } - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) static var runBoundaries : AttributedString.AttributeRunBoundaries? { get } - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) static var inheritedByAddedText : Bool { get } - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) static var invalidationConditions : Set? { get } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedStringKey { public var description: String { Self.name } - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public static var runBoundaries : AttributedString.AttributeRunBoundaries? { nil } - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public static var inheritedByAddedText : Bool { true } - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public static var invalidationConditions : Set? { nil } } // MARK: Attribute Scopes @dynamicMemberLookup @frozen -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public enum AttributeDynamicLookup { public subscript(_: T.Type) -> T { get { fatalError("Called outside of a dynamicMemberLookup subscript overload") } @@ -141,7 +141,7 @@ public enum AttributeDynamicLookup { extension AttributeDynamicLookup : Sendable {} @dynamicMemberLookup -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public struct ScopedAttributeContainer : Sendable { internal var storage : AttributedString._AttributeStorage diff --git a/Sources/FoundationEssentials/AttributedString/AttributedStringAttributeConstrainingBehavior.swift b/Sources/FoundationEssentials/AttributedString/AttributedStringAttributeConstrainingBehavior.swift index edf767c00..17ea247ef 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedStringAttributeConstrainingBehavior.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedStringAttributeConstrainingBehavior.swift @@ -18,7 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString._AttributeStorage { var hasConstrainedAttributes: Bool { self.contents.values.contains { value in @@ -56,7 +56,7 @@ extension AttributedString._AttributeStorage { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString._AttributeValue { var hasConstrainedAttributes: Bool { runBoundaries != nil @@ -68,7 +68,7 @@ extension AttributedString._AttributeValue { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedStringKey { static var constraintsInvolved: [AttributedString.AttributeRunBoundaries] { guard let constraint = Self.runBoundaries else { return [] } @@ -76,21 +76,21 @@ extension AttributedStringKey { } } -@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) +@available(FoundationAttributedString 5.7, *) extension Collection where Element == AttributedString.AttributeRunBoundaries { var _containsScalarConstraint: Bool { self.contains { $0._isScalarConstrained } } } -@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) +@available(FoundationAttributedString 5.7, *) extension Collection where Element == AttributedString.AttributeRunBoundaries? { var _containsScalarConstraint: Bool { self.contains { $0?._isScalarConstrained ?? false } } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Guts { // MARK: Index/Range Utilities diff --git a/Sources/FoundationEssentials/AttributedString/AttributedStringAttributeStorage.swift b/Sources/FoundationEssentials/AttributedString/AttributedStringAttributeStorage.swift index d10c84ff8..34f6e2457 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedStringAttributeStorage.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedStringAttributeStorage.swift @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { internal struct _AttributeValue : Hashable, CustomStringConvertible, Sendable { private typealias RawValue = any Sendable & Hashable @@ -108,7 +108,7 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) internal extension Dictionary where Key == String, Value == AttributedString._AttributeValue { var _attrStrDescription : String { let keyvals = self.reduce(into: "") { (res, entry) in @@ -118,7 +118,7 @@ internal extension Dictionary where Key == String, Value == AttributedString._At } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { internal struct _AttributeStorage: Hashable, Sendable { internal typealias AttributeMergePolicy = AttributedString.AttributeMergePolicy @@ -139,14 +139,14 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString._AttributeStorage: CustomStringConvertible { var description: String { contents._attrStrDescription } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString._AttributeStorage { var isEmpty: Bool { contents.isEmpty @@ -166,7 +166,7 @@ extension AttributedString._AttributeStorage { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString._AttributeStorage { internal func isEqual(to other: Self, comparing attributes: [String]) -> Bool { assert(!attributes.isEmpty) @@ -179,7 +179,7 @@ extension AttributedString._AttributeStorage { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString._AttributeStorage { func attributesForAddedText() -> Self { var storage = Self() diff --git a/Sources/FoundationEssentials/AttributedString/AttributedStringCodable.swift b/Sources/FoundationEssentials/AttributedString/AttributedStringCodable.swift index 33f28ab47..f8655da7f 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedStringCodable.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedStringCodable.swift @@ -30,27 +30,27 @@ extension Decoder { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public protocol EncodableAttributedStringKey : AttributedStringKey { static func encode(_ value: Value, to encoder: Encoder) throws } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public protocol DecodableAttributedStringKey : AttributedStringKey { static func decode(from decoder: Decoder) throws -> Value } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public typealias CodableAttributedStringKey = EncodableAttributedStringKey & DecodableAttributedStringKey -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension EncodableAttributedStringKey where Value : Encodable { public static func encode(_ value: Value, to encoder: Encoder) throws { try value.encode(to: encoder) } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension DecodableAttributedStringKey where Value : Decodable { public static func decode(from decoder: Decoder) throws -> Value { return try Value.init(from: decoder) @@ -58,18 +58,18 @@ extension DecodableAttributedStringKey where Value : Decodable { } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public protocol MarkdownDecodableAttributedStringKey : AttributedStringKey { static func decodeMarkdown(from decoder: Decoder) throws -> Value static var markdownName: String { get } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension MarkdownDecodableAttributedStringKey { public static var markdownName: String { name } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension MarkdownDecodableAttributedStringKey where Self : DecodableAttributedStringKey { public static func decodeMarkdown(from decoder: Decoder) throws -> Value { try Self.decode(from: decoder) @@ -77,7 +77,7 @@ extension MarkdownDecodableAttributedStringKey where Self : DecodableAttributedS } #if FOUNDATION_FRAMEWORK -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension EncodableAttributedStringKey where Value : NSSecureCoding & NSObject { public static func encode(_ value: Value, to encoder: Encoder) throws { let data = try NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true) @@ -86,7 +86,7 @@ extension EncodableAttributedStringKey where Value : NSSecureCoding & NSObject { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension DecodableAttributedStringKey where Value : NSSecureCoding & NSObject { public static func decode(from decoder: Decoder) throws -> Value { let container = try decoder.singleValueContainer() @@ -103,7 +103,7 @@ extension DecodableAttributedStringKey where Value : NSSecureCoding & NSObject { // MARK: AttributedString CodableWithConfiguration Conformance -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public struct AttributeScopeCodableConfiguration : Sendable { internal let attributesTable : [String : any AttributedStringKey.Type] @@ -124,7 +124,7 @@ public struct AttributeScopeCodableConfiguration : Sendable { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeScope { public static var encodingConfiguration: AttributeScopeCodableConfiguration { AttributeScopeCodableConfiguration(Self.self) } public static var decodingConfiguration: AttributeScopeCodableConfiguration { AttributeScopeCodableConfiguration(Self.self) } @@ -132,7 +132,7 @@ extension AttributeScope { #if FOUNDATION_FRAMEWORK // TODO: Support AttributedString codable conformance in FoundationPreview -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString : Codable { public func encode(to encoder: Encoder) throws { let conf = AttributeScopeCodableConfiguration(_loadDefaultAttributes()) @@ -145,7 +145,7 @@ extension AttributedString : Codable { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString : CodableWithConfiguration { private enum CodingKeys : String, CodingKey { @@ -348,7 +348,7 @@ extension AttributedString : CodableWithConfiguration { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeContainer : CodableWithConfiguration { public func encode(to encoder: Encoder, configuration: AttributeScopeCodableConfiguration) throws { try AttributedString.encodeAttributeContainer(self.storage, to: encoder, configuration: configuration) @@ -361,7 +361,7 @@ extension AttributeContainer : CodableWithConfiguration { #endif // FOUNDATION_FRAMEWORK -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension CodableConfiguration where ConfigurationProvider : AttributeScope { public init(wrappedValue: T, from keyPath: KeyPath) { self.wrappedValue = wrappedValue diff --git a/Sources/FoundationEssentials/AttributedString/AttributedStringProtocol.swift b/Sources/FoundationEssentials/AttributedString/AttributedStringProtocol.swift index 86471b480..edb0468f9 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedStringProtocol.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedStringProtocol.swift @@ -18,7 +18,7 @@ internal import _RopeModule internal import _FoundationCollections #endif -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { public enum AttributeMergePolicy : Sendable { case keepNew @@ -33,7 +33,7 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public protocol AttributedStringAttributeMutation { mutating func setAttributes(_ attributes: AttributeContainer) mutating func mergeAttributes(_ attributes: AttributeContainer, mergePolicy: AttributedString.AttributeMergePolicy) @@ -41,7 +41,7 @@ public protocol AttributedStringAttributeMutation { } @dynamicMemberLookup -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public protocol AttributedStringProtocol : AttributedStringAttributeMutation, Hashable, CustomStringConvertible, Sendable { @@ -52,10 +52,10 @@ public protocol AttributedStringProtocol var characters : AttributedString.CharacterView { get } var unicodeScalars : AttributedString.UnicodeScalarView { get } - @available(FoundationPreview 6.2, *) + @available(FoundationAttributedString 6.2, *) var utf8 : AttributedString.UTF8View { get } - @available(FoundationPreview 6.2, *) + @available(FoundationAttributedString 6.2, *) var utf16 : AttributedString.UTF16View { get } @preconcurrency subscript(_: K.Type) -> K.Value? where K.Value : Sendable { get set } @@ -66,7 +66,7 @@ public protocol AttributedStringProtocol } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedStringProtocol { var utf8 : AttributedString.UTF8View { AttributedString.UTF8View(__guts, in: Range(uncheckedBounds: (startIndex._value, endIndex._value))) @@ -77,7 +77,7 @@ extension AttributedStringProtocol { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedStringProtocol { public func settingAttributes(_ attributes: AttributeContainer) -> AttributedString { var new = AttributedString(self) @@ -103,7 +103,7 @@ extension AttributedStringProtocol { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedStringProtocol { internal var __guts: AttributedString.Guts { if let s = _specializingCast(self, to: AttributedString.self) { @@ -132,6 +132,7 @@ extension AttributedStringProtocol { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString { internal var _baseString: BigString { _guts.string @@ -146,6 +147,7 @@ extension AttributedString { } } +@available(FoundationAttributedString 5.5, *) extension AttributedSubstring { internal var _baseString: BigString { _guts.string @@ -162,14 +164,14 @@ extension AttributedSubstring { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedStringProtocol { // CustomStringConvertible public var description: String { __guts.description(in: _stringBounds) } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedStringProtocol { // Equatable, Hashable @_specialize(where Self == AttributedString, RHS == AttributedString) @_specialize(where Self == AttributedString, RHS == AttributedSubstring) @@ -186,7 +188,7 @@ extension AttributedStringProtocol { // Equatable, Hashable } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedStringProtocol { public func index(afterCharacter i: AttributedString.Index) -> AttributedString.Index { self.characters.index(after: i) @@ -262,7 +264,7 @@ extension AttributedStringProtocol { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedStringProtocol { internal func _range(of stringToFind: T, options: String.CompareOptions = []) -> Range? { diff --git a/Sources/FoundationEssentials/AttributedString/AttributedSubstring.swift b/Sources/FoundationEssentials/AttributedString/AttributedSubstring.swift index 4191d9d46..775b0a31d 100644 --- a/Sources/FoundationEssentials/AttributedString/AttributedSubstring.swift +++ b/Sources/FoundationEssentials/AttributedString/AttributedSubstring.swift @@ -19,7 +19,7 @@ internal import _FoundationCollections #endif @dynamicMemberLookup -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public struct AttributedSubstring: Sendable { /// The guts of the base attributed string. internal var _guts: AttributedString.Guts @@ -49,7 +49,7 @@ public struct AttributedSubstring: Sendable { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedSubstring { public var base: AttributedString { return AttributedString(_guts) @@ -64,7 +64,7 @@ extension AttributedSubstring { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedSubstring { // CustomStringConvertible public var description: String { // FIXME: Why have a custom definition for this if AttributedString falls back @@ -73,7 +73,7 @@ extension AttributedSubstring { // CustomStringConvertible } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedSubstring { // Equatable public static func == (lhs: Self, rhs: Self) -> Bool { if lhs._guts === rhs._guts && lhs._range == rhs._range { @@ -85,7 +85,7 @@ extension AttributedSubstring { // Equatable } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedSubstring : AttributedStringProtocol { public var startIndex: AttributedString.Index { .init(_range.lowerBound, version: _guts.version) @@ -159,7 +159,7 @@ extension AttributedSubstring : AttributedStringProtocol { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedSubstring { @preconcurrency public subscript(_: K.Type) -> K.Value? where K.Value : Sendable { diff --git a/Sources/FoundationEssentials/AttributedString/Conversion.swift b/Sources/FoundationEssentials/AttributedString/Conversion.swift index 7b06e0476..6511c7b80 100644 --- a/Sources/FoundationEssentials/AttributedString/Conversion.swift +++ b/Sources/FoundationEssentials/AttributedString/Conversion.swift @@ -22,13 +22,13 @@ internal import _FoundationCollections #endif extension String { - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public init(_ characters: Slice) { self.init(characters._characters) } #if false // FIXME: Make this public. - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) @backDeployed(before: macOS 14, iOS 17, tvOS 17, watchOS 10) public init(_ characters: AttributedString.CharacterView) { if #available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) { @@ -41,7 +41,7 @@ extension String { } #endif - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) @usableFromInline internal init(_characters: AttributedString.CharacterView) { self.init(_characters._characters) @@ -50,7 +50,7 @@ extension String { #if FOUNDATION_FRAMEWORK -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) public protocol ObjectiveCConvertibleAttributedStringKey : AttributedStringKey { associatedtype ObjectiveCValue : NSObject @@ -58,7 +58,7 @@ public protocol ObjectiveCConvertibleAttributedStringKey : AttributedStringKey { static func value(for object: ObjectiveCValue) throws -> Value } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension ObjectiveCConvertibleAttributedStringKey where Value : RawRepresentable, Value.RawValue == Int, ObjectiveCValue == NSNumber { public static func objectiveCValue(for value: Value) throws -> ObjectiveCValue { return NSNumber(value: value.rawValue) @@ -71,7 +71,7 @@ extension ObjectiveCConvertibleAttributedStringKey where Value : RawRepresentabl } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension ObjectiveCConvertibleAttributedStringKey where Value : RawRepresentable, Value.RawValue == String, ObjectiveCValue == NSString { public static func objectiveCValue(for value: Value) throws -> ObjectiveCValue { return value.rawValue as NSString @@ -91,7 +91,7 @@ internal struct _AttributeConversionOptions : OptionSet { static let dropThrowingAttributes = Self(rawValue: 1 << 0) } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeContainer { public init(_ dictionary: [NSAttributedString.Key : Any]) { // Passing .dropThrowingAttributes causes attributes that throw during conversion to be dropped, so it is safe to do try! here @@ -126,7 +126,7 @@ extension AttributeContainer { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension Dictionary where Key == NSAttributedString.Key, Value == Any { public init(_ container: AttributeContainer) { // Passing .dropThrowingAttributes causes attributes that throw during conversion to be dropped, so it is safe to do try! here @@ -161,7 +161,7 @@ extension Dictionary where Key == NSAttributedString.Key, Value == Any { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension NSAttributedString { public convenience init(_ attrStr: AttributedString) { // Passing .dropThrowingAttributes causes attributes that throw during conversion to be dropped, so it is safe to do try! here @@ -203,7 +203,7 @@ extension NSAttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString { public init(_ nsStr: NSAttributedString) { // Passing .dropThrowingAttributes causes attributes that throw during conversion to be dropped, so it is safe to do try! here @@ -286,7 +286,7 @@ extension AttributedString { #endif // FOUNDATION_FRAMEWORK -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension String.Index { // FIXME: Converting indices between different collection types does not make sense. // FIXME: (Indices are meaningless without the collection value to which they belong, @@ -300,7 +300,7 @@ extension String.Index { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributedString.Index { // FIXME: Converting indices between different collection types does not make sense. // FIXME: (Indices are meaningless without the collection value to which they belong, @@ -322,7 +322,7 @@ extension AttributedString.Index { #if FOUNDATION_FRAMEWORK -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension NSRange { public init( _ region: R, @@ -341,7 +341,7 @@ extension NSRange { self.init(location: utf16Start - utf16Base, length: utf16Length) } - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public init?(_ markdownSourcePosition: AttributedString.MarkdownSourcePosition, in target: S) { let startOffsets: AttributedString.MarkdownSourcePosition.Offsets let endOffsets: AttributedString.MarkdownSourcePosition.Offsets @@ -369,6 +369,7 @@ extension NSRange { #endif // FOUNDATION_FRAMEWORK +@available(FoundationAttributedString 5.5, *) extension AttributedString { /// A dummy collection type whose only purpose is to facilitate a `RangeExpression.relative(to:)` /// call that takes a range expression with string indices but needs to work on an @@ -430,7 +431,7 @@ extension BigString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension Range where Bound == AttributedString.Index { #if FOUNDATION_FRAMEWORK public init?(_ range: NSRange, in string: S) { @@ -491,6 +492,7 @@ extension Range where Bound == AttributedString.Index { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString { /// A dummy collection type whose only purpose is to facilitate a `RangeExpression.relative(to:)` /// call that takes a range expression with attributed string indices but needs to work on a @@ -518,7 +520,7 @@ extension AttributedString { } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension Range where Bound == String.Index { // FIXME: Converting indices between different collection types does not make sense. // FIXME: (Indices are meaningless without the collection value to which they belong, @@ -560,7 +562,7 @@ extension Range where Bound == String.Index { #if FOUNDATION_FRAMEWORK // TODO: Support AttributedString markdown in FoundationPreview - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public init?(_ markdownSourcePosition: AttributedString.MarkdownSourcePosition, in target: S) { if let start = markdownSourcePosition.startOffsets, let end = markdownSourcePosition.endOffsets { self = target.utf8.index(target.startIndex, offsetBy: start.utf8) ..< target.utf8.index(target.startIndex, offsetBy: end.utf8 + 1) diff --git a/Sources/FoundationEssentials/AttributedString/DiscontiguousAttributedSubstring.swift b/Sources/FoundationEssentials/AttributedString/DiscontiguousAttributedSubstring.swift index 649ceb730..ae286b8fe 100644 --- a/Sources/FoundationEssentials/AttributedString/DiscontiguousAttributedSubstring.swift +++ b/Sources/FoundationEssentials/AttributedString/DiscontiguousAttributedSubstring.swift @@ -20,7 +20,7 @@ internal import _FoundationCollections /// A discontiguous portion of an attributed string. @dynamicMemberLookup -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) public struct DiscontiguousAttributedSubstring: Sendable { /// The guts of the base attributed string. internal var _guts: AttributedString.Guts @@ -41,7 +41,7 @@ public struct DiscontiguousAttributedSubstring: Sendable { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension DiscontiguousAttributedSubstring { /// The underlying attributed string that the discontiguous attributed substring derives from. public var base: AttributedString { @@ -49,21 +49,21 @@ extension DiscontiguousAttributedSubstring { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension DiscontiguousAttributedSubstring : CustomStringConvertible { public var description: String { _guts.description(in: _indices) } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension DiscontiguousAttributedSubstring : Equatable { public static func == (lhs: Self, rhs: Self) -> Bool { AttributedString.Guts._characterwiseIsEqual(lhs.runs, to: rhs.runs) } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension DiscontiguousAttributedSubstring : Hashable { public func hash(into hasher: inout Hasher) { for range in _indices.ranges { @@ -72,7 +72,7 @@ extension DiscontiguousAttributedSubstring : Hashable { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension DiscontiguousAttributedSubstring : AttributedStringAttributeMutation { internal mutating func ensureUniqueReference() { // Note: slices should never discard the data outside their bounds, so we must make a @@ -155,7 +155,7 @@ extension DiscontiguousAttributedSubstring : AttributedStringAttributeMutation { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension DiscontiguousAttributedSubstring { /// The characters of the discontiguous attributed string, as a view into the underlying string. public var characters: DiscontiguousSlice { @@ -173,7 +173,7 @@ extension DiscontiguousAttributedSubstring { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension DiscontiguousAttributedSubstring { /// Returns an attribute value that corresponds to an attributed string key. /// @@ -263,7 +263,7 @@ extension DiscontiguousAttributedSubstring { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedString { /// Creates an attributed string from a discontiguous attributed substring. /// - Parameter substring: A discontiguous attributed substring to create the new attributed string from. @@ -279,7 +279,7 @@ extension AttributedString { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedStringProtocol { /// Returns a discontiguous substring of this attributed string using a set of ranges to indicate the discontiguous substring bounds. /// - Parameter indices: A set of ranges that indicate the bounds of the discontiguous substring to return. @@ -290,7 +290,7 @@ extension AttributedStringProtocol { } } -@available(FoundationPreview 6.2, *) +@available(FoundationAttributedString 6.2, *) extension AttributedString { /// Returns a discontiguous substring of this discontiguous attributed string using a set of ranges to indicate the discontiguous substring bounds. /// - Parameter indices: A set of ranges that indicate the bounds of the discontiguous substring to return. diff --git a/Sources/FoundationEssentials/AttributedString/FoundationAttributes.swift b/Sources/FoundationEssentials/AttributedString/FoundationAttributes.swift index c114f2158..aad294345 100644 --- a/Sources/FoundationEssentials/AttributedString/FoundationAttributes.swift +++ b/Sources/FoundationEssentials/AttributedString/FoundationAttributes.swift @@ -16,7 +16,7 @@ internal import Foundation_Private.NSAttributedString #endif -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeScopes { public var foundation: FoundationAttributes.Type { FoundationAttributes.self } @@ -32,39 +32,39 @@ extension AttributeScopes { public let measurement: MeasurementAttribute public let byteCount: ByteCountAttribute - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public let durationField: DurationFieldAttribute /// The base writing direction of a paragraph. - @available(FoundationPreview 6.2, *) + @available(FoundationAttributedString 6.2, *) public let writingDirection: WritingDirectionAttribute #if FOUNDATION_FRAMEWORK - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) public let agreementConcept: AgreementConceptAttribute - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) public let agreementArgument: AgreementArgumentAttribute - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) public let referentConcept: ReferentConceptAttribute - @available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) + @available(FoundationAttributedString 6.0, *) public let localizedNumberFormat: LocalizedNumberFormatAttribute // TODO: Support AttributedString markdown in FoundationPreview: https://github.com/apple/swift-foundation/issues/44 public let inlinePresentationIntent: InlinePresentationIntentAttribute public let presentationIntent: PresentationIntentAttribute - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public let markdownSourcePosition: MarkdownSourcePositionAttribute - @available(FoundationPreview 6.2, *) + @available(FoundationAttributedString 6.2, *) public let listItemDelimiter: ListItemDelimiterAttribute - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public let localizedStringArgumentAttributes: LocalizedStringArgumentAttributes public let inflectionAlternative: InflectionAlternativeAttribute public let morphology: MorphologyAttribute public let inflect: InflectionRuleAttribute @_spi(AutomaticGrammaticalAgreement) - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public let assumedFallbackInflection: AssumedFallbackInflectionAttribute #endif // FOUNDATION_FRAMEWORK } @@ -78,7 +78,7 @@ extension AttributeScopes { @available(*, unavailable) extension AttributeScopes.FoundationAttributes : Sendable {} -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeDynamicLookup { public subscript(dynamicMember keyPath: KeyPath) -> T { return self[T.self] @@ -91,7 +91,7 @@ extension AttributeDynamicLookup { } #if FOUNDATION_FRAMEWORK - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public subscript( dynamicMember keyPath: KeyPath ) -> T { @@ -102,10 +102,10 @@ extension AttributeDynamicLookup { // MARK: Attribute Definitions -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.FoundationAttributes { @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum LinkAttribute : CodableAttributedStringKey { public typealias Value = URL @@ -119,7 +119,7 @@ extension AttributeScopes.FoundationAttributes { #if FOUNDATION_FRAMEWORK @frozen - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) public enum ReferentConceptAttribute : CodableAttributedStringKey, MarkdownDecodableAttributedStringKey { public typealias Value = Int public static let name = NSAttributedString.Key.referentConcept.rawValue @@ -127,7 +127,7 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) public enum AgreementConceptAttribute : CodableAttributedStringKey, MarkdownDecodableAttributedStringKey { public typealias Value = Int public static let name = NSAttributedString.Key.agreeWithConcept.rawValue @@ -135,7 +135,7 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 14, iOS 17, tvOS 17, watchOS 10, *) + @available(FoundationAttributedString 5.9, *) public enum AgreementArgumentAttribute : CodableAttributedStringKey, MarkdownDecodableAttributedStringKey { public typealias Value = Int public static let name = NSAttributedString.Key.agreeWithArgument.rawValue @@ -143,7 +143,7 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum MorphologyAttribute : CodableAttributedStringKey, MarkdownDecodableAttributedStringKey { public typealias Value = Morphology public static let name = NSAttributedString.Key.morphology.rawValue @@ -151,7 +151,7 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum InflectionRuleAttribute : CodableAttributedStringKey, MarkdownDecodableAttributedStringKey { public typealias Value = InflectionRule public static let name = NSAttributedString.Key.inflectionRule.rawValue @@ -159,7 +159,7 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) @_spi(AutomaticGrammaticalAgreement) public enum AssumedFallbackInflectionAttribute : CodableAttributedStringKey, MarkdownDecodableAttributedStringKey { public typealias Value = Morphology @@ -168,7 +168,7 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) + @available(FoundationAttributedString 6.0, *) public enum LocalizedNumberFormatAttribute : CodableAttributedStringKey, MarkdownDecodableAttributedStringKey { public struct Value: Equatable, Hashable, Codable, Sendable { enum Format { @@ -202,14 +202,14 @@ extension AttributeScopes.FoundationAttributes { #endif // FOUNDATION_FRAMEWORK @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum LanguageIdentifierAttribute : CodableAttributedStringKey { public typealias Value = String public static let name = "NSLanguage" } @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum PersonNameComponentAttribute : CodableAttributedStringKey { public typealias Value = Component public static let name = "NSPersonNameComponentKey" @@ -219,7 +219,7 @@ extension AttributeScopes.FoundationAttributes { } } - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public struct NumberFormatAttributes: AttributeScope { public let numberSymbol: SymbolAttribute public let numberPart: NumberPartAttribute @@ -251,7 +251,7 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum DateFieldAttribute : CodableAttributedStringKey { public enum Field : Hashable, Codable, Sendable { case era @@ -383,7 +383,7 @@ extension AttributeScopes.FoundationAttributes { #if FOUNDATION_FRAMEWORK @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum InflectionAlternativeAttribute : CodableAttributedStringKey, MarkdownDecodableAttributedStringKey, ObjectiveCConvertibleAttributedStringKey { public typealias Value = AttributedString public typealias ObjectiveCValue = NSObject @@ -410,7 +410,7 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum InlinePresentationIntentAttribute : CodableAttributedStringKey, ObjectiveCConvertibleAttributedStringKey { public typealias Value = InlinePresentationIntent public typealias ObjectiveCValue = NSNumber @@ -426,21 +426,21 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum PresentationIntentAttribute : CodableAttributedStringKey { public typealias Value = PresentationIntent public static let name = NSAttributedString.Key.presentationIntentAttributeName.rawValue } @frozen - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public enum MarkdownSourcePositionAttribute: CodableAttributedStringKey { public static let name = NSAttributedString.Key.markdownSourcePosition.rawValue public typealias Value = AttributedString.MarkdownSourcePosition } @frozen - @available(FoundationPreview 6.2, *) + @available(FoundationAttributedString 6.2, *) public enum ListItemDelimiterAttribute : CodableAttributedStringKey, ObjectiveCConvertibleAttributedStringKey { public typealias Value = Character public typealias ObjectiveCValue = NSString @@ -480,27 +480,27 @@ extension AttributeScopes.FoundationAttributes { #endif // FOUNDATION_FRAMEWORK @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum AlternateDescriptionAttribute : CodableAttributedStringKey { public typealias Value = String public static let name = "NSAlternateDescription" } @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum ImageURLAttribute : CodableAttributedStringKey { public typealias Value = URL public static let name = "NSImageURL" } @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum ReplacementIndexAttribute : CodableAttributedStringKey { public typealias Value = Int public static let name = "NSReplacementIndex" } - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public struct MeasurementAttribute : CodableAttributedStringKey { public typealias Value = Component public static let name = "Foundation.MeasurementAttribute" @@ -511,7 +511,7 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) + @available(FoundationAttributedString 5.5, *) public enum ByteCountAttribute : CodableAttributedStringKey { public typealias Value = Component public static let name = "Foundation.ByteCountAttribute" @@ -536,7 +536,7 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) + @available(FoundationAttributedString 5.7, *) public enum DurationFieldAttribute : CodableAttributedStringKey { public typealias Value = Field public static let name = "Foundation.DurationFieldAttribute" @@ -553,7 +553,7 @@ extension AttributeScopes.FoundationAttributes { } /// The attribute key for the base writing direction of a paragraph. - @available(FoundationPreview 6.2, *) + @available(FoundationAttributedString 6.2, *) @frozen public enum WritingDirectionAttribute: CodableAttributedStringKey { public typealias Value = AttributedString.WritingDirection @@ -564,7 +564,7 @@ extension AttributeScopes.FoundationAttributes { } #if FOUNDATION_FRAMEWORK - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public struct LocalizedStringArgumentAttributes { // Represents all numeric arguments (i.e. those that use format specifiers such as %d, %f, etc.) @@ -575,7 +575,7 @@ extension AttributeScopes.FoundationAttributes { public let localizedURLArgument: LocalizedURLArgumentAttribute @frozen - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public enum LocalizedNumericArgumentAttribute : CodableAttributedStringKey { public static let name = "Foundation.LocalizedNumericArgumentAttribute" public enum Value : Hashable, Codable, Sendable { @@ -587,21 +587,21 @@ extension AttributeScopes.FoundationAttributes { } @frozen - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public enum LocalizedDateArgumentAttribute : CodableAttributedStringKey { public typealias Value = Date public static let name = "Foundation.LocalizedDateArgumentAttribute" } @frozen - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public enum LocalizedDateIntervalArgumentAttribute : CodableAttributedStringKey { public typealias Value = Range public static let name = "Foundation.LocalizedDateIntervalArgumentAttribute" } @frozen - @available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) + @available(FoundationAttributedString 5.7, *) public enum LocalizedURLArgumentAttribute : CodableAttributedStringKey { public typealias Value = URL public static let name = "Foundation.LocalizedURLArgumentAttribute" @@ -820,7 +820,7 @@ extension AttributeScopes.FoundationAttributes.LocalizedStringArgumentAttributes @available(*, unavailable) extension AttributeScopes.FoundationAttributes.LocalizedStringArgumentAttributes.LocalizedDateIntervalArgumentAttribute : Sendable {} -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.FoundationAttributes.LinkAttribute : ObjectiveCConvertibleAttributedStringKey { public typealias ObjectiveCValue = NSObject // NSURL or NSString @@ -841,17 +841,17 @@ extension AttributeScopes.FoundationAttributes.LinkAttribute : ObjectiveCConvert } } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.FoundationAttributes.LanguageIdentifierAttribute : MarkdownDecodableAttributedStringKey { public static let markdownName = "languageIdentifier" } -@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *) +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.FoundationAttributes.PersonNameComponentAttribute : ObjectiveCConvertibleAttributedStringKey { public typealias ObjectiveCValue = NSString } -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension AttributeScopes.FoundationAttributes.LocalizedNumberFormatAttribute.Value: _ObjectiveCBridgeable { public func _bridgeToObjectiveC() -> __NSLocalizedNumberFormatRule { switch self.format { @@ -878,6 +878,7 @@ extension AttributeScopes.FoundationAttributes.LocalizedNumberFormatAttribute.Va #endif // FOUNDATION_FRAMEWORK +@available(FoundationAttributedString 5.5, *) extension AttributedString { /// The writing direction of a piece of text. /// @@ -927,7 +928,7 @@ extension AttributedString { /// direction. In vertical scripts, a writing direction of ``leftToRight`` /// is interpreted as top-to-bottom and a writing direction of /// ``rightToLeft`` is interpreted as bottom-to-top. - @available(FoundationPreview 6.2, *) + @available(FoundationAttributedString 6.2, *) @frozen public enum WritingDirection: Codable, Hashable, CaseIterable, Sendable { /// A left-to-right writing direction in horizontal script. diff --git a/Sources/FoundationInternationalization/Formatting/ByteCountFormatStyle.swift b/Sources/FoundationInternationalization/Formatting/ByteCountFormatStyle.swift index 0ab8cf921..ad31dcfee 100644 --- a/Sources/FoundationInternationalization/Formatting/ByteCountFormatStyle.swift +++ b/Sources/FoundationInternationalization/Formatting/ByteCountFormatStyle.swift @@ -16,7 +16,7 @@ import FoundationEssentials internal import _FoundationICU -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public struct ByteCountFormatStyle: FormatStyle, Sendable { public var style: Style { get { attributed.style } set { attributed.style = newValue} } public var allowedUnits: Units { get { attributed.allowedUnits } set { attributed.allowedUnits = newValue} } @@ -247,7 +247,7 @@ public struct ByteCountFormatStyle: FormatStyle, Sendable { } } -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public extension FormatStyle where Self == ByteCountFormatStyle { static func byteCount(style: ByteCountFormatStyle.Style, allowedUnits: ByteCountFormatStyle.Units = .all, spellsOutZero: Bool = true, includesActualByteCount: Bool = false) -> Self { return ByteCountFormatStyle(style: style, allowedUnits: allowedUnits, spellsOutZero: spellsOutZero, includesActualByteCount: includesActualByteCount) @@ -284,6 +284,7 @@ private func localizedParens(locale: Locale) -> (String, String) { } } +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.FoundationAttributes.ByteCountAttribute.Component { internal init?(unumberFormatField: UNumberFormatFields, unit: ByteCountFormatStyle.Unit) { switch unumberFormatField { @@ -309,6 +310,7 @@ extension AttributeScopes.FoundationAttributes.ByteCountAttribute.Component { } } +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.FoundationAttributes.ByteCountAttribute.Unit { internal init(_ unit: ByteCountFormatStyle.Unit) { switch unit { diff --git a/Sources/FoundationInternationalization/Formatting/Date/Date+VerbatimFormatStyle.swift b/Sources/FoundationInternationalization/Formatting/Date/Date+VerbatimFormatStyle.swift index 26698f3b8..5fe39d255 100644 --- a/Sources/FoundationInternationalization/Formatting/Date/Date+VerbatimFormatStyle.swift +++ b/Sources/FoundationInternationalization/Formatting/Date/Date+VerbatimFormatStyle.swift @@ -35,10 +35,17 @@ extension Date { } /// Returns a type erased attributed variant of this style. + #if FOUNDATION_FRAMEWORK @available(macOS, deprecated: 15, introduced: 12, message: "Use attributedStyle instead") @available(iOS, deprecated: 18, introduced: 15, message: "Use attributedStyle instead") @available(tvOS, deprecated: 18, introduced: 15, message: "Use attributedStyle instead") @available(watchOS, deprecated: 11, introduced: 8, message: "Use attributedStyle instead") + #else + @available(macOS, deprecated: 26, introduced: 26, message: "Use attributedStyle instead") + @available(iOS, deprecated: 26, introduced: 26, message: "Use attributedStyle instead") + @available(tvOS, deprecated: 26, introduced: 26, message: "Use attributedStyle instead") + @available(watchOS, deprecated: 26, introduced: 26, message: "Use attributedStyle instead") + #endif public var attributed: AttributedStyle { .init(style: .verbatimFormatStyle(self)) } @@ -78,7 +85,7 @@ extension Date.VerbatimFormatStyle: ParseableFormatStyle { // MARK: Typed Attributed Style -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Date.VerbatimFormatStyle { /// The type preserving attributed variant of this style. /// @@ -176,7 +183,7 @@ extension Date.VerbatimFormatStyle : DiscreteFormatStyle { } } -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Date.VerbatimFormatStyle.Attributed : DiscreteFormatStyle { public func discreteInput(before input: Date) -> Date? { base.discreteInput(before: input) diff --git a/Sources/FoundationInternationalization/Formatting/Date/DateFormatStyle.swift b/Sources/FoundationInternationalization/Formatting/Date/DateFormatStyle.swift index 5a25b2548..057cf5021 100644 --- a/Sources/FoundationInternationalization/Formatting/Date/DateFormatStyle.swift +++ b/Sources/FoundationInternationalization/Formatting/Date/DateFormatStyle.swift @@ -241,10 +241,17 @@ extension Date { public var capitalizationContext: FormatStyleCapitalizationContext /// Returns a type erased attributed variant of this style. + #if FOUNDATION_FRAMEWORK @available(macOS, deprecated: 15, introduced: 12, message: "Use attributedStyle instead") @available(iOS, deprecated: 18, introduced: 15, message: "Use attributedStyle instead") @available(tvOS, deprecated: 18, introduced: 15, message: "Use attributedStyle instead") @available(watchOS, deprecated: 11, introduced: 8, message: "Use attributedStyle instead") + #else + @available(macOS, deprecated: 26, introduced: 26, message: "Use attributedStyle instead") + @available(iOS, deprecated: 26, introduced: 26, message: "Use attributedStyle instead") + @available(tvOS, deprecated: 26, introduced: 26, message: "Use attributedStyle instead") + @available(watchOS, deprecated: 26, introduced: 26, message: "Use attributedStyle instead") + #endif public var attributed: AttributedStyle { .init(style: .formatStyle(self)) } @@ -288,10 +295,17 @@ extension Date { // MARK: Type-Erased AttributedStyle + #if FOUNDATION_FRAMEWORK @available(macOS, deprecated: 15, introduced: 12, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") @available(iOS, deprecated: 18, introduced: 15, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") @available(tvOS, deprecated: 18, introduced: 15, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") @available(watchOS, deprecated: 11, introduced: 8, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") + #else + @available(macOS, deprecated: 26, introduced: 26, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") + @available(iOS, deprecated: 26, introduced: 26, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") + @available(tvOS, deprecated: 26, introduced: 26, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") + @available(watchOS, deprecated: 26, introduced: 26, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") + #endif public struct AttributedStyle : Sendable { enum InnerStyle: Codable, Hashable { @@ -338,15 +352,22 @@ extension Date { } } +#if FOUNDATION_FRAMEWORK @available(macOS, deprecated: 15, introduced: 12, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") @available(iOS, deprecated: 18, introduced: 15, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") @available(tvOS, deprecated: 18, introduced: 15, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") @available(watchOS, deprecated: 11, introduced: 8, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") +#else +@available(macOS, deprecated: 26, introduced: 26, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") +@available(iOS, deprecated: 26, introduced: 26, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") +@available(tvOS, deprecated: 26, introduced: 26, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") +@available(watchOS, deprecated: 26, introduced: 26, message: "Use Date.FormatStyle.Attributed or Date.VerbatimFormatStyle.Attributed instead") +#endif extension Date.AttributedStyle : FormatStyle {} // MARK: Typed Attributed Style -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Date.FormatStyle { /// The type preserving attributed variant of this style. /// @@ -557,7 +578,7 @@ extension Date.FormatStyle { // MARK: Symbol Modifiers Attributed Style -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Date.FormatStyle.Attributed { /// Change the representation of the era in the format. /// @@ -854,7 +875,7 @@ extension Date.FormatStyle : DiscreteFormatStyle { } } -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Date.FormatStyle.Attributed : DiscreteFormatStyle { public func discreteInput(before input: Date) -> Date? { base.discreteInput(before: input) @@ -1000,6 +1021,7 @@ extension Calendar { // MARK: Utils +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.FoundationAttributes.DateFieldAttribute.Field { init?(udateFormatField: UDateFormatField) { switch udateFormatField { @@ -1096,6 +1118,7 @@ extension Date.FormatStyle : CustomConsumingRegexComponent { } } +@available(FoundationAttributedString 5.5, *) extension String { func _attributedStringFromPositions(_ positions: [ICUDateFormatter.AttributePosition]) -> AttributedString { typealias DateFieldAttribute = AttributeScopes.FoundationAttributes.DateFieldAttribute.Field diff --git a/Sources/FoundationInternationalization/Formatting/Duration+Formatting.swift b/Sources/FoundationInternationalization/Formatting/Duration+Formatting.swift index cf2ad5b6c..a228ecf4d 100644 --- a/Sources/FoundationInternationalization/Formatting/Duration+Formatting.swift +++ b/Sources/FoundationInternationalization/Formatting/Duration+Formatting.swift @@ -37,7 +37,7 @@ extension Duration { /// Formats `self` using the hour-minute-second time pattern /// - Returns: A formatted string to describe the duration, such as "1:30:56" for a duration of 1 hour, 30 minutes, and 56 seconds - @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) + @available(FoundationAttributedString 5.7, *) public func formatted() -> String { return Self.TimeFormatStyle(pattern: .hourMinuteSecond).format(self) } diff --git a/Sources/FoundationInternationalization/Formatting/Duration+TimeFormatStyle.swift b/Sources/FoundationInternationalization/Formatting/Duration+TimeFormatStyle.swift index 2578c39d1..846273f04 100644 --- a/Sources/FoundationInternationalization/Formatting/Duration+TimeFormatStyle.swift +++ b/Sources/FoundationInternationalization/Formatting/Duration+TimeFormatStyle.swift @@ -21,13 +21,13 @@ let minuteSymbol: Character = "m" let secondSymbol: Character = "s" let quoteSymbol: Character = "'" -@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) +@available(FoundationAttributedString 5.7, *) extension Duration { /// Format style to format a `Duration` in a localized positional format. /// For example, one hour and ten minutes is displayed as “1:10:00” in /// the U.S. English locale, or “1.10.00” in the Finnish locale. - @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) + @available(FoundationAttributedString 5.7, *) public struct TimeFormatStyle : FormatStyle, Sendable { /// The units to display a Duration with and configurations for the units. @@ -152,7 +152,7 @@ extension Duration { internal typealias _TimeFormatStyle = TimeFormatStyle } -@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) +@available(FoundationAttributedString 5.7, *) extension FormatStyle where Self == Duration.TimeFormatStyle { /// A factory variable to create a time format style to format a duration. /// - Parameter pattern: A `Pattern` to specify the units to include in the displayed string and the behavior of the units. @@ -165,7 +165,7 @@ extension FormatStyle where Self == Duration.TimeFormatStyle { // MARK: - Attributed style -@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) +@available(FoundationAttributedString 5.7, *) extension Duration.TimeFormatStyle { /// Formats a duration as an attributed string with the `durationField` attribute key and `FoundationAttributes.DurationFieldAttribute` attribute. @@ -178,7 +178,7 @@ extension Duration.TimeFormatStyle { /// : { nil } /// 26.25 { durationField: .seconds } /// ``` - @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) + @available(FoundationAttributedString 5.7, *) @dynamicMemberLookup public struct Attributed : FormatStyle, Sendable { @@ -423,7 +423,7 @@ extension Duration.TimeFormatStyle { } } -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Duration.TimeFormatStyle { /// Returns a modified style that applies the given `grouping` rule to the highest field in the /// pattern. @@ -440,7 +440,7 @@ extension Duration.TimeFormatStyle { } } -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Duration.TimeFormatStyle.Attributed { /// Returns a modified style that applies the given `grouping` rule to the highest field in the /// pattern. @@ -453,7 +453,7 @@ extension Duration.TimeFormatStyle.Attributed { // MARK: Dynamic Member Lookup -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Duration.TimeFormatStyle.Attributed { private var innerStyle: Duration.TimeFormatStyle { get { @@ -480,7 +480,7 @@ extension Duration.TimeFormatStyle.Attributed { // MARK: DiscreteFormatStyle Conformance -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Duration.TimeFormatStyle.Attributed : DiscreteFormatStyle { public func discreteInput(before input: Duration) -> Duration? { Duration.TimeFormatStyle(pattern: pattern, locale: locale).discreteInput(before: input) @@ -491,7 +491,7 @@ extension Duration.TimeFormatStyle.Attributed : DiscreteFormatStyle { } } -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Duration.TimeFormatStyle : DiscreteFormatStyle { public func discreteInput(before input: Duration) -> Duration? { let (bound, isIncluded) = Duration.bound(for: input, in: interval(for: input), countingDown: true, roundingRule: self.pattern.roundingRule) diff --git a/Sources/FoundationInternationalization/Formatting/Duration+UnitsFormatStyle.swift b/Sources/FoundationInternationalization/Formatting/Duration+UnitsFormatStyle.swift index f17ce7548..e64543567 100644 --- a/Sources/FoundationInternationalization/Formatting/Duration+UnitsFormatStyle.swift +++ b/Sources/FoundationInternationalization/Formatting/Duration+UnitsFormatStyle.swift @@ -491,6 +491,7 @@ extension Duration { /// 26.25 { durationField: .seconds, component: .value } /// seconds { durationField: .seconds, component: .unit } /// ``` + @available(FoundationAttributedString 5.7, *) public var attributed: Attributed { Attributed(innerStyle: self) } @@ -532,7 +533,7 @@ extension FormatStyle where Self == Duration.UnitsFormatStyle { // MARK: - Attributed style -@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) +@available(FoundationAttributedString 5.7, *) extension Duration.UnitsFormatStyle { /// A format style to format a duration as an attributed string. Units in the string are annotated with the `durationField` and `measurement` attribute keys and the `DurationFieldAttribute` and `MeasurementAttribute` attribute values. @@ -550,7 +551,7 @@ extension Duration.UnitsFormatStyle { /// 26.25 { durationField: .seconds, component: .value } /// seconds { durationField: .seconds, component: .unit } /// ``` - @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) + @available(FoundationAttributedString 5.7, *) @dynamicMemberLookup public struct Attributed : FormatStyle, Sendable { @@ -632,7 +633,7 @@ extension Duration.UnitsFormatStyle { // MARK: Dynamic Member Lookup -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Duration.UnitsFormatStyle.Attributed { public subscript(dynamicMember key: KeyPath) -> T { innerStyle[keyPath: key] @@ -650,7 +651,7 @@ extension Duration.UnitsFormatStyle.Attributed { // MARK: DiscreteFormatStyle Conformance -@available(macOS 15, iOS 18, tvOS 18, watchOS 11, *) +@available(FoundationAttributedString 6.0, *) extension Duration.UnitsFormatStyle.Attributed : DiscreteFormatStyle { public func discreteInput(before input: Duration) -> Duration? { self.innerStyle.discreteInput(before: input) diff --git a/Sources/FoundationInternationalization/Formatting/Number/Decimal+FormatStyle.swift b/Sources/FoundationInternationalization/Formatting/Number/Decimal+FormatStyle.swift index cb2be15f3..4b1a2c869 100644 --- a/Sources/FoundationInternationalization/Formatting/Number/Decimal+FormatStyle.swift +++ b/Sources/FoundationInternationalization/Formatting/Number/Decimal+FormatStyle.swift @@ -22,6 +22,7 @@ extension Decimal { self.locale = locale } + @available(FoundationAttributedString 5.5, *) public var attributed: Attributed { return Attributed(style: self) } @@ -107,6 +108,7 @@ extension Decimal.FormatStyle { self.locale = locale } + @available(FoundationAttributedString 5.5, *) public var attributed: Attributed { return Attributed(style: self) } @@ -186,6 +188,7 @@ extension Decimal.FormatStyle { self.collection = Configuration.Collection(presentation: .standard) } + @available(FoundationAttributedString 5.5, *) public var attributed: Attributed { return Attributed(style: self) } @@ -262,6 +265,7 @@ extension Decimal.FormatStyle { } } + @available(FoundationAttributedString 5.5, *) public struct Attributed : Sendable { enum Style : Hashable, Codable, Sendable { case decimal(Decimal.FormatStyle) @@ -330,7 +334,7 @@ extension Decimal.FormatStyle.Percent : FormatStyle {} @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) extension Decimal.FormatStyle.Currency : FormatStyle {} -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) extension Decimal.FormatStyle.Attributed : FormatStyle {} @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) diff --git a/Sources/FoundationInternationalization/Formatting/Number/FloatingPointFormatStyle.swift b/Sources/FoundationInternationalization/Formatting/Number/FloatingPointFormatStyle.swift index 249259e5d..96c5a6ef1 100644 --- a/Sources/FoundationInternationalization/Formatting/Number/FloatingPointFormatStyle.swift +++ b/Sources/FoundationInternationalization/Formatting/Number/FloatingPointFormatStyle.swift @@ -23,6 +23,7 @@ public struct FloatingPointFormatStyle: Codable, Has self.locale = locale } + @available(FoundationAttributedString 5.5, *) public var attributed: FloatingPointFormatStyle.Attributed { return FloatingPointFormatStyle.Attributed(style: self) } @@ -85,6 +86,7 @@ extension FloatingPointFormatStyle { self.locale = locale } + @available(FoundationAttributedString 5.5, *) public var attributed: FloatingPointFormatStyle.Attributed { return FloatingPointFormatStyle.Attributed(style: self) } @@ -153,6 +155,7 @@ extension FloatingPointFormatStyle { self.collection = Configuration.Collection(presentation: .standard) } + @available(FoundationAttributedString 5.5, *) public var attributed: FloatingPointFormatStyle.Attributed { return FloatingPointFormatStyle.Attributed(style: self) } @@ -337,7 +340,7 @@ public extension FormatStyle where Self == FloatingPointFormatStyle.Per // MARK: - Attributed string -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) extension FloatingPointFormatStyle { public struct Attributed : Codable, Hashable, FormatStyle, Sendable { enum Style : Codable, Hashable, Sendable { diff --git a/Sources/FoundationInternationalization/Formatting/Number/ICUNumberFormatter.swift b/Sources/FoundationInternationalization/Formatting/Number/ICUNumberFormatter.swift index ed288d189..ed180022b 100644 --- a/Sources/FoundationInternationalization/Formatting/Number/ICUNumberFormatter.swift +++ b/Sources/FoundationInternationalization/Formatting/Number/ICUNumberFormatter.swift @@ -77,6 +77,7 @@ internal class ICUNumberFormatterBase : @unchecked Sendable { } } + @available(FoundationAttributedString 5.5, *) func attributedStringFromPositions(_ positions: [ICUNumberFormatter.AttributePosition], string: String) -> AttributedString { typealias NumberPartAttribute = AttributeScopes.FoundationAttributes.NumberFormatAttributes.NumberPartAttribute.NumberPart typealias NumberSymbolAttribute = AttributeScopes.FoundationAttributes.NumberFormatAttributes.SymbolAttribute.Symbol @@ -246,6 +247,7 @@ final class ICUNumberFormatter : ICUNumberFormatterBase, @unchecked Sendable { _create(with: .init(skeleton: style.collection.skeleton, localeIdentifier: style.locale.identifierCapturingPreferences)) } + @available(FoundationAttributedString 5.5, *) func attributedFormat(_ v: Value) -> AttributedString { guard let (str, attributes) = attributedFormatPositions(v) else { return AttributedString(v.fallbackDescription) @@ -294,6 +296,7 @@ final class ICUCurrencyNumberFormatter : ICUNumberFormatterBase, @unchecked Send _create(with: .init(skeleton: style.collection.skeleton, currencyCode: style.currencyCode, localeIdentifier: style.locale.identifierCapturingPreferences)) } + @available(FoundationAttributedString 5.5, *) func attributedFormat(_ v: Value) -> AttributedString { guard let (str, attributes) = attributedFormatPositions(v) else { return AttributedString(v.fallbackDescription) @@ -339,6 +342,7 @@ final class ICUPercentNumberFormatter : ICUNumberFormatterBase, @unchecked Senda _create(with: .init(skeleton: style.collection.skeleton, localeIdentifier: style.locale.identifierCapturingPreferences)) } + @available(FoundationAttributedString 5.5, *) func attributedFormat(_ v: Value) -> AttributedString { guard let (str, attributes) = attributedFormatPositions(v) else { return AttributedString(v.fallbackDescription) @@ -364,6 +368,7 @@ final class ICUByteCountNumberFormatter : ICUNumberFormatterBase, @unchecked Sen } } + @available(FoundationAttributedString 5.5, *) func attributedFormat(_ v: Value, unit: ByteCountFormatStyle.Unit) -> AttributedString { guard let (str, attributes) = attributedFormatPositions(v) else { return AttributedString(v.fallbackDescription) @@ -371,6 +376,7 @@ final class ICUByteCountNumberFormatter : ICUNumberFormatterBase, @unchecked Sen return attributedStringFromPositions(attributes, string: str, unit: unit) } + @available(FoundationAttributedString 5.5, *) private func attributedStringFromPositions(_ positions: [ICUNumberFormatter.AttributePosition], string: String, unit: ByteCountFormatStyle.Unit) -> AttributedString { typealias NumberPartAttribute = AttributeScopes.FoundationAttributes.NumberFormatAttributes.NumberPartAttribute.NumberPart typealias NumberSymbolAttribute = AttributeScopes.FoundationAttributes.NumberFormatAttributes.SymbolAttribute.Symbol @@ -422,6 +428,7 @@ final class ICUMeasurementNumberFormatter : ICUNumberFormatterBase, @unchecked S } } + @available(FoundationAttributedString 5.5, *) func attributedFormat(_ v: Value) -> AttributedString { guard let (str, attributes) = attributedFormatPositions(v) else { return AttributedString(v.fallbackDescription) @@ -430,6 +437,7 @@ final class ICUMeasurementNumberFormatter : ICUNumberFormatterBase, @unchecked S } /// Overrides superclass implementation to add the `MeasurementAttribute` property. + @available(FoundationAttributedString 5.5, *) override func attributedStringFromPositions(_ positions: [ICUNumberFormatter.AttributePosition], string: String) -> AttributedString { typealias NumberPartAttribute = AttributeScopes.FoundationAttributes.NumberFormatAttributes.NumberPartAttribute.NumberPart typealias NumberSymbolAttribute = AttributeScopes.FoundationAttributes.NumberFormatAttributes.SymbolAttribute.Symbol diff --git a/Sources/FoundationInternationalization/Formatting/Number/IntegerFormatStyle.swift b/Sources/FoundationInternationalization/Formatting/Number/IntegerFormatStyle.swift index 16f1d0142..216713089 100644 --- a/Sources/FoundationInternationalization/Formatting/Number/IntegerFormatStyle.swift +++ b/Sources/FoundationInternationalization/Formatting/Number/IntegerFormatStyle.swift @@ -25,6 +25,7 @@ public struct IntegerFormatStyle: Codable, Hashable, Senda self.locale = locale } + @available(FoundationAttributedString 5.5, *) public var attributed: IntegerFormatStyle.Attributed { return IntegerFormatStyle.Attributed(style: self) } @@ -89,6 +90,7 @@ extension IntegerFormatStyle { self.locale = locale } + @available(FoundationAttributedString 5.5, *) public var attributed: IntegerFormatStyle.Attributed { return IntegerFormatStyle.Attributed(style: self) } @@ -153,6 +155,7 @@ extension IntegerFormatStyle { self.collection = Configuration.Collection(presentation: .standard) } + @available(FoundationAttributedString 5.5, *) public var attributed: IntegerFormatStyle.Attributed { return IntegerFormatStyle.Attributed(style: self) } @@ -485,7 +488,7 @@ public extension FormatStyle { // MARK: - Attributed string -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) extension IntegerFormatStyle { public struct Attributed : Codable, Hashable, FormatStyle, Sendable { enum Style : Codable, Hashable { diff --git a/Sources/FoundationInternationalization/Formatting/Number/NumberAttributedFormat.swift b/Sources/FoundationInternationalization/Formatting/Number/NumberAttributedFormat.swift index 4c9b32f0c..acd789cca 100644 --- a/Sources/FoundationInternationalization/Formatting/Number/NumberAttributedFormat.swift +++ b/Sources/FoundationInternationalization/Formatting/Number/NumberAttributedFormat.swift @@ -16,6 +16,7 @@ import FoundationEssentials internal import _FoundationICU +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.FoundationAttributes.NumberFormatAttributes.SymbolAttribute.Symbol { init?(unumberFormatField: UNumberFormatFields) { switch unumberFormatField { @@ -35,6 +36,7 @@ extension AttributeScopes.FoundationAttributes.NumberFormatAttributes.SymbolAttr } } +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.FoundationAttributes.NumberFormatAttributes.NumberPartAttribute.NumberPart { init?(unumberFormatField: UNumberFormatFields) { switch unumberFormatField { @@ -48,6 +50,7 @@ extension AttributeScopes.FoundationAttributes.NumberFormatAttributes.NumberPart } } +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.FoundationAttributes.MeasurementAttribute.Component { init?(unumberFormatField: UNumberFormatFields) { switch unumberFormatField { diff --git a/Sources/TestSupport/TestSupport.swift b/Sources/TestSupport/TestSupport.swift index a8847500f..5031ba81a 100644 --- a/Sources/TestSupport/TestSupport.swift +++ b/Sources/TestSupport/TestSupport.swift @@ -137,7 +137,7 @@ public typealias PropertyListDecoder = FoundationEssentials.PropertyListDecoder @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) public typealias FormatStyle = FoundationEssentials.FormatStyle -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias ByteCountFormatStyle = FoundationInternationalization.ByteCountFormatStyle @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) public typealias ListFormatStyle = FoundationInternationalization.ListFormatStyle @@ -158,31 +158,31 @@ public typealias DiscreteFormatStyle = FoundationEssentials.DiscreteFormatStyle @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) public typealias StringStyle = FoundationInternationalization.StringStyle -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias AttributedString = FoundationEssentials.AttributedString -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias AttributeScope = FoundationEssentials.AttributeScope -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias AttributeContainer = FoundationEssentials.AttributeContainer -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias AttributeDynamicLookup = FoundationEssentials.AttributeDynamicLookup -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias AttributeScopes = FoundationEssentials.AttributeScopes -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias AttributedStringAttributeMutation = FoundationEssentials.AttributedStringAttributeMutation -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias AttributedStringKey = FoundationEssentials.AttributedStringKey -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias AttributedStringProtocol = FoundationEssentials.AttributedStringProtocol -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias AttributedSubstring = FoundationEssentials.AttributedSubstring -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias ScopedAttributeContainer = FoundationEssentials.ScopedAttributeContainer -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias CodableAttributedStringKey = FoundationEssentials.CodableAttributedStringKey -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias EncodableAttributedStringKey = FoundationEssentials.EncodableAttributedStringKey -@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(FoundationAttributedString 5.5, *) public typealias DecodableAttributedStringKey = FoundationEssentials.DecodableAttributedStringKey @available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) diff --git a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringCOWTests.swift b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringCOWTests.swift index d31a835c4..f4a39ce21 100644 --- a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringCOWTests.swift +++ b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringCOWTests.swift @@ -18,6 +18,7 @@ import Testing @testable import Foundation #endif +@available(FoundationAttributedString 5.5, *) extension AttributedStringProtocol { fileprivate mutating func genericSetAttribute() { self.testInt = 3 @@ -29,7 +30,7 @@ extension AttributedStringProtocol { private struct AttributedStringCOWTests { // MARK: - Utility Functions - + @available(FoundationAttributedString 5.5, *) func createAttributedString() -> AttributedString { var str = AttributedString("Hello", attributes: container) str += AttributedString(" ") @@ -37,6 +38,7 @@ private struct AttributedStringCOWTests { return str } + @available(FoundationAttributedString 5.5, *) func assertCOWCopy(sourceLocation: SourceLocation = #_sourceLocation, _ operation: (inout AttributedString) -> Void) { let str = createAttributedString() var copy = str @@ -44,6 +46,7 @@ private struct AttributedStringCOWTests { #expect(str != copy, "Mutation operation did not copy when multiple references exist", sourceLocation: sourceLocation) } + @available(FoundationAttributedString 5.5, *) func assertCOWCopyManual(sourceLocation: SourceLocation = #_sourceLocation, _ operation: (inout AttributedString) -> Void) { var str = createAttributedString() let gutsPtr = Unmanaged.passUnretained(str._guts) @@ -52,6 +55,7 @@ private struct AttributedStringCOWTests { #expect(gutsPtr.toOpaque() != newGutsPtr.toOpaque(), "Mutation operation with manual copy did not perform copy", sourceLocation: sourceLocation) } + @available(FoundationAttributedString 5.5, *) func assertCOWNoCopy(sourceLocation: SourceLocation = #_sourceLocation, _ operation: (inout AttributedString) -> Void) { var str = createAttributedString() let gutsPtr = Unmanaged.passUnretained(str._guts) @@ -60,37 +64,42 @@ private struct AttributedStringCOWTests { #expect(gutsPtr.toOpaque() == newGutsPtr.toOpaque(), "Mutation operation copied when only one reference exists", sourceLocation: sourceLocation) } + @available(FoundationAttributedString 5.5, *) func assertCOWBehavior(sourceLocation: SourceLocation = #_sourceLocation, _ operation: (inout AttributedString) -> Void) { assertCOWCopy(sourceLocation: sourceLocation, operation) assertCOWNoCopy(sourceLocation: sourceLocation, operation) } + @available(FoundationAttributedString 5.5, *) func makeSubrange(_ str: AttributedString) -> Range { return str.characters.index(str.startIndex, offsetBy: 2).. RangeSet { let rangeA = str.characters.index(str.startIndex, offsetBy: 2)..( string: AttributedString, matches expected: [(String, K.Value?)], @@ -43,6 +44,7 @@ private struct AttributedStringConstrainingBehaviorTests { } } + @available(FoundationAttributedString 5.5, *) func verify(string: AttributedString, matches expected: [(String, K.Value?, K2.Value?)], for key: KeyPath, _ key2: KeyPath, sourceLocation: SourceLocation = #_sourceLocation) where K.Value : Sendable, K2.Value : Sendable { @@ -60,6 +62,7 @@ private struct AttributedStringConstrainingBehaviorTests { } } + @available(FoundationAttributedString 5.5, *) func verify(string: AttributedString, matches expected: [(String, K.Value?, K2.Value?, K3.Value?)], for key: KeyPath, _ key2: KeyPath, _ key3: KeyPath, sourceLocation: SourceLocation = #_sourceLocation) where K.Value : Sendable, K2.Value : Sendable, K3.Value : Sendable { @@ -81,6 +84,7 @@ private struct AttributedStringConstrainingBehaviorTests { // MARK: Extending Run Tests + @available(FoundationAttributedString 5.5, *) @Test func extendingRunAddCharacters() { let str = AttributedString("Hello, world", attributes: .init().testInt(2).testNonExtended(1)) @@ -108,6 +112,7 @@ private struct AttributedStringConstrainingBehaviorTests { verify(string: result, matches: [("He", 2, 1), ("Hi!", 2, nil), ("rld", 2, 1)], for: \.testInt, \.testNonExtended) } + @available(FoundationAttributedString 5.5, *) @Test func extendingRunAddUnicodeScalars() { let str = AttributedString("Hello, world", attributes: .init().testInt(2).testNonExtended(1)) let scalarsStr = "A\u{0301}B" @@ -132,6 +137,7 @@ private struct AttributedStringConstrainingBehaviorTests { // MARK: - Paragraph Constrained Tests + @available(FoundationAttributedString 5.5, *) @Test func paragraphAttributeExpanding() { var str = AttributedString("Hello, world\nNext Paragraph") var range = str.index(afterCharacter: str.startIndex) ..< str.index(str.startIndex, offsetByCharacters: 3) @@ -153,6 +159,7 @@ private struct AttributedStringConstrainingBehaviorTests { verify(string: str, matches: [("Hello, world\n", 4), ("Next Paragraph", 4)], for: \.testParagraphConstrained) } + @available(FoundationAttributedString 5.5, *) @Test func paragraphAttributeRemoval() { var str = AttributedString("Hello, world\nNext Paragraph", attributes: .init().testParagraphConstrained(2)) var range = str.index(afterCharacter: str.startIndex) ..< str.index(str.startIndex, offsetByCharacters: 3) @@ -172,6 +179,7 @@ private struct AttributedStringConstrainingBehaviorTests { verify(string: str, matches: [("Hello, world\n", nil), ("Next Paragraph", nil)], for: \.testParagraphConstrained) } + @available(FoundationAttributedString 5.5, *) @Test func paragraphAttributeContainerApplying() { var container = AttributeContainer.testParagraphConstrained(2).testString("Hello") var str = AttributedString("Hello, world\nNext Paragraph") @@ -200,6 +208,7 @@ private struct AttributedStringConstrainingBehaviorTests { verify(string: str, matches: [("H", 4, nil, 1), ("el", 4, "Hello", 1), ("lo, w", 4, nil, 1), ("orld\n", 4, nil, 2), ("N", 4, nil, 2), ("ext Paragrap", 4, nil, 1), ("h", 4, "Hello", 2)], for: \.testParagraphConstrained, \.testString, \.testInt) } + @available(FoundationAttributedString 5.5, *) @Test func paragraphAttributeContainerReplacing() { var str = AttributedString("Hello, world\nNext Paragraph") let range = str.index(afterCharacter: str.startIndex) ..< str.index(str.startIndex, offsetByCharacters: 3) @@ -221,6 +230,7 @@ private struct AttributedStringConstrainingBehaviorTests { verify(string: result, matches: [("H", 3, 2, nil), ("el", 3, nil, true), ("lo, world\n", 3, 2, nil), ("Next Paragraph", nil, 2, nil)], for: \.testParagraphConstrained, \.testInt, \.testBool) } + @available(FoundationAttributedString 5.5, *) @Test func paragraphTextMutation() { let str = AttributedString("Hello, world\n", attributes: .init().testParagraphConstrained(1)) + AttributedString("Next Paragraph", attributes: .init().testParagraphConstrained(2)) @@ -265,6 +275,7 @@ private struct AttributedStringConstrainingBehaviorTests { verify(string: result, matches: [("Hello, wTest\n", 1), ("Replacementxt Paragraph", 1)], for: \.testParagraphConstrained) } + @available(FoundationAttributedString 5.5, *) @Test func paragraphAttributedTextMutation() { let str = AttributedString("Hello, world\n", attributes: .init().testParagraphConstrained(1)) + AttributedString("Next Paragraph", attributes: .init().testParagraphConstrained(2)) let singleReplacement = AttributedString("Test", attributes: .init().testParagraphConstrained(5).testSecondParagraphConstrained(6).testBool(true)) @@ -316,6 +327,7 @@ private struct AttributedStringConstrainingBehaviorTests { } #if FOUNDATION_FRAMEWORK + @available(FoundationAttributedString 5.5, *) @Test func paragraphFromUntrustedRuns() throws { let str = NSMutableAttributedString(string: "Hello ", attributes: [.testParagraphConstrained : NSNumber(2)]) str.append(NSAttributedString(string: "World", attributes: [.testParagraphConstrained : NSNumber(3), .testSecondParagraphConstrained : NSNumber(4)])) @@ -325,6 +337,7 @@ private struct AttributedStringConstrainingBehaviorTests { } #endif // FOUNDATION_FRAMEWORK + @available(FoundationAttributedString 5.5, *) @Test func paragraphFromReplacedSubrange() { let str = AttributedString("Before\nHello, world\nNext Paragraph\nAfter", attributes: .init().testParagraphConstrained(1)) @@ -349,6 +362,7 @@ private struct AttributedStringConstrainingBehaviorTests { // MARK: - Character Constrained Tests + @available(FoundationAttributedString 5.5, *) @Test func characterAttributeApply() { let str = AttributedString("*__*__**__*") @@ -367,6 +381,7 @@ private struct AttributedStringConstrainingBehaviorTests { verify(string: result, matches: [("*", nil, 1), ("__", nil, 1), ("*", nil, 1), ("__", nil, 1), ("*", nil, 1), ("*", nil, 1), ("__", nil, 1), ("*", 3, 1)], for: \.testCharacterConstrained, \.testInt) } + @available(FoundationAttributedString 5.5, *) @Test func characterAttributeSubCharacterApply() { let str = AttributedString("ABC \u{FFFD} DEF") @@ -399,6 +414,7 @@ private struct AttributedStringConstrainingBehaviorTests { } + @available(FoundationAttributedString 5.5, *) @Test func characterAttributeContainerReplacing() { var str = AttributedString("*__*__**__*") let range = str.index(afterCharacter: str.startIndex) ..< str.index(str.startIndex, offsetByCharacters: 4) @@ -420,6 +436,7 @@ private struct AttributedStringConstrainingBehaviorTests { verify(string: result, matches: [("*", nil, 2, nil), ("__", nil, nil, true), ("*", 3, nil, true), ("__", nil, 2, nil), ("*", nil, 2, nil), ("*", nil, 2, nil), ("__", nil, 2, nil), ("*", nil, 2, nil)], for: \.testCharacterConstrained, \.testInt, \.testBool) } + @available(FoundationAttributedString 5.5, *) @Test func characterTextMutation() { let str = AttributedString("*__*__**__*", attributes: .init().testCharacterConstrained(2)) @@ -449,6 +466,7 @@ private struct AttributedStringConstrainingBehaviorTests { } #if FOUNDATION_FRAMEWORK + @available(FoundationAttributedString 5.5, *) @Test func characterFromUntrustedRuns() throws { let str = NSMutableAttributedString(string: "*__*__**__*", attributes: [.testCharacterConstrained : NSNumber(2)]) str.append(NSAttributedString(string: "_*")) @@ -460,6 +478,7 @@ private struct AttributedStringConstrainingBehaviorTests { // MARK: Invalidation Tests + @available(FoundationAttributedString 5.5, *) @Test func invalidationAttributeChange() { let str = AttributedString("Hello, world", attributes: .init().testInt(1).testAttributeDependent(2)) @@ -494,6 +513,7 @@ private struct AttributedStringConstrainingBehaviorTests { verify(string: result, matches: [("Hello, world", 2, nil)], for: \.testInt, \.testAttributeDependent) } + @available(FoundationAttributedString 5.5, *) @Test func invalidationCharacterChange() { let str = AttributedString("Hello, world", attributes: .init().testInt(1).testCharacterDependent(2)) @@ -580,6 +600,7 @@ private struct AttributedStringConstrainingBehaviorTests { verify(string: result, matches: [("H", nil, nil, "Hello"), ("ello, world", 1, nil, nil)], for: \.testInt, \.testCharacterDependent, \.testString) } + @available(FoundationAttributedString 5.5, *) @Test func invalidationCharacterInsertionBetweenRuns() { var str = AttributedString("Hello", attributes: .init().testInt(1).testCharacterDependent(2)) str += AttributedString("World", attributes: .init().testInt(1).testCharacterDependent(3)) diff --git a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringDiscontiguousTests.swift b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringDiscontiguousTests.swift index ae247167b..524eb0348 100644 --- a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringDiscontiguousTests.swift +++ b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringDiscontiguousTests.swift @@ -20,8 +20,8 @@ import Foundation @Suite("Discontiguous AttributedString") private struct AttributedStringDiscontiguousTests { - @Test - func emptySlice() { + @available(FoundationAttributedString 5.5, *) + @Test func emptySlice() { let str = AttributedString() let slice = str[RangeSet()] #expect(slice.runs.isEmpty) @@ -44,8 +44,8 @@ private struct AttributedStringDiscontiguousTests { } } - @Test - func characters() { + @available(FoundationAttributedString 5.5, *) + @Test func characters() { let str = AttributedString("abcdefgabc") let fullSlice = str[str.startIndex ..< str.endIndex].characters let fullDiscontiguousSlice = str[RangeSet(str.startIndex ..< str.endIndex)].characters @@ -58,8 +58,8 @@ private struct AttributedStringDiscontiguousTests { #expect(Array(slice) == ["a", "b", "c", "a", "b", "c"]) } - @Test - func unicodeScalars() { + @available(FoundationAttributedString 5.5, *) + @Test func unicodeScalars() { let str = AttributedString("abcdefgabc") let fullSlice = str[str.startIndex ..< str.endIndex].unicodeScalars let fullDiscontiguousSlice = str[RangeSet(str.startIndex ..< str.endIndex)].unicodeScalars @@ -72,8 +72,8 @@ private struct AttributedStringDiscontiguousTests { #expect(Array(slice) == ["a", "b", "c", "a", "b", "c"]) } - @Test - func attributes() { + @available(FoundationAttributedString 5.5, *) + @Test func attributes() { let str = AttributedString("abcdefg") let rangeA = str.startIndex ..< str.index(str.startIndex, offsetByCharacters: 1) let rangeB = str.index(str.startIndex, offsetByCharacters: 2) ..< str.index(str.startIndex, offsetByCharacters: 3) @@ -179,8 +179,8 @@ private struct AttributedStringDiscontiguousTests { } } - @Test - func reinitialization() { + @available(FoundationAttributedString 5.5, *) + @Test func reinitialization() { var str = AttributedString("abcdefg") let rangeA = str.startIndex ..< str.index(str.startIndex, offsetByCharacters: 1) let rangeB = str.index(str.startIndex, offsetByCharacters: 2) ..< str.index(str.startIndex, offsetByCharacters: 3) @@ -192,8 +192,8 @@ private struct AttributedStringDiscontiguousTests { #expect(reinitialized == AttributedString("ace", attributes: AttributeContainer.testInt(2))) } - @Test - func reslicing() { + @available(FoundationAttributedString 5.5, *) + @Test func reslicing() { var str = AttributedString("abcdefg") let rangeA = str.startIndex ..< str.index(str.startIndex, offsetByCharacters: 1) let rangeB = str.index(str.startIndex, offsetByCharacters: 2) ..< str.index(str.startIndex, offsetByCharacters: 3) @@ -208,8 +208,8 @@ private struct AttributedStringDiscontiguousTests { #expect(str[RangeSet()][RangeSet()] == str[RangeSet()]) } - @Test - func runs() { + @available(FoundationAttributedString 5.5, *) + @Test func runs() { var str = AttributedString("AAA", attributes: AttributeContainer.testInt(2)) str += AttributedString("BBB", attributes: AttributeContainer.testInt(3).testString("foo")) str += AttributedString("CC", attributes: AttributeContainer.testInt(3).testString("bar")) @@ -234,8 +234,8 @@ private struct AttributedStringDiscontiguousTests { #expect(runs.reversed().map(\.range) == expectedRanges.reversed()) } - @Test - func coalescedRuns() { + @available(FoundationAttributedString 5.5, *) + @Test func coalescedRuns() { struct EquatableBox: Equatable, CustomStringConvertible { let t: T let u: U @@ -281,8 +281,8 @@ private struct AttributedStringDiscontiguousTests { #expect(runs[\.testString].reversed().map(EquatableBox.init) == testStringExpectation.reversed()) } - @Test - func removeSubranges() { + @available(FoundationAttributedString 5.5, *) + @Test func removeSubranges() { var str = AttributedString("abcdefg") let rangeA = str.startIndex ..< str.index(str.startIndex, offsetByCharacters: 1) let rangeB = str.index(str.startIndex, offsetByCharacters: 2) ..< str.index(str.startIndex, offsetByCharacters: 3) @@ -297,8 +297,8 @@ private struct AttributedStringDiscontiguousTests { #expect(str == result) } - @Test - func sliceSetter() { + @available(FoundationAttributedString 5.5, *) + @Test func sliceSetter() { var str = AttributedString("abcdefg") let rangeA = str.startIndex ..< str.index(str.startIndex, offsetByCharacters: 1) let rangeB = str.index(str.startIndex, offsetByCharacters: 2) ..< str.index(str.startIndex, offsetByCharacters: 3) @@ -332,8 +332,8 @@ private struct AttributedStringDiscontiguousTests { } } - @Test - func graphemesAcrossDiscontiguousRanges() { + @available(FoundationAttributedString 5.5, *) + @Test func graphemesAcrossDiscontiguousRanges() { let str = "a\n\u{301}" let attrStr = AttributedString(str) let strRangeA = str.startIndex ..< str.index(after: str.startIndex) // Range of 'a' diff --git a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringIndexTrackingTests.swift b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringIndexTrackingTests.swift index e89f1a4a0..17069e4b4 100644 --- a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringIndexTrackingTests.swift +++ b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringIndexTrackingTests.swift @@ -20,8 +20,8 @@ import Foundation @Suite("AttributedString Index Tracking") private struct AttributedStringIndexTrackingTests { - @Test - func basics() throws { + @available(FoundationAttributedString 5.5, *) + @Test func basics() throws { var text = AttributedString("ABC. Hello, world!") let original = text let helloRange = try #require(text.range(of: "Hello")) @@ -36,8 +36,8 @@ private struct AttributedStringIndexTrackingTests { #expect(text[updatedRanges[1]] == original[worldRange]) } - @Test - func insertionWithinRange() throws { + @available(FoundationAttributedString 5.5, *) + @Test func insertionWithinRange() throws { var text = AttributedString("Hello, world") var helloRange = try #require(text.range(of: "Hello")) @@ -48,8 +48,8 @@ private struct AttributedStringIndexTrackingTests { #expect(String(text[helloRange].characters) == "Hel_Goodbye_lo") } - @Test - func insertionAtStartOfRange() throws { + @available(FoundationAttributedString 5.5, *) + @Test func insertionAtStartOfRange() throws { var text = AttributedString("Hello, world") let helloRange = try #require(text.range(of: "llo")) @@ -60,8 +60,8 @@ private struct AttributedStringIndexTrackingTests { #expect(String(text[updatedHelloRange].characters) == "llo") } - @Test - func insertionAtEndOfRange() throws { + @available(FoundationAttributedString 5.5, *) + @Test func insertionAtEndOfRange() throws { var text = AttributedString("Hello, world") let helloRange = try #require(text.range(of: "llo")) @@ -72,8 +72,8 @@ private struct AttributedStringIndexTrackingTests { #expect(String(text[updatedHelloRange].characters) == "llo") } - @Test - func insertionAtEmptyRange() throws { + @available(FoundationAttributedString 5.5, *) + @Test func insertionAtEmptyRange() throws { var text = AttributedString("ABCDE") let idx = text.index(text.startIndex, offsetByCharacters: 3) @@ -85,8 +85,8 @@ private struct AttributedStringIndexTrackingTests { #expect(text.characters[updatedRange.lowerBound] == "D") } - @Test - func removalWithinRange() throws { + @available(FoundationAttributedString 5.5, *) + @Test func removalWithinRange() throws { var text = AttributedString("Hello, world") var helloRange = try #require(text.range(of: "Hello")) @@ -97,8 +97,8 @@ private struct AttributedStringIndexTrackingTests { #expect(String(text[helloRange].characters) == "Heo") } - @Test - func fullCollapse() throws { + @available(FoundationAttributedString 5.5, *) + @Test func fullCollapse() throws { do { var text = AttributedString("Hello, world") var helloRange = try #require(text.range(of: "Hello")) @@ -135,8 +135,8 @@ private struct AttributedStringIndexTrackingTests { } } - @Test - func collapseLeft() throws { + @available(FoundationAttributedString 5.5, *) + @Test func collapseLeft() throws { var text = AttributedString("Hello, world") var helloRange = try #require(text.range(of: "Hello")) @@ -147,8 +147,8 @@ private struct AttributedStringIndexTrackingTests { #expect(String(text[helloRange].characters) == "He") } - @Test - func collapseRight() throws { + @available(FoundationAttributedString 5.5, *) + @Test func collapseRight() throws { var text = AttributedString("Hello, world") var worldRange = try #require(text.range(of: "world")) @@ -159,8 +159,8 @@ private struct AttributedStringIndexTrackingTests { #expect(String(text[worldRange].characters) == "rld") } - @Test - func nesting() throws { + @available(FoundationAttributedString 5.5, *) + @Test func nesting() throws { var text = AttributedString("Hello, world") var helloRange = try #require(text.range(of: "Hello")) try text.transform(updating: &helloRange) { @@ -174,8 +174,8 @@ private struct AttributedStringIndexTrackingTests { } #if FOUNDATION_EXIT_TESTS - @Test - func trackingLostPreconditions() async { + @available(FoundationAttributedString 5.5, *) + @Test func trackingLostPreconditions() async { await #expect(processExitsWith: .failure) { var text = AttributedString("Hello, world") var helloRange = try #require(text.range(of: "Hello")) @@ -210,8 +210,8 @@ private struct AttributedStringIndexTrackingTests { } #endif - @Test - func trackingLost() throws { + @available(FoundationAttributedString 5.5, *) + @Test func trackingLost() throws { let text = AttributedString("Hello, world") let helloRange = try #require(text.range(of: "Hello")) @@ -247,8 +247,8 @@ private struct AttributedStringIndexTrackingTests { } } - @Test - func attributeMutation() throws { + @available(FoundationAttributedString 5.5, *) + @Test func attributeMutation() throws { var text = AttributedString("Hello, world!") let original = text let helloRange = try #require(text.range(of: "Hello")) @@ -264,8 +264,8 @@ private struct AttributedStringIndexTrackingTests { } #if FOUNDATION_EXIT_TESTS - @Test - func invalidInputRanges() async { + @available(FoundationAttributedString 5.5, *) + @Test func invalidInputRanges() async { await #expect(processExitsWith: .failure) { var text = AttributedString("Hello, world") let other = text + AttributedString("Extra text") diff --git a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringIndexValidityTests.swift b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringIndexValidityTests.swift index 5369467ea..b0fcd485b 100644 --- a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringIndexValidityTests.swift +++ b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringIndexValidityTests.swift @@ -20,8 +20,8 @@ import Foundation @Suite("AttributedString Index Validity") private struct AttributedStringIndexValidityTests { - @Test - public func startEndRange() { + @available(FoundationAttributedString 5.5, *) + @Test func startEndRange() { let str = AttributedString("Hello, world") #expect(str.startIndex.isValid(within: str)) @@ -94,8 +94,8 @@ private struct AttributedStringIndexValidityTests { } } - @Test - public func exhaustiveIndices() { + @available(FoundationAttributedString 5.5, *) + @Test func exhaustiveIndices() { let str = AttributedString("Hello Cafe\u{301} 👍🏻🇺🇸 World") for idx in str.characters.indices { #expect(idx.isValid(within: str)) @@ -111,8 +111,8 @@ private struct AttributedStringIndexValidityTests { } } - @Test - public func outOfBoundsContiguous() { + @available(FoundationAttributedString 5.5, *) + @Test func outOfBoundsContiguous() { let str = AttributedString("Hello, world") let subStart = str.index(afterCharacter: str.startIndex) let subEnd = str.index(beforeCharacter: str.endIndex) @@ -127,8 +127,8 @@ private struct AttributedStringIndexValidityTests { #expect(!(str.endIndex ..< str.endIndex).isValid(within: substr)) } - @Test - public func outOfBoundsDiscontiguous() { + @available(FoundationAttributedString 5.5, *) + @Test func outOfBoundsDiscontiguous() { let str = AttributedString("Hello, world") let idxA = str.index(afterCharacter: str.startIndex) let idxB = str.index(afterCharacter: idxA) @@ -148,8 +148,8 @@ private struct AttributedStringIndexValidityTests { #expect(!(str.endIndex ..< str.endIndex).isValid(within: substr)) } - @Test - public func mutationInvalidation() { + @available(FoundationAttributedString 5.5, *) + @Test func mutationInvalidation() { func checkInPlace(_ mutation: (inout AttributedString) -> (), sourceLocation: SourceLocation = #_sourceLocation) { var str = AttributedString("Hello World") let idxA = str.startIndex diff --git a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringTestSupport.swift b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringTestSupport.swift index df8f443d0..c45661dbc 100644 --- a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringTestSupport.swift +++ b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringTestSupport.swift @@ -26,6 +26,7 @@ extension NSAttributedString.Key { } #endif +@available(FoundationAttributedString 5.5, *) extension AttributeScopes.TestAttributes { enum TestIntAttribute: CodableAttributedStringKey { @@ -123,6 +124,7 @@ struct NonCodableType : Hashable { var inner : Int } +@available(FoundationAttributedString 5.5, *) extension AttributeScopes { var test: TestAttributes.Type { TestAttributes.self } @@ -141,6 +143,7 @@ extension AttributeScopes { } } +@available(FoundationAttributedString 5.5, *) extension AttributeDynamicLookup { subscript(dynamicMember keyPath: KeyPath) -> T { get { self[T.self] } diff --git a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringTests.swift b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringTests.swift index 36befc4e9..c33f303e9 100644 --- a/Tests/FoundationEssentialsTests/AttributedString/AttributedStringTests.swift +++ b/Tests/FoundationEssentialsTests/AttributedString/AttributedStringTests.swift @@ -38,6 +38,7 @@ import AppKit private struct AttributedStringTests { // MARK: - Enumeration Tests + @available(FoundationAttributedString 5.5, *) @Test func emptyEnumeration() { for _ in AttributedString().runs { Issue.record("Empty AttributedString should not enumerate any attributes") @@ -59,6 +60,7 @@ private struct AttributedStringTests { } } + @available(FoundationAttributedString 5.5, *) func verifyAttributes(_ runs: AttributedString.Runs.AttributesSlice1, string: AttributedString, expectation: [(String, T.Value?)], sourceLocation: SourceLocation = #_sourceLocation) where T.Value : Sendable { // Test that the attribute is correct when iterating through attribute runs var expectIterator = expectation.makeIterator() @@ -85,6 +87,7 @@ private struct AttributedStringTests { #expect(expectIterator.next() == nil, "Additional runs expected but not found", sourceLocation: sourceLocation) } + @available(FoundationAttributedString 5.5, *) func verifyAttributes(_ runs: AttributedString.Runs.AttributesSlice2, string: AttributedString, expectation: [(String, T.Value?, U.Value?)], sourceLocation: SourceLocation = #_sourceLocation) where T.Value : Sendable, U.Value : Sendable { // Test that the attributes are correct when iterating through attribute runs var expectIterator = expectation.makeIterator() @@ -141,6 +144,7 @@ private struct AttributedStringTests { } #endif // FOUNDATION_FRAMEWORK + @available(FoundationAttributedString 5.5, *) @Test func simpleEnumeration() throws { var attrStr = AttributedString("Hello", attributes: AttributeContainer().testInt(1)) attrStr += " " @@ -180,6 +184,7 @@ private struct AttributedStringTests { verifyAttributes(attrView[\.testInt, \.testDouble], string: attrStr, expectation: [("Hello", 1, nil), (" ", nil, nil), ("World", nil, 2.0)]) } + @available(FoundationAttributedString 5.5, *) @Test func sliceEnumeration() throws { var attrStr = AttributedString("Hello", attributes: AttributeContainer().testInt(1)) attrStr += AttributedString(" ") @@ -222,6 +227,7 @@ private struct AttributedStringTests { } #if FOUNDATION_FRAMEWORK + @available(FoundationAttributedString 5.5, *) @Test func nsSliceEnumeration() { var attrStr = AttributedString("Hello", attributes: AttributeContainer().testInt(1)) attrStr += AttributedString(" ") @@ -250,6 +256,7 @@ private struct AttributedStringTests { // MARK: - Attribute Tests + @available(FoundationAttributedString 5.5, *) @Test func simpleAttribute() { let attrStr = AttributedString("Foo", attributes: AttributeContainer().testInt(42)) let (value, range) = attrStr.runs[\.testInt][attrStr.startIndex] @@ -257,6 +264,7 @@ private struct AttributedStringTests { #expect(range == attrStr.startIndex ..< attrStr.endIndex) } + @available(FoundationAttributedString 5.5, *) @Test func constructorAttribute() { // TODO: Re-evaluate whether we want these. let attrStr = AttributedString("Hello", attributes: AttributeContainer().testString("Helvetica").testInt(2)) @@ -266,6 +274,7 @@ private struct AttributedStringTests { #expect(attrStr == expected) } + @available(FoundationAttributedString 5.5, *) @Test func addAndRemoveAttribute() { let attr : Int = 42 let attr2 : Double = 1.0 @@ -282,6 +291,7 @@ private struct AttributedStringTests { #expect(attrStr == expected2) } + @available(FoundationAttributedString 5.5, *) @Test func addingAndRemovingAttribute() { let container = AttributeContainer().testInt(1).testDouble(2.2) let attrStr = AttributedString("Test").mergingAttributes(container) @@ -292,6 +302,7 @@ private struct AttributedStringTests { #expect(doubleRemoved == AttributedString("Test", attributes: AttributeContainer().testInt(1))) } + @available(FoundationAttributedString 5.5, *) @Test func scopedAttributes() { var str = AttributedString("Hello, world", attributes: AttributeContainer().testInt(2).testDouble(3.4)) #expect(str.test.testInt == 2) @@ -308,6 +319,7 @@ private struct AttributedStringTests { #expect(str[range].test.testBool == true) } + @available(FoundationAttributedString 5.5, *) @Test func runAttributes() { var str = AttributedString("String", attributes: .init().testString("test1")) str += "None" @@ -322,6 +334,7 @@ private struct AttributedStringTests { // MARK: - Comparison Tests + @available(FoundationAttributedString 5.5, *) @Test func attributedStringEquality() { #expect(AttributedString() == AttributedString()) #expect(AttributedString("abc") == AttributedString("abc")) @@ -360,6 +373,7 @@ private struct AttributedStringTests { #expect(a2.characters.elementsEqual(a3.characters)) } + @available(FoundationAttributedString 5.5, *) @Test func attributedSubstringEquality() { let emptyStr = AttributedString("01234567890123456789") @@ -390,6 +404,7 @@ private struct AttributedStringTests { #expect(emptyStr[index0 ..< index5] == AttributedString("01234")) } + @available(FoundationAttributedString 5.5, *) @Test func runEquality() { var attrStr = AttributedString("Hello", attributes: AttributeContainer().testInt(1)) attrStr += AttributedString(" ") @@ -427,6 +442,7 @@ private struct AttributedStringTests { #expect(attrStr.runs != attrStr3.runs) } + @available(FoundationAttributedString 5.5, *) @Test func substringRunEquality() { var attrStr = AttributedString("Hello", attributes: AttributeContainer().testInt(1)) attrStr += AttributedString(" ") @@ -458,6 +474,7 @@ private struct AttributedStringTests { // MARK: - Mutation Tests + @available(FoundationAttributedString 5.5, *) @Test func directMutationCopyOnWrite() { var attrStr = AttributedString("ABC") let copy = attrStr @@ -467,6 +484,7 @@ private struct AttributedStringTests { #expect(attrStr != copy) } + @available(FoundationAttributedString 5.5, *) @Test func attributeMutationCopyOnWrite() { var attrStr = AttributedString("ABC") let copy = attrStr @@ -475,6 +493,7 @@ private struct AttributedStringTests { #expect(attrStr != copy) } + @available(FoundationAttributedString 5.5, *) @Test func sliceAttributeMutation() { let attr : Int = 42 let attr2 : Double = 1.0 @@ -494,6 +513,7 @@ private struct AttributedStringTests { #expect(copy != attrStr) } + @available(FoundationAttributedString 5.5, *) @Test func enumerationAttributeMutation() { var attrStr = AttributedString("A", attributes: AttributeContainer().testInt(1)) attrStr += AttributedString("B", attributes: AttributeContainer().testDouble(2.0)) @@ -511,6 +531,7 @@ private struct AttributedStringTests { #expect(expected == attrStr) } + @available(FoundationAttributedString 5.5, *) @Test func mutateMultipleAttributes() { var attrStr = AttributedString("A", attributes: AttributeContainer().testInt(1).testBool(true)) attrStr += AttributedString("B", attributes: AttributeContainer().testInt(1).testDouble(2)) @@ -578,6 +599,7 @@ private struct AttributedStringTests { #expect(changeRange1expected == changeRange1) } + @available(FoundationAttributedString 5.5, *) @Test func mutateAttributes() { var attrStr = AttributedString("A", attributes: AttributeContainer().testInt(1).testBool(true)) attrStr += AttributedString("B", attributes: AttributeContainer().testInt(1).testDouble(2)) @@ -639,6 +661,7 @@ private struct AttributedStringTests { #expect(changeRange2expected == changeRange2) } + @available(FoundationAttributedString 5.5, *) @Test func replaceAttributes() { var attrStr = AttributedString("A", attributes: AttributeContainer().testInt(1).testBool(true)) attrStr += AttributedString("B", attributes: AttributeContainer().testInt(1).testDouble(2)) @@ -679,6 +702,7 @@ private struct AttributedStringTests { } + @available(FoundationAttributedString 5.5, *) @Test func sliceMutation() { var attrStr = AttributedString("Hello World", attributes: AttributeContainer().testInt(1)) let start = attrStr.characters.index(attrStr.startIndex, offsetBy: 6) @@ -690,6 +714,7 @@ private struct AttributedStringTests { #expect(attrStr != AttributedString("Hello Goodbye", attributes: AttributeContainer().testInt(1))) } + @available(FoundationAttributedString 5.5, *) @Test func overlappingSliceMutation() throws { var attrStr = AttributedString("Hello, world!") attrStr[try #require(attrStr.range(of: "Hello"))].testInt = 1 @@ -705,6 +730,7 @@ private struct AttributedStringTests { #expect(attrStr == expected) } + @available(FoundationAttributedString 5.5, *) @Test func characters_replaceSubrange() throws { var attrStr = AttributedString("Hello World", attributes: AttributeContainer().testInt(1)) attrStr.characters.replaceSubrange(try #require(attrStr.range(of: " ")), with: " Good ") @@ -713,6 +739,7 @@ private struct AttributedStringTests { #expect(expected == attrStr) } + @available(FoundationAttributedString 5.5, *) @Test func charactersMutation_append() { var attrStr = AttributedString("Hello World", attributes: AttributeContainer().testInt(1)) attrStr.characters.append(contentsOf: " Goodbye") @@ -721,6 +748,7 @@ private struct AttributedStringTests { #expect(expected == attrStr) } + @available(FoundationAttributedString 5.5, *) @Test func unicodeScalars_replaceSubrange() { var attrStr = AttributedString("La Cafe\u{301}", attributes: AttributeContainer().testInt(1)) let unicode = attrStr.unicodeScalars @@ -730,6 +758,7 @@ private struct AttributedStringTests { #expect(expected == attrStr) } + @available(FoundationAttributedString 5.5, *) @Test func unicodeScalarsMutation_append() { var attrStr = AttributedString("Cafe", attributes: AttributeContainer().testInt(1)) attrStr.unicodeScalars.append("\u{301}") @@ -738,6 +767,7 @@ private struct AttributedStringTests { #expect(expected == attrStr) } + @available(FoundationAttributedString 5.5, *) @Test func subCharacterAttributeSetting() { var attrStr = AttributedString("Cafe\u{301}", attributes: AttributeContainer().testInt(1)) let cafRange = attrStr.characters.startIndex ..< attrStr.characters.index(attrStr.characters.startIndex, offsetBy: 3) @@ -753,6 +783,7 @@ private struct AttributedStringTests { #expect(expected == attrStr) } + @available(FoundationAttributedString 5.5, *) @Test func replaceSubrange_rangeExpression() { var attrStr = AttributedString("Hello World", attributes: AttributeContainer().testInt(1)) @@ -765,6 +796,7 @@ private struct AttributedStringTests { #expect(attrStr == expected) } + @available(FoundationAttributedString 5.5, *) @Test func settingAttributes() { var attrStr = AttributedString("Hello World", attributes: .init().testInt(1)) attrStr += AttributedString(". My name is Foundation!", attributes: .init().testBool(true)) @@ -775,6 +807,7 @@ private struct AttributedStringTests { #expect(result == expected) } + @available(FoundationAttributedString 5.5, *) @Test func addAttributedString() { let attrStr = AttributedString("Hello ", attributes: .init().testInt(1)) let attrStr2 = AttributedString("World", attributes: .init().testInt(2)) @@ -799,6 +832,7 @@ private struct AttributedStringTests { } } + @available(FoundationAttributedString 5.5, *) @Test func replaceSubrangeWithSubstrings() { let baseString = AttributedString("A", attributes: .init().testInt(1)) + AttributedString("B", attributes: .init().testInt(2)) @@ -829,6 +863,7 @@ private struct AttributedStringTests { #expect(targetString == expected) } + @available(FoundationAttributedString 5.5, *) func assertStringIsCoalesced(_ str: AttributedString) { var prev: AttributedString.Runs.Run? for run in str.runs { @@ -839,6 +874,7 @@ private struct AttributedStringTests { } } + @available(FoundationAttributedString 5.5, *) @Test func coalescing() { let str = AttributedString("Hello", attributes: .init().testInt(1)) let appendSame = str + AttributedString("World", attributes: .init().testInt(1)) @@ -899,6 +935,7 @@ private struct AttributedStringTests { #expect(str10.runs.count == 1) } + @available(FoundationAttributedString 5.5, *) @Test func replaceWithEmptyElements() { var str = AttributedString("Hello, world") let range = str.startIndex ..< str.characters.index(str.startIndex, offsetBy: 5) @@ -907,6 +944,7 @@ private struct AttributedStringTests { #expect(str == AttributedString(", world")) } + @available(FoundationAttributedString 5.5, *) @Test func description() { let string = AttributedString("A", attributes: .init().testInt(1)) + AttributedString("B", attributes: .init().testInt(2)) @@ -938,6 +976,7 @@ E { #expect(runsDesc == expected) } + @available(FoundationAttributedString 5.5, *) @Test func containerDescription() { let cont = AttributeContainer().testBool(false).testInt(1).testDouble(2.0).testString("3") @@ -952,6 +991,7 @@ E { #expect(desc.contains("\tTestBool = false\n")) } + @available(FoundationAttributedString 5.5, *) @Test func runAndSubstringDescription() { let string = AttributedString("A", attributes: .init().testInt(1)) + AttributedString("B", attributes: .init().testInt(2)) @@ -987,6 +1027,7 @@ E { #expect(subDescs == expected) } + @available(FoundationAttributedString 5.5, *) @Test func replacingAttributes() { var str = AttributedString("Hello", attributes: .init().testInt(2)) str += AttributedString("World", attributes: .init().testString("Test")) @@ -1000,6 +1041,7 @@ E { #expect(result == expected) } + @available(FoundationAttributedString 5.5, *) @Test func scopedAttributeContainer() { var str = AttributedString("Hello, world") @@ -1036,6 +1078,7 @@ E { #expect(str[otherRange].testBool == true) } + @available(FoundationAttributedString 5.5, *) @Test func mergeAttributes() { let originalAttributes = AttributeContainer.testInt(2).testBool(true) let newAttributes = AttributeContainer.testString("foo") @@ -1048,6 +1091,7 @@ E { #expect(str.mergingAttributes(overlappingAttributes, mergePolicy: .keepCurrent) == AttributedString("Hello, world", attributes: originalAttributes.testDouble(4.3))) } + @available(FoundationAttributedString 5.5, *) @Test func mergeAttributeContainers() { let originalAttributes = AttributeContainer.testInt(2).testBool(true) let newAttributes = AttributeContainer.testString("foo") @@ -1059,6 +1103,7 @@ E { #expect(originalAttributes.merging(overlappingAttributes, mergePolicy: .keepCurrent) == originalAttributes.testDouble(4.3)) } + @available(FoundationAttributedString 5.5, *) @Test func changingSingleCharacterUTF8Length() throws { var attrstr = AttributedString("\u{1F3BA}\u{1F3BA}") // UTF-8 Length of 8 attrstr.characters[attrstr.startIndex] = "A" // Changes UTF-8 Length to 5 @@ -1070,6 +1115,7 @@ E { // MARK: - Substring Tests + @available(FoundationAttributedString 5.5, *) @Test func substringBase() { let str = AttributedString("Hello World", attributes: .init().testInt(1)) var substr = str[str.startIndex ..< str.characters.index(str.startIndex, offsetBy: 5)] @@ -1084,6 +1130,7 @@ E { #expect(str2[range].base == str2) } + @available(FoundationAttributedString 5.5, *) @Test func substringGetAttribute() { let str = AttributedString("Hello World", attributes: .init().testInt(1)) let range = str.startIndex ..< str.characters.index(str.startIndex, offsetBy: 5) @@ -1097,6 +1144,7 @@ E { #expect(str2[range2].testBool == nil) } + @available(FoundationAttributedString 5.5, *) @Test func substringDescription() { var str = AttributedString("Hello", attributes: .init().testInt(2)) str += " " @@ -1108,6 +1156,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func substringReplaceAttributes() { var str = AttributedString("Hello", attributes: .init().testInt(2).testString("Foundation")) str += " " @@ -1123,6 +1172,7 @@ E { #expect(str == expected) } + @available(FoundationAttributedString 5.5, *) @Test func substringEquality() { let str = AttributedString("") let range = str.startIndex ..< str.endIndex @@ -1136,6 +1186,7 @@ E { #expect(substringB == substringB) } + @available(FoundationAttributedString 5.5, *) @Test func initializationFromSubstring() throws { var attrStr = AttributedString("yolo^+1 result<:s>^", attributes: AttributeContainer.testInt(2).testString("Hello")) attrStr.replaceSubrange(try #require(attrStr.range(of: "<:s>")), with: AttributedString("")) @@ -1166,6 +1217,7 @@ E { var attributedString = AttributedString() } + @available(FoundationAttributedString 5.5, *) @Test func jsonEncoding() throws { let encoder = JSONEncoder() var attrStr = AttributedString("Hello", attributes: AttributeContainer().testBool(true).testString("blue").testInt(1)) @@ -1179,6 +1231,7 @@ E { #expect(decoded.attributedString == attrStr) } + @available(FoundationAttributedString 5.5, *) @Test func decodingThenConvertingToNSAttributedString() throws { let encoder = JSONEncoder() var attrStr = AttributedString("Hello", attributes: AttributeContainer().testBool(true)) @@ -1193,6 +1246,7 @@ E { #expect(ns == decodedns) } + @available(FoundationAttributedString 5.5, *) @Test func customAttributeCoding() throws { struct MyAttributes : AttributeScope { var customCodable : AttributeScopes.TestAttributes.CustomCodableAttribute @@ -1215,6 +1269,7 @@ E { #expect(decoded.attributedString == attrStr) } + @available(FoundationAttributedString 5.5, *) @Test func customCodableTypeWithCodableAttributedString() throws { struct MyType : Codable, Equatable { var other: NonCodableType @@ -1254,6 +1309,7 @@ E { #expect(type == decoded) } + @available(FoundationAttributedString 5.5, *) @Test func codingErrorsPropagateUpToCallSite() { enum CustomAttribute : CodableAttributedStringKey { typealias Value = String @@ -1284,6 +1340,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func encodeWithPartiallyCodableScope() throws { enum NonCodableAttribute : AttributedStringKey { typealias Value = Int @@ -1311,6 +1368,7 @@ E { #expect(decoded.str == expected) } + @available(FoundationAttributedString 5.5, *) @Test func automaticCoding() throws { struct Obj : Codable, Equatable { @CodableConfiguration(from: AttributeScopes.TestAttributes.self) var attrStr = AttributedString() @@ -1359,6 +1417,7 @@ E { } + @available(FoundationAttributedString 5.5, *) @Test func manualCoding() throws { struct Obj : Codable, Equatable { var attrStr : AttributedString @@ -1452,6 +1511,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func codableRawRepresentableAttribute() throws { struct Attribute : CodableAttributedStringKey { static let name = "MyAttribute" @@ -1480,6 +1540,7 @@ E { #expect(decoded.str[Attribute.self] == .two) } + @available(FoundationAttributedString 5.5, *) @Test func containerEncoding() throws { struct ContainerContainer : Codable { @CodableConfiguration(from: AttributeScopes.TestAttributes.self) var container = AttributeContainer() @@ -1493,6 +1554,7 @@ E { #expect(obj.container == decoded.container) } + @available(FoundationAttributedString 5.5, *) @Test func defaultAttributesCoding() throws { struct DefaultContainer : Codable, Equatable { var str : AttributedString @@ -1506,6 +1568,7 @@ E { #expect(cont == decoded) } + @available(FoundationAttributedString 5.5, *) @Test func decodingMultibyteCharacters() throws { let json = "{\"str\": [\"🎺ABC\", {\"TestInt\": 2}]}" struct Object : Codable { @@ -1521,6 +1584,7 @@ E { // MARK: - Conversion Tests + @available(FoundationAttributedString 5.5, *) @Test func conversionToObjC() throws { var ourString = AttributedString("Hello", attributes: AttributeContainer().testInt(2)) ourString += AttributedString(" ") @@ -1532,6 +1596,7 @@ E { #expect(theirString == ourObjCString) } + @available(FoundationAttributedString 5.5, *) @Test func conversionFromObjC() throws { let nsString = NSMutableAttributedString(string: "Hello!") let rangeA = NSMakeRange(0, 3) @@ -1545,6 +1610,7 @@ E { #expect(string == convertedString) } + @available(FoundationAttributedString 5.5, *) @Test func roundTripConversion_boxed() throws { struct MyCustomType : Hashable { var num: Int @@ -1569,6 +1635,7 @@ E { #expect(converted[MyCustomAttribute.self] == customVal) } + @available(FoundationAttributedString 5.5, *) @Test func roundTripConversion_customConversion() throws { struct MyCustomType : Hashable { } @@ -1595,6 +1662,7 @@ E { #expect(converted[MyCustomAttribute.self] == customVal) } + @available(FoundationAttributedString 5.5, *) @Test func incompleteConversionFromObjC() throws { struct TestStringAttributeOnly : AttributeScope { var testString: AttributeScopes.TestAttributes.TestStringAttribute // Missing TestBoolAttribute @@ -1612,6 +1680,7 @@ E { #expect(converted == expected) } + @available(FoundationAttributedString 5.5, *) @Test func incompleteConversionToObjC() throws { struct TestStringAttributeOnly : AttributeScope { var testString: AttributeScopes.TestAttributes.TestStringAttribute // Missing TestBoolAttribute @@ -1625,6 +1694,7 @@ E { #expect(!attrs.keys.contains(.testBool)) } + @available(FoundationAttributedString 5.5, *) @Test func conversionNestedScope() throws { struct SuperScope : AttributeScope { var subscope : SubScope @@ -1647,6 +1717,7 @@ E { #expect(converted == expected) } + @available(FoundationAttributedString 5.5, *) @Test func conversionAttributeContainers() throws { let container = AttributeContainer.testInt(2).testDouble(3.1).testString("Hello") @@ -1665,6 +1736,7 @@ E { #expect(container == container2) } + @available(FoundationAttributedString 5.5, *) @Test func conversionFromInvalidObjectiveCValueTypes() throws { let nsStr = NSAttributedString(string: "Hello", attributes: [.testInt : "I am not an Int"]) #expect(throws: (any Error).self) { @@ -1696,6 +1768,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func conversionToUTF16() throws { // Ensure that we're correctly using UTF16 offsets with NSAS and UTF8 offsets with AS without mixing the two let multiByteCharacters = ["\u{2029}", "\u{1D11E}", "\u{1D122}", "\u{1F91A}\u{1F3FB}"] @@ -1713,6 +1786,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func conversionWithoutScope() throws { // Ensure simple conversion works (no errors when loading AppKit/UIKit/SwiftUI) let attrStr = AttributedString() @@ -1757,6 +1831,7 @@ E { } #if canImport(Accessibility) + @available(FoundationAttributedString 5.5, *) @Test func conversionWithoutScope_Accessibility() throws { let attributedString = AttributedString("Hello", attributes: .init().accessibilityTextCustom(["ABC"])) let nsAttributedString = NSAttributedString(attributedString) @@ -1772,6 +1847,7 @@ E { #endif #if canImport(AppKit) + @available(FoundationAttributedString 5.5, *) @Test func conversionWithoutScope_AppKit() throws { var container = AttributeContainer() container.appKit.kern = 2.3 @@ -1784,6 +1860,7 @@ E { #endif #if canImport(UIKit) + @available(FoundationAttributedString 5.5, *) @Test func conversionWithoutScope_UIKit() throws { var container = AttributeContainer() container.uiKit.kern = 2.3 @@ -1796,6 +1873,7 @@ E { #endif #if canImport(SwiftUI) + @available(FoundationAttributedString 5.5, *) @Test func conversionWithoutScope_SwiftUI() throws { var container = AttributeContainer() container.swiftUI.kern = 2.3 @@ -1807,6 +1885,7 @@ E { } #endif + @available(FoundationAttributedString 5.5, *) @Test func conversionCoalescing() throws { let nsStr = NSMutableAttributedString("Hello, world") nsStr.setAttributes([.link : NSURL(string: "http://apple.com")!, .testInt : NSNumber(integerLiteral: 2)], range: NSRange(location: 0, length: 6)) @@ -1818,6 +1897,7 @@ E { #expect(attrStr.link == nil) } + @available(FoundationAttributedString 5.5, *) @Test func unalignedConversion() throws { let tests: [(NSRange, Int)] = [ (NSRange(location: 0, length: 12), 1), @@ -1842,6 +1922,7 @@ E { // MARK: - View Tests + @available(FoundationAttributedString 5.5, *) @Test func charViewIndexing_backwardsFromEndIndex() { let testString = AttributedString("abcdefghi") let testChars = testString.characters @@ -1849,6 +1930,7 @@ E { #expect(testChars[testIndex] == "i") } + @available(FoundationAttributedString 5.5, *) @Test func attrViewIndexing() { var attrStr = AttributedString("A") attrStr += "B" @@ -1867,6 +1949,7 @@ E { #expect(attrStrRuns.count == 1) } + @available(FoundationAttributedString 5.5, *) @Test func unicodeScalarsViewIndexing() { let attrStr = AttributedString("Cafe\u{301}", attributes: AttributeContainer().testInt(1)) let unicode = attrStr.unicodeScalars @@ -1874,6 +1957,7 @@ E { #expect(unicode[unicode.index(unicode.endIndex, offsetBy: -2)] == "e") } + @available(FoundationAttributedString 5.5, *) @Test func characterSlicing() { let a: AttributedString = "\u{1f1fa}\u{1f1f8}" // Regional indicators U & S let i = a.unicodeScalars.index(after: a.startIndex) @@ -1884,6 +1968,7 @@ E { #expect(b.count == 0) } + @available(FoundationAttributedString 5.5, *) @Test func characterSlicing_RangeExpressions() { // Make sure `AttributedString` and `String` produce consistent results when slicing, // for every range expression, whether or not the bounds fall on `Character` boundaries. @@ -1941,6 +2026,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func unicodeScalarsSlicing() { let attrStr = AttributedString("Cafe\u{301}", attributes: AttributeContainer().testInt(1)) let range = attrStr.startIndex ..< attrStr.endIndex @@ -1962,6 +2048,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func protocolRunIndexing() { var str = AttributedString("Foo", attributes: .init().testInt(1)) str += AttributedString("Bar", attributes: .init().testInt(2)) @@ -1984,6 +2071,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func runSliceSubscripting() { var str = AttributedString("Foo", attributes: .init().testInt(1)) str += AttributedString("Bar", attributes: .init().testInt(2)) @@ -2014,6 +2102,7 @@ E { // MARK: - Other Tests + @available(FoundationAttributedString 5.5, *) @Test func initWithSequence() { let expected = AttributedString("Hello World", attributes: AttributeContainer().testInt(2)) let sequence: [Character] = ["H", "e", "l", "l", "o", " ", "W", "o", "r", "l", "d"] @@ -2029,6 +2118,7 @@ E { #expect(attrStr3 == expected) } + @available(FoundationAttributedString 5.5, *) @Test func longestEffectiveRangeOfAttribute() { var str = AttributedString("Abc") str += AttributedString("def", attributes: AttributeContainer.testInt(2).testString("World")) @@ -2044,6 +2134,7 @@ E { #expect(range == expectedRange) } + @available(FoundationAttributedString 5.5, *) @Test func attributeContainer() { var container = AttributeContainer().testBool(true).testInt(1) #expect(container.testBool == true) @@ -2060,6 +2151,7 @@ E { #expect(container.testBool == nil) } + @available(FoundationAttributedString 5.5, *) @Test func attributeContainerEquality() { let containerA = AttributeContainer().testInt(2).testString("test") let containerB = AttributeContainer().testInt(2).testString("test") @@ -2074,6 +2166,7 @@ E { #expect(containerD == containerE) } + @available(FoundationAttributedString 5.5, *) @Test func attributeContainerSetOnSubstring() { let container = AttributeContainer().testBool(true).testInt(1) @@ -2088,6 +2181,7 @@ E { #expect(run.testString == "yellow") } + @available(FoundationAttributedString 5.5, *) @Test func slice() { let attrStr = AttributedString("Hello World") let chars = attrStr.characters @@ -2096,6 +2190,7 @@ E { #expect(AttributedString(slice) == AttributedString("World")) } + @available(FoundationAttributedString 5.5, *) @Test func createStringsFromCharactersWithUnicodeScalarIndexes() { var attrStr = AttributedString("Caf", attributes: AttributeContainer().testString("a")) attrStr += AttributedString("e", attributes: AttributeContainer().testString("b")) @@ -2112,6 +2207,7 @@ E { #expect(strs2 == ["Caf", "", "e\u{301}"]) } + @available(FoundationAttributedString 5.5, *) @Test func settingAttributeOnSlice() throws { var attrString = AttributedString("This is a string.") var range = attrString.startIndex ..< attrString.characters.index(attrString.startIndex, offsetBy: 1) @@ -2145,6 +2241,7 @@ E { #expect(attrString.characters[startIndex] == "D") } + @available(FoundationAttributedString 5.5, *) @Test func expressibleByStringLiteral() { let variable : AttributedString = "Test" #expect(variable == AttributedString("Test")) @@ -2155,6 +2252,7 @@ E { takesAttrStr("Test") } + @available(FoundationAttributedString 5.5, *) @Test func hashing() { let attrStr = AttributedString("Hello, world.", attributes: .init().testInt(2).testBool(false)) let attrStr2 = AttributedString("Hello, world.", attributes: .init().testInt(2).testBool(false)) @@ -2170,6 +2268,7 @@ E { #expect(dictionary[attrStr2] == 456) } + @available(FoundationAttributedString 5.5, *) @Test func hashingSubstring() { let a: AttributedString = "aXa" let b: AttributedString = "bXb" @@ -2192,6 +2291,7 @@ E { #expect(hasherA.finalize() == hasherB.finalize()) } + @available(FoundationAttributedString 5.5, *) @Test func hashingContainer() { let containerA = AttributeContainer.testInt(2).testBool(false) let containerB = AttributeContainer.testInt(2).testBool(false) @@ -2207,6 +2307,7 @@ E { #expect(dictionary[containerB] == 456) } + @available(FoundationAttributedString 5.5, *) @Test func utf16String() { let multiByteCharacters = ["\u{2029}", "\u{1D11E}", "\u{1D122}", "\u{1F91A}\u{1F3FB}"] @@ -2219,6 +2320,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func plusOperators() { let ab = AttributedString("a") + AttributedString("b") #expect(ab == AttributedString("ab")) @@ -2242,6 +2344,7 @@ E { #expect(abc_lit == abc) } + @available(FoundationAttributedString 5.5, *) @Test func search() throws { let testString = AttributedString("abcdefghi") #expect(testString.range(of: "baba") == nil) @@ -2287,6 +2390,7 @@ E { #expect(testString.range(of: "abc", options: [.anchored, .backwards]) == nil) } + @available(FoundationAttributedString 5.5, *) @Test func substringSearch() throws { let fullString = AttributedString("___abcdefghi___") let testString = fullString[try #require(fullString.range(of: "abcdefghi"))] @@ -2333,6 +2437,7 @@ E { #expect(testString.range(of: "abc", options: [.anchored, .backwards]) == nil) } + @available(FoundationAttributedString 5.5, *) @Test func indexConversion() throws { let attrStr = AttributedString("ABCDE") let str = "ABCDE" @@ -2349,6 +2454,7 @@ E { #if FOUNDATION_FRAMEWORK + @available(FoundationAttributedString 5.5, *) @Test func rangeConversion() throws { let attrStr = AttributedString("ABCDE") let nsAS = NSAttributedString("ABCDE") @@ -2367,6 +2473,7 @@ E { #expect(String(attrStr[attrStrR_reconverted2].characters) == "BCD") } + @available(FoundationAttributedString 5.5, *) @Test func unalignedRangeConversion() { do { // U+0301 Combining Acute Accent (one unicode scalar, one UTF-16) @@ -2418,6 +2525,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func nsRangeConversionOnSlice() throws { let str = AttributedString("012345") let slice = str[str.index(str.startIndex, offsetByCharacters: 3) ..< str.endIndex] @@ -2428,6 +2536,7 @@ E { #endif // FOUNDATION_FRAMEWORK + @available(FoundationAttributedString 5.5, *) @Test func oobRangeConversion() { let attrStr = AttributedString("") let str = "Hello" @@ -2437,6 +2546,7 @@ E { #if FOUNDATION_FRAMEWORK // TODO: Support scope-specific AttributedString initialization in FoundationPreview + @available(FoundationAttributedString 5.5, *) @Test func scopedCopy() { var str = AttributedString("A") str += AttributedString("B", attributes: .init().testInt(2)) @@ -2474,6 +2584,7 @@ E { #expect(AttributedString(str[range], including: None.self) == AttributedString("BC")) } + @available(FoundationAttributedString 5.5, *) @Test func scopeIterationAPI() { struct TestScope : AttributeScope { let testInt: AttributeScopes.TestAttributes.TestIntAttribute @@ -2492,6 +2603,7 @@ E { } #endif // FOUNDATION_FRAMEWORK + @available(FoundationAttributedString 5.5, *) @Test func assignDifferentSubstring() { var attrStr1 = AttributedString("ABCDE") let attrStr2 = AttributedString("XYZ") @@ -2501,6 +2613,7 @@ E { #expect(attrStr1 == "AXE") } + @available(FoundationAttributedString 5.5, *) @Test func cowDuringSubstringMutation() { func frobnicate(_ sub: inout AttributedSubstring) { var new = sub @@ -2516,6 +2629,7 @@ E { } #if FOUNDATION_EXIT_TESTS + @available(FoundationAttributedString 5.5, *) @Test func reassignmentDuringMutation() async { await #expect(processExitsWith: .failure) { func frobnicate(_ sub: inout AttributedSubstring) { @@ -2528,6 +2642,7 @@ E { } #endif + @available(FoundationAttributedString 5.5, *) @Test func assignDifferentCharacterView() { var attrStr1 = AttributedString("ABC", attributes: .init().testInt(1)) + AttributedString("DE", attributes: .init().testInt(3)) let attrStr2 = AttributedString("XYZ", attributes: .init().testInt(2)) @@ -2536,6 +2651,7 @@ E { #expect(attrStr1 == AttributedString("XYZ", attributes: .init().testInt(1))) } + @available(FoundationAttributedString 5.5, *) @Test func cowDuringCharactersMutation() { func frobnicate(_ chars: inout AttributedString.CharacterView) { var new = chars @@ -2548,6 +2664,7 @@ E { #expect(attrStr == AttributedString("XYZ", attributes: .init().testInt(1))) } + @available(FoundationAttributedString 5.5, *) @Test func assignDifferentUnicodeScalarView() { var attrStr1 = AttributedString("ABC", attributes: .init().testInt(1)) + AttributedString("DE", attributes: .init().testInt(3)) let attrStr2 = AttributedString("XYZ", attributes: .init().testInt(2)) @@ -2556,6 +2673,7 @@ E { #expect(attrStr1 == AttributedString("XYZ", attributes: .init().testInt(1))) } + @available(FoundationAttributedString 5.5, *) @Test func cowDuringUnicodeScalarsMutation() { func frobnicate(_ chars: inout AttributedString.CharacterView) { var new = chars @@ -2568,6 +2686,7 @@ E { #expect(attrStr == AttributedString("XYZ", attributes: .init().testInt(1))) } + @available(FoundationAttributedString 5.5, *) @Test func utf88View() { let testStrings = [ "Hello, world", @@ -2597,6 +2716,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func utf16View() { let testStrings = [ "Hello, world", @@ -2626,6 +2746,7 @@ E { } } + @available(FoundationAttributedString 5.5, *) @Test func attributeContainerFiltering() { #expect(AttributeContainer().filter(runBoundaries: nil) == AttributeContainer()) #expect(AttributeContainer().filter(runBoundaries: .paragraph) == AttributeContainer()) @@ -2647,6 +2768,7 @@ E { #expect(testConstrainedContainer.filter(inheritedByAddedText: false) == AttributeContainer.testNonExtended(5)) } + @available(FoundationAttributedString 5.5, *) @Test func writingDirectionBehavior() throws { // Indicate that this sentence is primarily right to left, because the English term "Swift" is embedded into an Arabic sentence. var string = AttributedString("Swift مذهل!", attributes: .init().writingDirection(.rightToLeft)) diff --git a/Tests/FoundationInternationalizationTests/Formatting/ByteCountFormatStyleTests.swift b/Tests/FoundationInternationalizationTests/Formatting/ByteCountFormatStyleTests.swift index 40bea6531..14db109a7 100644 --- a/Tests/FoundationInternationalizationTests/Formatting/ByteCountFormatStyleTests.swift +++ b/Tests/FoundationInternationalizationTests/Formatting/ByteCountFormatStyleTests.swift @@ -20,6 +20,7 @@ private struct ByteCountFormatStyleTests { static let locales = [Locale(identifier: "en_US"), .init(identifier: "fr_FR"), .init(identifier: "zh_TW"), .init(identifier: "zh_CN"), .init(identifier: "ar")] @Test(arguments: locales) + @available(FoundationAttributedString 5.5, *) func zeroSpelledOutKb(locale: Locale) { let localizedZerosSpelledOutKb: [Locale: String] = [ Locale(identifier: "en_US"): "Zero kB", @@ -33,6 +34,7 @@ private struct ByteCountFormatStyleTests { } @Test(arguments: locales) + @available(FoundationAttributedString 5.5, *) func zeroSpelledOutBytes(locale: Locale) { let localizedZerosSpelledOutBytes: [Locale: String] = [ Locale(identifier: "en_US"): "Zero bytes", @@ -90,6 +92,7 @@ private struct ByteCountFormatStyleTests { #if FIXED_86386674 @Test(arguments: locales) + @available(FoundationAttributedString 5.5, *) func singularUnitsBinary(locale: Locale) { for i in 0...5 { let value: Int64 = (1 << (i*10)) @@ -100,6 +103,7 @@ private struct ByteCountFormatStyleTests { #if FIXED_86386684 @Test(arguments: locales) + @available(FoundationAttributedString 5.5, *) func singularUnitsDecimal(locale: Locale) { for i in 0...5 { #expect(Int64(pow(10.0, Double(i*3))).formatted(.byteCount(style: .file).locale(locale)) == localizedSingular[locale]![i]) @@ -107,19 +111,23 @@ private struct ByteCountFormatStyleTests { } #endif + @available(FoundationAttributedString 5.5, *) @Test func localizedParens() { #expect(1024.formatted(.byteCount(style: ByteCountFormatStyle.Style.binary, includesActualByteCount: true).locale(.init(identifier: "zh_TW"))) == "1 kB(1,024 byte)") #expect(1024.formatted(.byteCount(style: ByteCountFormatStyle.Style.binary, includesActualByteCount: true).locale(.init(identifier: "en_US"))) == "1 kB (1,024 bytes)") } + @available(FoundationAttributedString 5.5, *) @Test func actualByteCount() { #expect(1024.formatted(.byteCount(style: ByteCountFormatStyle.Style.file, includesActualByteCount: true).locale(.init(identifier: "en_US"))) == "1 kB (1,024 bytes)") } + @available(FoundationAttributedString 5.5, *) @Test func rtl() { #expect(1024.formatted(.byteCount(style: ByteCountFormatStyle.Style.binary, includesActualByteCount: true).locale(.init(identifier: "ar_SA"))) == "١ كيلوبايت (١٬٠٢٤ بايت)") } + @available(FoundationAttributedString 5.5, *) @Test func attributed() { var expected: [Segment] @@ -187,6 +195,7 @@ private struct ByteCountFormatStyleTests { } #if !_pointerBitWidth(_32) + @available(FoundationAttributedString 5.5, *) @Test func testEveryAllowedUnit() { // 84270854: The largest unit supported currently is pb let expectations: [ByteCountFormatStyle.Units: String] = [ @@ -208,6 +217,7 @@ private struct ByteCountFormatStyleTests { #endif } +@available(FoundationAttributedString 5.5, *) fileprivate struct Segment { let string: String let number: AttributeScopes.FoundationAttributes.NumberFormatAttributes.NumberPartAttribute.NumberPart? @@ -228,6 +238,7 @@ fileprivate struct Segment { } +@available(FoundationAttributedString 5.5, *) extension Sequence where Element == Segment { var attributedString: AttributedString { self.map { segment in diff --git a/Tests/FoundationInternationalizationTests/Formatting/DateFormatStyleTests.swift b/Tests/FoundationInternationalizationTests/Formatting/DateFormatStyleTests.swift index 83dabb19f..babc46741 100644 --- a/Tests/FoundationInternationalizationTests/Formatting/DateFormatStyleTests.swift +++ b/Tests/FoundationInternationalizationTests/Formatting/DateFormatStyleTests.swift @@ -597,6 +597,7 @@ private struct DateFormatStyleTests { } } +@available(FoundationAttributedString 5.5, *) extension Sequence where Element == (String, AttributeScopes.FoundationAttributes.DateFieldAttribute.Field?) { var attributedString: AttributedString { self.map { pair in @@ -609,8 +610,11 @@ extension Sequence where Element == (String, AttributeScopes.FoundationAttribute private struct DateAttributedFormatStyleTests { var enUSLocale = Locale(identifier: "en_US") var gmtTimeZone = TimeZone(secondsFromGMT: 0)! - + + @available(FoundationAttributedString 5.5, *) typealias Segment = (String, AttributeScopes.FoundationAttributes.DateFieldAttribute.Field?) + + @available(FoundationAttributedString 5.5, *) @Test func attributedFormatStyle() throws { let baseStyle = Date.FormatStyle(locale: enUSLocale, timeZone: gmtTimeZone) // dateFormatter.date(from: "2021-04-12 15:04:32")! @@ -634,6 +638,7 @@ private struct DateAttributedFormatStyleTests { } } + @available(FoundationAttributedString 5.5, *) @Test func individualFields() throws { let baseStyle = Date.FormatStyle(locale: enUSLocale, timeZone: gmtTimeZone) // dateFormatter.date(from: "2021-04-12 15:04:32")! @@ -660,6 +665,7 @@ private struct DateAttributedFormatStyleTests { } } + @available(FoundationAttributedString 5.5, *) @Test func codable() throws { let encoder = JSONEncoder() let decoder = JSONDecoder() @@ -673,6 +679,7 @@ private struct DateAttributedFormatStyleTests { } } + @available(FoundationAttributedString 5.5, *) @Test func settingLocale() throws { // dateFormatter.date(from: "2021-04-12 15:04:32")! let date = Date(timeIntervalSinceReferenceDate: 639932672.0) @@ -693,6 +700,7 @@ private struct DateAttributedFormatStyleTests { } #if FOUNDATION_FRAMEWORK + @available(FoundationAttributedString 5.5, *) @Test func formattingWithPrefsOverride() { let date = Date(timeIntervalSince1970: 0) let enUS = "en_US" @@ -855,6 +863,7 @@ private struct DateAttributedFormatStyleTests { private struct DateVerbatimFormatStyleTests { var utcTimeZone = TimeZone(identifier: "UTC")! + @available(FoundationAttributedString 5.5, *) @Test func formats() throws { // dateFormatter.date(from: "2021-01-23 14:51:20")! let date = Date(timeIntervalSinceReferenceDate: 633106280.0) @@ -877,6 +886,7 @@ private struct DateVerbatimFormatStyleTests { verify("\(hour: .defaultDigits(clock: .twelveHour, hourCycle: .zeroBased)) heures et \(minute: .twoDigits) minutes", expected: "2 heures et 51 minutes") } + @available(FoundationAttributedString 5.5, *) @Test func parseable() throws { // dateFormatter.date(from: "2021-01-23 14:51:20")! let date = Date(timeIntervalSinceReferenceDate: 633106280.0) @@ -898,6 +908,7 @@ private struct DateVerbatimFormatStyleTests { } // Test parsing strings containing `abbreviated` names + @available(FoundationAttributedString 5.5, *) @Test func nonLenientParsingAbbreviatedNames() throws { // dateFormatter.date(from: "1970-01-01 00:00:00")! @@ -941,6 +952,7 @@ private struct DateVerbatimFormatStyleTests { #endif // FIXED_ICU_74_DAYPERIOD } + @available(FoundationAttributedString 5.5, *) @Test func issue95845290() throws { let formatString: Date.FormatString = "\(weekday: .abbreviated) \(month: .abbreviated) \(day: .twoDigits) \(hour: .twoDigits(clock: .twentyFourHour, hourCycle: .zeroBased)):\(minute: .twoDigits):\(second: .twoDigits) \(timeZone: .iso8601(.short)) \(year: .defaultDigits)" let enGB = Locale(identifier: "en_GB") @@ -958,9 +970,11 @@ private struct DateVerbatimFormatStyleTests { #expect(date == Date(timeIntervalSinceReferenceDate: 677261400.0)) } } - + + @available(FoundationAttributedString 5.5, *) typealias Segment = (String, AttributeScopes.FoundationAttributes.DateFieldAttribute.Field?) + @available(FoundationAttributedString 5.5, *) @Test func attributedString() throws { // dateFormatter.date(from: "2021-01-23 14:51:20")! let date = Date(timeIntervalSinceReferenceDate: 633106280.0) @@ -984,11 +998,13 @@ private struct DateVerbatimFormatStyleTests { ("20", .second)]) } + @available(FoundationAttributedString 5.5, *) @Test func storedVar() { _ = Date.FormatStyle.dateTime _ = Date.ISO8601FormatStyle.iso8601 } + @available(FoundationAttributedString 5.5, *) @Test func allIndividualFields() { // dateFormatter.date(from: "2021-01-23 14:51:20")! let date = Date(timeIntervalSinceReferenceDate: 633106280.0) diff --git a/Tests/FoundationInternationalizationTests/Formatting/DurationTimeFormatStyleTests.swift b/Tests/FoundationInternationalizationTests/Formatting/DurationTimeFormatStyleTests.swift index b161b68bd..ab80b41bb 100644 --- a/Tests/FoundationInternationalizationTests/Formatting/DurationTimeFormatStyleTests.swift +++ b/Tests/FoundationInternationalizationTests/Formatting/DurationTimeFormatStyleTests.swift @@ -298,6 +298,7 @@ private struct DurationToMeasurementAdditionTests { private struct TestDurationTimeFormatStyle { let enUS = Locale(identifier: "en_US") + @available(FoundationAttributedString 5.5, *) func assertFormattedWithPattern(seconds: Int, milliseconds: Int = 0, pattern: Duration._TimeFormatStyle.Pattern, grouping: NumberFormatStyleConfiguration.Grouping? = nil, expected: String, sourceLocation: SourceLocation = #_sourceLocation) { var style = Duration.TimeFormatStyle(pattern: pattern).locale(enUS) if let grouping { @@ -306,6 +307,7 @@ private struct TestDurationTimeFormatStyle { #expect(Duration(seconds: Int64(seconds), milliseconds: Int64(milliseconds)).formatted(style) == expected, sourceLocation: sourceLocation) } + @available(FoundationAttributedString 5.5, *) @Test func durationPatternStyle() { assertFormattedWithPattern(seconds: 3695, pattern: .hourMinute, expected: "1:02") assertFormattedWithPattern(seconds: 3695, pattern: .hourMinute(padHourToLength: 1, roundSeconds: .down), expected: "1:01") @@ -318,6 +320,7 @@ private struct TestDurationTimeFormatStyle { assertFormattedWithPattern(seconds: 3695, milliseconds: 350, pattern: .minuteSecond(padMinuteToLength: 2, fractionalSecondsLength: 2), expected: "61:35.35") } + @available(FoundationAttributedString 5.5, *) @Test func durationPatternPadding() { assertFormattedWithPattern(seconds: 3695, pattern: .hourMinute(padHourToLength: 2), expected: "01:02") assertFormattedWithPattern(seconds: 3695, pattern: .hourMinuteSecond(padHourToLength: 2), expected: "01:01:35") @@ -325,12 +328,14 @@ private struct TestDurationTimeFormatStyle { assertFormattedWithPattern(seconds: 3695, milliseconds: 500, pattern: .hourMinuteSecond(padHourToLength: 2, fractionalSecondsLength: 2), expected: "01:01:35.50") } + @available(FoundationAttributedString 5.5, *) @Test func durationPatternGrouping() { assertFormattedWithPattern(seconds: 36950000, pattern: .hourMinute(padHourToLength: 2), grouping: nil, expected: "10,263:53") assertFormattedWithPattern(seconds: 36950000, pattern: .hourMinute(padHourToLength: 2), grouping: .automatic, expected: "10,263:53") assertFormattedWithPattern(seconds: 36950000, pattern: .hourMinute(padHourToLength: 2), grouping: .never, expected: "10263:53") } + @available(FoundationAttributedString 5.5, *) @Test func noFractionParts() { // minutes, seconds @@ -401,6 +406,7 @@ private struct TestDurationTimeFormatStyle { assertFormattedWithPattern(seconds: 5399, milliseconds: 500, pattern: .hourMinute, expected: "1:30") } + @available(FoundationAttributedString 5.5, *) @Test func showFractionalSeconds() { // minutes, seconds @@ -445,6 +451,7 @@ private struct TestDurationTimeFormatStyle { assertFormattedWithPattern(seconds: 7199, milliseconds: 995, pattern: .hourMinuteSecond(padHourToLength: 2, fractionalSecondsLength: 2), expected: "02:00:00.00") } + @available(FoundationAttributedString 5.5, *) @Test func negativeValues() { assertFormattedWithPattern(seconds: 0, milliseconds: -499, pattern: .hourMinuteSecond, expected: "0:00:00") assertFormattedWithPattern(seconds: 0, milliseconds: -500, pattern: .hourMinuteSecond, expected: "0:00:00") @@ -471,6 +478,7 @@ private struct TestDurationTimeFormatStyle { // MARK: - Attributed string test +@available(FoundationAttributedString 5.5, *) extension Sequence where Element == DurationTimeAttributedStyleTests.Segment { var attributedString: AttributedString { self.map { tuple in @@ -487,13 +495,17 @@ extension Sequence where Element == DurationTimeAttributedStyleTests.Segment { @Suite("Duration.TimeFormatStyle.Attributed") private struct DurationTimeAttributedStyleTests { + @available(FoundationAttributedString 5.5, *) typealias Segment = (String, AttributeScopes.FoundationAttributes.DurationFieldAttribute.Field?) + let enUS = Locale(identifier: "en_US") + @available(FoundationAttributedString 5.5, *) func assertWithPattern(seconds: Int, milliseconds: Int = 0, pattern: Duration._TimeFormatStyle.Pattern, expected: [Segment], locale: Locale = Locale(identifier: "en_US"), sourceLocation: SourceLocation = #_sourceLocation) { #expect(Duration(seconds: Int64(seconds), milliseconds: Int64(milliseconds)).formatted(.time(pattern: pattern).locale(locale).attributed) == expected.attributedString, sourceLocation: sourceLocation) } + @available(FoundationAttributedString 5.5, *) @Test func attributedStyle_enUS() { assertWithPattern(seconds: 3695, pattern: .hourMinute, expected: [ ("1", .hours), @@ -558,6 +570,7 @@ private struct DurationTimeAttributedStyleTests { @Suite("Duration.TimeFormatStyle Discrete Conformance") private struct TestDurationTimeDiscreteConformance { + @available(FoundationAttributedString 5.5, *) @Test func basics() throws { var style: Duration.TimeFormatStyle style = .init(pattern: .minuteSecond(padMinuteToLength: 0, roundFractionalSeconds: .down)).locale(Locale(identifier: "en_US")) @@ -642,6 +655,7 @@ private struct TestDurationTimeDiscreteConformance { #expect(style.discreteInput(before: .seconds(-1)) == .milliseconds(-1500)) } + @available(FoundationAttributedString 5.5, *) @Test func regressions() throws { var style: Duration._TimeFormatStyle @@ -650,6 +664,7 @@ private struct TestDurationTimeDiscreteConformance { #expect(try #require(style.discreteInput(after: Duration(secondsComponent: -8, attosecondsComponent: -531546586433266880))) <= Duration(secondsComponent: 30, attosecondsComponent: 0)) } + @available(FoundationAttributedString 5.5, *) @Test(arguments: [FloatingPointRoundingRule.up, .down, .towardZero, .awayFromZero, .toNearestOrAwayFromZero, .toNearestOrEven].flatMap { roundingRule in [ diff --git a/Tests/FoundationInternationalizationTests/Formatting/DurationUnitsFormatStyleTests.swift b/Tests/FoundationInternationalizationTests/Formatting/DurationUnitsFormatStyleTests.swift index c3bd0b1b6..979ed68c0 100644 --- a/Tests/FoundationInternationalizationTests/Formatting/DurationUnitsFormatStyleTests.swift +++ b/Tests/FoundationInternationalizationTests/Formatting/DurationUnitsFormatStyleTests.swift @@ -902,6 +902,7 @@ private struct DurationUnitsFormatStyleTests { // MARK: - Attributed string test +@available(FoundationAttributedString 5.5, *) extension Sequence where Element == DurationUnitAttributedFormatStyleTests.Segment { var attributedString: AttributedString { self.map { tuple in @@ -920,10 +921,13 @@ extension Sequence where Element == DurationUnitAttributedFormatStyleTests.Segme @Suite("Duration.UnitsFormatStyle.Attributed") private struct DurationUnitAttributedFormatStyleTests { + @available(FoundationAttributedString 5.5, *) typealias Segment = (String, AttributeScopes.FoundationAttributes.DurationFieldAttribute.Field?, AttributeScopes.FoundationAttributes.MeasurementAttribute.Component?) + let enUS = Locale(identifier: "en_US") let frFR = Locale(identifier: "fr_FR") + @available(FoundationAttributedString 5.5, *) @Test func attributedStyle_enUS() { let d1 = Duration.seconds(2 * 3600 + 43 * 60 + 24) // 2hr 43min 24s let d2 = Duration.seconds(43 * 60 + 24) // 43min 24s @@ -1091,6 +1095,7 @@ private struct DurationUnitAttributedFormatStyleTests { ].attributedString) } + @available(FoundationAttributedString 5.5, *) @Test func testAttributedStyle_frFR() { let d1 = Duration.seconds(2 * 3600 + 43 * 60 + 24) // 2hr 43min 24s let d0 = Duration.seconds(0) diff --git a/Tests/FoundationInternationalizationTests/Formatting/NumberFormatStyleTests.swift b/Tests/FoundationInternationalizationTests/Formatting/NumberFormatStyleTests.swift index 2623c40cf..6325a8a69 100644 --- a/Tests/FoundationInternationalizationTests/Formatting/NumberFormatStyleTests.swift +++ b/Tests/FoundationInternationalizationTests/Formatting/NumberFormatStyleTests.swift @@ -261,7 +261,12 @@ final class NumberFormatStyleTests: XCTestCase { XCTAssertEqual(Float64.nan.formatted(.currency(code: "USD").locale(Locale(identifier: "uz_Cyrl"))), "ҳақиқий сон эмас US$") } + @available(FoundationAttributedString 5.5, *) func testFormattedAttributedLeadingDotSyntax() throws { + if #unavailable(FoundationAttributedString 5.5) { + throw XCTSkip("This test is not available on this OS version") + } + let int = 42 XCTAssertEqual(int.formatted(.number.attributed), IntegerFormatStyle().attributed.format(int)) XCTAssertEqual(int.formatted(.percent.attributed), IntegerFormatStyle.Percent().attributed.format(int)) @@ -1634,8 +1639,10 @@ final class IntegerFormatStyleExhaustiveTests: XCTestCase { // MARK: - Attributed string +@available(FoundationAttributedString 5.5, *) fileprivate typealias Segment = (String, AttributeScopes.FoundationAttributes.NumberFormatAttributes.NumberPartAttribute.NumberPart?, AttributeScopes.FoundationAttributes.NumberFormatAttributes.SymbolAttribute.Symbol?) +@available(FoundationAttributedString 5.5, *) extension Sequence where Element == Segment { var attributedString: AttributedString { self.map { tuple in @@ -1652,15 +1659,23 @@ extension Sequence where Element == Segment { } } +@available(FoundationAttributedString 5.5, *) extension AttributedString { fileprivate var string: String { String(self._guts.string) } } +@available(FoundationAttributedString 5.5, *) class TestNumberAttributeFormatStyle: XCTestCase { let enUS = Locale(identifier: "en_US") let frFR = Locale(identifier: "fr_FR") + + override func setUpWithError() throws { + if #unavailable(FoundationAttributedString 5.5) { + throw XCTSkip("This test is not available on this OS version") + } + } func testIntegerStyle() throws { let style: IntegerFormatStyle = .init(locale: enUS) @@ -2203,7 +2218,11 @@ extension NumberFormatStyleTests { extension NumberFormatStyleTests { + @available(FoundationAttributedString 5.5, *) func testIntegerFormatStyleBigNumberNoCrash() throws { + if #unavailable(FoundationAttributedString 5.5) { + throw XCTSkip("This test is not available on this OS version") + } let uint64Style: IntegerFormatStyle = .init(locale: enUSLocale) XCTAssertEqual(uint64Style.format(UInt64.max), "18,446,744,073,709,551,615") XCTAssertEqual(UInt64.max.formatted(.number.locale(enUSLocale)), "18,446,744,073,709,551,615")