Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.
65 changes: 65 additions & 0 deletions Sources/SwiftDoc/AvailabilityAttribute.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import SwiftSemantics

public enum AvailabilityAttributeType: Equatable {
/// all platforms (marked with *)
case allPlatforms
case platform(platform: String, version: String?)
case introduced(version: String?)
case deprecated(version: String?)
case obsoleted(version: String?)
case renamed(message: String)
case message(message: String)
case unavailable(version: String?)
}

extension AvailabilityAttributeType {
init?(from argument: Attribute.Argument) {
switch argument.value {
case "*":
self = .allPlatforms
return
case "introduced":
self = .introduced(version: nil)
return
case "deprecated":
self = .deprecated(version: nil)
return
case "obsoleted":
self = .obsoleted(version: nil)
return
case "unavailable":
self = .unavailable(version: nil)
return
case "iOS", "macOS", "tvOS", "watchOS", "swift":
self = .platform(platform: argument.value, version: nil)
default:
guard let name = argument.name else {
return nil
}

switch name {
case "iOS", "macOS", "tvOS", "watchOS", "swift":
self = .platform(platform: name, version: argument.value)
case "introduced":
self = .introduced(version: argument.value)
case "deprecated":
self = .deprecated(version: argument.value)
case "obsoleted":
self = .obsoleted(version: argument.value)
case "renamed":
self = .renamed(message: argument.value)
case "message":
self = .message(message: argument.value)
default: return nil
}
}
}
}

public final class AvailabilityAttribute {
public let attributes: [AvailabilityAttributeType]

init(arguments: [Attribute.Argument]) {
attributes = arguments.compactMap { AvailabilityAttributeType.init(from: $0) }
}
}
6 changes: 6 additions & 0 deletions Sources/SwiftDoc/Symbol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ public final class Symbol {
public var isDocumented: Bool {
return documentation?.isEmpty == false
}

public var availabilityAttributes: [AvailabilityAttribute] {
let availableAttributes = api.attributes.filter({ $0.name == "available" })

return availableAttributes.compactMap { AvailabilityAttribute(arguments: $0.arguments) }
}
}

// MARK: - Equatable
Expand Down
38 changes: 38 additions & 0 deletions Tests/SwiftDocTests/AvailabilityAttributeTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import XCTest

import SwiftDoc
import SwiftSemantics
import struct SwiftSemantics.Protocol
import SwiftSyntax

final class AvailabilityAttributeTypesTests: XCTestCase {
func testBasicAvailabilityType() throws {
let source = #"""

@available(iOS, deprecated: 13, renamed: "NewAndImprovedViewController")
class OldViewController: UIViewController { }

"""#

let url = try temporaryFile(contents: source)
let sourceFile = try SourceFile(file: url, relativeTo: url.deletingLastPathComponent())

let symbol = sourceFile.symbols[0]
XCTAssert(symbol.api is Class)

XCTAssertEqual(symbol.availabilityAttributes.count, 1)

let attributes = symbol.availabilityAttributes.first!.attributes
XCTAssertEqual(attributes.count, 3)

let iOS = attributes[0]
XCTAssertEqual(iOS, AvailabilityAttributeType.platform(platform: "iOS", version: nil))

let deprecation = attributes[1]
XCTAssertEqual(deprecation, AvailabilityAttributeType.deprecated(version: "13"))

let renamed = attributes[2]
XCTAssertEqual(renamed, AvailabilityAttributeType.renamed(message: "\"NewAndImprovedViewController\""))

}
}