diff --git a/Sources/SymbolKit/Mixin.swift b/Sources/SymbolKit/Mixin.swift new file mode 100644 index 0000000..9ea7ec4 --- /dev/null +++ b/Sources/SymbolKit/Mixin.swift @@ -0,0 +1,24 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +/** + A protocol that allows extracted symbols to have extra data + aside from the base ``SymbolGraph/Symbol``. + */ +public protocol Mixin: Codable { + /** + The key under which a mixin's data is filed. + + > Important: With respect to deserialization, this framework assumes `mixinKey`s between instances of `SymbolMixin` are unique. + */ + static var mixinKey: String { get } +} diff --git a/Sources/SymbolKit/SymbolGraph/Misc/LineList.swift b/Sources/SymbolKit/SymbolGraph/LineList/LineList.swift similarity index 89% rename from Sources/SymbolKit/SymbolGraph/Misc/LineList.swift rename to Sources/SymbolKit/SymbolGraph/LineList/LineList.swift index b747a09..58692b2 100644 --- a/Sources/SymbolKit/SymbolGraph/Misc/LineList.swift +++ b/Sources/SymbolKit/SymbolGraph/LineList/LineList.swift @@ -202,37 +202,3 @@ extension SymbolGraph.LineList { } } } - -extension SymbolGraph.LineList { - /** - Represents a selection in text: a start and end position, a half-open range. - */ - public struct SourceRange: Equatable, Codable { - /** - The range's start position. - */ - public var start: Position - - /** - The range's end position. - */ - public var end: Position - } -} - -extension SymbolGraph.LineList.SourceRange { - /** - Represents a cursor position in text. - */ - public struct Position: Equatable, Codable { - /** - The zero-based line number of a document. - */ - public var line: Int - - /** - The zero-based *byte offset* into a line. - */ - public var character: Int - } -} diff --git a/Sources/SymbolKit/SymbolGraph/LineList/SourceRange/SourceRange+Position.swift b/Sources/SymbolKit/SymbolGraph/LineList/SourceRange/SourceRange+Position.swift new file mode 100644 index 0000000..0863588 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/LineList/SourceRange/SourceRange+Position.swift @@ -0,0 +1,28 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.LineList.SourceRange { + /** + Represents a cursor position in text. + */ + public struct Position: Equatable, Codable { + /** + The zero-based line number of a document. + */ + public var line: Int + + /** + The zero-based *byte offset* into a line. + */ + public var character: Int + } +} diff --git a/Sources/SymbolKit/SymbolGraph/LineList/SourceRange/SourceRange.swift b/Sources/SymbolKit/SymbolGraph/LineList/SourceRange/SourceRange.swift new file mode 100644 index 0000000..4b8f098 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/LineList/SourceRange/SourceRange.swift @@ -0,0 +1,28 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.LineList { + /** + Represents a selection in text: a start and end position, a half-open range. + */ + public struct SourceRange: Equatable, Codable { + /** + The range's start position. + */ + public var start: Position + + /** + The range's end position. + */ + public var end: Position + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Relationship.swift b/Sources/SymbolKit/SymbolGraph/Relationship.swift deleted file mode 100644 index 4d449e4..0000000 --- a/Sources/SymbolKit/SymbolGraph/Relationship.swift +++ /dev/null @@ -1,269 +0,0 @@ -/* - This source file is part of the Swift.org open source project - - Copyright (c) 2021 Apple Inc. and the Swift project authors - Licensed under Apache License v2.0 with Runtime Library Exception - - See https://swift.org/LICENSE.txt for license information - See https://swift.org/CONTRIBUTORS.txt for Swift project authors -*/ - -extension SymbolGraph { - /** - A relationship between two `Symbol`s; a directed edge in a graph. - */ - public struct Relationship: Codable { - /// The precise identifier of the symbol that has a relationship. - public var source: String - - /// The precise identifier of the symbol that the `source` is related to. - public var target: String - - /// The type of relationship that this edge represents. - public var kind: Kind - - /// A fallback display name for the target if its module's symbol graph - /// is not available. - public var targetFallback: String? - - /// Extra information about a relationship that is not necessarily common to all relationships - public var mixins: [String: Mixin] = [:] - - enum CodingKeys: String, CaseIterable, CodingKey { - // Base - case source - case target - case kind - case targetFallback - - // Mixins - case swiftConstraints - case sourceOrigin - - static var mixinKeys: Set { - return [ - .swiftConstraints, - .sourceOrigin - ] - } - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - source = try container.decode(String.self, forKey: .source) - target = try container.decode(String.self, forKey: .target) - kind = try container.decode(Kind.self, forKey: .kind) - targetFallback = try container.decodeIfPresent(String.self, forKey: .targetFallback) - let mixinKeys = Set(container.allKeys).intersection(CodingKeys.mixinKeys) - for key in mixinKeys { - if let decoded = try decodeMixinForKey(key, from: container) { - mixins[key.stringValue] = decoded - } - } - } - - func decodeMixinForKey(_ key: CodingKeys, from container: KeyedDecodingContainer) throws -> Mixin? { - switch key { - case .swiftConstraints: - return try container.decode(Swift.GenericConstraints.self, forKey: key) - case .sourceOrigin: - return try container.decode(SourceOrigin.self, forKey: key) - default: - return nil - } - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - // Base - - try container.encode(kind, forKey: .kind) - try container.encode(source, forKey: .source) - try container.encode(target, forKey: .target) - try container.encode(targetFallback, forKey: .targetFallback) - - // Mixins - - for (key, mixin) in mixins { - let key = CodingKeys(rawValue: key)! - switch key { - case .swiftConstraints: - try container.encode(mixin as! Swift.GenericConstraints, forKey: key) - case .sourceOrigin: - try container.encode(mixin as! SourceOrigin, forKey: key) - default: - fatalError("Unknown mixin key \(key.rawValue)!") - } - } - } - - public init(source: String, target: String, kind: Kind, targetFallback: String?) { - self.source = source - self.target = target - self.kind = kind - self.targetFallback = targetFallback - } - } -} - -extension SymbolGraph.Relationship { - /// The kind of relationship. - public struct Kind: Codable, RawRepresentable, Equatable, Hashable { - public var rawValue: String - public init(rawValue: String) { - self.rawValue = rawValue - } - - /** - A symbol `A` is a member of another symbol `B`. - - For example, a method or field of a class would be - a member of that class. - - The implied inverse of this relationship is that - symbol `B` is the owner of a member symbol `A`. - */ - public static let memberOf = Kind(rawValue: "memberOf") - - /** - A symbol `A` conforms to an interface/protocol symbol `B`. - - For example, a class `C` that conforms to protocol `P` in Swift would - use this relationship. - - The implied inverse of this relationship is that - a symbol `B` that has a conformer `A`. - */ - public static let conformsTo = Kind(rawValue: "conformsTo") - - /** - A symbol `A` inherits another symbol `B`. - - For example, a derived class inherits from a base class, - or a protocol that refines another protocol would use this relationship. - - The implied inverse of this relationship is that - a symbol `B` is a base of another symbol `A`. - */ - public static let inheritsFrom = Kind(rawValue: "inheritsFrom") - - /** - A symbol `A` serves as a default implementation of - an interface requirement `B`. - - The implied inverse of this relationship is that - an interface requirement `B` has a default implementation of `A`. - */ - public static let defaultImplementationOf = Kind(rawValue: "defaultImplementationOf") - - /** - A symbol `A` overrides another symbol `B`, typically through inheritance. - - The implied inverse of this relationship is that - a symbol `A` is the base of symbol `B`. - */ - public static let overrides = Kind(rawValue: "overrides") - - /** - A symbol `A` is a requirement of interface `B`. - - The implied inverse of this relationship is that - an interface `B` has a requirement of `A`. - */ - public static let requirementOf = Kind(rawValue: "requirementOf") - - /** - A symbol `A` is an optional requirement of interface `B`. - - The implied inverse of this relationship is that - an interface `B` has an optional requirement of `A`. - */ - public static let optionalRequirementOf = Kind(rawValue: "optionalRequirementOf") - } -} - -// MARK: - Mixins - -extension SymbolGraph.Relationship { - /// A mixin defining a source symbol's origin. - public struct SourceOrigin: Mixin, Codable, Hashable { - public static var mixinKey = "sourceOrigin" - - /// Precise Identifier - public var identifier: String - - /// Display Name - public var displayName: String - - public init(identifier: String, displayName: String) { - self.identifier = identifier - self.displayName = displayName - } - - enum CodingKeys: String, CodingKey { - case identifier, displayName - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.identifier = try container.decode(String.self, forKey: .identifier) - self.displayName = try container.decode(String.self, forKey: .displayName) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(identifier, forKey: .identifier) - try container.encode(displayName, forKey: .displayName) - } - } - - /// A view of a relationship in terms of the Swift programming language. - public var swift: Swift { - return .init(relationship: self) - } - - /// A view of a relationship in terms of the Swift programming language. - public struct Swift { - /// The relationship that may have Swift-specific information. - public var relationship: SymbolGraph.Relationship - - public init(relationship: SymbolGraph.Relationship) { - self.relationship = relationship - } - - /// The generic constraints on a relationship. - /// - /// > Note: `conformsTo` relationships may have constraints for *conditional conformance*. - public var genericConstraints: [SymbolGraph.Symbol.Swift.GenericConstraint] { - guard let genericConstraints = relationship.mixins[GenericConstraints.mixinKey] as? GenericConstraints else { - return [] - } - return genericConstraints.constraints - } - } -} - -extension SymbolGraph.Relationship.Swift { - /// A mixin collecting Swift generic constraints. - public struct GenericConstraints: Mixin, Codable, Hashable { - public static var mixinKey = "swiftConstraints" - - /// Generic constraints. - public var constraints: [SymbolGraph.Symbol.Swift.GenericConstraint] - - public init(constraints: [SymbolGraph.Symbol.Swift.GenericConstraint]) { - self.constraints = constraints - } - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - self.constraints = try container.decode([SymbolGraph.Symbol.Swift.GenericConstraint].self) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(constraints) - } - } -} diff --git a/Sources/SymbolKit/SymbolGraph/Relationship/Relationship+Kind.swift b/Sources/SymbolKit/SymbolGraph/Relationship/Relationship+Kind.swift new file mode 100644 index 0000000..33af373 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Relationship/Relationship+Kind.swift @@ -0,0 +1,87 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Relationship { + /// The kind of relationship. + public struct Kind: Codable, RawRepresentable, Equatable, Hashable { + public var rawValue: String + public init(rawValue: String) { + self.rawValue = rawValue + } + + /** + A symbol `A` is a member of another symbol `B`. + + For example, a method or field of a class would be + a member of that class. + + The implied inverse of this relationship is that + symbol `B` is the owner of a member symbol `A`. + */ + public static let memberOf = Kind(rawValue: "memberOf") + + /** + A symbol `A` conforms to an interface/protocol symbol `B`. + + For example, a class `C` that conforms to protocol `P` in Swift would + use this relationship. + + The implied inverse of this relationship is that + a symbol `B` that has a conformer `A`. + */ + public static let conformsTo = Kind(rawValue: "conformsTo") + + /** + A symbol `A` inherits another symbol `B`. + + For example, a derived class inherits from a base class, + or a protocol that refines another protocol would use this relationship. + + The implied inverse of this relationship is that + a symbol `B` is a base of another symbol `A`. + */ + public static let inheritsFrom = Kind(rawValue: "inheritsFrom") + + /** + A symbol `A` serves as a default implementation of + an interface requirement `B`. + + The implied inverse of this relationship is that + an interface requirement `B` has a default implementation of `A`. + */ + public static let defaultImplementationOf = Kind(rawValue: "defaultImplementationOf") + + /** + A symbol `A` overrides another symbol `B`, typically through inheritance. + + The implied inverse of this relationship is that + a symbol `A` is the base of symbol `B`. + */ + public static let overrides = Kind(rawValue: "overrides") + + /** + A symbol `A` is a requirement of interface `B`. + + The implied inverse of this relationship is that + an interface `B` has a requirement of `A`. + */ + public static let requirementOf = Kind(rawValue: "requirementOf") + + /** + A symbol `A` is an optional requirement of interface `B`. + + The implied inverse of this relationship is that + an interface `B` has an optional requirement of `A`. + */ + public static let optionalRequirementOf = Kind(rawValue: "optionalRequirementOf") + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Relationship/Relationship+SourceOrigin.swift b/Sources/SymbolKit/SymbolGraph/Relationship/Relationship+SourceOrigin.swift new file mode 100644 index 0000000..14b53b3 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Relationship/Relationship+SourceOrigin.swift @@ -0,0 +1,45 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Relationship { + /// A mixin defining a source symbol's origin. + public struct SourceOrigin: Mixin, Codable, Hashable { + public static var mixinKey = "sourceOrigin" + + /// Precise Identifier + public var identifier: String + + /// Display Name + public var displayName: String + + public init(identifier: String, displayName: String) { + self.identifier = identifier + self.displayName = displayName + } + + enum CodingKeys: String, CodingKey { + case identifier, displayName + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + identifier = try container.decode(String.self, forKey: .identifier) + displayName = try container.decode(String.self, forKey: .displayName) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(identifier, forKey: .identifier) + try container.encode(displayName, forKey: .displayName) + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Relationship/Relationship.swift b/Sources/SymbolKit/SymbolGraph/Relationship/Relationship.swift new file mode 100644 index 0000000..f4ab369 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Relationship/Relationship.swift @@ -0,0 +1,108 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +extension SymbolGraph { + /** + A relationship between two `Symbol`s; a directed edge in a graph. + */ + public struct Relationship: Codable { + /// The precise identifier of the symbol that has a relationship. + public var source: String + + /// The precise identifier of the symbol that the `source` is related to. + public var target: String + + /// The type of relationship that this edge represents. + public var kind: Kind + + /// A fallback display name for the target if its module's symbol graph + /// is not available. + public var targetFallback: String? + + /// Extra information about a relationship that is not necessarily common to all relationships + public var mixins: [String: Mixin] = [:] + + enum CodingKeys: String, CaseIterable, CodingKey { + // Base + case source + case target + case kind + case targetFallback + + // Mixins + case swiftConstraints + case sourceOrigin + + static var mixinKeys: Set { + return [ + .swiftConstraints, + .sourceOrigin, + ] + } + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + source = try container.decode(String.self, forKey: .source) + target = try container.decode(String.self, forKey: .target) + kind = try container.decode(Kind.self, forKey: .kind) + targetFallback = try container.decodeIfPresent(String.self, forKey: .targetFallback) + let mixinKeys = Set(container.allKeys).intersection(CodingKeys.mixinKeys) + for key in mixinKeys { + if let decoded = try decodeMixinForKey(key, from: container) { + mixins[key.stringValue] = decoded + } + } + } + + func decodeMixinForKey(_ key: CodingKeys, from container: KeyedDecodingContainer) throws -> Mixin? { + switch key { + case .swiftConstraints: + return try container.decode(Swift.GenericConstraints.self, forKey: key) + case .sourceOrigin: + return try container.decode(SourceOrigin.self, forKey: key) + default: + return nil + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + // Base + + try container.encode(kind, forKey: .kind) + try container.encode(source, forKey: .source) + try container.encode(target, forKey: .target) + try container.encode(targetFallback, forKey: .targetFallback) + + // Mixins + + for (key, mixin) in mixins { + let key = CodingKeys(rawValue: key)! + switch key { + case .swiftConstraints: + try container.encode(mixin as! Swift.GenericConstraints, forKey: key) + case .sourceOrigin: + try container.encode(mixin as! SourceOrigin, forKey: key) + default: + fatalError("Unknown mixin key \(key.rawValue)!") + } + } + } + + public init(source: String, target: String, kind: Kind, targetFallback: String?) { + self.source = source + self.target = target + self.kind = kind + self.targetFallback = targetFallback + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Relationship/Swift/Swift+GenericConstraints.swift b/Sources/SymbolKit/SymbolGraph/Relationship/Swift/Swift+GenericConstraints.swift new file mode 100644 index 0000000..130bc22 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Relationship/Swift/Swift+GenericConstraints.swift @@ -0,0 +1,35 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Relationship.Swift { + /// A mixin collecting Swift generic constraints. + public struct GenericConstraints: Mixin, Codable, Hashable { + public static var mixinKey = "swiftConstraints" + + /// Generic constraints. + public var constraints: [SymbolGraph.Symbol.Swift.GenericConstraint] + + public init(constraints: [SymbolGraph.Symbol.Swift.GenericConstraint]) { + self.constraints = constraints + } + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + constraints = try container.decode([SymbolGraph.Symbol.Swift.GenericConstraint].self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(constraints) + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Relationship/Swift/Swift.swift b/Sources/SymbolKit/SymbolGraph/Relationship/Swift/Swift.swift new file mode 100644 index 0000000..94ff711 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Relationship/Swift/Swift.swift @@ -0,0 +1,38 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Relationship { + /// A view of a relationship in terms of the Swift programming language. + public var swift: Swift { + return .init(relationship: self) + } + + /// A view of a relationship in terms of the Swift programming language. + public struct Swift { + /// The relationship that may have Swift-specific information. + public var relationship: SymbolGraph.Relationship + + public init(relationship: SymbolGraph.Relationship) { + self.relationship = relationship + } + + /// The generic constraints on a relationship. + /// + /// > Note: `conformsTo` relationships may have constraints for *conditional conformance*. + public var genericConstraints: [SymbolGraph.Symbol.Swift.GenericConstraint] { + guard let genericConstraints = relationship.mixins[GenericConstraints.mixinKey] as? GenericConstraints else { + return [] + } + return genericConstraints.constraints + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Availability/Availability+AvailabilityItem.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Availability/Availability+AvailabilityItem.swift new file mode 100644 index 0000000..d187978 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Availability/Availability+AvailabilityItem.swift @@ -0,0 +1,165 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol.Availability { + /** + Availability of a symbol in a particular domain. + */ + public struct AvailabilityItem: Codable { + /** + The domain in which this availability applies; if undefined, applies to all reasonable domains. + */ + public var domain: Domain? + + /** + The version in which a symbol appeared. + */ + public var introducedVersion: SymbolGraph.SemanticVersion? + + /** + The version in which a symbol was deprecated. + + > Note: If a symbol is *unconditionally deprecated*, this key should be undefined or `null` (see below). + */ + public var deprecatedVersion: SymbolGraph.SemanticVersion? + + /** + The version in which a symbol was obsoleted. + + > Note: If a symbol is *unconditionally obsoleted*, this key should be undefined or `null` (see below). + */ + public var obsoletedVersion: SymbolGraph.SemanticVersion? + + /** + A message further describing availability for documentation purposes. + */ + public var message: String? + + /** + If a symbol was renamed at this point, its new name is given here. + + > Note: This is not necessarily an identifier but an attribute string provided by a compiler. + */ + public var renamed: String? + + /** + If defined and `true`, is unconditionally deprecated regardless + of version, and possibly regardless of domain. + If undefined, assume `false`. + */ + public var isUnconditionallyDeprecated: Bool + + /** + If defined and `true`, is unconditionally unavailable regardless + of version, and possibly regardless of domain. + If undefined, assume `false`. + */ + public var isUnconditionallyUnavailable: Bool + + /** + A formal but lenient indication that this symbol will definitely be deprecated + in future version of the availability domain, but the version hasn't + been decided yet. This is also known as *soft deprecation*. + + Soft deprecation should not provide build errors, runtime errors, or + warnings that can be upgraded to errors, but provides extra time for + usage of a symbol to decrease before providing an explicit + availability deadline. + + If a symbol is formally deprecated with an explicit version in the + `deprecated` property above, the `willEventuallyBeDeprecated` key + should not exist. In the event that it is still included + despite this specification, `deprecated` should always take precedence + over this property in clients. + */ + public var willEventuallyBeDeprecated: Bool + + enum CodingKeys: String, CodingKey { + case domain + case introducedVersion = "introduced" + case deprecatedVersion = "deprecated" + case obsoletedVersion = "obsoleted" + case message + case renamed + case isUnconditionallyDeprecated + case isUnconditionallyUnavailable + case willEventuallyBeDeprecated + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let domain = try container.decodeIfPresent(Domain.self, forKey: .domain) + if domain?.rawValue == "*" { + self.domain = nil + } else { + self.domain = domain + } + introducedVersion = try container.decodeIfPresent(SymbolGraph.SemanticVersion.self, forKey: .introducedVersion) + deprecatedVersion = try container.decodeIfPresent(SymbolGraph.SemanticVersion.self, forKey: .deprecatedVersion) + obsoletedVersion = try container.decodeIfPresent(SymbolGraph.SemanticVersion.self, forKey: .obsoletedVersion) + message = try container.decodeIfPresent(String.self, forKey: .message) + renamed = try container.decodeIfPresent(String.self, forKey: .renamed) + isUnconditionallyDeprecated = try container.decodeIfPresent(Bool.self, forKey: .isUnconditionallyDeprecated) ?? false + isUnconditionallyUnavailable = try container.decodeIfPresent(Bool.self, forKey: .isUnconditionallyUnavailable) ?? false + willEventuallyBeDeprecated = try container.decodeIfPresent(Bool.self, forKey: .willEventuallyBeDeprecated) ?? false + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(domain, forKey: .domain) + if let introducedVersion = introducedVersion { + try container.encode(introducedVersion, forKey: .introducedVersion) + } + if let deprecatedVersion = deprecatedVersion { + try container.encode(deprecatedVersion, forKey: .deprecatedVersion) + } + if let obsoletedVersion = obsoletedVersion { + try container.encode(obsoletedVersion, forKey: .obsoletedVersion) + } + if let message = message { + try container.encode(message, forKey: .message) + } + if let renamed = renamed { + try container.encode(renamed, forKey: .renamed) + } + if isUnconditionallyDeprecated { + try container.encode(isUnconditionallyDeprecated, forKey: .isUnconditionallyDeprecated) + } + if isUnconditionallyUnavailable { + try container.encode(isUnconditionallyUnavailable, forKey: .isUnconditionallyUnavailable) + } + if willEventuallyBeDeprecated { + try container.encode(willEventuallyBeDeprecated, forKey: .willEventuallyBeDeprecated) + } + } + + public init(domain: SymbolGraph.Symbol.Availability.Domain?, + introducedVersion: SymbolGraph.SemanticVersion?, + deprecatedVersion: SymbolGraph.SemanticVersion?, + obsoletedVersion: SymbolGraph.SemanticVersion?, + message: String?, + renamed: String?, + isUnconditionallyDeprecated: Bool, + isUnconditionallyUnavailable: Bool, + willEventuallyBeDeprecated: Bool) { + self.domain = domain + self.introducedVersion = introducedVersion + self.deprecatedVersion = deprecatedVersion + self.obsoletedVersion = obsoletedVersion + self.message = message + self.renamed = renamed + self.isUnconditionallyDeprecated = isUnconditionallyDeprecated + self.isUnconditionallyUnavailable = isUnconditionallyUnavailable + self.willEventuallyBeDeprecated = willEventuallyBeDeprecated + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Availability/Availability+Domain.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Availability/Availability+Domain.swift new file mode 100644 index 0000000..1f54e2c --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Availability/Availability+Domain.swift @@ -0,0 +1,106 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol.Availability { + /** + A versioned context where a symbol resides. + + For example, a domain can be an operating system, programming language, + or perhaps a web platform. + + A single framework, library, or module could theoretically be + an `AvailabilityDomain`, as it is a containing context and almost always + has a version. + However, availability is usually tied to some larger platform like an SDK for + an operating system like *iOS*. + + There may be exceptions when there isn't a reasonable larger context. + For example, a web framework's larger context is simply *the Web*. + Therefore, a web framework could be its own domain so that deprecations and + API changes can be tracked across versions of that framework. + */ + public struct Domain: Codable, RawRepresentable { + public var rawValue: String + public init(rawValue: String) { + self.rawValue = rawValue + } + + /** + The Swift Programming Language. + + This domain main indicate that a symbol is unavailable + in Swift, or availability applies to particular versions + of Swift. + */ + public static let swift = "Swift" + + /** + The Swift Package Manager Package Description Format. + */ + public static let swiftPM = "SwiftPM" + + /** + Apple's macOS operating system. + */ + public static let macOS = "macOS" + + /** + An application extension for the macOS operating system. + */ + public static let macOSAppExtension = "macOSAppExtension" + + /** + The iOS operating system. + */ + public static let iOS = "iOS" + + /** + An application extension for the iOS operating system. + */ + public static let iOSAppExtension = "iOSAppExtension" + + /** + The watchOS operating system. + */ + public static let watchOS = "watchOS" + + /** + An application extension for the watchOS operating system. + */ + public static let watchOSAppExtension = "watchOSAppExtension" + + /** + The tvOS operating system. + */ + public static let tvOS = "tvOS" + + /** + An application extension for the tvOS operating system. + */ + public static let tvOSAppExtension = "tvOSAppExtension" + + /** + The Mac Catalyst platform. + */ + public static let macCatalyst = "macCatalyst" + + /** + An application extension for the Mac Catalyst platform. + */ + public static let macCatalystAppExtension = "macCatalystAppExtension" + + /** + A Linux-based operating system, but not a specific distribution. + */ + public static let linux = "Linux" + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Availability/Availability.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Availability/Availability.swift new file mode 100644 index 0000000..7453894 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Availability/Availability.swift @@ -0,0 +1,56 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /** + Availability is described by a *domain* and the versions in which + certain events may have occurred, such as a symbol's appearance in a framework, + its deprecation, obsolescence, or removal. + A symbol may have zero or more availability items. + + For example, + a class introduced in iOS 11 would have: + + - a availability domain of `"iOS"` and + - an `introduced` version of `11.0.0`. + + As another example, + a method `foo` that was renamed to `bar` in iOS 10.1 would have: + + - an availability domain of `"iOS"`, + - a `deprecated` version `10.1.0`, and + - a `renamed` string of `"bar"`. + + Some symbols may be *unconditionally* unavailable or deprecated. + This means that the availability applies to any version, and + possibly to all domains if the `availabilityDomain` key is undefined. + */ + public struct Availability: Mixin, Codable { + public static let mixinKey = "availability" + + public var availability: [AvailabilityItem] + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + availability = try container.decode([AvailabilityItem].self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(availability) + } + + public init(availability: [AvailabilityItem]) { + self.availability = availability + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/DeclarationFragments/DeclarationFragments.swift b/Sources/SymbolKit/SymbolGraph/Symbol/DeclarationFragments/DeclarationFragments.swift new file mode 100644 index 0000000..1a78239 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/DeclarationFragments/DeclarationFragments.swift @@ -0,0 +1,157 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /** + A mix-in that generically describes the fragments + of a symbol's declaration in a particular language, allowing for idiomatic + presentation. + + For example, one can use this to drive a "code snippet" + with syntax highlighting for a function signature. + + For example, the following declaration in Swift: + + ```swift + func foo(_ sequence: S) -> Int { + // ... + } + ``` + + Would be represented with the following list of tokens when displaying + the declaration fragment: + + ```json + [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "identifier", + "spelling": "foo" + }, + { + "kind": "punctuation", + "spelling": "<" + }, + { + "kind": "identifier", + "spelling": "S" + }, + { + "kind": "punctuation", + "spelling": ":" + }, + { + "kind": "trivia", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "spelling": "Sequence", + "preciseIdentifier": "$sST" + }, + { + "kind": "punctuation", + "spelling": ">" + }, + { + "kind": "punctuation", + "spelling": "(" + }, + { + "kind": "identifier", + "spelling": "_" + }, + { + "kind": "trivia", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "seq" + }, + { + "kind": "punctuation", + "spelling": ":" + }, + { + "kind": "typeIdentifier", + "spelling": "Sequence", + "preciseIdentifier": "$sST" + }, + { + "kind": "punctuation", + "spelling": ":" + }, + { + "kind": "identifier", + "spelling": "S" + }, + { + "kind": "punctuation", + "spelling": ")" + }, + { + "kind": "trivia", + "spelling": " " + }, + { + "kind": "punctuation", + "spelling": "->" + }, + { + "kind": "trivia", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "spelling": "Int", + "preciseIdentifier": "$sSi" + } + ] + ``` + */ + public struct DeclarationFragments: Mixin, Codable { + public static let mixinKey = "declarationFragments" + + /** + A list of fragments spelling out the declarations, + allowing for a presentation that's idiomatic to the source language + and cross-referencing identifiers to other symbols in the module. + + > Note: These may not necessarily, literally be lexer tokens but they may be. + */ + public var declarationFragments: [Fragment] + + /** + Initialize a declaration fragments mix-in with the given list of fragments. + + - Parameters: + - declarationFragments: The list of fragments spelling out the declaration. + */ + public init(declarationFragments: [Fragment]) { + self.declarationFragments = declarationFragments + } + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + declarationFragments = try container.decode([Fragment].self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(declarationFragments) + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/DeclarationFragments/Fragment/Fragment+Kind.swift b/Sources/SymbolKit/SymbolGraph/Symbol/DeclarationFragments/Fragment/Fragment+Kind.swift new file mode 100644 index 0000000..7f326d6 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/DeclarationFragments/Fragment/Fragment+Kind.swift @@ -0,0 +1,95 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol.DeclarationFragments.Fragment { + /** + The kind of declaration fragment. + */ + public struct Kind: Equatable, Codable, RawRepresentable { + public var rawValue: String + public init?(rawValue: String) { + self.rawValue = rawValue + } + + /** + A keyword in the programming language, such as `return` in C or `func` in Swift. + */ + public static let keyword = Kind(rawValue: "keyword")! + + /** + An attribute in the programming language. + */ + public static let attribute = Kind(rawValue: "attribute")! + + /** + An integer or floating point literal, such as `0`, `1.0f`, or `0xFF`. + */ + public static let numberLiteral = Kind(rawValue: "number")! + + /** + A string literal such as `"foo"`. + */ + public static let stringLiteral = Kind(rawValue: "string")! + + /** + An identifier such as a parameter name. + */ + public static let identifier = Kind(rawValue: "identifier")! + + /** + An identifier for a type. + */ + public static let typeIdentifier = Kind(rawValue: "typeIdentifier")! + + /** + A generic parameter, such as the `T` in C++ `template `. + */ + public static let genericParameter = Kind(rawValue: "genericParameter")! + + /** + A function parameter when viewed externally as a client. + + For example, in Swift: + + ```swift + func foo(ext int: Int) {} + ``` + + `ext` is an external parameter name, whereas `int` is an internal + parameter name. + */ + public static let externalParameter = Kind(rawValue: "externalParam")! + + /** + A function parameter when viewed internally from the implementation. + + For example, in Swift: + + ```swift + func foo(ext int: Int) {} + ``` + + `ext` is an external parameter name, whereas `int` is an internal + parameter name. + + > Note: Although these are not a part of a function's interface, + > such as in Swift, they have historically been easier to refer + > to in prose. + */ + public static let internalParameter = Kind(rawValue: "internalParam")! + + /** + General purpose or unlabeled text. + */ + public static let text = Kind(rawValue: "text")! + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/DeclarationFragments/Fragment/Fragment.swift b/Sources/SymbolKit/SymbolGraph/Symbol/DeclarationFragments/Fragment/Fragment.swift new file mode 100644 index 0000000..67ed166 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/DeclarationFragments/Fragment/Fragment.swift @@ -0,0 +1,53 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol.DeclarationFragments { + /** + A general-purpose fragment of syntax spelling out a declaration. + + For example, a C function might break up `int main(int argc, char **argv)` + or a Swift structure might break up into `struct MyStruct`. + */ + public struct Fragment: Equatable, Codable { + /** + The kind of fragment, such as a token keyword, identifier, + or span of text. + */ + public var kind: Kind + + /** + How the token was spelled in the source code. + */ + public var spelling: String + + /** + A precise identifier if the fragment corresponds to another symbol. + This may be useful for linking to other symbols when displaying + function parameter types. + */ + public var preciseIdentifier: String? + + /** + Initialize a fragment with the given `kind`, `spelling`, and `preciseIdentifier`. + + - Parameters: + - kind: The kind of fragment. + - spelling: How the token was spelled in the source code. + - preciseIdentifier: A precise identifier if the fragment corresponds to another symbol. + */ + public init(kind: Kind, spelling: String, preciseIdentifier: String?) { + self.kind = kind + self.spelling = spelling + self.preciseIdentifier = preciseIdentifier + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/FunctionSignature/FunctionSignature+FunctionParameter.swift b/Sources/SymbolKit/SymbolGraph/Symbol/FunctionSignature/FunctionSignature+FunctionParameter.swift new file mode 100644 index 0000000..25b981c --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/FunctionSignature/FunctionSignature+FunctionParameter.swift @@ -0,0 +1,43 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol.FunctionSignature { + /// An argument of a callable symbol. + public struct FunctionParameter: Codable { + enum CodingKeys: String, CodingKey { + case name + case declarationFragments + case children + } + + /// The name of the symbol, as referred to in user code (must match the name used in the documentation comment). + public var name: String // should we differentiate between internal and external names? + /// The syntax used to create the parameter. + public var declarationFragments: [SymbolGraph.Symbol.DeclarationFragments.Fragment] + /// Sub-parameters of the parameter. + public var children: [FunctionParameter] + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + name = try container.decode(String.self, forKey: .name) + declarationFragments = try container.decodeIfPresent([SymbolGraph.Symbol.DeclarationFragments.Fragment].self, forKey: .declarationFragments) ?? [] + children = try container.decodeIfPresent([FunctionParameter].self, forKey: .children) ?? [] + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(name, forKey: .name) + try container.encode(declarationFragments, forKey: .declarationFragments) + try container.encode(children, forKey: .children) + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/FunctionSignature/FunctionSignature.swift b/Sources/SymbolKit/SymbolGraph/Symbol/FunctionSignature/FunctionSignature.swift new file mode 100644 index 0000000..86a9ada --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/FunctionSignature/FunctionSignature.swift @@ -0,0 +1,45 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /// The arguments of a callable symbol. + public struct FunctionSignature: Mixin, Codable { + enum CodingKeys: String, CodingKey { + case parameters + case returns + } + + public static let mixinKey = "functionSignature" + + /** + The parameters of the function. + */ + public var parameters: [FunctionParameter] + + /** + The fragments spelling out the return type of the function signature if applicable. + */ + public var returns: [DeclarationFragments.Fragment] + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + parameters = try container.decodeIfPresent([FunctionParameter].self, forKey: .parameters) ?? [] + returns = try container.decodeIfPresent([DeclarationFragments.Fragment].self, forKey: .returns) ?? [] + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(parameters, forKey: .parameters) + try container.encode(returns, forKey: .returns) + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Namespace.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Namespace.swift new file mode 100644 index 0000000..fbdabbe --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Namespace.swift @@ -0,0 +1,16 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /// A namespace for Swift-specific data. + public enum Swift {} +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+Extension.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+Extension.swift new file mode 100644 index 0000000..ef991e5 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+Extension.swift @@ -0,0 +1,51 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol.Swift { + /** + If the Symbol is from Swift, this mixin describes the extension context in which it was defined. + */ + public struct Extension: Mixin { + public static let mixinKey = "swiftExtension" + + /** + The module whose type was extended. + + > Note: This module maybe different than where the symbol was actually defined. For example, one can create a public extension on the Swift Standard Library's `String` type in a different module, so `extendedModule` would be `Swift`. + */ + public var extendedModule: String + + /** + The generic constraints on the extension, if any. + */ + public var constraints: [GenericConstraint] + + enum CodingKeys: String, CodingKey { + case extendedModule + case constraints + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + extendedModule = try container.decode(String.self, forKey: .extendedModule) + constraints = try container.decodeIfPresent([GenericConstraint].self, forKey: .constraints) ?? [] + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(extendedModule, forKey: .extendedModule) + if !constraints.isEmpty { + try container.encode(constraints, forKey: .constraints) + } + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+GenericConstraint.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+GenericConstraint.swift new file mode 100644 index 0000000..d8b1324 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+GenericConstraint.swift @@ -0,0 +1,86 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol.Swift { + /// A generic constraint between two types. + public struct GenericConstraint: Codable, Hashable { + public enum Kind: String, Codable { + /** + A conformance constraint, such as: + + ```swift + extension Thing where Thing.T: Sequence { + // ... + } + ``` + */ + case conformance + + /** + A superclass constraint, such as: + + ```swift + extension Thing where Thing.T: NSObject { + // ... + } + ``` + */ + case superclass + + /** + A same-type constraint, such as: + + ```swift + extension Thing where Thing.T == Int { + // ... + } + ``` + */ + case sameType + } + + enum CodingKeys: String, CodingKey { + case kind + case leftTypeName = "lhs" + case rightTypeName = "rhs" + } + + /** + The kind of generic constraint. + */ + public var kind: Kind + + /** + The spelling of the left-hand side of the constraint. + */ + public var leftTypeName: String + + /** + The spelling of the right-hand side of the constraint. + */ + public var rightTypeName: String + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + kind = try container.decode(Kind.self, forKey: .kind) + leftTypeName = try container.decode(String.self, forKey: .leftTypeName) + rightTypeName = try container.decode(String.self, forKey: .rightTypeName) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(kind, forKey: .kind) + try container.encode(leftTypeName, forKey: .leftTypeName) + try container.encode(rightTypeName, forKey: .rightTypeName) + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+GenericParameter.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+GenericParameter.swift new file mode 100644 index 0000000..5021e96 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+GenericParameter.swift @@ -0,0 +1,51 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol.Swift { + /** + A generic parameter of a declaration, such as the `T` in `foo(...)`. + */ + public struct GenericParameter: Codable { + /// The name of the generic parameter. + public var name: String + + /** + The index of the generic parameter. + + For example, in the following function signature, + + ```swift + func foo(x: T, y: U) + ``` + + `T` has index 0 and `U` has index 1. + */ + public var index: Int + + /** + The depth of the generic parameter. + + For example, in the following generic structure, + + ```swift + struct MyStruct { + func foo(x: U, y: T) { + // ... + } + } + ``` + + `T` has depth 0 and `U` has depth 1. + */ + public var depth: Int + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+Generics.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+Generics.swift new file mode 100644 index 0000000..c8f139e --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Swift/Swift+Generics.swift @@ -0,0 +1,67 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol.Swift { + /** + The generic signature of a declaration or type. + */ + public struct Generics: Mixin { + public static let mixinKey = "swiftGenerics" + + enum CodingKeys: String, CodingKey { + case parameters + case constraints + } + + /** + The generic parameters of a declaration. + + For example, in the following generic function signature, + + ```swift + func foo(_ thing: T) { ... } + ``` + + `T` is a *generic parameter*. + */ + public var parameters: [GenericParameter] + + /** + The generic constraints of a declaration. + + For example, in the following generic function signature, + + ```swift + func foo(_ s: S) where S: Sequence + ``` + + There is a *conformance constraint* involving `S`. + */ + public var constraints: [GenericConstraint] + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + parameters = try container.decodeIfPresent([GenericParameter].self, forKey: .parameters) ?? [] + constraints = try container.decodeIfPresent([GenericConstraint].self, forKey: .constraints) ?? [] + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + if !parameters.isEmpty { + try container.encode(parameters, forKey: .parameters) + } + if !constraints.isEmpty { + try container.encode(constraints, forKey: .constraints) + } + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+AccessControl.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+AccessControl.swift new file mode 100644 index 0000000..6d8a2a5 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+AccessControl.swift @@ -0,0 +1,22 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /// The language-agnostic access control of a symbol, + /// such as "public", "private", "protected". + public struct AccessControl: Codable, RawRepresentable, Hashable { + public var rawValue: String + public init(rawValue: String) { + self.rawValue = rawValue + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Identifier.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Identifier.swift new file mode 100644 index 0000000..45efaf3 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Identifier.swift @@ -0,0 +1,30 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /// Information that uniquely identifies the symbol inside the module. + public struct Identifier: Codable, Hashable { + /** + A string that uniquely identifies a symbol within a module in the event of ambiguities. A precise identifier need not be human readable. + For example, languages that use [name mangling](https://en.wikipedia.org/wiki/Name_mangling) should use this field for a mangled name. + */ + public var precise: String + + /// The name of the language for which this symbol provides an interface, such as `swift` or `c`. + public var interfaceLanguage: String + + public init(precise: String, interfaceLanguage: String) { + self.precise = precise + self.interfaceLanguage = interfaceLanguage + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Kind.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Kind.swift new file mode 100644 index 0000000..586cac6 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Kind.swift @@ -0,0 +1,49 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /// A description of a symbol's kind, such as a structure or protocol. + public struct Kind: Equatable, Codable { + /// A unique identifier for this symbol's kind. + public var identifier: KindIdentifier + + /// A display name for a kind of symbol. + /// + /// For example, a Swift class might use `"Class"`. + /// This display name should not be abbreviated: + /// for instance, use `"Structure"` instead of `"Struct"` if applicable. + public var displayName: String + + /// Initializes a new ``SymbolGraph/Symbol/Kind-swift.struct`` with an already-parsed + /// ``SymbolGraph/Symbol/KindIdentifier`` and display name. + public init(parsedIdentifier: KindIdentifier, displayName: String) { + identifier = parsedIdentifier + self.displayName = displayName + } + + /// Initializes a new ``SymbolGraph/Symbol/Kind-swift.struct`` by parsing a new + /// ``SymbolGraph/Symbol/KindIdentifier`` from the given identifier string, and combining it + /// with a display name. + @available(*, deprecated, message: "Use init(rawIdentifier:displayName:) instead") + public init(identifier: String, displayName: String) { + self.init(rawIdentifier: identifier, displayName: displayName) + } + + /// Initializes a new ``SymbolGraph/Symbol/Kind-swift.struct`` by parsing a new + /// ``SymbolGraph/Symbol/KindIdentifier`` from the given identifier string, and combining it + /// with a display name. + public init(rawIdentifier: String, displayName: String) { + identifier = KindIdentifier(identifier: rawIdentifier) + self.displayName = displayName + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+KindIdentifier.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+KindIdentifier.swift new file mode 100644 index 0000000..3003140 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+KindIdentifier.swift @@ -0,0 +1,165 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /** + A unique identifier of a symbol's kind, such as a structure or protocol. + */ + public enum KindIdentifier: Equatable, Hashable, Codable, CaseIterable { + case `associatedtype` + case `class` + case `deinit` + case `enum` + case `case` + case `func` + case `operator` + case `init` + case method + case property + case `protocol` + case `struct` + case `subscript` + case typeMethod + case typeProperty + case typeSubscript + case `typealias` + case `var` + + case module + + case unknown + + /// A string that uniquely identifies the symbol kind. + /// + /// If the original kind string was not recognized, this will return `"unknown"`. + public var identifier: String { + switch self { + case .associatedtype: return "associatedtype" + case .class: return "class" + case .deinit: return "deinit" + case .enum: return "enum" + case .case: return "enum.case" + case .func: return "func" + case .operator: return "func.op" + case .`init`: return "init" + case .method: return "method" + case .property: return "property" + case .protocol: return "protocol" + case .struct: return "struct" + case .subscript: return "subscript" + case .typeMethod: return "type.method" + case .typeProperty: return "type.property" + case .typeSubscript: return "type.subscript" + case .typealias: return "typealias" + case .var: return "var" + case .module: return "module" + case .unknown: return "unknown" + } + } + + // FIXME: Save "unknown" symbol kinds in a synchronized set to prevent loss of data (rdar://84276085) + + /// Check the given identifier string against the list of known identifiers. + /// + /// - Parameter identifier: The identifier string to check. + /// - Returns: The matching `KindIdentifier` case, or `nil` if there was no match. + private static func lookupIdentifier(identifier: String) -> KindIdentifier? { + switch identifier { + case "associatedtype": return .associatedtype + case "class": return .class + case "deinit": return .deinit + case "enum": return .enum + case "enum.case": return .case + case "func": return .func + case "func.op": return .operator + case "init": return .`init` + case "method": return .method + case "property": return .property + case "protocol": return .protocol + case "struct": return .struct + case "subscript": return .subscript + case "type.method": return .typeMethod + case "type.property": return .typeProperty + case "type.subscript": return .typeSubscript + case "typealias": return .typealias + case "var": return .var + case "module": return .module + default: return nil + } + } + + /// Compares the given identifier against the known default symbol kinds, and returns whether it matches one. + /// + /// The identifier will also be checked without its first component, so that (for example) `"swift.func"` + /// will be treated the same as just `"func"`, and match `.func`. + /// + /// - Parameter identifier: The identifier string to compare. + /// - Returns: `true` if the given identifier matches a known symbol kind; otherwise `false`. + public static func isKnownIdentifier(_ identifier: String) -> Bool { + var kind: KindIdentifier? + + if let cachedDetail = Self.lookupIdentifier(identifier: identifier) { + kind = cachedDetail + } else { + let cleanIdentifier = KindIdentifier.cleanIdentifier(identifier) + kind = Self.lookupIdentifier(identifier: cleanIdentifier) + } + + return kind != nil + } + + /// Parses the given identifier to return a matching symbol kind. + /// + /// The identifier will also be checked without its first component, so that (for example) `"swift.func"` + /// will be treated the same as just `"func"`, and match `.func`. + /// + /// - Parameter identifier: The identifier string to parse. + public init(identifier: String) { + // Check if the identifier matches a symbol kind directly. + if let firstParse = Self.lookupIdentifier(identifier: identifier) { + self = firstParse + } else { + // For symbol graphs which include a language identifier with their symbol kinds + // (e.g. "swift.func" instead of just "func"), strip off the language prefix and + // try again. + let cleanIdentifier = KindIdentifier.cleanIdentifier(identifier) + self = Self.lookupIdentifier(identifier: cleanIdentifier) ?? .unknown + } + } + + public init(from decoder: Decoder) throws { + let identifier = try decoder.singleValueContainer().decode(String.self) + self = KindIdentifier(identifier: identifier) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(identifier) + } + + /// Strips the first component of the given identifier string, so that (for example) `"swift.func"` will return `"func"`. + /// + /// Symbol graphs may store symbol kinds as either bare identifiers (e.g. `"class"`, `"enum"`, etc), or as identifiers + /// prefixed with the language identifier (e.g. `"swift.func"`, `"objc.method"`, etc). This method allows us to + /// treat the language-prefixed symbol kinds as equivalent to the "bare" symbol kinds. + /// + /// - Parameter identifier: An identifier string to clean. + /// - Returns: A new identifier string without its first component, or the original identifier if there was only one component. + private static func cleanIdentifier(_ identifier: String) -> String { + // FIXME: Take an "expected" language identifier instead of universally dropping the first component? (rdar://84276085) + if let periodIndex = identifier.firstIndex(of: ".") { + return String(identifier[identifier.index(after: periodIndex)...]) + } + return identifier + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Location.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Location.swift new file mode 100644 index 0000000..8af848a --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Location.swift @@ -0,0 +1,34 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /** + The place where a symbol was originaly declared in a source file. + + This information may not always be available for many reasons, such + as compiler infrastructure limitations, or filesystem security concerns. + */ + public struct Location: Mixin { + public static let mixinKey = "location" + + /** + The URI of the file in which the symbol was originally declared, + suitable for display in a user interface. + */ + public var uri: String + + /** + The range of the declaration in the file, not including its documentation comment. + */ + public var position: SymbolGraph.LineList.SourceRange.Position + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Mutability.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Mutability.swift new file mode 100644 index 0000000..01dad89 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Mutability.swift @@ -0,0 +1,38 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /** + A mix-in that specifies whether a symbol is immutable in its host language. + + For example, a constant member `let x = 1` in a Swift structure + would have `isReadOnly` set to `true`. + */ + public struct Mutability: Mixin, Equatable, Codable { + public static let mixinKey = "isReadOnly" + + /** + Whether a symbol is *immutable* or "read-only". + */ + public var isReadOnly: Bool + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + isReadOnly = try container.decode(Bool.self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(isReadOnly) + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Names.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Names.swift new file mode 100644 index 0000000..fa0e6b4 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+Names.swift @@ -0,0 +1,47 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /** + The names of a symbol, suitable for display in various contexts. + */ + public struct Names: Codable, Equatable { + /** + A name suitable for use a title on a "page" of documentation. + */ + public var title: String + + /** + An abbreviated form of the symbol's declaration for displaying in navigators where there may be limited horizontal space. + */ + public var navigator: [DeclarationFragments.Fragment]? + + /** + An abbreviated form of the symbol's declaration for displaying in subheadings or lists. + */ + public var subHeading: [DeclarationFragments.Fragment]? + + /** + A name to use in documentation prose or inline link titles. + + > Note: If undefined, use the `title`. + */ + public var prose: String? + + public init(title: String, navigator: [DeclarationFragments.Fragment]?, subHeading: [DeclarationFragments.Fragment]?, prose: String?) { + self.title = title + self.navigator = navigator + self.subHeading = subHeading + self.prose = prose + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+SPI.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+SPI.swift new file mode 100644 index 0000000..ee7f845 --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol+SPI.swift @@ -0,0 +1,34 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph.Symbol { + /// Whether the symbol is marked as a System Programming Interface in source. + public struct SPI: Mixin, Codable { + public static let mixinKey = "spi" + + public var isSPI: Bool + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + isSPI = try container.decode(Bool.self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(isSPI) + } + + public init(isSPI: Bool) { + self.isSPI = isSPI + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/Symbol/Symbol.swift b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol.swift index b919616..5127521 100644 --- a/Sources/SymbolKit/SymbolGraph/Symbol/Symbol.swift +++ b/Sources/SymbolKit/SymbolGraph/Symbol/Symbol.swift @@ -9,7 +9,6 @@ */ extension SymbolGraph { - /** A symbol from a module. @@ -54,7 +53,7 @@ extension SymbolGraph { /// The in-source documentation comment attached to a symbol. public var docComment: LineList? - + /// If the symbol has a documentation comment, whether the documentation comment is from /// the same module as the symbol or not. /// @@ -63,7 +62,7 @@ extension SymbolGraph { guard let docComment = docComment, !docComment.lines.isEmpty else { return nil } - + // As a current implementation detail, documentation comments from within the current module has range information but // documentation comments that are inherited from other modules don't have any range information. // @@ -116,7 +115,7 @@ extension SymbolGraph { .swiftGenerics, .location, .functionSignature, - .spi + .spi, ] } } @@ -208,1192 +207,3 @@ extension SymbolGraph { } } } - -extension SymbolGraph.Symbol { - /// The language-agnostic access control of a symbol, - /// such as "public", "private", "protected". - public struct AccessControl: Codable, RawRepresentable, Hashable { - public var rawValue: String - public init(rawValue: String) { - self.rawValue = rawValue - } - } -} - -extension SymbolGraph.Symbol { - /// Information that uniquely identifies the symbol inside the module. - public struct Identifier: Codable, Hashable { - /** - A string that uniquely identifies a symbol within a module in the event of ambiguities. A precise identifier need not be human readable. - For example, languages that use [name mangling](https://en.wikipedia.org/wiki/Name_mangling) should use this field for a mangled name. - */ - public var precise: String - - /// The name of the language for which this symbol provides an interface, such as `swift` or `c`. - public var interfaceLanguage: String - - public init(precise: String, interfaceLanguage: String) { - self.precise = precise - self.interfaceLanguage = interfaceLanguage - } - } -} - -extension SymbolGraph.Symbol { - /// A description of a symbol's kind, such as a structure or protocol. - public struct Kind: Equatable, Codable { - /// A unique identifier for this symbol's kind. - public var identifier: KindIdentifier - - /// A display name for a kind of symbol. - /// - /// For example, a Swift class might use `"Class"`. - /// This display name should not be abbreviated: - /// for instance, use `"Structure"` instead of `"Struct"` if applicable. - public var displayName: String - - /// Initializes a new ``SymbolGraph/Symbol/Kind-swift.struct`` with an already-parsed - /// ``SymbolGraph/Symbol/KindIdentifier`` and display name. - public init(parsedIdentifier: KindIdentifier, displayName: String) { - self.identifier = parsedIdentifier - self.displayName = displayName - } - - /// Initializes a new ``SymbolGraph/Symbol/Kind-swift.struct`` by parsing a new - /// ``SymbolGraph/Symbol/KindIdentifier`` from the given identifier string, and combining it - /// with a display name. - @available(*, deprecated, message: "Use init(rawIdentifier:displayName:) instead") - public init(identifier: String, displayName: String) { - self.init(rawIdentifier: identifier, displayName: displayName) - } - - /// Initializes a new ``SymbolGraph/Symbol/Kind-swift.struct`` by parsing a new - /// ``SymbolGraph/Symbol/KindIdentifier`` from the given identifier string, and combining it - /// with a display name. - public init(rawIdentifier: String, displayName: String) { - self.identifier = KindIdentifier(identifier: rawIdentifier) - self.displayName = displayName - } - } -} - -extension SymbolGraph.Symbol { - /** - A unique identifier of a symbol's kind, such as a structure or protocol. - */ - public enum KindIdentifier: Equatable, Hashable, Codable, CaseIterable { - case `associatedtype` - case `class` - case `deinit` - case `enum` - case `case` - case `func` - case `operator` - case `init` - case `method` - case `property` - case `protocol` - case `struct` - case `subscript` - case `typeMethod` - case `typeProperty` - case `typeSubscript` - case `typealias` - case `var` - - case `module` - - case `unknown` - - - /// A string that uniquely identifies the symbol kind. - /// - /// If the original kind string was not recognized, this will return `"unknown"`. - public var identifier: String { - get { - switch self { - case .associatedtype : return "associatedtype" - case .class : return "class" - case .deinit : return "deinit" - case .enum : return "enum" - case .case : return "enum.case" - case .func : return "func" - case .operator : return "func.op" - case .`init` : return "init" - case .method : return "method" - case .property : return "property" - case .protocol : return "protocol" - case .struct : return "struct" - case .subscript : return "subscript" - case .typeMethod : return "type.method" - case .typeProperty : return "type.property" - case .typeSubscript : return "type.subscript" - case .typealias : return "typealias" - case .var : return "var" - case .module : return "module" - case .unknown : return "unknown" - } - } - } - - // FIXME: Save "unknown" symbol kinds in a synchronized set to prevent loss of data (rdar://84276085) - - /// Check the given identifier string against the list of known identifiers. - /// - /// - Parameter identifier: The identifier string to check. - /// - Returns: The matching `KindIdentifier` case, or `nil` if there was no match. - private static func lookupIdentifier(identifier: String) -> KindIdentifier? { - switch identifier { - case "associatedtype" : return .associatedtype - case "class" : return .class - case "deinit" : return .deinit - case "enum" : return .enum - case "enum.case" : return .case - case "func" : return .func - case "func.op" : return .operator - case "init" : return .`init` - case "method" : return .method - case "property" : return .property - case "protocol" : return .protocol - case "struct" : return .struct - case "subscript" : return .subscript - case "type.method" : return .typeMethod - case "type.property" : return .typeProperty - case "type.subscript" : return .typeSubscript - case "typealias" : return .typealias - case "var" : return .var - case "module" : return .module - default : return nil - } - } - - /// Compares the given identifier against the known default symbol kinds, and returns whether it matches one. - /// - /// The identifier will also be checked without its first component, so that (for example) `"swift.func"` - /// will be treated the same as just `"func"`, and match `.func`. - /// - /// - Parameter identifier: The identifier string to compare. - /// - Returns: `true` if the given identifier matches a known symbol kind; otherwise `false`. - public static func isKnownIdentifier(_ identifier: String) -> Bool { - var kind: KindIdentifier? = nil - - if let cachedDetail = Self.lookupIdentifier(identifier: identifier) { - kind = cachedDetail - } else { - let cleanIdentifier = KindIdentifier.cleanIdentifier(identifier) - kind = Self.lookupIdentifier(identifier: cleanIdentifier) - } - - return kind != nil - } - - /// Parses the given identifier to return a matching symbol kind. - /// - /// The identifier will also be checked without its first component, so that (for example) `"swift.func"` - /// will be treated the same as just `"func"`, and match `.func`. - /// - /// - Parameter identifier: The identifier string to parse. - public init(identifier: String) { - // Check if the identifier matches a symbol kind directly. - if let firstParse = Self.lookupIdentifier(identifier: identifier) { - self = firstParse - } else { - // For symbol graphs which include a language identifier with their symbol kinds - // (e.g. "swift.func" instead of just "func"), strip off the language prefix and - // try again. - let cleanIdentifier = KindIdentifier.cleanIdentifier(identifier) - self = Self.lookupIdentifier(identifier: cleanIdentifier) ?? .unknown - } - } - - public init(from decoder: Decoder) throws { - let identifier = try decoder.singleValueContainer().decode(String.self) - self = KindIdentifier(identifier: identifier) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(identifier) - } - - /// Strips the first component of the given identifier string, so that (for example) `"swift.func"` will return `"func"`. - /// - /// Symbol graphs may store symbol kinds as either bare identifiers (e.g. `"class"`, `"enum"`, etc), or as identifiers - /// prefixed with the language identifier (e.g. `"swift.func"`, `"objc.method"`, etc). This method allows us to - /// treat the language-prefixed symbol kinds as equivalent to the "bare" symbol kinds. - /// - /// - Parameter identifier: An identifier string to clean. - /// - Returns: A new identifier string without its first component, or the original identifier if there was only one component. - private static func cleanIdentifier(_ identifier: String) -> String { - // FIXME: Take an "expected" language identifier instead of universally dropping the first component? (rdar://84276085) - if let periodIndex = identifier.firstIndex(of: ".") { - return String(identifier[identifier.index(after: periodIndex)...]) - } - return identifier - } - } -} - -extension SymbolGraph.Symbol { - /** - The names of a symbol, suitable for display in various contexts. - */ - public struct Names: Codable, Equatable { - /** - A name suitable for use a title on a "page" of documentation. - */ - public var title: String - - /** - An abbreviated form of the symbol's declaration for displaying in navigators where there may be limited horizontal space. - */ - public var navigator: [DeclarationFragments.Fragment]? - - /** - An abbreviated form of the symbol's declaration for displaying in subheadings or lists. - */ - public var subHeading: [DeclarationFragments.Fragment]? - - /** - A name to use in documentation prose or inline link titles. - - > Note: If undefined, use the `title`. - */ - public var prose: String? - - public init(title: String, navigator: [DeclarationFragments.Fragment]?, subHeading: [DeclarationFragments.Fragment]?, prose: String?) { - self.title = title - self.navigator = navigator - self.subHeading = subHeading - self.prose = prose - } - } -} - -extension SymbolGraph.Symbol { - /// Whether the symbol is marked as a System Programming Interface in source. - public struct SPI: Mixin, Codable { - public static let mixinKey = "spi" - - public var isSPI: Bool - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - isSPI = try container.decode(Bool.self) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(isSPI) - } - - public init(isSPI: Bool) { - self.isSPI = isSPI - } - } -} - -extension SymbolGraph.Symbol { - /** - Availability is described by a *domain* and the versions in which - certain events may have occurred, such as a symbol's appearance in a framework, - its deprecation, obsolescence, or removal. - A symbol may have zero or more availability items. - - For example, - a class introduced in iOS 11 would have: - - - a availability domain of `"iOS"` and - - an `introduced` version of `11.0.0`. - - As another example, - a method `foo` that was renamed to `bar` in iOS 10.1 would have: - - - an availability domain of `"iOS"`, - - a `deprecated` version `10.1.0`, and - - a `renamed` string of `"bar"`. - - Some symbols may be *unconditionally* unavailable or deprecated. - This means that the availability applies to any version, and - possibly to all domains if the `availabilityDomain` key is undefined. - */ - public struct Availability: Mixin, Codable { - public static let mixinKey = "availability" - - public var availability: [AvailabilityItem] - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - availability = try container.decode([AvailabilityItem].self) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(availability) - } - - public init(availability: [AvailabilityItem]) { - self.availability = availability - } - } -} - -extension SymbolGraph.Symbol.Availability { - /** - Availability of a symbol in a particular domain. - */ - public struct AvailabilityItem: Codable { - /** - The domain in which this availability applies; if undefined, applies to all reasonable domains. - */ - public var domain: Domain? - - /** - The version in which a symbol appeared. - */ - public var introducedVersion: SymbolGraph.SemanticVersion? - - /** - The version in which a symbol was deprecated. - - > Note: If a symbol is *unconditionally deprecated*, this key should be undefined or `null` (see below). - */ - public var deprecatedVersion: SymbolGraph.SemanticVersion? - - /** - The version in which a symbol was obsoleted. - - > Note: If a symbol is *unconditionally obsoleted*, this key should be undefined or `null` (see below). - */ - public var obsoletedVersion: SymbolGraph.SemanticVersion? - - /** - A message further describing availability for documentation purposes. - */ - public var message: String? - - /** - If a symbol was renamed at this point, its new name is given here. - - > Note: This is not necessarily an identifier but an attribute string provided by a compiler. - */ - public var renamed: String? - - /** - If defined and `true`, is unconditionally deprecated regardless - of version, and possibly regardless of domain. - If undefined, assume `false`. - */ - public var isUnconditionallyDeprecated: Bool - - /** - If defined and `true`, is unconditionally unavailable regardless - of version, and possibly regardless of domain. - If undefined, assume `false`. - */ - public var isUnconditionallyUnavailable: Bool - - /** - A formal but lenient indication that this symbol will definitely be deprecated - in future version of the availability domain, but the version hasn't - been decided yet. This is also known as *soft deprecation*. - - Soft deprecation should not provide build errors, runtime errors, or - warnings that can be upgraded to errors, but provides extra time for - usage of a symbol to decrease before providing an explicit - availability deadline. - - If a symbol is formally deprecated with an explicit version in the - `deprecated` property above, the `willEventuallyBeDeprecated` key - should not exist. In the event that it is still included - despite this specification, `deprecated` should always take precedence - over this property in clients. - */ - public var willEventuallyBeDeprecated: Bool - - enum CodingKeys: String, CodingKey { - case domain - case introducedVersion = "introduced" - case deprecatedVersion = "deprecated" - case obsoletedVersion = "obsoleted" - case message - case renamed - case isUnconditionallyDeprecated - case isUnconditionallyUnavailable - case willEventuallyBeDeprecated - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let domain = try container.decodeIfPresent(Domain.self, forKey: .domain) - if domain?.rawValue == "*" { - self.domain = nil - } else { - self.domain = domain - } - self.introducedVersion = try container.decodeIfPresent(SymbolGraph.SemanticVersion.self, forKey: .introducedVersion) - self.deprecatedVersion = try container.decodeIfPresent(SymbolGraph.SemanticVersion.self, forKey: .deprecatedVersion) - self.obsoletedVersion = try container.decodeIfPresent(SymbolGraph.SemanticVersion.self, forKey: .obsoletedVersion) - self.message = try container.decodeIfPresent(String.self, forKey: .message) - self.renamed = try container.decodeIfPresent(String.self, forKey: .renamed) - self.isUnconditionallyDeprecated = try container.decodeIfPresent(Bool.self, forKey: .isUnconditionallyDeprecated) ?? false - self.isUnconditionallyUnavailable = try container.decodeIfPresent(Bool.self, forKey: .isUnconditionallyUnavailable) ?? false - self.willEventuallyBeDeprecated = try container.decodeIfPresent(Bool.self, forKey: .willEventuallyBeDeprecated) ?? false - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(domain, forKey: .domain) - if let introducedVersion = introducedVersion { - try container.encode(introducedVersion, forKey: .introducedVersion) - } - if let deprecatedVersion = deprecatedVersion { - try container.encode(deprecatedVersion, forKey: .deprecatedVersion) - } - if let obsoletedVersion = obsoletedVersion { - try container.encode(obsoletedVersion, forKey: .obsoletedVersion) - } - if let message = message { - try container.encode(message, forKey: .message) - } - if let renamed = renamed { - try container.encode(renamed, forKey: .renamed) - } - if isUnconditionallyDeprecated { - try container.encode(isUnconditionallyDeprecated, forKey: .isUnconditionallyDeprecated) - } - if isUnconditionallyUnavailable { - try container.encode(isUnconditionallyUnavailable, forKey: .isUnconditionallyUnavailable) - } - if willEventuallyBeDeprecated { - try container.encode(willEventuallyBeDeprecated, forKey: .willEventuallyBeDeprecated) - } - } - - public init(domain: SymbolGraph.Symbol.Availability.Domain?, - introducedVersion: SymbolGraph.SemanticVersion?, - deprecatedVersion: SymbolGraph.SemanticVersion?, - obsoletedVersion: SymbolGraph.SemanticVersion?, - message: String?, - renamed: String?, - isUnconditionallyDeprecated: Bool, - isUnconditionallyUnavailable: Bool, - willEventuallyBeDeprecated: Bool) { - self.domain = domain - self.introducedVersion = introducedVersion - self.deprecatedVersion = deprecatedVersion - self.obsoletedVersion = obsoletedVersion - self.message = message - self.renamed = renamed - self.isUnconditionallyDeprecated = isUnconditionallyDeprecated - self.isUnconditionallyUnavailable = isUnconditionallyUnavailable - self.willEventuallyBeDeprecated = willEventuallyBeDeprecated - } - } -} - -extension SymbolGraph.Symbol.Availability { - /** - A versioned context where a symbol resides. - - For example, a domain can be an operating system, programming language, - or perhaps a web platform. - - A single framework, library, or module could theoretically be - an `AvailabilityDomain`, as it is a containing context and almost always - has a version. - However, availability is usually tied to some larger platform like an SDK for - an operating system like *iOS*. - - There may be exceptions when there isn't a reasonable larger context. - For example, a web framework's larger context is simply *the Web*. - Therefore, a web framework could be its own domain so that deprecations and - API changes can be tracked across versions of that framework. - */ - public struct Domain: Codable, RawRepresentable { - public var rawValue: String - public init(rawValue: String) { - self.rawValue = rawValue - } - - /** - The Swift Programming Language. - - This domain main indicate that a symbol is unavailable - in Swift, or availability applies to particular versions - of Swift. - */ - public static let swift = "Swift" - - /** - The Swift Package Manager Package Description Format. - */ - public static let swiftPM = "SwiftPM" - - /** - Apple's macOS operating system. - */ - public static let macOS = "macOS" - - /** - An application extension for the macOS operating system. - */ - public static let macOSAppExtension = "macOSAppExtension" - - /** - The iOS operating system. - */ - public static let iOS = "iOS" - - /** - An application extension for the iOS operating system. - */ - public static let iOSAppExtension = "iOSAppExtension" - - /** - The watchOS operating system. - */ - public static let watchOS = "watchOS" - - /** - An application extension for the watchOS operating system. - */ - public static let watchOSAppExtension = "watchOSAppExtension" - - /** - The tvOS operating system. - */ - public static let tvOS = "tvOS" - - /** - An application extension for the tvOS operating system. - */ - public static let tvOSAppExtension = "tvOSAppExtension" - - /** - The Mac Catalyst platform. - */ - public static let macCatalyst = "macCatalyst" - - /** - An application extension for the Mac Catalyst platform. - */ - public static let macCatalystAppExtension = "macCatalystAppExtension" - - /** - A Linux-based operating system, but not a specific distribution. - */ - public static let linux = "Linux" - } -} - -extension SymbolGraph.Symbol { - /** - A mix-in that generically describes the fragments - of a symbol's declaration in a particular language, allowing for idiomatic - presentation. - - For example, one can use this to drive a "code snippet" - with syntax highlighting for a function signature. - - For example, the following declaration in Swift: - - ```swift - func foo(_ sequence: S) -> Int { - // ... - } - ``` - - Would be represented with the following list of tokens when displaying - the declaration fragment: - - ```json - [ - { - "kind": "keyword", - "spelling": "func" - }, - { - "kind": "identifier", - "spelling": "foo" - }, - { - "kind": "punctuation", - "spelling": "<" - }, - { - "kind": "identifier", - "spelling": "S" - }, - { - "kind": "punctuation", - "spelling": ":" - }, - { - "kind": "trivia", - "spelling": " " - }, - { - "kind": "typeIdentifier", - "spelling": "Sequence", - "preciseIdentifier": "$sST" - }, - { - "kind": "punctuation", - "spelling": ">" - }, - { - "kind": "punctuation", - "spelling": "(" - }, - { - "kind": "identifier", - "spelling": "_" - }, - { - "kind": "trivia", - "spelling": " " - }, - { - "kind": "identifier", - "spelling": "seq" - }, - { - "kind": "punctuation", - "spelling": ":" - }, - { - "kind": "typeIdentifier", - "spelling": "Sequence", - "preciseIdentifier": "$sST" - }, - { - "kind": "punctuation", - "spelling": ":" - }, - { - "kind": "identifier", - "spelling": "S" - }, - { - "kind": "punctuation", - "spelling": ")" - }, - { - "kind": "trivia", - "spelling": " " - }, - { - "kind": "punctuation", - "spelling": "->" - }, - { - "kind": "trivia", - "spelling": " " - }, - { - "kind": "typeIdentifier", - "spelling": "Int", - "preciseIdentifier": "$sSi" - } - ] - ``` - */ - public struct DeclarationFragments: Mixin, Codable { - public static let mixinKey = "declarationFragments" - - /** - A list of fragments spelling out the declarations, - allowing for a presentation that's idiomatic to the source language - and cross-referencing identifiers to other symbols in the module. - - > Note: These may not necessarily, literally be lexer tokens but they may be. - */ - public var declarationFragments: [Fragment] - - /** - Initialize a declaration fragments mix-in with the given list of fragments. - - - Parameters: - - declarationFragments: The list of fragments spelling out the declaration. - */ - public init(declarationFragments: [Fragment]) { - self.declarationFragments = declarationFragments - } - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - declarationFragments = try container.decode([Fragment].self) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(declarationFragments) - } - } -} - -extension SymbolGraph.Symbol.DeclarationFragments { - /** - A general-purpose fragment of syntax spelling out a declaration. - - For example, a C function might break up `int main(int argc, char **argv)` - or a Swift structure might break up into `struct MyStruct`. - */ - public struct Fragment: Equatable, Codable { - /** - The kind of fragment, such as a token keyword, identifier, - or span of text. - */ - public var kind: Kind - - /** - How the token was spelled in the source code. - */ - public var spelling: String - - /** - A precise identifier if the fragment corresponds to another symbol. - This may be useful for linking to other symbols when displaying - function parameter types. - */ - public var preciseIdentifier: String? - - /** - Initialize a fragment with the given `kind`, `spelling`, and `preciseIdentifier`. - - - Parameters: - - kind: The kind of fragment. - - spelling: How the token was spelled in the source code. - - preciseIdentifier: A precise identifier if the fragment corresponds to another symbol. - */ - public init(kind: Kind, spelling: String, preciseIdentifier: String?) { - self.kind = kind - self.spelling = spelling - self.preciseIdentifier = preciseIdentifier - } - } -} - -extension SymbolGraph.Symbol.DeclarationFragments.Fragment { - /** - The kind of declaration fragment. - */ - public struct Kind: Equatable, Codable, RawRepresentable { - public var rawValue: String - public init?(rawValue: String) { - self.rawValue = rawValue - } - - /** - A keyword in the programming language, such as `return` in C or `func` in Swift. - */ - public static let keyword = Kind(rawValue: "keyword")! - - /** - An attribute in the programming language. - */ - public static let attribute = Kind(rawValue: "attribute")! - - /** - An integer or floating point literal, such as `0`, `1.0f`, or `0xFF`. - */ - public static let numberLiteral = Kind(rawValue: "number")! - - /** - A string literal such as `"foo"`. - */ - public static let stringLiteral = Kind(rawValue: "string")! - - /** - An identifier such as a parameter name. - */ - public static let identifier = Kind(rawValue: "identifier")! - - /** - An identifier for a type. - */ - public static let typeIdentifier = Kind(rawValue: "typeIdentifier")! - - /** - A generic parameter, such as the `T` in C++ `template `. - */ - public static let genericParameter = Kind(rawValue: "genericParameter")! - - /** - A function parameter when viewed externally as a client. - - For example, in Swift: - - ```swift - func foo(ext int: Int) {} - ``` - - `ext` is an external parameter name, whereas `int` is an internal - parameter name. - */ - public static let externalParameter = Kind(rawValue: "externalParam")! - - /** - A function parameter when viewed internally from the implementation. - - For example, in Swift: - - ```swift - func foo(ext int: Int) {} - ``` - - `ext` is an external parameter name, whereas `int` is an internal - parameter name. - - > Note: Although these are not a part of a function's interface, - > such as in Swift, they have historically been easier to refer - > to in prose. - */ - public static let internalParameter = Kind(rawValue: "internalParam")! - - /** - General purpose or unlabeled text. - */ - public static let text = Kind(rawValue: "text")! - } -} - -extension SymbolGraph.Symbol { - /// The arguments of a callable symbol. - public struct FunctionSignature: Mixin, Codable { - - enum CodingKeys: String, CodingKey { - case parameters - case returns - } - - public static let mixinKey = "functionSignature" - - /** - The parameters of the function. - */ - public var parameters: [FunctionParameter] - - /** - The fragments spelling out the return type of the function signature if applicable. - */ - public var returns: [DeclarationFragments.Fragment] - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.parameters = try container.decodeIfPresent([FunctionParameter].self, forKey: .parameters) ?? [] - self.returns = try container.decodeIfPresent([DeclarationFragments.Fragment].self, forKey: .returns) ?? [] - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(parameters, forKey: .parameters) - try container.encode(returns, forKey: .returns) - } - } -} - -extension SymbolGraph.Symbol.FunctionSignature { - /// An argument of a callable symbol. - public struct FunctionParameter: Codable { - enum CodingKeys: String, CodingKey { - case name - case declarationFragments - case children - } - - - /// The name of the symbol, as referred to in user code (must match the name used in the documentation comment). - public var name: String // should we differentiate between internal and external names? - /// The syntax used to create the parameter. - public var declarationFragments: [SymbolGraph.Symbol.DeclarationFragments.Fragment] - /// Sub-parameters of the parameter. - public var children: [FunctionParameter] - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.name = try container.decode(String.self, forKey: .name) - self.declarationFragments = try container.decodeIfPresent([SymbolGraph.Symbol.DeclarationFragments.Fragment].self, forKey: .declarationFragments) ?? [] - self.children = try container.decodeIfPresent([FunctionParameter].self, forKey: .children) ?? [] - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(name, forKey: .name) - try container.encode(declarationFragments, forKey: .declarationFragments) - try container.encode(children, forKey: .children) - } - } -} - -extension SymbolGraph.Symbol { - /** - A mix-in that specifies whether a symbol is immutable in its host language. - - For example, a constant member `let x = 1` in a Swift structure - would have `isReadOnly` set to `true`. - */ - public struct Mutability: Mixin, Equatable, Codable { - public static let mixinKey = "isReadOnly" - - /** - Whether a symbol is *immutable* or "read-only". - */ - public var isReadOnly: Bool - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - isReadOnly = try container.decode(Bool.self) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - try container.encode(isReadOnly) - } - } -} - -extension SymbolGraph.Symbol { - /** - The place where a symbol was originaly declared in a source file. - - This information may not always be available for many reasons, such - as compiler infrastructure limitations, or filesystem security concerns. - */ - public struct Location: Mixin { - public static let mixinKey = "location" - - /** - The URI of the file in which the symbol was originally declared, - suitable for display in a user interface. - */ - public var uri: String - - /** - The range of the declaration in the file, not including its documentation comment. - */ - public var position: SymbolGraph.LineList.SourceRange.Position - } -} - -extension SymbolGraph.Symbol { - /// A namespace for Swift-specific data. - public enum Swift { - /// A generic constraint between two types. - public struct GenericConstraint: Codable, Hashable { - public enum Kind: String, Codable { - /** - A conformance constraint, such as: - - ```swift - extension Thing where Thing.T: Sequence { - // ... - } - ``` - */ - case conformance - - /** - A superclass constraint, such as: - - ```swift - extension Thing where Thing.T: NSObject { - // ... - } - ``` - */ - case superclass - - /** - A same-type constraint, such as: - - ```swift - extension Thing where Thing.T == Int { - // ... - } - ``` - */ - case sameType - } - - enum CodingKeys: String, CodingKey { - case kind - case leftTypeName = "lhs" - case rightTypeName = "rhs" - } - - /** - The kind of generic constraint. - */ - public var kind: Kind - - /** - The spelling of the left-hand side of the constraint. - */ - public var leftTypeName: String - - /** - The spelling of the right-hand side of the constraint. - */ - public var rightTypeName: String - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.kind = try container.decode(Kind.self, forKey: .kind) - self.leftTypeName = try container.decode(String.self, forKey: .leftTypeName) - self.rightTypeName = try container.decode(String.self, forKey: .rightTypeName) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(kind, forKey: .kind) - try container.encode(leftTypeName, forKey: .leftTypeName) - try container.encode(rightTypeName, forKey: .rightTypeName) - } - } - - /** - A generic parameter of a declaration, such as the `T` in `foo(...)`. - */ - public struct GenericParameter: Codable { - /// The name of the generic parameter. - public var name: String - - /** - The index of the generic parameter. - - For example, in the following function signature, - - ```swift - func foo(x: T, y: U) - ``` - - `T` has index 0 and `U` has index 1. - */ - public var index: Int - - /** - The depth of the generic parameter. - - For example, in the following generic structure, - - ```swift - struct MyStruct { - func foo(x: U, y: T) { - // ... - } - } - ``` - - `T` has depth 0 and `U` has depth 1. - */ - public var depth: Int - } - - /** - If the Symbol is from Swift, this mixin describes the extension context in which it was defined. - */ - public struct Extension: Mixin { - public static let mixinKey = "swiftExtension" - - /** - The module whose type was extended. - - > Note: This module maybe different than where the symbol was actually defined. For example, one can create a public extension on the Swift Standard Library's `String` type in a different module, so `extendedModule` would be `Swift`. - */ - public var extendedModule: String - - /** - The generic constraints on the extension, if any. - */ - public var constraints: [Swift.GenericConstraint] - - enum CodingKeys: String, CodingKey { - case extendedModule - case constraints - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.extendedModule = try container.decode(String.self, forKey: .extendedModule) - self.constraints = try container.decodeIfPresent([GenericConstraint].self, forKey: .constraints) ?? [] - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(extendedModule, forKey: .extendedModule) - if !constraints.isEmpty { - try container.encode(constraints, forKey: .constraints) - } - } - } - - /** - The generic signature of a declaration or type. - */ - public struct Generics: Mixin { - public static let mixinKey = "swiftGenerics" - - enum CodingKeys: String, CodingKey { - case parameters - case constraints - } - - /** - The generic parameters of a declaration. - - For example, in the following generic function signature, - - ```swift - func foo(_ thing: T) { ... } - ``` - - `T` is a *generic parameter*. - */ - public var parameters: [GenericParameter] - - /** - The generic constraints of a declaration. - - For example, in the following generic function signature, - - ```swift - func foo(_ s: S) where S: Sequence - ``` - - There is a *conformance constraint* involving `S`. - */ - public var constraints: [GenericConstraint] - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.parameters = try container.decodeIfPresent([GenericParameter].self, forKey: .parameters) ?? [] - self.constraints = try container.decodeIfPresent([GenericConstraint].self, forKey: .constraints) ?? [] - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - if !parameters.isEmpty { - try container.encode(parameters, forKey: .parameters) - } - if !constraints.isEmpty { - try container.encode(constraints, forKey: .constraints) - } - } - } - } -} - -/** - A protocol that allows extracted symbols to have extra data - aside from the base ``SymbolGraph/Symbol``. - */ -public protocol Mixin: Codable { - /** - The key under which a mixin's data is filed. - - > Important: With respect to deserialization, this framework assumes `mixinKey`s between instances of `SymbolMixin` are unique. - */ - static var mixinKey: String { get } -} diff --git a/Sources/SymbolKit/SymbolGraph/SymbolGraph+Metadata.swift b/Sources/SymbolKit/SymbolGraph/SymbolGraph+Metadata.swift new file mode 100644 index 0000000..5c331bb --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/SymbolGraph+Metadata.swift @@ -0,0 +1,29 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph { + public struct Metadata: Codable { + /// The version of the serialization format. + public var formatVersion: SemanticVersion + + /// A string describing the tool or system that generated the data for this symbol graph. + /// + /// This should include a name and version if possible to track down potential + /// serialization bugs. + public var generator: String + + public init(formatVersion: SemanticVersion, generator: String) { + self.formatVersion = formatVersion + self.generator = generator + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/SymbolGraph+Module.swift b/Sources/SymbolKit/SymbolGraph/SymbolGraph+Module.swift new file mode 100644 index 0000000..c13414f --- /dev/null +++ b/Sources/SymbolKit/SymbolGraph/SymbolGraph+Module.swift @@ -0,0 +1,35 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2021 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See https://swift.org/LICENSE.txt for license information + See https://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import Foundation + +extension SymbolGraph { + /// A ``Module-swift.struct`` describes the module from which the symbols were extracted.. + public struct Module: Codable { + /// The name of the module. + public var name: String + + /// Optional bystander module names. + public var bystanders: [String]? + + /// The platform intended for deployment. + public var platform: Platform + + /// The [semantic version](https://semver.org) of the module, if availble. + public var version: SemanticVersion? + + public init(name: String, platform: Platform, version: SemanticVersion? = nil, bystanders: [String]? = nil) { + self.name = name + self.platform = platform + self.version = version + self.bystanders = bystanders + } + } +} diff --git a/Sources/SymbolKit/SymbolGraph/OperatingSystem.swift b/Sources/SymbolKit/SymbolGraph/SymbolGraph+OperatingSystem.swift similarity index 92% rename from Sources/SymbolKit/SymbolGraph/OperatingSystem.swift rename to Sources/SymbolKit/SymbolGraph/SymbolGraph+OperatingSystem.swift index b797823..79db961 100644 --- a/Sources/SymbolKit/SymbolGraph/OperatingSystem.swift +++ b/Sources/SymbolKit/SymbolGraph/SymbolGraph+OperatingSystem.swift @@ -25,8 +25,8 @@ extension SymbolGraph { public var minimumVersion: SemanticVersion? public init(name: String, minimumVersion: SemanticVersion? = nil) { - self.name = name - self.minimumVersion = minimumVersion + self.name = name + self.minimumVersion = minimumVersion } } } diff --git a/Sources/SymbolKit/SymbolGraph/Platform.swift b/Sources/SymbolKit/SymbolGraph/SymbolGraph+Platform.swift similarity index 99% rename from Sources/SymbolKit/SymbolGraph/Platform.swift rename to Sources/SymbolKit/SymbolGraph/SymbolGraph+Platform.swift index f35f3b4..3e45011 100644 --- a/Sources/SymbolKit/SymbolGraph/Platform.swift +++ b/Sources/SymbolKit/SymbolGraph/SymbolGraph+Platform.swift @@ -9,7 +9,6 @@ */ extension SymbolGraph { - /// A ``Platform`` describes the deployment environment for a ``Module-swift.struct``. public struct Platform: Codable { /** diff --git a/Sources/SymbolKit/SymbolGraph/Misc/SemanticVersion.swift b/Sources/SymbolKit/SymbolGraph/SymbolGraph+SemanticVersion.swift similarity index 81% rename from Sources/SymbolKit/SymbolGraph/Misc/SemanticVersion.swift rename to Sources/SymbolKit/SymbolGraph/SymbolGraph+SemanticVersion.swift index d84c1a5..537e6de 100644 --- a/Sources/SymbolKit/SymbolGraph/Misc/SemanticVersion.swift +++ b/Sources/SymbolKit/SymbolGraph/SymbolGraph+SemanticVersion.swift @@ -48,11 +48,11 @@ extension SymbolGraph { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - self.major = try container.decode(Int.self, forKey: .major) - self.minor = try container.decodeIfPresent(Int.self, forKey: .minor) ?? 0 - self.patch = try container.decodeIfPresent(Int.self, forKey: .patch) ?? 0 - self.prerelease = try container.decodeIfPresent(String.self, forKey: .prerelease) - self.buildMetadata = try container.decodeIfPresent(String.self, forKey: .buildMetadata) + major = try container.decode(Int.self, forKey: .major) + minor = try container.decodeIfPresent(Int.self, forKey: .minor) ?? 0 + patch = try container.decodeIfPresent(Int.self, forKey: .patch) ?? 0 + prerelease = try container.decodeIfPresent(String.self, forKey: .prerelease) + buildMetadata = try container.decodeIfPresent(String.self, forKey: .buildMetadata) } public var description: String { diff --git a/Sources/SymbolKit/SymbolGraph/SymbolGraph.swift b/Sources/SymbolKit/SymbolGraph/SymbolGraph.swift index a15edb8..e515520 100644 --- a/Sources/SymbolKit/SymbolGraph/SymbolGraph.swift +++ b/Sources/SymbolKit/SymbolGraph/SymbolGraph.swift @@ -18,7 +18,7 @@ public struct SymbolGraph: Codable { /// The module that this symbol graph represents. public var module: Module - + /// The symbols in a module: the nodes in a graph, mapped by precise identifier. public var symbols: [String: Symbol] @@ -31,7 +31,6 @@ public struct SymbolGraph: Codable { self.symbols = [String: Symbol](symbols.lazy.map({ ($0.identifier.precise, $0) }), uniquingKeysWith: { old, new in SymbolGraph._symbolToKeepInCaseOfPreciseIdentifierConflict(old, new) }) - self.relationships = relationships } @@ -60,7 +59,7 @@ public struct SymbolGraph: Codable { try container.encode(Array(symbols.values), forKey: .symbols) try container.encode(relationships, forKey: .relationships) } - + public static func _symbolToKeepInCaseOfPreciseIdentifierConflict(_ lhs: Symbol, _ rhs: Symbol) -> Symbol { if lhs.declarationContainsAsyncKeyword() { return rhs @@ -74,50 +73,10 @@ public struct SymbolGraph: Codable { } } -private extension SymbolGraph.Symbol { - func declarationContainsAsyncKeyword() -> Bool { +extension SymbolGraph.Symbol { + fileprivate func declarationContainsAsyncKeyword() -> Bool { return (mixins[DeclarationFragments.mixinKey] as? DeclarationFragments)?.declarationFragments.contains(where: { fragment in fragment.kind == .keyword && fragment.spelling == "async" }) == true } } - -extension SymbolGraph { - public struct Metadata: Codable { - /// The version of the serialization format. - public var formatVersion: SemanticVersion - - /// A string describing the tool or system that generated the data for this symbol graph. - /// - /// This should include a name and version if possible to track down potential - /// serialization bugs. - public var generator: String - - public init(formatVersion: SemanticVersion, generator: String) { - self.formatVersion = formatVersion - self.generator = generator - } - } - - /// A ``Module-swift.struct`` describes the module from which the symbols were extracted.. - public struct Module: Codable { - /// The name of the module. - public var name: String - - /// Optional bystander module names. - public var bystanders: [String]? - - /// The platform intended for deployment. - public var platform: Platform - - /// The [semantic version](https://semver.org) of the module, if availble. - public var version: SemanticVersion? - - public init(name: String, platform: Platform, version: SemanticVersion? = nil, bystanders: [String]? = nil) { - self.name = name - self.platform = platform - self.version = version - self.bystanders = bystanders - } - } -} diff --git a/Sources/SymbolKit/SymbolGraph/UnifiedSymbolGraph/GraphCollector.swift b/Sources/SymbolKit/UnifiedSymbolGraph/GraphCollector.swift similarity index 100% rename from Sources/SymbolKit/SymbolGraph/UnifiedSymbolGraph/GraphCollector.swift rename to Sources/SymbolKit/UnifiedSymbolGraph/GraphCollector.swift diff --git a/Sources/SymbolKit/SymbolGraph/UnifiedSymbolGraph/UnifiedSymbol.swift b/Sources/SymbolKit/UnifiedSymbolGraph/UnifiedSymbol.swift similarity index 100% rename from Sources/SymbolKit/SymbolGraph/UnifiedSymbolGraph/UnifiedSymbol.swift rename to Sources/SymbolKit/UnifiedSymbolGraph/UnifiedSymbol.swift diff --git a/Sources/SymbolKit/SymbolGraph/UnifiedSymbolGraph/UnifiedSymbolGraph.swift b/Sources/SymbolKit/UnifiedSymbolGraph/UnifiedSymbolGraph.swift similarity index 100% rename from Sources/SymbolKit/SymbolGraph/UnifiedSymbolGraph/UnifiedSymbolGraph.swift rename to Sources/SymbolKit/UnifiedSymbolGraph/UnifiedSymbolGraph.swift diff --git a/Tests/SymbolKitTests/LineList/LineListTests.swift b/Tests/SymbolKitTests/SymbolGraph/LineList/LineListTests.swift similarity index 100% rename from Tests/SymbolKitTests/LineList/LineListTests.swift rename to Tests/SymbolKitTests/SymbolGraph/LineList/LineListTests.swift diff --git a/Tests/SymbolKitTests/LineList/SemanticVersionTests.swift b/Tests/SymbolKitTests/SymbolGraph/LineList/SemanticVersionTests.swift similarity index 100% rename from Tests/SymbolKitTests/LineList/SemanticVersionTests.swift rename to Tests/SymbolKitTests/SymbolGraph/LineList/SemanticVersionTests.swift diff --git a/Tests/SymbolKitTests/Symbol/SymbolKindTests.swift b/Tests/SymbolKitTests/SymbolGraph/Symbol/SymbolKindTests.swift similarity index 100% rename from Tests/SymbolKitTests/Symbol/SymbolKindTests.swift rename to Tests/SymbolKitTests/SymbolGraph/Symbol/SymbolKindTests.swift